【问题标题】:How to change the Timzone of a ZonedDateTime without converting the time如何在不转换时间的情况下更改 ZonedDateTime 的时区
【发布时间】:2019-11-01 13:25:56
【问题描述】:

我有一个ZonedDateTime,它是使用DateTimeOffset 和一个时区ID(字符串)创建的,我还有一个DateTimeZone

我的特殊情况是我需要更改 ZonedDateTime 的Zone 而无需实际转换时间(即我有 18:00 UTC-4:00,我想将其更改为 18:00 UTC- 8 没有相应地转换 18:00)

我找到的唯一相关函数是.WithZone(DateTimeZone),但这似乎会根据提供的区域转换我的时间

如何在不转换时间的情况下更改 ZonedDateTime 的“时区”?

编辑我找到了一个似乎可行的解决方案:

private DateTimeOffset myFunction(DateTimeOffset dateTimeOffset, string timeZoneId) {
    // get the DateTimeZone (i.e. Etc/GMT)
    DateTimeZone timezone = DateTimeZoneProviders.Tzdb[timeZoneId];

    // create a new DTO with the previous date/time values, but with the DateTimeZone Offset
    var newDTO = new DateTimeOffset(dateTimeOffset.DateTime, timezone.GetUtcOffset(SystemClock.Instance.GetCurrentInstant()).ToTimeSpan());

    // create a ZonedDateTime based on the new DTO
    var nodaDTO = ZonedDateTime.FromDateTimeOffset(newDTO);

    // the correct datetime in the correct zone
    var finalProduct = nodaDTO.WithZone(timezone);

    return finalProduct.ToDateTimeOffset();
}

【问题讨论】:

  • 请你提供一些你在做什么的示例代码?目前这听起来很奇怪——可能有更好的方法来解决你试图解决的更大问题。 (你总是可以得到ZonedDateTimeLocalDateTime,然后在上面使用InZone ......但在这里做这件事很奇怪。你基本上是说在原始ZonedDateTime 中表示的瞬间应该被忽略。这至少让我感到紧张。你可能有一个特殊的原因 - 但我很想听听。)
  • @JonSkeet 我相信我找到了解决方案 - 我已经更新了我的问题以包含我可能的解决方案代码
  • 您已经编辑了问题,但它仍然不能真正帮助我们了解您想要实现的目标。我敢肯定,一旦我们对您要完成的工作有了更多的了解,将它比这简单得多会很容易-示例输入和预期输出在这里将非常有用. (同样,有一个DateTimeOffset 是很奇怪的,但想完全忽略它的偏移量......)
  • 我相信您的代码非常损坏 - 您假设您想要的偏移量与该时区的 current 偏移量不同。如果您收到的是冬季 DTO 而现在是夏季,该怎么办?感觉就像你真的想要LocalDateTime.FromDateTime(dateTimeOffset.DateTime).InZoneLeniently(zone) - 但是那个“宽大”的部分是你需要仔细考虑的。如果给定时区的日期/时间不明确或被跳过,您想做什么?你怎么开始有一个不正确的DateTimeOffset?你能解决导致这种情况的上游问题吗?
  • 很高兴我能够将它引向一个有用的方向,即使这意味着我无法在答案中展示 Noda Time 的专业知识 ;)

标签: c# .net datetime datetimeoffset nodatime


【解决方案1】:

如 cmets 所述,这样做的愿望通常表明上游有问题 - 如果你可以在那里修复它,你应该这样做。

如果您最终遇到DateTimeOffset 的情况,其中本地部分绝对正确但偏移量不正确,并且您确实无法更早修复数据,那么您需要找到正确的 UTC当地时间的偏移量。重要的是要注意本地时间可能是不明确的(如果它发生在“回退”转换期间)或跳过(如果它发生在“弹簧向前”转换期间),您应该弄清楚在这种情况下该怎么做。

您可以为此使用DateTimeZone.MapLocal

private DateTimeOffset myFunction(DateTimeOffset dateTimeOffset, string timeZoneId)
{
    var unspecifiedDateTime = DateTime.SpecifyKind(dateTimeOffset.DateTime, DateTimeKind.Unspecified);
    var zone = DateTimeZoneProviders.Tzdb[timeZoneId];
    var local = LocalDateTime.FromDateTime(unspecifiedDateTime);
    ZoneLocalMapping mapping = zone.MapLocal(local);
    // Read documentation for details of this; you can easily detect the
    // unambiguous/ambiguous/skipped cases here. You should decide what to do with them.
    ZoneInterval mappedInterval = mapping.EarlyInterval;
    TimeSpan bclOffset = mappedInterval.WallOffset.ToTimeSpan();
    return new DateTimeOff(unspecifiedDateTime, bclOffset);
}

【讨论】:

    【解决方案2】:

    你能用新的时区偏移量创建一个新的DateTimeOffset 变量吗?毕竟您现有的所有ZonedDateTime 值仅代表全局的一个“真实”时间,如果我们正在考虑时间概念,更新偏移量将更新正确的时间。

    否则,您可以在目标时区创建一个新的 DateTimeOffset,然后使用 Subtract 方法修改您现有的时间。它将返回一个新的 DateTimeOffset 值。 像这样:https://stackoverflow.com/a/49518361/8191918

    【讨论】:

      猜你喜欢
      • 2013-09-30
      • 2018-07-24
      • 1970-01-01
      • 2023-03-09
      • 2015-10-26
      • 2021-01-31
      • 1970-01-01
      • 2012-05-29
      • 2023-03-17
      相关资源
      最近更新 更多