3

I'm inserting records in the data table in c# where conversion of datetime is giving em extra 5 hours.

DateTime.ParseExact("2020-02-19T15:28:36.207Z", "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture);

This gives me 8:28 pm instead of 3:28 pm Here is the response from c#

{2/19/2020 8:28:36 PM}
    Date: {2/19/2020 12:00:00 AM}
    Day: 19
    DayOfWeek: Wednesday
    DayOfYear: 50
    Hour: 20
    Kind: Local
    Millisecond: 207
    Minute: 28
    Month: 2
    Second: 36
    Ticks: 637177409162070000
    TimeOfDay: {20:28:36.2070000}
    Year: 2020```

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
M Usama Alvi
  • 187
  • 1
  • 15

3 Answers3

6

It's converting to local time. If you specify DateTimeStyles.AdjustToUniversal as a final argument, you'll end up with a value with a Kind of Universal and a time of 3:28pm:

var result = DateTime.ParseExact(
    "2020-02-19T15:28:36.207Z",
    "yyyy-MM-ddTHH:mm:ss.fffZ",
    CultureInfo.InvariantCulture,
    DateTimeStyles.AdjustToUniversal);

Note that the enum value name is somewhat unfortunate here, as you're not really adjusting - you're saying that you don't want an adjustment to local time. From the docs:

If the input string denotes a UTC time, through a time zone specifier or AssumeUniversal, no conversion occurs.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

The DateTime is formatted in ISO 8601 in UTC (with the "Z" suffix). Parsing it back in Roundtrip mode (DateTime.Parse("...", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind)) will automatically handle it correctly:

Strings that are passed to the Parse, TryParse, ParseExact, and TryParseExact methods of DateTime and DateTimeOffset can be parsed by using the "O" or "o" format specifier if they are in one of these formats. In the case of DateTime objects, the parsing overload that you call should also include a styles parameter with a value of DateTimeStyles.RoundtripKind. Note that if you call a parsing method with the custom format string that corresponds to the "O" or "o" format specifier, you won't get the same results as "O" or "o". This is because parsing methods that use a custom format string can't parse the string representation of date and time values that lack a time zone component or use "Z" to indicate UTC. [my emphasis]

What's going wrong in the code: By specifying "Z" as a character in your format string, you are matching the character "Z" literally (uppercase "Z" is not a custom format specifier), which leads to throwing away the time zone information and depending on the DateTimeStyles parameter to interpret the time zone. It's possible to pick the right value for this, but the better option is to use the round-trip format mode which already knows how to take care of this.

Edit: annoyingly, DateTime.ParseExact( datestr, "o", CultureInfo.InvariantCulture ) (parsing with "o") doesn't work, but parsing with the DateTimeStyles.RoundtripKind parameter does. Thanks to @SirRufo for pointing this out.

Jesper
  • 7,477
  • 4
  • 40
  • 57
1

You can change your date time format string to yyyy-MM-ddTHH:mm:ss.fff'Z' and get a time without time zone offset, because Z format specifier is for offset between current time zone and UTC:

the "z" custom format specifier represents the signed offset of the local operating system's time zone from Coordinated Universal Time (UTC), measured in hours.

After placing it into quotes you'll get a correct result

var result = DateTime.ParseExact("2020-02-19T15:28:36.207Z", "yyyy-MM-ddTHH:mm:ss.fff'Z'", CultureInfo.InvariantCulture); //returns 2/19/2020 3:28:36 PM

Extra 5 hours means that your OS time zone is UTC+5

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66