5

I have date and time strings already in UTC. I need to use those strings to create a DateTime object.

This is the code I'm using. The problem is the time gets converted and my UTC time on the datetime object is no longer correct. I'm giving UTC values so they shouldn't get converted again.

string format = $"{dateFormat}_{timeFormat}";
string value = $"{dateValue}_{timeValue}";

var x = DateTimeOffset.ParseExact(value, format, CultureInfo.CurrentCulture).UtcDateTime;

where dateFormat = "ddMMyy", timeFormat = "HHmmss", dateValue = "191194" and timeValue = "225446".

DenaliHardtail
  • 27,362
  • 56
  • 154
  • 233
  • The issue here is that your DateTimeOffset object will be offset by default to whatever the system timezone offset is. So, if the machine running your code is UTC-4, then .UtcDateTime will be whatever your value is + 4 hours. – Brian Driscoll Oct 06 '15 at 19:45

4 Answers4

11

D Stanley's answer certainly works, but is slightly more complex than you need - if you want a DateTime as the result, you don't need to use DateTimeOffset at all, as DateTime.ParseExact handles DateTimeStyles.AssumeUniversal as well, although you need to specify AdjustToUniversal so that the result is in UTC. (Otherwise it's adjusted to the local time zone automatically - and unhelpfully, IMO, but that's a battle for another day.)

var x = DateTime.ParseExact(
     value, 
     format, 
     CultureInfo.CurrentCulture,  
     DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);

Sample code (that revealed to me the need for DateTimeStyles.AdjustToUniversal):

using System;
using System.Globalization;

class Test
{
    static void Main(string[] args)
    {
        string text = "2015-06-10 20:52:13";        
        string format = "yyyy-MM-dd HH:mm:ss";
        var dateTime = DateTime.ParseExact(
            text,
            format, 
            CultureInfo.InvariantCulture,
            DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
        Console.WriteLine(dateTime);  // 10/06/2015 20:52:13 on my box
        Console.WriteLine(dateTime.Kind); // Utc
    }
}

I'd be careful using CultureInfo.CurrentCulture, by the way - bare in mind the fact that it can affect the calendar system in use as well as format strings etc.

(As a side-note of course, I'd recommend using my Noda Time library instead. In this case I'd probably suggest parsing your time using a LocalTimeFormat, your date using a LocalDateFormat, then adding the results together to get a LocalDateTime that you could then convert to a ZonedDateTime using UTC. Or you could use your existing approach to create a ZonedDateTimePattern or InstantPattern, of course.)

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

This solution also will be helpful if you have your date not as one string. Just use DateTimeKind.Utc as constructor parameter of DateTime:

new DateTime(2020, 05, 07, 18, 33, 0, DateTimeKind.Utc);
Siarhei Kavaleuski
  • 1,450
  • 14
  • 15
4

Use the overload of DateTimeOffset.ParseExact that takes a DateTimeStyles value:

var x = DateTimeOffset.ParseExact(value, 
                                  format, 
                                  CultureInfo.CurrentCulture,  
                                  DateTimeStyles.AssumeUniversal)
                      .UtcDateTime;

Note that the call to UtcDateTime doesn't hurt anything, but the time will already be in UTC time (which is what you want) so it will give you back the equivalent DateTime value. You can just use DateTime.ParseExact as Jon suggests, which has the same overload.

D Stanley
  • 149,601
  • 11
  • 178
  • 240
  • If you just use `.DateTime` in your code above, you end up with a Kind of Unspecified... so you really do need UtcDateTime, or some other trick. – Jon Skeet Oct 06 '15 at 19:54
0

The question specifies the date string sent is UTC, which is fine. If you were not that lucky and were given a datetime to convert but you know the input's timeZoneInfo then you could get the UTC datetime like this. It seems that DateTimeKind.Unspecified is needed.

            var strippedOfType = new DateTime(
                year: input.Year,
                month: input.Month,
                day: input.Day,
                hour: input.Hour,
                minute: input.Minute,
                second: input.Second,
                DateTimeKind.Unspecified
            );

            var utc = TimeZoneInfo.ConvertTimeToUtc(strippedOfType, sourceTimeZoneInfo);
andrew pate
  • 3,833
  • 36
  • 28