为什么DateTime上的独立操作顺序(Add和ToLocalTime / ToUniversalTime)会更改结果? [英] Why does order of independent operations (Add and ToLocalTime/ToUniversalTime) on DateTime changes the outcome?

查看:97
本文介绍了为什么DateTime上的独立操作顺序(Add和ToLocalTime / ToUniversalTime)会更改结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这两行产生的结果相同(结果在我的时区中),这是预期的:

  new DateTime(1970, 1,1).ToLocalTime()。AddHours(10000)// [21.02.1971 17:00:00] 
new DateTime(1970,1,1).AddHours(10000).ToLocalTime()// [ 21.02.1971 17:00:00]

现在,这两行产生两个不同的结果:

 新的DateTime(1970,1,1).ToLocalTime()。AddHours(100000)// [29.05.1981 17:00:00 ] 
新的DateTime(1970,1,1).AddHours(100000).ToLocalTime()// [29.05.1981 18:00:00]

这似乎很奇怪,我不明白为什么会这样。我知道Jon Skeet会争辩说我们根本不应该使用 DateTime ,因为它不够好,而应使用 nodatime ,但是出于好奇,很有趣的是知道为什么会这样。



逻辑上,时间点不会根据操作顺序而改变,并且仍然是同一时间,虽然显然不在C#中。



PS ToUniveralTime 的行为相同,在第二个示例中产生2个不同的结果(减少一小时)。

解决方案

我假设您在英国(我们在UTC呆了冬天,但在夏天改用UTC + 1)。因此,在1970年1月1日午夜,我们使用UTC。




  • new DateTime(1970,1, 1).ToLocalTime()不执行任何操作,除了将 Kind 更改为Local以外,因为DateTime假定我们在UTC中指定了一个时间点。然后,我们增加10,000小时,这使我们到达了冬季的某个时间点。

  • new DateTime(1970,1,1).AddHours(10,000)也将我们带到了冬季UTC,所以 .ToLocalTime()再次不执行任何操作,除了将Kind更改为Local。



但是,当我们增加100,000小时时,情况会有所不同,因为这使我们在达到夏令时之后达到了一个点。




  • 新的DateTime(1970,1,1).ToLocalTime()。AddHours(100000)更改像以前一样对本地$ ,然后增加100,000小时的报价。我们从UTC迁移到UTC + 1并没有任何升值。

  • new DateTime(1970,1,1).AddHours(100000)但是将我们带到当地时间和UTC有所不同的时间点,因为我们是在1981年3月29日之后,夏令时开始了。 .ToLocalTime()因此会发现存在1小时的差异并将其相加,导致时间提前了1小时。



值得记住的是 DateTime 起作用。它代表时间的瞬间-自一个纪元以来的滴答声。它还 具有 Kind 属性,该属性表示该时间是基于当地时间,UTC还是未指定(即您尚未

例如, new DateTime(1980,4,1,0,0,0,DateTimeKind.Local)(我选择的是DST之后的日期),并且 new DateTime(1980,4,1,0,0,0,DateTimeKind.Utc)将<他们的 Ticks 属性的em>相同值,并且它们打印相同的字符串。但是,调用 .ToLocalTime()会执行不同的操作:在第一种情况下,它什么都不做(因为 DateTime 已经存在在当地时间),但在第二秒它会将 DateTime 添加一个小时的价格变动。



所以请记住,请始终跟踪种类是什么,并注意它在UTC /本地时间之间转换时的影响。 DateTime 本身并不是特别聪明,但是时区转换方法 do Kind周围有很多特殊情况的逻辑



我认为您可能应该使用 DateTimeOffset 而不是 DateTime -它可以向您显示您当前所在的时区,并消除了未指定和我的PC所在的时区这些笨拙的概念。尝试使用 DateTimeOffsets 重复此实验。


These two lines produces the same result (results are in my timezone) which is expected:

new DateTime(1970, 1, 1).ToLocalTime().AddHours(10000) // [21.02.1971 17:00:00]
new DateTime(1970, 1, 1).AddHours(10000).ToLocalTime() // [21.02.1971 17:00:00]

Now these two lines produces two different results:

new DateTime(1970, 1, 1).ToLocalTime().AddHours(100000) // [29.05.1981 17:00:00]
new DateTime(1970, 1, 1).AddHours(100000).ToLocalTime() // [29.05.1981 18:00:00]

That seem really strange and I cannot quite understand why this is happening. I know Jon Skeet would argue that we should not use DateTime at all since it's not good enough and use nodatime instead, but out of curiosity it's interesting to know why exactly is this happening.

Logically the point in time does not change depending on the order of operation and it's still the same time, though apparently it is not in C#.

P.S. ToUniveralTime behaves the same way and produces 2 different results in the second example (off by one hour).

解决方案

I'm assuming you're in the UK (where we spent the winter on UTC, but switch to UTC+1 in the summer). Therefore at midnight on 1/1/1970 we're on UTC.

  • new DateTime(1970, 1, 1).ToLocalTime() does nothing, except changes Kind to Local, because DateTime assumes that we specified a point in time in UTC. We then add 10,000 hours, which brings us to a point in winter time.
  • new DateTime(1970, 1, 1).AddHours(10,000) also brings us to a point in winter time UTC, so .ToLocalTime() again does nothing, except change Kind to Local.

However, things get different when we add 100,000 hours, since that brings us to a point after daylight savings kicks in.

  • new DateTime(1970, 1, 1).ToLocalTime().AddHours(100000) changes Kind to Local as before, and then adds 100,000 hours's worth of ticks. There's no appreciation that we moved from UTC to UTC+1.
  • new DateTime(1970, 1, 1).AddHours(100000) however brings us to a point in time where local time and UTC differ, because we're after the 29th March 1981 and daylight savings has kicked in. .ToLocalTime() therefore spots that there's a 1-hour difference and adds it, resulting in a time which is 1 hour ahead.

It's worth remember how DateTime behaves. It represents an instant in time - a number of ticks since an epoch. It also has a Kind property, which says whether that time is based on local time, UTC, or is "Unspecified" (i.e. you haven't told it).

For example, new DateTime(1980, 4, 1, 0, 0, 0, DateTimeKind.Local) (I chose a date after DST), and new DateTime(1980, 4, 1, 0, 0, 0, DateTimeKind.Utc) have the same value for their Ticks property, and they print the same string. However, calling .ToLocalTime() does different things: in the first case it does nothing (because the DateTime is already in local time), but in the second it adds an hour's worth of ticks to the DateTime.

So remember, always keep track of what Kind is, and be aware of the effect that it has when converting between UTC/local time. DateTime itself isn't particularly smart, but the timezone conversion methods do have a lot of special-case logic around Kind which can throw you.

I'd argue that you should probably be using DateTimeOffset instead of DateTime - that shows you what timezone you're currently in, and does away with the woolly notions of "Unspecified" and "Whatever timezone my PC is in". Try repeating this experiment with DateTimeOffsets.

这篇关于为什么DateTime上的独立操作顺序(Add和ToLocalTime / ToUniversalTime)会更改结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆