C#和JavaScript之间时间差异的解释

11
这基于在C#中计算自1970年以来的毫秒数会产生与JavaScript不同的日期C#版本的Javascript Date.getTime()
对于所有这些计算,请假定它们是在中央标准时间进行的,因此比协调世界时(UTC)晚6小时(此偏移量稍后将再次出现)。
我知道JavaScript的Date对象基于Unix纪元(1970年1月1日午夜)。所以,如果我这样做:
//remember that JS months are 0-indexed, so February == 1
var d = new Date(2014,1,28);
d.getTime();

我的输出将是:

1393567200000

这代表自 Unix 纪元以来的毫秒数。这很好。在相关问题中,人们想要将这个功能翻译成 C#,而“天真”的实现通常看起来像这样:
//the date of interest in UTC
DateTime e = new DateTime(2014, 2, 28, 0, 0, 0, DateTimeKind.Utc);
//the Unix Epoch
DateTime s = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
//the difference between the two
TimeSpan t = (e - s);
var x = t.TotalMilliseconds;
Console.WriteLine(x);

输出结果如下:

1393545600000

这是21,600,000毫秒,即6小时的差异:与进行这些计算的时区的UTC准确偏移量。

为了使C#实现与JavaScript匹配,这是实现方式:

//DateTimeKind.Unspecified
DateTime st=new DateTime(1970,1,1);
//DateTimeKind.Unspecified
DateTime e = new DateTime(2014,2,28);
//translate e to UTC, but leave st as is
TimeSpan t= (e.ToUniversalTime()-st);
var x = t.TotalMilliseconds;
Console.WriteLine(x);

我希望得到与JavaScript输出匹配的输出:

1393567200000

我还没有找到为什么我们要将代表Unix纪元的DateTime保留为Unspecified以匹配JavaScript的解释。我们不应该使用DateTimeKind.Utc获得正确的结果吗?我没有理解哪些细节?这对我来说是一个纯粹学术性的问题,我只是想知道为什么会这样。

2个回答

7
正如你所指出的,.getTime()返回的是自1970年1月1日00:00:00 UTC以来的毫秒数。
这意味着在计算中,.getTime包含了与UTC的偏移量,正如你所注意到的那样。
为了让C#代码反映出这一点,从中减去的时间必须包含时区信息,而1970年1月1日00:00:00则必须是UTC时间。
通过几个例子可能更容易理解。给定:
DateTime e = new DateTime(2014, 2, 28, 0, 0, 0);
DateTime s = new DateTime(1970, 1, 1, 0, 0, 0);
  1. e - s 是不正确的,因为 s 不是一个 UTC 时间。
  2. e.ToUniversalTime() - s.ToUniversalTime() 是不正确的,因为 e 不再包括来自 UTC 的偏移量(就像 JavaScript 中的计算一样)
  3. e.ToUniversalTime() - s 正确的,因为我们使用了 UTC 时间,并且要减去的时间包括了来自 UTC 的偏移量。

当我直接处理 DateTime.Ticks 时,这对我来说更容易看出:

e.Ticks // 635291424000000000
s.Ticks // 621355968000000000

e.Ticks - s.Ticks // 13935456000000000 ("naive" implementation)
e.ToUniversalTime().Ticks - s.Ticks // 13935636000000000 (correct output)

再次强调,最后一个例子满足我们的所有要求。Unix纪元在UTC时间中,而我们正在处理的时间仍保留其原始偏移量。


啊,我没有理解到的关键点是 getTime() 考虑了时区。这很合理。我一直以为所有 JS 的日期计算都是基于 UTC 的。 - Sven Grosen
@ledbutter:当我阅读它时,这也让我感到困惑。谢谢你提出这个好问题 :) - Andrew Whitaker
getTime 不考虑时区。在这里的示例代码中,是 new Date 构造函数考虑了时区。 - Matt Johnson-Pint

2
我知道JavaScript的日期对象是基于Unix纪元(即1970年1月1日午夜)的。内部上,它只是从纪元开始计算的毫秒数。但是当你调用日期构造函数或查看.toString()的输出时,它会使用代码运行所在地的本地时间。
如果你想要以UTC指定输入,那么你必须使用不同的命令:
var ts = Date.UTC(2014,1,28);  // returns a numeric timestamp, not a Date object

var dt = new Date(ts);         // if you want a date object

var s = dt.toUTCString();      // if you want the output to be in UTC

这是否意味着你的第一行代码与原始JavaScript(调用getTime的代码)处于不同的“时间点”?如果数字时间戳不同,那么它们肯定不是相同的“时间点”。 - onefootswill
1
没错。如果OP的时区确实是美国中部时间,那么使用相同的值但是相对于UTC创建的时间点就是不同的。 - Matt Johnson-Pint

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接