我有一个带有DateTime和时间跨度的Kind = DateTimeKind.Utc实例。

var dt = DateTime.UtcNow;
var ts = TimeSpan.FromDays(1);


本地化dt然后添加ts时,由于夏令时,我得到的结果与添加ts然后进行本地化时的结果不同。

var localizedFirst = dt.ToLocalTime() + ts; //Does account for daylight savings
var addedFirst = (dt + ts).ToLocalTime(); //Does not account for daylight savings


这似乎很奇怪。添加本地化偏移量和时间跨度偏移量不应该是可交换和关联的吗?

我发现了一个类似的问题:Why doesn't DateTime.ToLocalTime() take into account daylight savings?这个问题主要涉及将DateTimeString相互转换。我仅使用DateTimeTimeSpan算术。

建议使用DateTimeKind.Unspecified这个问题的最佳答案,以便运行时将未指定的日期假定为UTC,然后在本地化时将其正确转换。令我惊讶的是,它确实有效。如果我这样创建一个新的DateTime

var dt2 = new DateTime(dt.Ticks, DateTimeKind.Unspecified);


然后,这两个操作顺序都将返回正确的结果并节省日光。

(dt2 + ts).ToLocalTime()
dt2.ToLocalTime() + ts


这一切对我来说都是荒谬的。为什么需要将Utc日期转换为Unspecified只是为了将其正确转换为Local?看来应该将其视为错误。

其他详情:


框架:.NET 4.6.1
我的当地时区:美国东部标准时间
dt使用的实际值:11/5/2017 2:36:13pm UTC
ts使用的实际值:TimeSpan.FromDays(699)
dt的本地等效项:11/5/2017 9:36:13am
(dt + ts).ToLocalTime()的值:10/5/2019 10:36:13am
dt.ToLocalTime() + ts的值:10/5/2019 9:36:13am

最佳答案

几点:


TimeSpan表示经过的时间长度。它的“天”是标准时间,恰好是24小时。
在该日的当地时区,由于DST后备转换,因此有25个小时。
总是在不考虑时区的情况下(通过DateTime运算符或+函数)添加Add...对象。换句话说,无论原始的.Kind属性是什么,输出都将具有相同的.Kind属性,但是在加/减过程中根本不考虑该类型。
因此,在转换为本地时间后进行添加不会占25小时的一天。这也是有问题的,因为有可能落在一个不存在或存在两次的本地时间值上。


因此,当您在代码注释中说“是否(或不)考虑夏时制”时,从技术上讲,您将其撤消了。由于UTC没有过渡,因此localizedFirst变量是错误地假定本地日期为24小时的结果,而addedFirst变量是正确地从本地时区应用DST规则的结果,即在时间轴上的原始点之后经过了24小时。

同样,设置DateTimeKind.Unspecified不会改变这种情况的效果,因为DateTime.ToLocalTime()方法会将DateTimeKind.Unspecified视为DateTimeKind.UtcSee the table in the remarks of the documentation here.的确,我试图复制您的结果,并且仅仅通过改变种类就无法使dt2的值有所不同。如果可以,请具体说明这一点。

值得指出的是,消除这种混淆正是Noda Time库存在的原因。在Noda Time中,这些操作由两种截然不同的操作表示:


LocalDateTime + Period = LocalDateTime
Instant + Duration = Instant

关于c# - DateTime.ToLocalTime与夏令时不能正常工作,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47160663/

10-09 07:05