Unix时间戳记:使用ToUnixTimeMilliseconds和TimeSpan.TotalMilliseconds

时间:2018-11-15 21:25:40

标签: c# datetime unix-timestamp

我正在将DateTime转换为Unix时间。据我了解,这两种方法应该返回相同的结果。

选项1

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = dtfoo2.ToUnixTimeMilliseconds();

选项2

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = (Int64)(dtfoo2.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds;

选项1返回1287525600000,选项2返回1287529200000。

为什么我得到不同的结果?

2 个答案:

答案 0 :(得分:3)

通知:我现在使用的是UTC + 9,问题的根源是时区偏移量,因此请理解,我看到的Unix时间可能与您自己的时间有所不同。


区别在于您如何处理日期对象。根据由此产生的差异,我假设您的时区为CET(或者您使用的是rextester,我相信是在德国)。

考虑以下代码:

var dtfoo = new DateTime(2010, 10, 20);
var dtfoo2 = new DateTimeOffset(dtfoo);
var dtfoo3 = dtfoo2.ToUniversalTime();
  1. 第一行使用DateTimeKind of "Unspecified"创建一个DateTime
  2. 第二行从中创建一个DateTimeOffset对象。由于未指定DateTimeKind,因此使用了UTC的系统时间偏移。
  3. 第三行将此日期转换为UTC。

为{2引用documentation

  

如果DateTime.Kind的值为DateTimeKind.Local或DateTimeKind.Unspecified,则将新实例的DateTime属性设置为等于dateTime,并且将Offset属性设置为等于本地系统当前时区的偏移量。

现在让我们写出1-3的往返格式日期字符串:

2010-10-20T00:00:00.0000000
2010-10-20T00:00:00.0000000+09:00
2010-10-19T15:00:00.0000000+00:00

我使用的是UTC + 9,因此DateTimeOffset的创建正确,偏移量为+ 9h。将其转换为通用后,我们将在19日下午3点到达。不幸的是,这导致.ToUnixTimeMilliseconds()的输出为1287500400000,即2010-10-19T15:00:00Z。该值已取决于机器的时区。

因此,现在让我们看一下第二个示例:

DateTime dtfoo = new DateTime(2010, 10, 20);
DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo).ToUniversalTime();
long afoo = (Int64)(dtfoo2.Subtract(new DateTime(1970, 1, 1))).TotalMilliseconds;

好的,我们将其分为不同的部分,以便我们可以看到系统认为它们代表的时间(记住我在UTC + 9中):

  1. new DateTime(2010, 10, 20).ToString("o")-2010-10-20T00:00:00.0000000
  2. new DateTimeOffset(dtfoo).ToString("o")-2010-10-20T00:00:00.0000000 + 09:00
  3. new DateTimeOffset(dtfoo).ToUniversalTime()-2010-10-19T15:00:00.0000000 + 00:00
  4. new DateTime(1970, 1, 1).ToString("o")-1970-01-01T00:00:00.0000000

因此,您正在有效地执行此计算:

(DateTimeOffset.Parse("2010-10-19T15:00:00.0000000+00:00") - DateTime.Parse("1970-01-01T00:00:00.0000000")).TotalMilliseconds

这将输出1287532800000,它等于2010-10-20T00:00:00Z。由于减法是如何完成的,因此您可以得到正确的结果:

  1. DateTimeimplicitly castDateTimeOffset,相当于new DateTimeOffset(DateTime.Parse("1970-01-01T00:00:00.000000"))-这意味着两个输入日期都经过相同的时区更改。
  2. 通过调用DateTime的{​​{1}}属性,将subtraction的两个日期都转换为DateTimeOffset对象。

那么我们如何解决您的原始示例?通过构造.UtcDateTime时指定偏移量,我们可以从方程式中取出本地时区偏移量:

DateTimeOffset

现在,这给了我们与上一个测试DateTime dtfoo = new DateTime(2010, 10, 20); DateTimeOffset dtfoo2 = new DateTimeOffset(dtfoo, TimeSpan.Zero).ToUniversalTime(); long afoo = dtfoo2.ToUnixTimeMilliseconds(); 中相同的值。如果通过使用1287532800000简化此操作,则应确认我们走在正确的轨道上:

DateTimeOffset.Parse

我们可以看到它也输出Console.WriteLine(DateTimeOffset.Parse("2010-10-20T00:00:00Z").ToUnixTimeMilliseconds());

因此,总而言之,您的问题源于1287532800000构造函数如何使用DateTimeKind DateTimeOffset(datetime)Unspecified处理日期。根据您机器的时区,它会使您产生的通用时间产生偏差。这会导致不正确的Unix时间偏移。要解决该问题,只需按照我上面描述的方法之一创建您的Local

答案 1 :(得分:0)

差异可能是因为ToUnixTimeMilliseconds不需要花费leap秒的时间。

文档内容如下:

https://docs.microsoft.com/en-us/dotnet/api/system.datetimeoffset.tounixtimemilliseconds?view=netframework-4.7.2

  

Unix时间表示自此以来经过的秒数   1970-01-01T00:00:00Z(世界标准时间1970年1月1日,上午12:00)。它不是   考虑leap秒。此方法返回的数量   Unix时间中的毫秒数。

TimeSpan.TotalMilliseconds并未提及。

https://docs.microsoft.com/en-us/dotnet/api/system.timespan.totalmilliseconds?view=netframework-4.7.2

  

此属性将该实例的值从刻度线转换为   毫秒。此数字可能包括整数和分数   毫秒。