DateTime synchronization with a known but not set time zone

I had a problem with the date and time partitioning:

I am trying to parse a datetime string extracted from a german website. It is specified in the format "day.month.year 24hours: minutes", for example:

01.01.2011 17:00 

And it is always in the German time zone. But here the problem arises:

  • '01.01.2011 17:00' should be analyzed by the DateTime structure from '01.01.2011 16:00' in UTC (here the time zone is CET, without daylight saving time)
  • while '01.06.2011 17:00' should be analyzed by the DateTime structure from '01.01.2011 15:00' in UTC (here the time zone is CEST, with daylight saving time)

I do not know how to achieve this. If I set my local clock to the German time zone and I parse using DateTime.ParseExact and the DateTimeStyles.AssumeLocal and DateTimeStyles.AdjustToUniversal flag, it will be parsed correctly. However, I want any client to parse it regardless of the local clock and time zone. In addition, I do not want to do the time zone itself, because it depends on the date (summer: -2 / winter: -1).

Once I have the datetime in UTC, it would be easy to convert it to any local timezone.

+6
source share
2 answers

Seeing that the task cannot be archived using the WP7 / Silverlight environment, I wrote a small helper that does the job:

 public static class DateTimeHelper { /// <summary> /// Tries to parse the given datetime string that is not annotated with a timezone /// information but known to be in the CET/CEST zone and returns a DateTime struct /// in UTC (so it can be converted to the devices local time). If it could not be /// parsed, result contains the current date/time in UTC. /// </summary> public static bool TryParseCetCest(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result) { // Parse datetime, knowing it is in CET/CEST timezone. Parse as universal as we fix it afterwards if (!DateTime.TryParseExact(s, format, provider, style, out result)) { result = DateTime.UtcNow; return false; } result = DateTime.SpecifyKind(result, DateTimeKind.Utc); // The boundaries of the daylight saving time period in CET and CEST (_not_ in UTC!) // Both DateTime structs are of kind 'Utc', to be able to compare them with the parsing result DateTime DstStart = LastSundayOf(result.Year, 3).AddHours(2); DateTime DstEnd = LastSundayOf(result.Year, 10).AddHours(3); // Are we inside the daylight saving time period? if (DstStart.CompareTo(result) <= 0 && result.CompareTo(DstEnd) < 0) result = result.AddHours(-2); // CEST = UTC+2h else result = result.AddHours(-1); // CET = UTC+1h return true; } /// <summary> /// Returns the last sunday of the given month and year in UTC /// </summary> private static DateTime LastSundayOf(int year, int month) { DateTime firstOfNextMonth = new DateTime(year, month + 1, 1, 0, 0, 0, DateTimeKind.Utc); return firstOfNextMonth.AddDays(firstOfNextMonth.DayOfWeek == DayOfWeek.Sunday ? -7 : (-1 * (int)firstOfNextMonth.DayOfWeek)); } } 

The trick was to analyze without the DateTimeStyles.AssumeUniversal flag (this means that TryParseExact assumes the date is UTC and returns the date converted / adjusted to local), defining it as UTC and then manually setting it to the actual UTC are equivalent.

This follows the DST rules that can be found here . I tested it with all 4 boundary cases just before / after the start / end of daylight saving time. This again showed the importance of testing: I had to change the < operator in DstStart.CompareTo(result) < 0 to <= to give the correct result.

I had the feeling that I was inventing the wheel here (which I do not like to do), but did not want to use a special library for this simple work. I looked at Noda Time, which is a great project, but I think it is not necessary for this.

Hope I can save a little on this little helper. This is intentionally not common to all time zones (if you need it, use lib, such as Noda Time), but for those cases when you have only one fixed single time zone, as in my case.

+1
source

It looks like you know in what time zone you should disassemble it. Assuming .NET 3.5 (and therefore TimeZoneInfo ), you should logically:

  • Analyze it as "local" time (undefined time)
  • Convert this local time to UTC

Unfortunately DateTime makes this a bit more complicated . EDIT: I thought you wanted to parse the parsing using DateTimeStyles.AssumeUniversal , but this results in returning the local DateTime , annoyingly. Basically you want to get a DateTime with the right time so you can use:

 parsed = DateTime.SpecifyKind(parsed, DateTimeKind.Unspecified); 

Then you can get the UTC value with:

 DateTime utc = TimeZoneInfo.ConvertTimeToUtc(parsed, germanTimeZone); 

Please note that you really want to specify an β€œindefinite” date first so that you can convert it to UTC in an arbitrary time zone. You should also remember that local time is ambiguous (occurs twice) or impossible (does not occur at all) due to DST changes.

And yes, it will be much easier in Noda Time when it ends :)

+4
source

Source: https://habr.com/ru/post/896226/


All Articles