.NET NodaTime Как создать собственный часовой пояс?

Я хочу создать пользовательский (несуществующий) часовой пояс, который следует точно тем же правилам, что и Европа/Лондон, однако единственное отличие состоит в том, что смещение должно составлять -5 часов от UTC.

В целях тестирования, это то, что я пытался. Как указать летнее время? Или эта реализация совершенно неверна?

   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));
        }
    }

person Community    schedule 20.09.2016    source источник
comment
Я никогда раньше не использовал NodaTime, но могу сказать вам, что ваша функция GetHashCode совершенно неверна. Он должен возвращать значение, которое является относительно уникальным, чтобы идентифицировать разные значения. Я бы рекомендовал вернуть хэш-код идентификатора зоны. Я предполагаю, что базовый класс уже должен делать что-то подобное.   -  person Bradley Uffner    schedule 20.09.2016
comment
Спасибо за ваш ответ. Я обязательно исправлю.   -  person    schedule 20.09.2016
comment
Я не думаю, что у NodaTime есть API, чтобы сделать это легко, но я уверен, что Джон скоро ответит на этот вопрос. :) Любопытно, каков вариант использования этого бизнеса/приложения? Мне всегда любопытно, когда люди говорят, что им нужны настраиваемые часовые пояса. Насколько мне известно, в большинстве случаев реального использования это не требуется.   -  person Matt Johnson-Pint    schedule 20.09.2016
comment
@BradleyUffner: Нет, возврат постоянного значения всегда является правильной реализацией GetHashCode. Обычно это не оптимально, но всегда подчиняется контракту GetHashCode. Вернуть хеш идентификатора было бы лучше, конечно... но сказать, что это совершенно неправильно, это... совершенно неправильно.   -  person Jon Skeet    schedule 20.09.2016
comment
@MattJohnson Мне лично не нравится идея создания пользовательских часовых поясов. Играть со временем кажется неправильным. Я не могу раскрывать бизнес-логику, но в нашем приложении есть настраиваемые часовые пояса для обработки определенного типа обработки.   -  person    schedule 21.09.2016
comment
В настоящее время у нас плохая реализация обработки часовых поясов, поэтому я использую NodaTime для ее улучшения.   -  person    schedule 21.09.2016
comment
@Abz - Если речь идет о попытке рассматривать время после полуночи как один и тот же логический рабочий день, обычно смещение часового пояса - это взлом, и вам лучше записать его в реальную бизнес-логику. Просто мой опыт.   -  person Matt Johnson-Pint    schedule 21.09.2016


Ответы (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 — в начале и в конце времени, когда свойства Start и End не будут работать, но это должно быть абсолютно нормально для любого момента, с которым вы, вероятно, столкнетесь.

person Jon Skeet    schedule 20.09.2016
comment
Конечно, инкапсуляция существующей зоны tzdb, вероятно, здесь проще всего. Но мне интересно, насколько сложно было бы, если бы действительно был полный набор пользовательских дат перехода на летнее время или другие изменения смещения, которые можно было бы реализовать с нуля? - person Matt Johnson-Pint; 20.09.2016
comment
@MattJohnson: если у вас уже есть набор моментов перехода, он будет очень похож на github.com/nodatime/nodatime/blob/master/src/NodaTime/TimeZones/ - person Jon Skeet; 20.09.2016
comment
Можно ли это исправить, чтобы он работал в конце времени? Я хотел бы использовать это во время обеда в ресторане в конце вселенной. - person ; 21.09.2016
comment
@Amy: Ха - боюсь, Noda Time не заходит так далеко :) Однако каждое утро перед завтраком он делает 6 невозможных вещей. - person Jon Skeet; 21.09.2016
comment
Большое спасибо, Джон! и остальные из вас. Это решило мою проблему. - person ; 21.09.2016