简体   繁体   中英

How to parse time into DateTimeOffset in a specific time zone?

Given the 11:00 PM , and knowing that the server is running using UTC time, I need to take that time parse it into a DateTimeOffset from a specific TimeZone.

For example if the docker container's time running the server is 2:00 AM 6/3/2022, I need to be able to check if current date time now in 'Eastern Standard Time' zone, is past 6/2/2022 11:00 PM or before.

To get localized DateTime now I have the following code which works as expected:

TimeZoneInfo tzInfo = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
DateTime nowLocalTime = TimeZoneInfo.ConvertTime(DateTime.Now, tzInfo);
DateTimeOffset targetDateTimeOffset =
                new DateTimeOffset(nowLocalTime,
                tzInfo.GetUtcOffset
                (
                    DateTime.SpecifyKind(nowLocalTime, DateTimeKind.Local)
                ));

I thought I had it figured out for parsing the time into DateTime and then getting the specific DateTimeOffset object, until it hit past midnight on the server. Since the server's time is now 12:01 AM 6/3/2022 when I run the following code:

string timeOfDay = "11:00 AM";
TimeZoneInfo tzInfo = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
DateTime.TryParse(timeOfDay, out DateTime dateTime);
DateTimeOffset targetDateTimeOffset =
                new DateTimeOffset
                (
                    dateTime,
                    tzInfo.GetUtcOffset
                    (
                       DateTime.SpecifyKind(dateTime, 
                       DateTimeKind.Local)
                    )
                );

This now returns 6/3/2022 11:00PM . This makes sense but I need to get DateTimeOffset parsed into the specified TimeZone. Because right now in 'Eastern Standard Time' zone it is 6/2/2022 not 6/3/2022. So basically I need to take 11:00 PM parse it into DateTimeOffset of the provided TimeZone, is that possible?

The .net DateTime type was designed before the age of cloud computing. Where you only had to worry about the machine's .Local time or .Utc . IMHO DateTimeKind.Unspecified should be marked [Obsolete] and any API behaviour which relies on it should instead throw an exception.

TimeZoneInfo.ConvertTime(DateTime, TimeZoneInfo) is a particularly strange function. If you pass a DateTimeKind.Unspecified , or a TimeZoneInfo other than TimeZoneInfo.Local or TimeZoneInfo.Utc , the result is essentially unusable.

IMHO you're better off pushing the problem of parsing and displaying date / time values to the client. Force the client to parse any date time strings in their local timezone. Then either use UTC everywhere, or use DateTimeOffset to store the timezone explicitly.

It's easy enough to get the current time in a specific timezone;

TimeZoneInfo tzInfo = TimeZoneInfo.FindSystemTimeZoneById(zoneId);
DateTimeOffset tzLocalTime = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzInfo);

Unfortunately while you can parse a string and .AssumeLocal or .AssumeUniversal , anything else is barely supported or documented. While you can provide a CultureInfo for parsing non-gregorian calendars, there's no DateTimeOffset.Parse which takes a default TimeZoneInfo parameter. The closest I've found is to check if the string contains an offset, based on this question .

static DateTimeOffset ParseAsDateTimeOffset(string s, TimeZoneInfo defaultTimeZone, CultureInfo culture = null)
{
    if (Regex.IsMatch(s, @"(Z|[+-]\d{2}:\d{2})$"))
        return DateTimeOffset.Parse(s, culture ?? CultureInfo.InvariantCulture);

    var dt = DateTime.Parse(s, culture ?? CultureInfo.InvariantCulture);
    return new DateTimeOffset(dt, defaultTimeZone.GetUtcOffset(dt));
}

While this works for most of the year, I'm not certain if it works properly for time values around DST adjustments. But without an explicit offset, those values are going to be wrong anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM