none
DateTime.Ticks bug?

    Question

  • Hi.

     

    I'm having a problem with DateTime.Ticks since last day saving hour change. Here's a code snippet to show the problem:

     

    Code Snippet
            public void DateTimeBug()
            {
                DateTime dt = DateTime.Now;
                long t1 = dt.Ticks;
                dt = dt.ToUniversalTime();
                long t2 = dt.Ticks;
                long t3 = t2 - t1;
                Console.WriteLine(t3);
                //t3 SHOULD be 0, but it displays -36000000000!!
            }

     

    The DateTime instance is the same, being a local time (in my case, GMT timezone) or UTC time. The value for Ticks property should be always the same. Am I right?

     

    Thanks.

    Tiago

    Monday, April 02, 2007 11:35 AM

Answers

  • The thing is, assuming DST without temporal changes, "12:00:00, January 1, 0001" UTC was actually at the same time as "12:00:00, January 1, 0001" Local Lisbon Time, because it was Winter Time, when Local Lisbon Time is GMT (it's GMT + 1 during Summer Time).

    So the number of ticks in either UTC or Local Lisbon Time should be equal, right?

     

     Btw, I'm a different Tiago from the other guy that originally made this post. I just have the same name and the same bug... Sad

     

    Quoting Peter Ritchie:

    DateTime.Ticks is documented as "number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001".  That is 1-Jan-0001 local time.  If you convert your DateTime to UTC, Ticks will then be number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 UTC.  Potentially different that 1-Jan-0001 local time, ergo the two Ticks values will be different.

    Tuesday, April 03, 2007 2:49 PM

All replies

  • DateTime is a ValueType data type, so "instance" is somewhat trickier than Reference Types. When you re-assign dt to UniversalTime, the entire value is swapped out for a new date-time value (the universal time value). Your variable no longer has any knowledge of the original value or the original time zone. Since UTC time = local time - UTC offset, the ticks will not be the same.
    Monday, April 02, 2007 5:18 PM
  • It is not a bug.

    "The UniversalTime does not switch to summer time",

    http://wwp.greenwichmeantime.com/

     

    In London, we just moved to the summer time. It is 18:30, but the UniversalTime  is 17h30.

     

    Regards

     

    Monday, April 02, 2007 5:33 PM
  • If you live in the GMT timezone, there is one hour difference between local time and UTC time when daylight savings time is in effect.  That's exactly what you get back.
    Monday, April 02, 2007 5:46 PM
    Moderator
  • You're right when you say the entire value is replaced for a new datetime value. But both values (the old and the new ones) should be the same instant in time. The intrinsic value of the datetime is the same, being it in London or Dubai, GMT with daylight saving or UTC, it doesn´t matter. What changes is the way the datetime value is represented.

     

    That's why, I think, the Ticks property should be immutable.

     

    Thanks for your response.

     

    Tuesday, April 03, 2007 9:06 AM
  • Hello folks,

     

      I guess there is a bit of confusion regarding this post. Lets all think about the moment when the local time change takes place:

      It's now 0:59:59 AM, imagine DateTime.Now.Ticks returns A.

      After a second it's now 2:00:00 AM, if DateTime.Now.Ticks returns A + 10000000 where do these 10000000 ticks come from? Should the Ticks conversion of a DateTime be considered a serialization of the DateTime value? I mean, this way we can't really use the Ticks property to count time.

      Imagine if I wanted to know how many hours passed between two events? If I use Ticks to compare them I can have +1h or -1h if a DST change takes place between the two events. Should we use a DateTime2 - DateTime1 operation and work with the TimeSpan instead?

     

      Regards,

      Tiago Dias

       http://ptsoft.net/tdd/

    Tuesday, April 03, 2007 10:50 AM
  • You're overlooking the DateTime.Kind property.  For example:

          DateTime dt = DateTime.Now;
          Console.WriteLine(dt.Kind.ToString());
          dt = dt.ToUniversalTime();
          Console.WriteLine(dt.Kind.ToString());

    outputs:

    Local
    Utc

    As long as you don't change Kind, DateTime.Tick is fine as a clock.
    Tuesday, April 03, 2007 11:34 AM
    Moderator
  • I think you didn't get it yet. There's 2 different things:

    1. the time instant
    2. the representation of that instant

    The first should be independent of the second. Imagine the time instant Neil Armstrong landed the moon. It was  20:17:39 UTC on July 20, 1969. In Lisbon, Portugal, it was 21:17:29. Does that mean Armstrong landed the moon twice? Of course not. Let's see it in action:

     

    Code Snippet

            public void ArmstrongTimeInstant()
            {
                //the time instant Armstrong landed the moon, Kind = UTC
                DateTime armstrongUTCTime = new DateTime(1969, 7, 20, 20, 17, 39, DateTimeKind.Utc);
                Console.WriteLine(string.Format("Armstrong UTC landing Time: {0}", armstrongUTCTime));
                //the ticks value for this instant
                long armstrongUTCTicks = armstrongUTCTime.Ticks;
                Console.WriteLine(string.Format("Armstrong UTC landing Time in ticks: {0}", armstrongUTCTicks));

                //the SAME time instant, now on my local time zone (London, Lisbon, GMT)
                DateTime armstrongLocalTime = armstrongUTCTime.ToLocalTime();
                Console.WriteLine(string.Format("Armstrong Local (Lisbon, Portugal) landing Time: {0}", armstrongLocalTime));
                //the ticks value for this instant
                long armstrongLocalTicks = armstrongLocalTime.Ticks;
                Console.WriteLine(string.Format("Armstrong Local (Lisbon, Portugal) landing Time in ticks: {0}", armstrongLocalTicks));

                //armstrongUTCTicks and armstrongLocalTicks SHOULD be equal, but...
                long ticksDiff = armstrongUTCTicks - armstrongLocalTicks;
                Console.WriteLine(string.Format("Ticks diff: {0}", ticksDiff));
            }

     

     Output:

     Armstrong UTC landing Time: 20-07-1969 20:17:39
    Armstrong UTC landing Time in ticks: 621214138590000000
    Armstrong Local (Lisbon, Portugal) landing Time: 20-07-1969 21:17:39
    Armstrong Local (Lisbon, Portugal) landing Time in ticks: 621214174590000000
    Ticks diff: -36000000000

     

    The rule should be "The Ticks value should be immutable, independently of the TimeZone we're in, or the date format, or whatever else.".

     

    Another interesting thing is: in Java and Javascript, this is true. If you go here http://msdn2.microsoft.com/en-us/library/cd9w2te4.aspx you can see this:

     

    "dateVal

    Required. If a numeric value, dateVal represents the number of milliseconds in Universal Coordinated Time between the specified date and midnight January 1, 1970. If a string, dateVal is parsed according to the rules in the parse method. The dateVal argument can also be a VT_DATE value as returned from some ActiveX® objects.

    "

    Note that ticks is counted from January 1, 1970 UTC. In .net DateTime.Ticks, the value is (http://msdn2.microsoft.com/en-us/library/system.datetime.ticks.aspx):

     

    "The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001."

     

    Note the lack of the UTC part... That means, the Ticks property is counted from 12:00:00 January 1, 0001 Local Time. And that's the bug.

     

    Regards,

    Tiago

    Tuesday, April 03, 2007 12:16 PM
  • Please explain your interpretation of the Kind property.
    Tuesday, April 03, 2007 12:43 PM
    Moderator
  • DateTime.Ticks is documented as "number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001".  That is 1-Jan-0001 local time.  If you convert your DateTime to UTC, Ticks will then be number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 UTC.  Potentially different that 1-Jan-0001 local time, ergo the two Ticks values will be different.
    Tuesday, April 03, 2007 2:18 PM
    Moderator
  • Yes Peter, you're right. Documentation says "number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001", so it is not a bug... It's this way "by design". blah

     

    The point here is that the Ticks property can't be used as a datetime instance "unique identifier"... although it SHOULD! (IMHO, of course)

     

    That's a bit frustrating. I programmed in java for years, and I'm not used to this kind of behavior when working with Dates. I thing that this leads to annoying bugs.

     

    I'll have to do a workaround to solve my problem, because I need to convert a .net DateTime into a Javascript Date. Something like "if day saving mode then datetime = datetime.addHours(-1)"... not pretty...

     

    thank you all

    Tiago

    Tuesday, April 03, 2007 2:38 PM
  • from BOL:

     

    DateTime.Kind Property 
    Gets a value that indicates whether the time represented by this instance is based on local time, Coordinated Universal Time (UTC), or neither.
     
    Whether based on local time or UTC, the intrinsic value should be the same. Don't you think?
     
    thanks,
    Tiago
    Tuesday, April 03, 2007 2:39 PM
  • DateTime will be expanded in the next release of .NET (see http://blogs.msdn.com/bclteam/archive/2005/03/15/396440.aspx).  But, the fact remains that Ticks must be rooted to some timezone.  Regardless of which the BCL designers pick they'll not please everyone.  Ticks could be a unique identifier, as you suggest; but I don't see the point.  You're then overloading Ticks for something it really should be used for.  If you want a unique identifier, regardless of timezone, use ToString("o").
    Tuesday, April 03, 2007 2:45 PM
    Moderator
  • The thing is, assuming DST without temporal changes, "12:00:00, January 1, 0001" UTC was actually at the same time as "12:00:00, January 1, 0001" Local Lisbon Time, because it was Winter Time, when Local Lisbon Time is GMT (it's GMT + 1 during Summer Time).

    So the number of ticks in either UTC or Local Lisbon Time should be equal, right?

     

     Btw, I'm a different Tiago from the other guy that originally made this post. I just have the same name and the same bug... Sad

     

    Quoting Peter Ritchie:

    DateTime.Ticks is documented as "number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001".  That is 1-Jan-0001 local time.  If you convert your DateTime to UTC, Ticks will then be number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 UTC.  Potentially different that 1-Jan-0001 local time, ergo the two Ticks values will be different.

    Tuesday, April 03, 2007 2:49 PM
  • If you're converting from/to other languages I would suggest using a standard format (like RFC1123) and use that to pass date time from one object type to another: DateTime.ToString("R")
    Tuesday, April 03, 2007 2:54 PM
    Moderator
  • I just read the blog post at http://blogs.msdn.com/bclteam/archive/2005/03/15/396440.aspx. This seems a solution to the problem I described, in particular the section "Robust During Daylight Savings Transitions". This is exactly the issue I described earlier on. Naturally the best practise is to use UTC for all arithmetic. But when conversion between formats, namely to Javascript, like Tiago's problem, the Whidbey fix would help...

    Tuesday, April 03, 2007 2:57 PM