Практическое руководство. Создание часовых поясов с правилами коррекции

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

  • Часовой пояс никогда не определен в реестре локальной системы.

  • Данные о часовом поясе были изменены или удалены из реестра.

  • Часовой пояс не содержит точных сведений о корректировках часового пояса для определенного исторического периода.

В таких случаях можно вызвать метод, чтобы определить часовой CreateCustomTimeZone пояс, необходимый приложению. Перегрузки этого метода можно использовать для создания часового пояса с правилами корректировки или без них. Если часовой пояс поддерживает летнее время, можно определить корректировки с помощью фиксированных или плавающих правил корректировки. (Определения этих терминов см. в разделе "Терминология часового пояса" в разделе "Терминология часового пояса"Обзор часового пояса.)

Внимание

Пользовательские часовые пояса, созданные путем вызова CreateCustomTimeZone метода, не добавляются в реестр. Вместо этого они могут быть доступны только через ссылку на объект, возвращаемую вызовом CreateCustomTimeZone метода.

В этом разделе показано, как создать часовой пояс с правилами корректировки. Чтобы создать часовой пояс, который не поддерживает правила корректировки летнего времени, см. статью "Практическое руководство. Создание часовых поясов без правил корректировки".

Создание часового пояса с правилами с плавающей корректировкой

  1. Для каждой корректировки (т. е. для каждого перехода от стандартного времени в течение определенного интервала времени) сделайте следующее:

    1. Определите время начала перехода для корректировки часового пояса.

      Необходимо вызвать TimeZoneInfo.TransitionTime.CreateFloatingDateRule метод и передать его DateTime значение, определяющее время перехода, целочисленное значение, определяющее месяц перехода, целочисленное значение, определяющее неделю, на которой происходит переход, и DayOfWeek значение, определяющее день недели, на которой происходит переход. Этот метод вызывает создание экземпляра TimeZoneInfo.TransitionTime объекта.

    2. Определите конечное время перехода для корректировки часового пояса. Для этого требуется еще один вызов TimeZoneInfo.TransitionTime.CreateFloatingDateRule метода. Этот метод вызывает экземпляр второго TimeZoneInfo.TransitionTime объекта.

    3. CreateAdjustmentRule Вызовите метод и передайте его действующие даты начала и окончания корректировки, объект, TimeSpan определяющий время перехода, а также два TimeZoneInfo.TransitionTime объекта, определяющие, когда происходит переход на летнее время и с летнего времени. Этот метод вызывает создание экземпляра TimeZoneInfo.AdjustmentRule объекта.

    4. TimeZoneInfo.AdjustmentRule Назначьте объект массиву TimeZoneInfo.AdjustmentRule объектов.

  2. Определите отображаемое имя часового пояса. Отображаемое имя соответствует довольно стандартному формату, в котором смещение часового пояса от координированного универсального времени (UTC) заключено в скобки и за ним следует строка, которая определяет часовой пояс, один или несколько городов в часовом поясе или один или несколько стран или регионов часового пояса.

  3. Определите имя стандартного часового пояса. Как правило, эта строка также используется в качестве идентификатора часового пояса.

  4. Определите имя дневного времени часового пояса.

  5. Если вы хотите использовать идентификатор, отличный от стандартного имени часового пояса, определите идентификатор часового пояса.

  6. Создайте TimeSpan экземпляр объекта, который определяет смещение часового пояса из UTC. Часовые пояса со временем, превышающими utc, имеют положительное смещение. Часовые пояса с временем, предшествующим utc, имеют отрицательное смещение.

  7. TimeZoneInfo.CreateCustomTimeZone(String, TimeSpan, String, String, String, TimeZoneInfo+AdjustmentRule[]) Вызовите метод, чтобы создать экземпляр нового часового пояса.

Пример

В следующем примере определяется центральный стандартный часовой пояс для США, который включает правила корректировки для различных интервалов времени от 1918 до настоящего.

TimeZoneInfo cst;
// Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
TimeSpan delta = new TimeSpan(1, 0, 0);
TimeZoneInfo.AdjustmentRule adjustment;
List<TimeZoneInfo.AdjustmentRule> adjustmentList = new List<TimeZoneInfo.AdjustmentRule>();
// Declare transition time variables to hold transition time information
TimeZoneInfo.TransitionTime transitionRuleStart, transitionRuleEnd;

// Define new Central Standard Time zone 6 hours earlier than UTC
// Define rule 1 (for 1918-1919)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 03, 05, DayOfWeek.Sunday);
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 10, 05, DayOfWeek.Sunday);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1918, 1, 1), new DateTime(1919, 12, 31), delta,
                                                           transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 2 (for 1942)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 02, 09);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1942, 1, 1), new DateTime(1942, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 3 (for 1945)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 23, 0, 0), 08, 14);
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 09, 30);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1945, 1, 1), new DateTime(1945, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define end rule (for 1967-2006)
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 10, 5, DayOfWeek.Sunday);
// Define rule 4 (for 1967-73)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 05, DayOfWeek.Sunday);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1967, 1, 1), new DateTime(1973, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 5 (for 1974 only)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 01, 06);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1974, 1, 1), new DateTime(1974, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 6 (for 1975 only)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(new DateTime(1, 1, 1, 2, 0, 0), 02, 23);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1975, 1, 1), new DateTime(1975, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 7 (1976-1986)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 05, DayOfWeek.Sunday);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1976, 1, 1), new DateTime(1986, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 8 (1987-2006)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 04, 01, DayOfWeek.Sunday);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1987, 1, 1), new DateTime(2006, 12, 31),
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);
// Define rule 9 (2007- )
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 03, 02, DayOfWeek.Sunday);
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 11, 01, DayOfWeek.Sunday);
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(2007, 1, 1), DateTime.MaxValue.Date,
                                                           delta, transitionRuleStart, transitionRuleEnd);
adjustmentList.Add(adjustment);

// Convert list of adjustment rules to an array
TimeZoneInfo.AdjustmentRule[] adjustments = new TimeZoneInfo.AdjustmentRule[adjustmentList.Count];
adjustmentList.CopyTo(adjustments);

cst = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", new TimeSpan(-6, 0, 0),
      "(GMT-06:00) Central Time (US Only)", "Central Standard Time",
      "Central Daylight Time", adjustments);
Dim cst As TimeZoneInfo
' Declare necessary TimeZoneInfo.AdjustmentRule objects for time zone
Dim delta As New TimeSpan(1, 0, 0)
Dim adjustment As TimeZoneInfo.AdjustmentRule
Dim adjustmentList As New List(Of TimeZoneInfo.AdjustmentRule)
' Declare transition time variables to hold transition time information
Dim transitionRuleStart, transitionRuleEnd As TimeZoneInfo.TransitionTime

' Define new Central Standard Time zone 6 hours earlier than UTC
' Define rule 1 (for 1918-1919)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 03, 05, DayOfWeek.Sunday)
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 10, 05, DayOfWeek.Sunday)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1918#, #12/31/1919#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 2 (for 1942)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(#2:00:00AM#, 02, 09)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1942#, #12/31/1942#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 3 (for 1945)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(#11:00:00PM#, 08, 14)
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFixedDateRule(#2:00:00AM#, 09, 30)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1945#, #12/31/1945#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define end rule (for 1967-2006)
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#02:00:00AM#, 10, 5, DayOfWeek.Sunday)
' Define rule 4 (for 1967-73)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 05, DayOfWeek.Sunday)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1967#, #12/31/1973#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 5 (for 1974 only)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(#2:00:00AM#, 01, 06)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1974#, #12/31/1974#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 6 (for 1975 only)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFixedDateRule(#2:00:00AM#, 02, 23)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1975#, #12/31/1975#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 7 (1976-1986)
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 05, DayOfWeek.Sunday)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1976#, #12/31/1986#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 8 (1987-2006)  
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 04, 01, DayOfWeek.Sunday)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/1987#, #12/31/2006#, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)
' Define rule 9 (2007- )  
transitionRuleStart = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 03, 02, DayOfWeek.Sunday)
transitionRuleEnd = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(#2:00:00AM#, 11, 01, DayOfWeek.Sunday)
adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(#01/01/2007#, Date.MaxValue.Date, delta, transitionRuleStart, transitionRuleEnd)
adjustmentList.Add(adjustment)

' Convert list of adjustment rules to an array
Dim adjustments(adjustmentList.Count - 1) As TimeZoneInfo.AdjustmentRule
adjustmentList.CopyTo(adjustments)

cst = TimeZoneInfo.CreateCustomTimeZone("Central Standard Time", New TimeSpan(-6, 0, 0), _
      "(GMT-06:00) Central Time (US Only)", "Central Standard Time", _
      "Central Daylight Time", adjustments)

Часовой пояс, созданный в этом примере, содержит несколько правил корректировки. Необходимо обеспечить, чтобы действующие даты начала и окончания любого правила корректировки не перекрывались с датами другого правила корректировки. Если есть перекрытие, InvalidTimeZoneException создается исключение.

Для правил с плавающей корректировкой значение 5 передается week параметру CreateFloatingDateRule метода, чтобы указать, что переход происходит на прошлой неделе определенного месяца.

При создании массива объектов, используемых TimeZoneInfo.AdjustmentRule в TimeZoneInfo.CreateCustomTimeZone(String, TimeSpan, String, String, String, TimeZoneInfo+AdjustmentRule[]) вызове метода, код может инициализировать массив до размера, необходимого для количества настроек, создаваемых для часового пояса. Вместо этого этот пример кода вызывает Add метод для добавления каждого правила корректировки TimeZoneInfo.AdjustmentRule в универсальную List<T> коллекцию объектов. Затем код вызывает CopyTo метод для копирования членов этой коллекции в массив.

В примере также используется CreateFixedDateRule метод для определения корректировки фиксированной даты. Это похоже на вызов CreateFloatingDateRule метода, за исключением того, что требуется только время, месяц и день перехода параметров.

Пример можно проверить с помощью кода, например следующего:

TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

DateTime pastDate1 = new DateTime(1942, 2, 11);
Console.WriteLine("Is {0} daylight saving time: {1}", pastDate1,
                  cst.IsDaylightSavingTime(pastDate1));

DateTime pastDate2 = new DateTime(1967, 10, 29, 1, 30, 00);
Console.WriteLine("Is {0} ambiguous: {1}", pastDate2,
                  cst.IsAmbiguousTime(pastDate2));

DateTime pastDate3 = new DateTime(1974, 1, 7, 2, 59, 00);
Console.WriteLine("{0} {1} is {2} {3}", pastDate3,
                  est.IsDaylightSavingTime(pastDate3) ?
                      est.DaylightName : est.StandardName,
                  TimeZoneInfo.ConvertTime(pastDate3, est, cst),
                  cst.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(pastDate3, est, cst)) ?
                      cst.DaylightName : cst.StandardName);
//
// This code produces the following output to the console:
//
//    Is 2/11/1942 12:00:00 AM daylight saving time: True
//    Is 10/29/1967 1:30:00 AM ambiguous: True
//    1/7/1974 2:59:00 AM Eastern Standard Time is 1/7/1974 2:59:00 AM Central Daylight Time
Dim est As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time")

Dim pastDate1 As Date = #2/11/1942#
Console.WriteLine("Is {0} daylight saving time: {1}", pastDate1, _
                  cst.IsDaylightSavingTime(pastDate1))

Dim pastDate2 As Date = #10/29/1967 1:30AM#
Console.WriteLine("Is {0} ambiguous: {1}", pastDate2, _
                  cst.IsAmbiguousTime(pastDate2))

Dim pastDate3 As Date = #1/7/1974 2:59AM#
Console.WriteLine("{0} {1} is {2} {3}", pastDate3, _
                  IIf(est.IsDaylightSavingTime(pastDate3), _
                      est.DaylightName, est.StandardName), _
                  TimeZoneInfo.ConvertTime(pastDate3, est, cst), _
                  IIf(cst.IsDaylightSavingTime(TimeZoneInfo.ConvertTime(pastDate3, est, cst)), _
                      cst.DaylightName, cst.StandardName))
'
' This code produces the following output to the console:
' 
'    Is 2/11/1942 12:00:00 AM daylight saving time: True
'    Is 10/29/1967 1:30:00 AM ambiguous: True
'    1/7/1974 2:59:00 AM Eastern Standard Time is 1/7/1974 2:59:00 AM Central Daylight Time                            

Компиляция кода

Для этого примера требуются:

  • Импортируются следующие пространства имен:

    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    
    Imports System.Collections.Generic
    Imports System.Collections.ObjectModel
    
    

См. также