【问题标题】:.NET NodaTime How do I create a custom TimeZone?.NET NodaTime 如何创建自定义时区?
【发布时间】:2016-09-20 14:41:25
【问题描述】:

我想创建一个自定义的(不存在的)时区,它遵循与欧洲/伦敦完全相同的规则,但唯一的区别是偏移量应该是距 UTC 的 -5 小时。

出于测试目的,这是我正在尝试的。如何指定夏令时?还是这个实现完全错误?

   public class MyTimeZone : DateTimeZone
    {
        public MyTimeZone()
            : base("MyTimeZone", true, Offset.FromHours(-5), Offset.FromHours(-5))
        {

        }

        protected override bool EqualsImpl(DateTimeZone zone)
        {
            if (zone.Id == "MyTimeZone")
                return true;

            return false;
        }

        public override int GetHashCode()
        {
            return 0001;
        }

        public override NodaTime.TimeZones.ZoneInterval GetZoneInterval(Instant instant)
        {
            return new ZoneInterval("MyTimeZone", new Instant(DateTime.MinValue.Ticks), new Instant(DateTime.MaxValue.Ticks), Offset.FromHours(-5), Offset.FromHours(-5));
        }
    }

【问题讨论】:

  • 我以前从未使用过NodaTime,但我可以告诉你,你的GetHashCode 函数完全错误。它需要返回一个相对唯一的值,以便识别不同的值。我建议返回区域 ID 的哈希码。我的猜测是基类应该已经在做类似的事情了。
  • 感谢您的回复。我会确保纠正它。
  • 我不认为 N​​odaTime 有一个 API 可以轻松做到这一点,但我相信 Jon 很快就会来回答这个问题。 :) 很好奇,这个的业务/应用程序用例是什么?当人们说他们需要自定义时区时,我总是很好奇。据我所知,大多数实际的实际使用并不真正需要它。
  • @BradleyUffner:不,返回一个常量值始终是GetHashCode正确实现。它通常不是最优,但它始终遵守GetHashCode 的约定。返回 ID 的哈希值会更好,当然……但是说它“完全错误”是……完全错误的。
  • @MattJohnson 我个人不喜欢创建自定义时区的想法。玩弄时间似乎是不对的。我无法透露业务逻辑,但我们的应用程序中有自定义时区来处理某些类型的处理。

标签: c# .net timezone nodatime


【解决方案1】:

这当然不是一个非常常见的场景,但它绝对受到支持。 (例如,与创建自己的日历不同。)

您可以通过GetZoneInterval 指定夏令时 - 该方法是该类的关键。正确处理的重要事项是:

  • 具有最小/最大偏移量的链式构造函数调用(您的最大值将是 UTC-4,而不是 UTC-5)
  • GetZoneInterval
  • 等式/哈希码,目前您始终可以使身份相等。

例如,您可以:

public class LondonOffsetZone : DateTimeZone
{
    private readonly DateTimeZone london;

    // This assumes London has a minimum of +0 and a maximum of +1.
    // To do it better, you'd resolve Europe/London and find *its*
    // min/max, and add -5 hours to each.
    public LondonOffsetZone()
        : base("LondonOffset", false, Offset.FromHours(-5), Offset.FromHours(-4))
    {
        london = DateTimeZoneProviders.Tzdb["Europe/London"];
    }

    public override int GetHashCode() => RuntimeHelpers.GetHashCode(this);

    // Base Equals method will have handled reference equality already.
    protected override bool EqualsImpl(DateTimeZone other) => false;

    public override ZoneInterval GetZoneInterval(Instant instant)
    {
        // Return the same zone interval, but offset by 5 hours.
        var londonInterval = london.GetZoneInterval(instant);
        return new ZoneInterval(
            londonInterval.Name,
            londonInterval.Start,
            londonInterval.End,
            londonInterval.WallOffset + Offset.FromHours(-5),
            londonInterval.Savings);
    }
}

这将失败 - 至少在 Noda Time 2.0 中 - 在时间的开始和结束时,StartEnd 属性将不起作用,但对于您可能的任何瞬间它都应该是绝对好的真正的相遇。

【讨论】:

  • 当然,在这里封装现有的 tzdb 区域可能是最简单的。但我想知道如果真的有一套完整的自定义 DST 转换日期或其他偏移更改要从头开始实施,那会有多复杂?
  • @MattJohnson:如果你已经有一组转换瞬间,那么它最终会看起来很像github.com/nodatime/nodatime/blob/master/src/NodaTime/TimeZones/…
  • 这个问题可以修复,让它在时间结束时工作吗?我想在宇宙尽头的餐厅用餐时使用它。
  • @Amy:哈 - 恐怕 Noda Time 不会走那么远 :) 不过,它确实每天早上早餐前会做 6 件不可能的事情。
  • 非常感谢乔恩!和你们其他人。这解决了我的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多