Поделиться через


Практическое руководство. Отображение дат в календарях, отличных от григорианского

Обновлен: Ноябрь 2007

Типы DateTime и DateTimeOffset используют григорианский календарь в качестве календаря по умолчанию. Это означает, что вызов метода ToString для значения даты и времени выведет строковое представление даты и времени в григорианском календаре даже в том случае, если значение даты и времени создавалось с помощью другого календаря. Это показано в следующем примере, в котором используется два различных способа создания значения даты и времени с персидским календарем. Однако при вызове метода ToString значения даты и времени в нем по-прежнему отображаются в григорианском календаре. В этом примере представлены два часто используемых неверных способа отображения даты в заданном календаре.

Dim persianCal As New PersianCalendar()

      Dim persianDate As Date = persianCal.ToDateTime(1387, 3, 18, _
                                                      12, 0, 0, 0)
      Console.WriteLine(persianDate.ToString())

      persianDate = New DateTime(1387, 3, 18, persianCal)
      Console.WriteLine(persianDate.ToString())
      ' The example displays the following output to the console:
      '       6/7/2008 12:00:00 PM
      '       6/7/2008 12:00:00 AM
PersianCalendar persianCal = new PersianCalendar();

      DateTime persianDate = persianCal.ToDateTime(1387, 3, 18, 12, 0, 0, 0);
      Console.WriteLine(persianDate.ToString());

      persianDate = new DateTime(1387, 3, 18, persianCal);
      Console.WriteLine(persianDate.ToString());
      // The example displays the following output to the console:
      //       6/7/2008 12:00:00 PM
      //       6/7/2008 12:00:00 AM

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

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

  1. Создайте экземпляр календаря, производного от класса Calendar, представляющего календарь, который будет использоваться.

  2. Создайте экземпляр объекта CultureInfo, представляющего региональные параметры, которые будут использоваться для отображения даты.

  3. Вызовите метод Array.Exists<T>, чтобы определить, является ли объект календаря элементом массива, возвращенного свойством CultureInfo.OptionalCalendars. Это означает, что календарь может использоваться в качестве календаря по умолчанию для объекта CultureInfo. Если он не является элементом массива, следуйте инструкциям в разделе "Отображение даты в любом календаре".

  4. Присвойте объект календаря свойству Calendar объекта DateTimeFormatInfo, возвращаемого свойством CultureInfo.DateTimeFormat.

    Bb882586.alert_note(ru-ru,VS.90).gifПримечание.

    Класс CultureInfo также имеет свойство Calendar. Однако это свойство только для чтения и является константой. Оно не изменяется для отражения нового календаря по умолчанию, присвоенного свойству DateTimeFormatInfo.Calendar.

  5. Вызовите метод ToString или метод ToString и передайте ему объект CultureInfo, для которого на предыдущем шаге был изменен календарь по умолчанию.

Отображение даты в любом календаре

  1. Создайте экземпляр календаря, производного от класса Calendar, представляющего календарь, который будет использоваться.

  2. Определите, какие элементы даты и времени должны отображаться в строковом представлении значения даты и времени.

  3. Для каждого элемента даты и времени, который требуется отобразить, вызовите метод объекта календаря Get. Доступны следующие методы:

    • GetYear — отображение года в соответствующем календаре.

    • GetMonth — отображение месяца в соответствующем календаре.

    • GetDayOfMonth — отображение числа дней в месяце в соответствующем календаре.

    • GetHour — отображение часа дня в соответствующем календаре.

    • GetMinute — отображение минут в часе в соответствующем календаре.

    • GetSecond — отображение секунд в минуте в соответствующем календаре.

    • GetMilliseconds — отображение миллисекунд в секунде в соответствующем календаре.

Пример

В примере отображается дата с помощью двух различных календарей. Отображается дата после определения исламского календаря в качестве календаря по умолчанию для региональных параметров ar-JO, а также дата с помощью персидского календаря, который не поддерживается в региональных параметрах fa-IR как дополнительный календарь.

Imports System.Globalization

Public Class CalendarDates
   Public Shared Sub Main()
      Dim hijriCal As New HijriCalendar()
      Dim hijriUtil As New CalendarUtility(hijriCal)
      Dim hijriDate1 As Date = New Date(1429, 6, 29, hijriCal)
      Dim hijriDate2 As DateTimeOffset = New DateTimeOffset(hijriDate1, _
                                         TimeZoneInfo.Local.GetUtcOffset(hijriDate1))
      Dim jc As CultureInfo = CultureInfo.CreateSpecificCulture("ar-JO")

      ' Display the date using the Gregorian calendar.
      Console.WriteLine("Using the system default culture: {0}", _
                        hijriDate1.ToString("d"))
      ' Display the date using the ar-JO culture's original default calendar.
      Console.WriteLine("Using the ar-JO culture's original default calendar: {0}", _
                        hijriDate1.ToString("d", jc))
      ' Display the date using the Hijri calendar.
      Console.WriteLine("Using the ar-JO culture with Hijri as the default calendar:")
      ' Display a Date value.
      Console.WriteLine(hijriUtil.DisplayDate(hijriDate1, jc))
      ' Display a DateTimeOffset value.
      Console.WriteLine(hijriUtil.DisplayDate(hijriDate2, jc))

      Console.WriteLine()

      Dim persianCal As New PersianCalendar()
      Dim persianUtil As New CalendarUtility(persianCal)
      Dim ic As CultureInfo = CultureInfo.CreateSpecificCulture("fa-IR")

      ' Display the date using the ir-FA culture's default calendar.
      Console.WriteLine("Using the ir-FA culture's default calendar: {0}", _      
                        hijriDate1.ToString("d", ic))
      ' Display a Date value.
      Console.WriteLine(persianUtil.DisplayDate(hijriDate1, ic))
      ' Display a DateTimeOffset value.
      Console.WriteLine(persianUtil.DisplayDate(hijriDate2, ic))
   End Sub
End Class

Public Class CalendarUtility
   Private thisCalendar As Calendar
   Private targetCulture As CultureInfo

   Public Sub New(cal As Calendar)
      Me.thisCalendar = cal
   End Sub

   Private Function CalendarExists(culture As CultureInfo) As Boolean
      Me.targetCulture = culture
      Return Array.Exists(Me.targetCulture.OptionalCalendars, _
                          AddressOf Me.HasSameName)
   End Function 

   Private Function HasSameName(cal As Calendar) As Boolean
      If cal.ToString() = thisCalendar.ToString() Then
         Return True
      Else
         Return False
      End If
   End Function

   Public Function DisplayDate(dateToDisplay As Date, _
                               culture As CultureInfo) As String
      Dim displayOffsetDate As DateTimeOffset = dateToDisplay
      Return DisplayDate(displayOffsetDate, culture)
   End Function

   Public Function DisplayDate(dateToDisplay As DateTimeOffset, _
                               culture As CultureInfo) As String
      Dim specifier As String = "yyyy/MM/dd"

      If Me.CalendarExists(culture) Then
         Console.WriteLine("Displaying date in supported {0} calendar...", _
                           thisCalendar.GetType().Name)
         culture.DateTimeFormat.Calendar = Me.thisCalendar
         Return dateToDisplay.ToString(specifier, culture)
      Else
         Console.WriteLine("Displaying date in unsupported {0} calendar...", _
                           thisCalendar.GetType().Name)

         Dim separator As String = targetCulture.DateTimeFormat.DateSeparator

         Return thisCalendar.GetYear(dateToDisplay.DateTime).ToString("0000") & separator & _
                thisCalendar.GetMonth(dateToDisplay.DateTime).ToString("00") & separator & _
                thisCalendar.GetDayOfMonth(dateToDisplay.DateTime).ToString("00") 
      End If             
   End Function
End Class
' The example displays the following output to the console:
'       Using the system default culture: 7/3/2008
'       Using the ar-JO culture's original default calendar: 03/07/2008
'       Using the ar-JO culture with Hijri as the default calendar:
'       Displaying date in supported HijriCalendar calendar...
'       1429/06/29
'       Displaying date in supported HijriCalendar calendar...
'       1429/06/29
'       
'       Using the ir-FA culture's default calendar: 7/3/2008
'       Displaying date in unsupported PersianCalendar calendar...
'       1387/04/13
'       Displaying date in unsupported PersianCalendar calendar...
'       1387/04/13
using System;
using System.Globalization;

public class CalendarDates
{
   public static void Main()
   {
      HijriCalendar hijriCal = new HijriCalendar();
      CalendarUtility hijriUtil = new CalendarUtility(hijriCal);
      DateTime hijriDate1 = new DateTime(1429, 6, 29, hijriCal);
      DateTimeOffset hijriDate2 = new DateTimeOffset(hijriDate1, 
                                  TimeZoneInfo.Local.GetUtcOffset(hijriDate1));
      CultureInfo jc = CultureInfo.CreateSpecificCulture("ar-JO");

      // Display the date using the Gregorian calendar.
      Console.WriteLine("Using the system default culture: {0}", 
                        hijriDate1.ToString("d"));
      // Display the date using the ar-JO culture's original default calendar.
      Console.WriteLine("Using the ar-JO culture's original default calendar: {0}", 
                        hijriDate1.ToString("d", jc));
      // Display the date using the Hijri calendar.
      Console.WriteLine("Using the ar-JO culture with Hijri as the default calendar:");
      // Display a Date value.
      Console.WriteLine(hijriUtil.DisplayDate(hijriDate1, jc));
      // Display a DateTimeOffset value.
      Console.WriteLine(hijriUtil.DisplayDate(hijriDate2, jc));

      Console.WriteLine();

      PersianCalendar persianCal = new PersianCalendar();
      CalendarUtility persianUtil = new CalendarUtility(persianCal);
      CultureInfo ic = CultureInfo.CreateSpecificCulture("fa-IR");

      // Display the date using the ir-FA culture's default calendar.
      Console.WriteLine("Using the ir-FA culture's default calendar: {0}",       
                        hijriDate1.ToString("d", ic));
      // Display a Date value.
      Console.WriteLine(persianUtil.DisplayDate(hijriDate1, ic));
      // Display a DateTimeOffset value.
      Console.WriteLine(persianUtil.DisplayDate(hijriDate2, ic));
   }
}

public class CalendarUtility
{
   private Calendar thisCalendar;
   private CultureInfo targetCulture;

   public CalendarUtility(Calendar cal)
   {
      this.thisCalendar = cal;
   }

   private bool CalendarExists(CultureInfo culture)
   {
      this.targetCulture = culture;
      return Array.Exists(this.targetCulture.OptionalCalendars, 
                          this.HasSameName);
   }

   private bool HasSameName(Calendar cal)
   {
      if (cal.ToString() == thisCalendar.ToString())
         return true;
      else
         return false;
   }

   public string DisplayDate(DateTime dateToDisplay, CultureInfo culture)
   {
      DateTimeOffset displayOffsetDate = dateToDisplay;
      return DisplayDate(displayOffsetDate, culture);
   }

   public string DisplayDate(DateTimeOffset dateToDisplay, 
                             CultureInfo culture)
   {
      string specifier = "yyyy/MM/dd";

      if (this.CalendarExists(culture))
      {
         Console.WriteLine("Displaying date in supported {0} calendar...", 
                           this.thisCalendar.GetType().Name);
         culture.DateTimeFormat.Calendar = this.thisCalendar;
         return dateToDisplay.ToString(specifier, culture);
      }
      else
      {
         Console.WriteLine("Displaying date in unsupported {0} calendar...", 
                           thisCalendar.GetType().Name);

         string separator = targetCulture.DateTimeFormat.DateSeparator;

         return thisCalendar.GetYear(dateToDisplay.DateTime).ToString("0000") +
                separator +
                thisCalendar.GetMonth(dateToDisplay.DateTime).ToString("00") + 
                separator +
                thisCalendar.GetDayOfMonth(dateToDisplay.DateTime).ToString("00"); 
      }
   } 
}
// The example displays the following output to the console:
//       Using the system default culture: 7/3/2008
//       Using the ar-JO culture's original default calendar: 03/07/2008
//       Using the ar-JO culture with Hijri as the default calendar:
//       Displaying date in supported HijriCalendar calendar...
//       1429/06/29
//       Displaying date in supported HijriCalendar calendar...
//       1429/06/29
//       
//       Using the ir-FA culture's default calendar: 7/3/2008
//       Displaying date in unsupported PersianCalendar calendar...
//       1387/04/13
//       Displaying date in unsupported PersianCalendar calendar...
//       1387/04/13

Каждый объект CultureInfo может поддерживать один или несколько календарей, которые обозначены свойством OptionalCalendars. Один из них обозначается как календарь по умолчанию для региональных параметров и возвращается свойством только для чтения CultureInfo.Calendar. Другие дополнительные календари могут быть назначены как календари по умолчанию путем присваивания объекта Calendar, представляющего календарь, свойству DateTimeFormatInfo.Calendar, возвращаемому свойством CultureInfo.DateTimeFormat. Однако некоторые календари, например персидский календарь, представленный классом PersianCalendar, не могут служить дополнительными календарями в любых региональных параметрах.

В примере определяется повторно используемый служебный класс календаря CalendarUtility для обработки множества данных, связанных с созданием строкового представления даты с помощью конкретного календаря. В классе CalendarUtility представлены следующие элементы:

  • Параметризованный конструктор, единственным параметром которого является объект Calendar, которым представлена дата. Он присваивается закрытому полю класса.

  • Закрытый метод CalendarExists, который возвращает логическое значение, показывающее, поддерживается ли календарь, представленный объектом CalendarUtility, объектом CultureInfo, переданным методу в качестве параметра. Этот метод создает оболочку вызова для метода Array.Exists<T>, которому он передает массив CultureInfo.OptionalCalendars.

  • Закрытый метод HasSameName, присвоенный делегату Predicate<T>, передается в качестве параметра методу Array.Exists<T>. Каждый элемент массива передается методу до тех пор, пока метод не вернет значение true. Этот метод определяет, совпадает ли имя дополнительного календаря с именем календаря, представленного объектом CalendarUtility.

  • Перегруженный открытый метод DisplayDate, которому передается два параметра: значение DateTime или DateTimeOffset, выражаемое в календаре, представленном объектом CalendarUtility, а также региональные параметры, правила форматирования которых будут использоваться. Его поведение при возврате строкового представления даты зависит от того, поддерживается ли целевой календарь в региональных параметрах, правила форматирования которых будут использоваться.

Независимо от календаря, используемого для создания значения DateTime или значения DateTimeOffset в этом примере, это значение обычно выражается в виде григорианской даты. Это происходит потому, что типы DateTime и DateTimeOffset не сохраняют никаких данных календаря. Внутренне они представлены как число тактов, прошедших с момента полуночи 1 января 0001 года. Интерпретация этого числа зависит от календаря. В большинстве региональных параметров по умолчанию используется григорианский календарь.

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

Для этого примера требуется ссылка на System.Core.dll.

Откомпилируйте код из командной строки, используя csc.exe или vb.exe. Чтобы откомпилировать код в Visual Studio, поместите его в шаблон проекта консольного приложения.

См. также

Основные понятия

Руководства по форматированию