Pedro Costa
Pedro Costa

Reputation: 2996

Unix Timestamp in seconds to C# DateTime is not UTC

I am aware that Unix Timestamp are UTC in nature (misleading, this is not true, new Date() will always be on the browser/server timezone, and .getTime() reflects that).

How come when converting to a C# DateTime is is not UTC.

I've converted the date August, 9 2092 to timespamp in seconds (3869074800),

new Date('August, 9 2092').getTime()/1000

or https://codepen.io/pnmcosta/pen/rpvjVp

But when converting to a C# date, it's not UTC (8/8/2092 11:00:00 PM)? Even though the EPOCH has been created as UTC:

using System;

public class Program
{
    public readonly static DateTime EPOCH_UNIX = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    private readonly static double MaxUnixSeconds = (DateTime.MaxValue.ToUniversalTime() - EPOCH_UNIX).TotalSeconds;
    public static void Main()
    {
        Console.WriteLine(FromUnixTimeStamp(3869074800));
    }

    public static DateTime FromUnixTimeStamp(long value)
    {
        return value > MaxUnixSeconds ? EPOCH_UNIX.AddMilliseconds(value) : EPOCH_UNIX.AddSeconds(value);
    }
}

or https://dotnetfiddle.net/ERySea

How best to handle this scenario, bearing in mind that time is not of importance, but the day should be correct?

EDIT 2

Think I may have hacked the date to figure out the offset (updated https://dotnetfiddle.net/ERySea) to:

using System;

public class Program
{
    public readonly static DateTime EPOCH_UNIX = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    private readonly static long MaxUnixSeconds = (long)(DateTime.MaxValue.ToUniversalTime() - EPOCH_UNIX).TotalSeconds;

    public static void Main()
    {
        // date with DST (Daylight savings time), e.g. 08/09/2092 (DD/MM/yyyy) 
        // is stored as, e.g. 3869074800 seconds, from EPOCH_UNIX
        // instead of 3869078400 (UTC, without offsets) as it should be!
        DateTime dt = FromUnixTimeStamp(3869074800);
        Console.WriteLine("Date: {0:dd MMM yyyy HH:mm}", dt);

        // fix DST offset
        if (dt.Hour != 0)
        {
            int offset = 24 - dt.Hour;
            dt = dt.AddHours(offset);
            Console.WriteLine("Offset: {0}", offset);
        }

        // fix century (if date of birth)
        if (dt.Year >= DateTime.UtcNow.Year)
            dt = dt.AddYears(-100);

        Console.WriteLine("Fixed Date: {0:dd MMM yyyy HH:mm}", dt);
    }

    public static DateTime FromUnixTimeStamp(long value)
    {
        return value > MaxUnixSeconds ? EPOCH_UNIX.AddMilliseconds(value) : EPOCH_UNIX.AddSeconds(value);
    }
}

Upvotes: 2

Views: 2580

Answers (2)

phuzi
phuzi

Reputation: 13060

The problem is JavaScript not C#, or more correctly your premise what new Date('August, 9 2092').getTime()/1000 represents.

JavaScript will create a new Date as being in local time zone not UTC. So

new Date('August, 9 2092')

is actually

Sat Aug 09 2092 00:00:00 GMT+0100 (GMT Daylight Time)

Notice the offset? This is actually Fri Aug 08 2092 23:00:00 UTC+0000 so the epoch you get from JavaScript is not what you intended.

You should subtract the timezone offset (in minutes multiplied by 60) to get UTC though.

var date = new Date('August, 9 2092');
var timestamp = date.getTime()/1000 - date.getTimezoneOffset()*60;
// timestamp == 3869078400

EDIT

Rather than fudging the calculation, you'd be better off assuming the timestamp is local...

Change

public readonly static DateTime EPOCH_UNIX = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

to

public readonly static DateTime EPOCH_UNIX = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);

At least then the result is 08 Aug 2092 23:00 Local.

Upvotes: 1

Derek
Derek

Reputation: 145

According to https://www.epochconverter.com/ the UNIX timestamp of 3869074800 is 8/8/2092 11:00:00 PM, so C# is correctly displaying it in GMT. UTC and GMT are... not the same, but for the purposes of a human reading it it's accurate to say that you can treat them as the same.

Your problem lies in how you got the UNIX timestamp of 3869074800.

Upvotes: 1

Related Questions