我有一个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?这个问题更多地涉及将DateTime
转换为String
和从DateTime
转换。我只使用TimeSpan
和DateTimeKind.Unspecified
算术。
该问题的最佳答案建议使用DateTime
,以便运行时假设未指定的日期为UTC,然后在本地化时将其正确转换。我很惊讶这实际上有效。如果我像这样创建一个新的var dt2 = new DateTime(dt.Ticks, DateTimeKind.Unspecified);
:
(dt2 + ts).ToLocalTime()
dt2.ToLocalTime() + ts
然后,两个操作命令都会以夏令时返回正确的结果。
Utc
这对我来说似乎都很荒谬。为什么我需要将Unspecified
日期转换为Local
才能将其正确转换为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
的价值:{{1}} 答案 0 :(得分:4)
此声明有效地要求提前一天,但所有其他属性(小时,分钟)保持不变:
var localizedFirst = dt.ToLocalTime() + ts;
虽然这个陈述询问在经过24小时(经过时间)之后当地时间是多少:
var addedFirst = (dt + ts).ToLocalTime();
将UTC中的所有内容保留到最后一分钟,然后转换为本地时间进行输出,这是一个很好的论据。
修改:或者相反,如果您不希望在添加或减少天数时更改本地小时数和分钟数,请在添加TimeSpan
之前转换为本地时间。 然而,正如马特·约翰逊正确指出的那样,你可能会以这种方式结束本地时间,这个时间要么无效(时钟在那个时间前进),要么模棱两可(时钟会回来,所以那个时间发生了两次)。请参阅下面的评论,了解如何确定这一点。
答案 1 :(得分:4)
几点:
TimeSpan
代表经过的持续时间。它的“天数”是标准天,正好是24小时。
当天,在当地时区,由于DST回落过渡,有25个小时。
对DateTime
对象(+
运算符或Add...
函数)的添加始终不考虑时区。换句话说,无论原始.Kind
属性是什么,输出都将具有相同的.Kind
属性,但在加/减期间根本不考虑该类型。
因此,在转换为本地时间后添加不会占25小时。这也是有问题的,因为它可能落在不存在或存在两次的本地时间值上。
因此,当您在代码注释中说“确实(或不支持)夏令时”时,从技术上讲,您已将其反转。由于UTC没有转换,localizedFirst
变量是错误地假设本地日期为24小时的结果,而addedFirst
变量是从本地时区正确应用DST规则的结果。在时间线上原始点之后经过24小时的点。
此外,设置DateTimeKind.Unspecified
不会更改此情况的效果,因为DateTime.ToLocalTime()
方法会将DateTimeKind.Unspecified
视为DateTimeKind.Utc
。 See the table in the remarks of the documentation here.实际上,我试图复制您的结果,并且只是通过更改类型无法使dt2
的值变为任何不同。如果可以的话,请详细说明这一点。
值得指出的是,消除这种混淆正是Noda Time库存在的原因。在Noda Time中,这些由两个非常不同的操作表示:
LocalDateTime + Period = LocalDateTime
Instant + Duration = Instant