2015-09-03 2 views
0

У меня есть DST правила, как это:Преобразование правила перехода на летнее время для DateTime в C#

"2, -1,1,3600000"

  • 2 является нулевой основе месяц
  • The - 1 - номер недели, содержащий день, -1 означает последнюю неделю в месяце, которая содержит день
  • 1 день недели, 1 - воскресенье до 7 - суббота
  • 3600000 - это mS с полуночи в назначенный день, когда изменение на/f rom DST будет иметь место и выражается в местном времени, включая DST, поэтому конец времени переключения DST находится в DST.

Каков правильный способ его преобразования в C# DateTime?

До сих пор я сделал это:

public static DateTime ConvertDstRule(int year, string rule, bool isEndRule) 
{ 
    const int DaysInWeek = 7; 
    var ruleName = isEndRule ? "endRule" : "startRule"; 

    var startStrings = rule.Split(','); 
    var month = Convert.ToInt32(startStrings[0]); 
    if ((month < 0) || (month > 11)) 
    { 
     throw new ArgumentOutOfRangeException(ruleName, "The month value must be between 0 and 11"); 
    } 

    var week = Convert.ToInt32(startStrings[1]); 
    if ((week < -1) || (week > 5)) 
    { 
     throw new ArgumentOutOfRangeException(ruleName, "The week value must be between -1 and 5"); 
    } 

    if ((Convert.ToInt32(startStrings[2]) < 1) || (Convert.ToInt32(startStrings[2]) > 7)) 
    { 
     throw new ArgumentOutOfRangeException(ruleName, "The day value must be between 1 and 7"); 
    } 

    var day = (DayOfWeek)(Convert.ToInt32(startStrings[2]) - 1); // DayOfWeek is zero based so shift by one. 
    var timeOffset = Convert.ToInt64(startStrings[3]); 
    if ((timeOffset/1000/60) > 86400) 
    { 
     throw new ArgumentOutOfRangeException(ruleName, "The time offset is limited to one day"); 
    } 

    // Find the start of the relevant year. 
    var startTime = new DateTime(year, 1, 1); 

    // Add on the month to get to the start of the selected month. 
    startTime = startTime.AddMonths(month); 

    // If the week is negative then go to the first occurance of the day in 
    // the next month, adding a negative week number will jump back into 
    // the previous month. 
    if (week < 0) 
    { 
     startTime = startTime.AddMonths(1); 
    } 
    else 
    { 
     week = week - 1; 
    } 

    // Jump to the first occurence of the day to switch in that month. 
    var monthStartsOn = startTime.DayOfWeek; 
    var daysToSwitchDay = (int)day - (int)monthStartsOn; 

    // This is likely to be negative as most zones switch on a Sunday 
    if (daysToSwitchDay < 0) 
    { 
     daysToSwitchDay = DaysInWeek + daysToSwitchDay; // daysToSwitchDay is negative so add it. 
    } 

    startTime = startTime.AddDays(daysToSwitchDay); // Now on the correct day. 

    startTime = startTime.AddDays(week * 7); // Week counts from 1. 

    startTime = startTime.AddMilliseconds(timeOffset); 
    if (isEndRule) 
    { 
     startTime = startTime.AddHours(-1); // Take off the DST hour to convert it to UTC. 
    } 

    return startTime; 
} 

ли она учитывает получасовые изменения летнего времени, как в Индии? Вы можете обнаружить ошибку в этом коде?

+3

Тот факт, что вы пытаетесь написать этот код самостоятельно, является ошибкой для меня. Вы должны использовать [nodatime] (http://nodatime.org/). –

+2

Кроме того, вопросы проверки кода не соответствуют теме. Они должны быть опубликованы на codereview.stackexchange.com –

+0

Если эти правила DST предназначены для гипотетических стран, не имеющих стран и часовых поясов, тогда я все же уверен, что вы можете использовать nodatime, но если эти правила DST предназначены для реальных стран и часовых поясов, nodatime уже есть ваши ответы. –

ответ

1

Несколько вещей:

  • Тип входа вы описываете называется "Transition Rule". Или вне контекста часовых поясов, это особый тип «правила повторения». Он просто описывает шаблон для определения того, когда конкретный момент времени имеет место для данного года, в зависимости от месяца, недели и дня недели.

  • Правило перехода не сообщает вам все, что вам нужно знать для расчета значений для часовых поясов. В частности, он не сообщает вам, что такое смещение от UTC до или после перехода, или направление корректировки смещения. Кроме того, вам понадобится набор из них, так как обычно их два в год, но также может быть любое количество из них. Например, в 2014 году Russia had only one transition и Egypt had four. Также учтите, что эти правила со временем изменились, поэтому одно правило или даже одна пара правил не расскажут вам, как конвертировать значения для всех точек во времени. Для данного часового пояса вам необходимо установить набор правил, что мы имеем в виду, когда говорим «часовой пояс».

  • В .NET Framework класс TimeZoneInfo используется для работы с часовыми поясами. Он содержит подклассы, TimeZoneInfo.AdjustmentRule и TimeZoneInfo.TransitionTime. В частности, есть внутренняя функция в TimeZoneInfo под названием TransitionTimeToDateTime, которая делает именно то, что вы просите. Он принимает TransitionTime и год и дает DateTime, что переход происходит в течение года. Вы можете найти это in the .NET Reference Source here.

Однако, если вы действительно думаете, что вы хотите, чтобы попытаться реализовать правила часового пояса из собственных источников данных, вы должны думать о нескольких вещах:

  1. Вы действительно думаете, что вы можете сделать лучше, чем сотни людей, которые были перед вами? Может быть, так, но не входите в это с «это простое» отношение. Я предлагаю вам watch this short video, и сделайте много исследований, прежде чем пытаться это сделать.

  2. Вы думаете о том, как сохранить содержание? Правила часовых поясов часто меняются. Ежегодно во всем мире может быть около десятка изменений. Планируете ли вы следить за новостями, дискуссионными форумами, правительственными пресс-релизами и другими источниками? Готовы ли вы действовать, когда правительство не дает такого предупреждения, что правила DST будут меняться?

  3. Какое влияние это окажет на вашу систему, если что-то неточно? Он может варьироваться от незначительного (например: блог или форум) до критического (например, расписания авиакомпаний, связи, медицинские, финансовые и т. Д.).

Дополнительно:

  • Предложение использования Noda Time от комментариев на вопрос является хорошим, но, к сожалению, Нода время не имеет каких-либо конкретных API для интерпретации только одно правило перехода. Вместо этого предпочтительнее использовать существующие зоны TZDB, такие как "America/New_York". Кроме того, вы можете использовать класс TimeZoneInfo в .NET Framework с идентификаторами, например "Eastern Standard Time".

  • Внутренне, Noda Time обрабатывает правила перехода через класс ZoneYearOffset. Вы можете видеть, как TransitionRule соответствует ZoneYearOffset в this code.

  • В вашем примере кода, комментариев "Take off the DST hour to convert it to UTC." крайне вводит в заблуждение. Вывод вашей функции производится по местному времени. UTC не имеет к этому никакого отношения. Нигде в коде, который вы показали здесь, вы отслеживаете смещения от UTC, либо с DST, либо без него. Я думаю, вы имели в виду «... преобразовать его в стандартное время», но я не уверен, почему вы захотите это сделать. Эта конкретная функция не должна пытаться объяснить это.

  • Вы также спросили: «Учитывается ли это в течение получасовых изменений в летнее время, как в Индии?» Вопрос недействителен, потому что у Индии нет ДСТ. Его стандартное смещение часового пояса имеет полчаса (UTC + 05: 30), но нет DST. Единственное место в мире, которое в настоящее время использует уклонение DST на полчаса, это лорд-Хоу-Айленд, который представлен часовым поясом "Australia/Lord_Howe" в tzdb и в настоящее время не имеет эквивалента Windows. В любом месте в мире (за исключением нескольких исследовательских станций в Антарктиде), если используется DST, смещение перехода составляет один час.