16

When trying to convert date/time from string to DateTime, I'm not getting the correct value.

DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ",    CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

And my result is 2012-08-09 8:51:14 PM. Why is it being offset? I just want it to be the same value going in.

u84six
  • 4,604
  • 6
  • 38
  • 65

5 Answers5

25

You are parsing the UTC date but the DateTime.Kind is local. You should parse with DateTimeStyles.AdjustToUniversal to mark the Kind as Utc.

        DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);

        Trace.WriteLine(testDate);  //  8/9/2012 8:51:14 PM
        Trace.WriteLine(testDate.ToString()); //  8/9/2012 8:51:14 PM
        Trace.WriteLine(testDate.ToUniversalTime()); //  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.Kind); // Local

       testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

        Trace.WriteLine(testDate);//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.ToString());//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.ToUniversalTime());//  8/10/2012 12:51:14 AM
        Trace.WriteLine(testDate.Kind); // Utc
John Sobolewski
  • 4,512
  • 1
  • 20
  • 26
  • Note: Steve hit the nail on the head. Notice how after changing to "AdjustToUniversal" it prints as UTC by default... and when asked for as "ToUniversal". Basically what you where doing was getting the data and it was parsing the UTC time into a local time (marking it as local time)... by switching the style you said parse this and mark it as UTC. – John Sobolewski Oct 08 '12 at 18:38
  • Ok, so the debugger is translating it based on my server. Hmm, so you use trace for debugging because of this? – u84six Oct 08 '12 at 18:59
  • So even though it comes in as universal, I will have to convert it to universal if I want to display it? Strange implementation, but I guess I can deal with it. – u84six Oct 08 '12 at 19:03
  • The debugger is likely translating what you see utilizing ToString which is much more usefull than whatever number it stores internally to represent a time/kind... etc... – John Sobolewski Oct 08 '12 at 19:46
10

Aware this is an answer many years later, but came across this today and once I worked out my problem wanted to add some context I didn't see in other answers.

Going back to the OPs code snippet the reason it doesn't do what the OP expected of taking a UTC time string and storing it as a UTC DateTime is because the DateTimeStyles.AssumeUniversal only specifies that the input string is a UTC string. By default C# will create DateTime's as a DateTimeKind.Local. This was pointed out in another answer. This means the time is converted from UTC to Local time.

To make sure that your end result ends up being a UTC DateTime you need to use the DateTimeStyles of DateTimeStyles.AdjustToUniversal. This was also mentioned in other answers. However, if your input string doesn't have an obvious timezone then it may be assumed to be local and then converted from Local to UTC.

Luckily DateTimeStyles is actually a flag enum meaning we can use both the above options at the same time. E.g:

DateTime testDate = DateTime.ParseExact("2012-08-10T00:51:14.146Z", "yyyy-MM-ddTHH:mm:ss.fffZ",    CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal);
MarkOwen320
  • 121
  • 1
  • 7
  • 1
    `DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal` working! And `testDate.Date.Kind` is also good -> `DateTimeKind.Utc` – marbel82 Dec 11 '21 at 18:18
5

You should use DateTimeStyles.AdjustToUniversal. The input DateTime is already universal, and the AdjustToUniversal enum option will convert the input to local time though you will get a resultant Kind of DateTimeKind.Unspecified.

Steve Danner
  • 21,818
  • 7
  • 41
  • 51
3

What is your server timezone, if you use AssumeUniversal it will convert your input time to UTC time.

You probably in EST then.

HOKBONG
  • 795
  • 7
  • 17
2

I propose simply that you want to use .AssumeLocal instead of .AssumeUniversal.

You have a time stamp with unknown time zone, and if you know that the time stamp refers to an event that happened in your local time zone, then you should tell the parse to assume that the time stamp is local to you (i.e. in your time zone).

By using .AssumeUniversal, you are instructing the parser to treat the time stamp as if it was a UTC time stamp, which when you display it using your local time zone, it's automatically offset by that amount.

Edit:

One important thing: The capital "Z" in the time stamp suggests it is a UTC time stamp, which means you do want to treat it as Universal. If you want to treat it as a local time stamp, you should remove the Z from the time stamp and the corresponding parse string.

Reference: http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx#KSpecifier

Community
  • 1
  • 1
JYelton
  • 35,664
  • 27
  • 132
  • 191