39

How do I convert datetime to timestamp using C# .NET (ignoring the current timezone)?

I am using the below code:

private long ConvertToTimestamp(DateTime value)
{
    long epoch = (value.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
    return epoch;
}

But it returns the timestamp value according to the current time zone & and I need the result without using the current timezone.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
User
  • 391
  • 1
  • 3
  • 5

4 Answers4

76

At the moment you're calling ToUniversalTime() - just get rid of that:

private long ConvertToTimestamp(DateTime value)
{
    long epoch = (value.Ticks - 621355968000000000) / 10000000;
    return epoch;
}

Alternatively, and rather more readably IMO:

private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
...

private static long ConvertToTimestamp(DateTime value)
{
    TimeSpan elapsedTime = value - Epoch;
    return (long) elapsedTime.TotalSeconds;
}

EDIT: As noted in the comments, the Kind of the DateTime you pass in isn't taken into account when you perform subtraction. You should really pass in a value with a Kind of Utc for this to work. Unfortunately, DateTime is a bit broken in this respect - see my blog post (a rant about DateTime) for more details.

You might want to use my Noda Time date/time API instead which makes everything rather clearer, IMO.

Daniel
  • 331
  • 3
  • 10
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Prefer the second one too. The Op didn't say what he wanted it for but is the output equatable to what SqlServer would generate when creating a timestamp if you converted it to binary? Also why the cast to long, haven't fired up VS to check but does TotalSeconds not return a long? – Bronumski Mar 21 '12 at 23:32
  • @Bronumski: No, it returns a `double`. I don't know whether it's comparable, I'm afraid - I don't know what SQL Server does. – Jon Skeet Mar 22 '12 at 06:43
  • SQL Server has 0 = 1900-01-01 00:00:00.000, according to me lame test of creating a datetime and stuffing numbers into it. Adding 1 adds 1 day. Adding 0.5 adds 12 hours. The value can be less than 0 for years before 1900. – Brian Mar 22 '12 at 14:35
  • @Brian: Right, in that case you'd need to tweak it - use a different epoch, and take TotalDays instead. – Jon Skeet Mar 22 '12 at 14:36
  • @JonSkeet we really need to use `new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)` to get `Epoch` correctly as DateTime wothout a `Kind` corresponds to user local `TimeZone` – Arash Milani Jun 01 '13 at 10:43
  • 1
    @A rash: Yes, that's better - although it's still not quite enough, as the kind isn't taken into account when subtracting. Also, an unspecified kind isn't the same as local - it's all a bit nuts. My Noda Time library deals with this more clearly, IMO :) – Jon Skeet Jun 01 '13 at 12:38
  • 2
    @ArashMilani - You might be able to adjust the above code to work with `Local` kinds, but there's no way to make it work with `Unspecified` kind since it doesn't know anything about how it relates to UTC. And since `Local` only comes from `DateTime.Now`, where you could have just used `DateTime.UtcNow`, then there really isn't any benefit to doing this with other kinds than `Utc`. I can attest to NodaTime being a much better solution. See also [this blog post](http://codeofmatt.com/2013/04/25/the-case-against-datetime-now/) I wrote. – Matt Johnson-Pint Jun 01 '13 at 15:18
9

I'm not exactly sure what it is that you want. Do you want a TimeStamp? Then you can do something simple like:

TimeStamp ts = TimeStamp.FromTicks(value.ToUniversalTime().Ticks);

Since you named a variable epoch, do you want the Unix time equivalent of your date?

DateTime unixStart = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc);
long epoch = (long)Math.Floor((value.ToUniversalTime() - unixStart).TotalSeconds);
Jensen
  • 3,498
  • 2
  • 26
  • 43
  • DateTime unixStart = DateTime.SpecifyKind(new DateTime(1970, 1, 1), DateTimeKind.Utc); long epoch = (long)Math.Floor((value.ToUniversalTime() - unixStart).TotalSeconds); this also returns the same result as that of my code... – User Mar 21 '12 at 23:18
  • Then I don't understand what's wrong with your code. I use this in production code to get the Unix timestamp (which is UTC) and as far as I know it works. No matter which timezone the `value` is in, I always get the correct corresponding UTC time. – Jensen Mar 22 '12 at 05:58
  • If you just want the epoch time, corresponding to the same timezone as the original value, then the code posted by Jon Skeet is correct. – Jensen Mar 22 '12 at 06:11
2

Find timestamp from DateTime:

private long ConvertToTimestamp(DateTime value)
{
    TimeZoneInfo NYTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
    DateTime NyTime = TimeZoneInfo.ConvertTime(value, NYTimeZone);
    TimeZone localZone = TimeZone.CurrentTimeZone;
    System.Globalization.DaylightTime dst = localZone.GetDaylightChanges(NyTime.Year);
    NyTime = NyTime.AddHours(-1);
    DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0).ToLocalTime();
    TimeSpan span = (NyTime - epoch);
    return (long)Convert.ToDouble(span.TotalSeconds);
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Vivekveer
  • 29
  • 3
1

JonSkeet has a good answer but as an alternative if you wanted to keep the result more portable you could convert the date into an ISO 8601 format which could then be read into most other frameworks but this may fall outside your requirements.

value.ToUniversalTime().ToString("O");
Bronumski
  • 14,009
  • 6
  • 49
  • 77