2016-05-19 4 views
0

Я пытаюсь построить логический набор записей часовых поясов, представляющий пятилетний период, когда стоп и дата начала/время совпадают с тем, что человек воспринимает как момент изменения времени. Например, в Америке/New_York ид, я хочу:NodaTime ZoneIntervals

03/13/2016 2:00 am - 11/06/2016 01:59:59 am gmtOffset: -4:00 
11/06/2016 2:00 am - 03/12/2017 01:59:59 am gmtOffset: -5:00 

Я могу построить эти записи, но я не вижу другого пути, чем не начать до 1912 года, когда ДСТ вошел в силу и отслеживать Конечный момент для все интервалы зон. Я не вижу способа определить смещение в действии, когда начинается период интервальной записи, кроме предыдущей записи интервала. Есть ли способ сделать это, используя только одну запись ZoneInterval?

Вопрос отметил в коде:

private void processTZ() 
    { 
     IDateTimeZoneProvider provider = DateTimeZoneProviders.Tzdb; 

     using (StreamWriter sw = new StreamWriter(@"c:\tzOut.txt")) 
     { 
      foreach (string id in provider.Ids) 
      { 
       sw.WriteLine("Id: {0}", id); 
       DateTimeZone zone = provider[id]; 

       // Time period I wish to create logical representation. 
       Instant instantValidityBegin = (new LocalDateTime(2014, 1, 1, 0, 0)).InZoneLeniently(zone).ToInstant(); 
       Instant instantValidityEnd = (new LocalDateTime(2019, 12, 31, 23, 59, 59, 0)).InZoneLeniently(zone).ToInstant(); 

       // Time period from zone intervals to iterate. The first year dst was observed was 1916. 
       Instant instantFetchYearBegin = (new LocalDateTime(1916, 1, 1, 0, 0)).InZoneLeniently(zone).ToInstant(); 
       Instant instantFetchYearEnd = (new LocalDateTime(2019, 12, 31, 23, 59, 0)).InZoneLeniently(zone).ToInstant(); 

       // Get the intervals 
       IEnumerable<NodaTime.TimeZones.ZoneInterval> intervals = zone.GetZoneIntervals(instantFetchYearBegin, instantFetchYearEnd); 

       // Determine number of intervals for this tzId. 
       int count = 0; 
       foreach (NodaTime.TimeZones.ZoneInterval zi in intervals) 
        count++; 

       bool singleEntry = (1 == count); 

       // myStart and myEnd are desired output period 
       // capture IsoLocalEnd of an interval to be used as the start date of program output (myStart). Don't display older than 1900. 
       DateTime myStart, myEnd, prevEnd = new DateTime(1900, 1, 1); 

       foreach (NodaTime.TimeZones.ZoneInterval zi in intervals) 
       { 
        if (singleEntry) 
        { 
         // No question here 
        } 
        else 
        { 
         // skip intervals for this tzId that represent a period beginning after time period I want. 
         if (instantValidityEnd < zi.Start) 
          break; 

         // Skip intervals ending prior to time period I want, but capture the IsoLocalEnd to be used for report output. 
         if (zi.End < instantValidityBegin) 
         { 
          prevEnd = (zi.End == Instant.MinValue) ? prevEnd = new DateTime(1900, 1, 1) : prevEnd = zi.IsoLocalEnd.ToDateTimeUnspecified(); ; 
          continue; 
         } 

         // ***Question*** Can this myStart value be determined using the current interval record instead of storing the previous interval's IsoLocalEnd?? 
         myStart = prevEnd; 
         if (zi.End == Instant.MaxValue) 
          prevEnd = myEnd = new DateTime(9999, 12, 31); 
         else 
         { 
          prevEnd = zi.IsoLocalEnd.ToDateTimeUnspecified(); 
          myEnd = prevEnd.Subtract(TimeSpan.FromSeconds(1)); // force period back 1 second for logical representation. 
         } 


         sw.WriteLine("Name: " + zi.Name); 
         sw.WriteLine("Multi Entry: {0}", zi.ToString()); 
         sw.WriteLine("myStart: {0:G} myEnd: {1:G} gmtOffset: {2:G}", myStart, myEnd, zi.WallOffset.ToTimeSpan()); 
         sw.WriteLine(); 
        } 
       } 

       sw.WriteLine("------------------------------------------------------------------"); 
       sw.WriteLine(); 
      } 
     } 
    } 
+0

Чтобы быть более точным, время начала интервала «выключено» значением dst предыдущей записи; однако предыдущая конечная запись хранит время, необходимое для этого типа логического представления. –

+1

[Документы для 'ZoneInterval'] (http://nodatime.org/1.3.x/api/?topic=html/Properties_T_NodaTime_TimeZones_ZoneInterval.htm) содержит комментарий о' IsoLocalEnd', не включая сохранение. Тем не менее, неясно, используете ли вы это, или используете «Start» и «End», и конвертируете их. Не могли бы вы изменить свой вопрос, чтобы показать код, который у вас есть? Возможно, мы сможем помочь вам, если вы это сделаете.См. Также [Как создать минимальный, полный и проверенный пример] (http://stackoverflow.com/help/mcve) и [Как задать хороший вопрос?] (Http://stackoverflow.com/help/ how-to-ask) –

+0

«Я не вижу способа определить смещение, действующее на запись ZoneInterval» - вот для чего «WallOffset». Кроме того, у меня возникли проблемы с пониманием вашего вопроса, которого я боюсь. –

ответ

1

В любой ZoneInterval записи, IsoLocalStart и IsoLocalEnd являются относительно этого конкретного интервала, используя один и тот же WallOffset значение для обеих сторон.

Если вы хотите узнать актуальное местное время, вы можете использовать Start и End минуты и преобразовать их в определенный часовой пояс.

zi.Start.InZone(zone) 
zi.End.InZone(zone) 

Вы увидите, что LocalDateTime от исходного значения соответствует IsoLocalStart, но конечное значение не делает. К тому моменту, когда этот момент наблюдается, он теперь покрывается смещением следующего интервала. Не забывайте, что это полуоткрытый интервалов. [inclusive-start, exclusive-end).

Давайте вернемся к примеру в исходном запросе:

03/13/2016 2:00 am - 11/06/2016 01:59:59 am gmtOffset: -4:00 
11/06/2016 2:00 am - 03/12/2017 01:59:59 am gmtOffset: -5:00 

Это на самом деле не работает так. В марте местное время перемещается с 1:59:59 am до 3:00:00 am, пропуская более часа. Поэтому первая строка должна начинаться с 3:00 am, а не 2:00 am. В ноябре местное время перемещается с 01:59:59 am на 1:00:00 am, повторяя час. Поэтому вторая строка должна начинаться с 1:00 am, а не 2:00 am. Кажется, что ваша диаграмма пытается сделать локальное время непрерывным, а это не так.

Кроме того, вы обнаружите, что по соглашению многие люди думают о времени перехода как о 2:00, а о том, что 1:59:59. Подумайте об этом как приближается 2:00. Вот почему IsoLocalEnd представлен смещением текущего интервала, и вы можете использовать это поле для такой цели.

Также вы можете проверить, how timeanddate.com показывает это. Они решили показать только конечные значения, которые могут сделать вещи более ясными.

+0

Да, требуется постоянное местное время. Моя компания принимает мировые расписания поездок и строит индивидуальные поездки, обрабатывающие точки подключения на периоды больше года. Вывод находится в терабайтах и ​​экспоненциально зависит от количества входных записей. Единая входная запись может представлять собой несколько лет расписания рейсов/поездов/судов, которые вылетают/прибывают в «постоянное время». Для точного вывода pgm должен анализировать постоянное время и интерполировать (grrrrrrr). Спасибо вам за тщательный ответ! –

+0

Непрерывное местное время - это не реальность. См. Диаграммы в [dst tag wiki] (http://stackoverflow.com/tags/dst/info). Вот почему Noda Time имеет «InZoneLeniently» и связанные с ним методы. Тем не менее, вы, вероятно, найдете на практике, что время отправления путешествия обычно не запланировано вблизи переходов DST. Время прибытия может быть. Используйте время отправления + продолжительность для подтверждения времени прибытия. –

Смежные вопросы