我的理解是DateTime.Today
给出了当地时区中今天午夜的时间。
DateTime.Today.AddDays(1)
总是在当地时区显示明天午夜,还是有时会因为夏令时而关闭?
即.AddDays(1) == .AddHours(24)
,或者它在调整夏令时时有时不同。
如果是.AddDays(1) == .AddHours(24)
,有没有办法把明天午夜的时间定在当地(可能是23、24或25小时后)?
1。'纯日期时间
关键是要记住,DateTime
"只是"一个容器,它容纳了所谓的ticks
"自1/10001 12:00am以来经过的100纳秒间隔数">。DateTime
不保存它所指向的时间指的是哪个时区的信息。
当你调用AddDays时,你实际上是在添加一个常量TicksPerDay
tick:
public DateTime AddDays(double value) {
return Add(value, MillisPerDay);
}
private DateTime Add(double value, int scale) {
(...)
return AddTicks(millis * TicksPerMillisecond);
}
AddHours
也会导致添加记号。
当您致电AddHours(24)
时,您的意思是请将24小时添加到"YYYY-MM-DD HH:MM:SS"(第二天15:00->15:00,与时区或夏令时无关)。您不是在请求24小时后的时间(24小时后可能是14:00或16:00)。
为了回答"24小时后是什么时间?"需要时区信息(请参阅下面的NodaTime)。
同样,AddHours(25)
的意思是:请在"YYYY-MM-DD HH:MM:SS"上加1天1小时。DateTime
2019年10月12日14:07加上25小时始终为2019年10月份15:07。
请注意,DateTime
适用于闰年(只需要静态规则)。
2.节点时间
Noda时间允许您"通过"时间,即添加经过的时间量。换句话说,它可以让你回答"n小时后是什么时间?">
在日期和时间算术中,我们可以阅读。
时间线算法非常简单,除了在使用ZonedDateTime时,由于夏令时转换,您可能不会总是得到预期的结果:
DateTimeZone london = DateTimeZoneProviders.Tzdb["Europe/London"]; // 12:45am on March 25th 2012 LocalDateTime local = new LocalDateTime(2012, 3, 25, 0, 45, 00); ZonedDateTime before = london.AtStrictly(local); ZonedDateTime after = before + Duration.FromMinutes(20);
我们从当地时间凌晨12点45分开始。我们添加的时间实际上是"经验"时间——就好像我们只等了20分钟一样。然而,当天凌晨1点,欧洲/伦敦时区的时钟提前了一个小时,所以我们的当地时间是凌晨2点05分,而不是你预期的凌晨1点05分。
相反的效果可能发生在另一个夏令时转换时,时钟向后而不是向前:所以凌晨1点45分后的20分钟很容易变成凌晨1点05分!因此,即使我们在ZonedDateTime中公开了"本地时间"的概念,对其执行的任何运算都是使用底层时间线计算的。
我的理解是
DateTime.Today
在当地时区给出了今天午夜的时间。
这基本上是正确的,但有一个边缘情况。它确实会使用本地时区来确定当前日期,时间设置为00:00:00.0000000
。所得到的.Kind
将是DateTimeKind.Local
。它所做的相当于以下任何一项:
DateTime.Now.Date
DateTime.UtcNow.ToLocalTime().Date
TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Local).Date
// etc.
(有关完整列表,请参阅System.DateTime.Now和System.DateTime.Today之间的差异。)
请注意,在我的所有示例中,.Date
是最后一个。该属性只是将时间设置为零。它保留.Kind
,但不以任何方式对其进行评估。
如果你处理的时区在午夜有一个转换,即时钟从23:59
到01:00
,那么边缘情况就会发挥作用。由于没有00:00
,那么来自DateTime.Today
的结果将是不存在的本地时间。一个这样的例子是2019-09-08
上的智利圣地亚哥。那一天午夜不存在。
DateTime.Today.AddDays(1)
总是在当地时区显示明天午夜,还是有时会因为夏令时而关闭?即
.AddDays(1) == .AddHours(24)
,或者它在调整夏令时时有时不同。
AddDays
或AddHours
函数都不考虑时区。它们都只需加上整整24小时。与.Date
属性一样,这些函数保留.Kind
,但不会以某种方式对其求值。
如果是
.AddDays(1) == .AddHours(24)
,有没有办法获得当地明天午夜的时间(可能是23、24或25小时后)?
如前所述,请记住午夜可能不存在,您只需要针对这种可能性进行调整。这里有一个仅使用DateTime
:的扩展方法
static DateTime AdjustToValidTime(this DateTime dt, TimeZoneInfo tz)
{
if (!tz.IsInvalidTime(dt))
{
// The time is already valid
return dt;
}
// Get the adjustment rule that applies
var rule = tz.GetAdjustmentRules()
.First(x => x.DateStart <= dt && x.DateEnd > dt);
// Get the transition gap. Often will be one hour, but not always
TimeSpan gap = rule.DaylightDelta;
// Add the gap to adjust to a valid time
return dt.Add(gap);
}
你可以这样使用它(例如):
DateTime tomorrow = DateTime.Today.AddDays(1).AdjustToValidTime(TimeZoneInfo.Local);
如果你想看到一天没有午夜的情况,你可以这样使用:
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific SA Standard Time");
DateTime today = new DateTime(2019, 9, 8);
DateTime adjusted = today.AdjustToValidTime(tz); // Will be 2019-09-08 01:00
夏令时不会自动调整,您需要根据代码进行调整,然后才能使用
DateTime.Today.AddDays(1)
即使在夏令时下,它也会给你第二天的午夜时间。
正确管理时区和夏令时使用使用Noda time.net库
Noda时间