.Net DateTime with local time and DST

I'm afraid I really don't understand how the .Net class DateTimehandles local timestamps (I live in Germany, so my language is de_DE). Perhaps someone can enlighten me a little; -)

The constructor DateTimecan be called using the parameters of the year, month, etc. Alternatively, a value may be provided DateTimeKind Local, Utcor Unspecified(= default).

Example:

DateTime a = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Local);
DateTime b = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Utc);
DateTime c = new DateTime(2015, 03, 29, 02, 30, 00, DateTimeKind.Unspecified);
DateTime d = new DateTime(2015, 03, 29, 02, 30, 00);

By definition, the values ​​of c and d are identical. But if I compare everything with each other, all four are identical. Checking objects in the VS debugger shows that the value Ticks(s InternalTicks) are the same for everyone. However, the internal values dateDataare different, but the comparison operator is explicitly ignored.

As you can see, I built the value on March 29 of this year, 02:30. This point in time does not exist in our time zone, because it is skipped by switching to summer time. Therefore, I expected to get an exception for constructing the object a, but this did not happen.

In addition, it DateTimehas a method ToUniversalTime()that converts a value that is interpreted as local time for an equivalent UTC value. For testing, I ran the loop as follows:

DateTime dt = new DateTime(2015, 03, 29, 01, 58, 00, DateTimeKind.Local);
DateTime dtEnd = new DateTime(2015, 03, 29, 03, 03, 00, DateTimeKind.Local);
while (dt < dtEnd)
{
    Log(" Localtime " + dt + " converted to UTC is " + dt.ToUniversalTime());
    dt = dt.AddMinutes(1);
}

Result:

Localtime 29.03.2015 01:58:00 converted to UTC is 29.03.2015 00:58:00
Localtime 29.03.2015 01:59:00 converted to UTC is 29.03.2015 00:59:00
Localtime 29.03.2015 02:00:00 converted to UTC is 29.03.2015 01:00:00
Localtime 29.03.2015 02:01:00 converted to UTC is 29.03.2015 01:01:00
Localtime 29.03.2015 02:02:00 converted to UTC is 29.03.2015 01:02:00
...
Localtime 29.03.2015 02:58:00 converted to UTC is 29.03.2015 01:58:00
Localtime 29.03.2015 02:59:00 converted to UTC is 29.03.2015 01:59:00
Localtime 29.03.2015 03:00:00 converted to UTC is 29.03.2015 01:00:00
Localtime 29.03.2015 03:01:00 converted to UTC is 29.03.2015 01:01:00
Localtime 29.03.2015 03:02:00 converted to UTC is 29.03.2015 01:02:00

Thus .Net has no problem converting non-existent timestamps from local time to UTC. In addition, adding a minute to an existing local time stamp is not local and gives a nonexistent time stamp.

64- UTC, 4 , .

, UTC , .

: ( .Net)? DateTimeKind, ? , ( 23:59:60): -)

+4
2

. , DateTimeOffset DateTime ( ), Noda Time , , .

-, MSDN , :

UTC , . . (, -) .

...

(, UTC ) , .

, , . , , API . , 02:00 03:00 , , , , , DST.

BTW, Noda Time, : ZoneLocalMappingResolver, LocalDateTime ZonedDateTime localDateTime.InZone. , InZoneStrictly InZoneLeniently, , DateTime.

:

, UTC , .

, . ( , 3 4.) UTC-to-local . UTC spring -forward DST DST. - DST.

:

( .Net)?

DateTime dt = new DateTime(2015, 03, 29, 01, 58, 00, DateTimeKind.Local);
DateTime dtEnd = new DateTime(2015, 03, 29, 03, 03, 00, DateTimeKind.Local);

// I'm putting this here in case you want to work with a different time zone
TimeZoneInfo tz = TimeZoneInfo.Local; // you would change this variable here

// Create DateTimeOffset wrappers so the offset doesn't get lost
DateTimeOffset dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));
DateTimeOffset dtoEnd = new DateTimeOffset(dtEnd, tz.GetUtcOffset(dtEnd));

// Or, if you're only going to work with the local time zone, you can use
// this constructor, which assumes TimeZoneInfo.Local
//DateTimeOffset dto = new DateTimeOffset(dt);
//DateTimeOffset dtoEnd = new DateTimeOffset(dtEnd);

while (dto < dtoEnd)
{
    Log(" Localtime " + dto + " converted to UTC is " + dto.ToUniversalTime());

    // Math with DateTimeOffset is safe in instantaneous time,
    // but it might not leave you at the desired offset by local time.
    dto = dto.AddMinutes(1);

    // The offset might have changed in the local zone.
    // Adjust it by either of the following (with identical effect).
    dto = TimeZoneInfo.ConvertTime(dto, tz);
    //dto = dto.ToOffset(tz.GetUtcOffset(dto));
}

DateTimeKind, ?

DateTime . , . .NET 2.0 DateTimeKind.

, , . :

DateTime result = DateTime.UtcNow.ToUniversalTime();

DateTime result = DateTime.Now.ToLocalTime();

.NET 2.0 , ToUniversalTime ToLocalTime , . , .

, . , , , .

DateTime now = DateTime.Now;
Assert.True(now.ToUniversalTime().ToLocalTime() == now);

Jon Skeet , .NET Reference coreclr.

, ( 23:59:60): -)

.NET, Noda Time. Win32- API, Windows.

Windows, NTP. , , . :

Real World              Windows
--------------------    --------------------
2015-06-30T23:59:58Z    2015-06-30T23:59:58Z
2015-06-30T23:59:59Z    2015-06-30T23:59:59Z
2015-06-30T23:59:60Z    2015-07-01T00:00:00Z   <-- one sec behind
2015-07-01T00:00:00Z    2015-07-01T00:00:01Z
2015-07-01T00:00:01Z    2015-07-01T00:00:02Z   
2015-07-01T00:00:02Z    2015-07-01T00:00:02Z   <-- NTP sync
2015-07-01T00:00:03Z    2015-07-01T00:00:03Z

2 , . , . - . , - .

, . , , ( ).

API API 59 . , , , .

DateTime.Parse("2015-06-30T23:59:60Z")

. , (2015-06-30T23:59:59Z), (2015-07-01T00:00:00Z).

+5

, DateTime .NET - , , , , ..

DateTimeOffset, offset. DateTimeOffset , , . . - , . , DST .

NodaTime

+3

All Articles