【问题标题】:Get time until local time is N hours from now, taking summer-time changes into account获取时间,直到本地时间从现在起 N 小时,考虑到夏季时间的变化
【发布时间】:2017-04-04 09:04:46
【问题描述】:

时区和夏令时的变化尤其让我感到困惑。在英国,我们有 GMT/BST:

在英国的最后一个星期日凌晨 1 点,时钟会提前 1 小时 3 月,10 月的最后一个星期日凌晨 2 点返回 1 小时。这 时钟提前 1 小时的时期称为英国夏令时 (英国夏令时)。

给定当地时间 00:00,我希望能够计算到当地时间 03:00 的时间。通常这只是 3 小时,但在 3 月 26 日(3 月的最后一个星期日)00:00 - 03:00 实际上是 2 小时。同样,当时钟在 10 月从 00:00 到 03:00 倒退时是 4 小时。

.Net DateTime 类及其方法对我来说是微不足道的还是我需要小心?

在我的情况下,我正在使用字符串,所以我正在寻找一种方法:

TimeSpan DifferenceBetweenLocalTimes(string startDateTime,string endDateTime) 

我可以看到像TimeZoneInfo.IsDaylightSavingTime 这样的东西,但是如何使用它来做我希望的事情并不明显。我的应用程序将每个日历日的当地午夜视为一个严格的界限,即不是每天都是 24 小时,每年一次我得到一天 23 小时和一天 25 小时。

【问题讨论】:

  • 作为一个附带问题...如果我有endDateTime = 26/3/2017 01:30 鉴于时钟从 01:00 -> 02:00 在该日期跳跃会发生什么?这个时间真的存在吗?!
  • 嗯,你可以自己回答这个问题。答案是肯定的,时间已经存在,没有.net 不会为你做夏令时,不同的时区会在一年中的不同时间做。如果你有时区,你也许可以做时差。
  • 所以 DST 更改是由 Windows 更改时区直接驱动的,而 .Net 对此一无所知?即它的工作方式与我在这两次手动更改控制面板中的时区完全一样?
  • 您可以使用 UTC 进行所有逻辑处理,并且只对输出进行本地化?
  • @ChrisPickford 我不确定当我将午夜作为我的严格界限时它会如何工作;一年一次,我的一天是 23 小时,一年一次是 25 小时……在 Utc 工作不会隐藏这一点吗?

标签: c# .net datetime timezone


【解决方案1】:

您可以使用TimeZoneInfo 类来获取从本地日期时间到 UTC 的偏移量(包括日光技巧)。例如

var timeZone =TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
var date1 = DateTime.Parse("2017-03-26 00:00:00");
var date2 = DateTime.Parse("2017-03-26 03:00:00");
var dto1 = new DateTimeOffset(date1, timeZone.GetUtcOffset(date1));
var dto2 = new DateTimeOffset(date2, timeZone.GetUtcOffset(date2));

var diff1 = (dto2 - dto1).TotalHours;

Console.WriteLine(diff1); // this is 2 hours

GetUtcOffset 方法返回该时区的时间与 UTC 之间的时间差

【讨论】:

  • 次要 nitpick - 您可以使用 "TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");" 找到该区域
  • 我可以简单地调用DateTime.Parse(...) 来获得合适的date1date2 值...没有DateTimeKind 混乱?
  • @Mr.Boy 它取决于目标字符串。例如,如果您这样做var test = DateTime.Parse("2017-03-26 03:00:00", CultureInfo.InvariantCulture);,则生成的 DateTime 将具有未指定的种类,这正是您所需要的。但是,如果您这样做:DateTime.Parse("2017-03-26 03:00:00 +01:00", CultureInfo.InvariantCulture); - 结果将具有类型 Local(并且确实代表您当地区域的时间)- 这不是您所需要的。
  • @Mr.Boy 是的,你可以,它使用DateTimeKind.Unspecified 生成日期时间(假设字符串中没有时区组件)。代码再次更新
【解决方案2】:

虽然tchrikch's answer 完全合理(恕我直言,应该被接受),但值得添加基于Noda Time 的解决方案。

// Parse input as LocalDateTime values (since they represent a local date and time)
var pattern = LocalDateTimePattern.CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt1 = pattern.Parse("2017-03-26 00:00:00").Value;
LocalDateTime ldt2 = pattern.Parse("2017-03-26 03:00:00").Value;

// Apply a specific time zone, now making them ZonedDateTime values
// Using "lenient" conversions allows for default handling of ambiguous/invalid values
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/London"];
ZonedDateTime zdt1 = ldt1.InZoneLeniently(tz);
ZonedDateTime zdt2 = ldt2.InZoneLeniently(tz);

// Now simply determine the elapsed duration between these
Duration result = zdt2 - zdt1;

请注意,ZonedDateTime 值之间的减法是在 NodaTime 2.0 中添加的。如果您使用的是旧版本,则需要这样做:

Duration result = zdt2.ToInstant() - zdt1.ToInstant();

【讨论】:

    猜你喜欢
    • 2021-01-21
    • 1970-01-01
    • 2013-09-18
    • 2013-01-15
    • 1970-01-01
    • 2012-09-08
    • 2021-03-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多