Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange Behavior Converting Unix Time to DateTime in .NET

I've got a problem with the Italian Daylight Saving Time. Converting the unix 687481200000 in .NET looks unpredictable (sure I'm missing something).

As you can see typing in your browser console:

console.log(new Date(687481200000).toLocaleString('it-IT', {timeZone: 'Europe/Rome', timeZoneName: 'short'}));

the unix timestamp value of 687481200000 should return the italian date 1991-10-15 00:00:00 (in Italy the date is typed 15/10/1991 but we are always talking about 15 October).

Now I want you to take a look at this snippet

https://dotnetfiddle.net/jKShoE

When I run it in the browser using Compiler: .NET 6 I get

Data e ora italiane: 10/15/1991 00:00:00

changing the Compiler to .NET 4.7.2

https://dotnetfiddle.net/GV7FYD

I got

Data e ora italiane: 10/15/1991 1:00:00 AM

And If I copy that code in a new .NET 6 project in visual studio 2022

Data e ora italiane: 15/10/1991 01:00:00

Someone can explain me why? Is there a way to get the correct hour 00:00:00 without using external libraries (like NodaTime)?

Ps: working on Windows 10.0.19045 Build 19045, Italian localization

Edit: here's the code from the fiddle.

using System;

public class Program
{
    public static void Main()
    {
        long unixMilliseconds = 687481200000;

        DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(unixMilliseconds);

        TimeZoneInfo italianTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");

        DateTimeOffset italianDateTimeOffset = TimeZoneInfo.ConvertTime(dateTimeOffset, italianTimeZone);

        DateTime italianDateTime = italianDateTimeOffset.DateTime;

        Console.WriteLine("Data e ora italiane: " + italianDateTime);
    }
}

Edit 2: Revised code

I had to dig deeper and found more answers once I searched for TimeZoneInfo.AdjustmentRule on stackoverflow.

using System;
using System.Linq;
public class Program
{
    public static void Main()
    {
        // A representation for UTC 14/10/1991 23:00:00 +00:00  
        long unixMilliseconds = 687481200000;
        // Looking at epochconverter.com 
        // UTC 14/10/1991 23:00:00 +00:00  
        // corresponds to italian 15 october 1991 00:00:00 GMT+01:00

        // Store the UTC time in dateTimeOffset
        DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds(unixMilliseconds);
        Console.WriteLine(dateTimeOffset);
        // .NET 6:       10/14/1991 23:00:00 +00:00
        // .NET 4.7.2:   10/14/1991 11:00:00 PM +00:00


        // Applying the following pattern:
        // https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset.fromunixtimemilliseconds?view=net-8.0#remarks

        // I was wrong, my current timezone is "W. Europe Standard Time" but the nature of the problem remains unchanged.
        // I retrieved my TimeZoneInfo this way:
        TimeZoneInfo italianTimeZone = TimeZoneInfo.Local;
        Console.WriteLine("TimeZoneInfo.Local.Id: " + TimeZoneInfo.Local.Id); // I got here W. Europe Standard Time

        // so retrieving it by ID to make it work on fiddler
        italianTimeZone = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
        Console.WriteLine("TimeZoneInfo Id: " + italianTimeZone.Id); // Once again to check

        Console.WriteLine("TimeZoneInfo: " + italianTimeZone.ToString());
        // .NET 6:       (UTC+01:00) Central European Time (Berlin)
        // .NET 4.7.2:   (UTC+01:00) Amsterdam, Berlino, Berna, Roma, Stoccolma, Vienna


        Console.WriteLine("Daylight : " + italianTimeZone.IsDaylightSavingTime(dateTimeOffset));
        // fiddler .NET 6 :   False
        // fiddler .NET 4.7 : True
        // "my PC" .NET 6 :   True

        // Now look at this:
        Console.WriteLine("Rules count: " + italianTimeZone.GetAdjustmentRules().Length);
        // fiddler .NET 6 :   79
        // fiddler .NET 4.7 : 1
        // "my PC" .NET 6 :   1

        // Only in the fiddler .NET 6 the full set of rules is available.
        
        // BONUS
        string iso8601 = "1991-10-14T23:00:00Z";
        long myDate = DateTimeOffset.Parse(iso8601).ToUnixTimeMilliseconds();
        Console.WriteLine("My date: " + myDate); // My date: 687481200000 on every system
    }
}

I am still not clear on how and who manages the time zone database, whether it's the operating system or the .NET framework, but it seems to me that this configuration is complex enough to make me opt for the use of NodaTime (I don't want to mess with the machine configuration in order to get valid results).

You can see the enumeration of the daylight rules here: Showing Transition Times

like image 725
Akrax Avatar asked Oct 24 '25 15:10

Akrax


1 Answers

It'a a matter of daylight time:

In .Net 6 : https://dotnetfiddle.net/qP1icN

Daylight : False
Data e ora italiane: 10/15/1991 00:00:00

In .Net 4.7.2 : https://dotnetfiddle.net/7eBu3y

Daylight : True
Data e ora italiane: 10/15/1991 1:00:00 AM

People get paid to handle this kind of problem worldwide...

like image 53
gobes Avatar answered Oct 26 '25 05:10

gobes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!