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


Работа с календарями

Хотя значение даты и времени представляет момент времени, его строковое представление чувствительно к культуре и зависит как от соглашений, используемых для отображения значений даты и времени определённой культурой, так и от календаря, используемого этой культурой. В этом разделе рассматривается поддержка календарей в .NET и рассматривается использование классов календарей при работе со значениями даты.

Календари в .NET

Все календари в .NET являются производными от System.Globalization.Calendar класса, который предоставляет базовую реализацию календаря. Одним из классов, наследуемых от Calendar класса, является EastAsianLunisolarCalendar класс, который является базовым классом для всех лунисолярных календарей. .NET включает следующие реализации календаря:

  • ChineseLunisolarCalendar, представляющий китайский лунисолярный календарь.

  • GregorianCalendar, представляющий григорианский календарь. Этот календарь также делится на подтипы (например, арабский и ближневосточный французский), которые определяются System.Globalization.GregorianCalendarTypes перечислением. Свойство GregorianCalendar.CalendarType задает подтип григорианского календаря.

  • HebrewCalendar, представляющий ивритский календарь.

  • HijriCalendar, представляющий календарь Хиджри.

  • JapaneseCalendar, представляющий японский календарь.

  • JapaneseLunisolarCalendar, представляющий японский луносолярный календарь.

  • JulianCalendar, представляющий джулианский календарь.

  • KoreanCalendar, представляющий корейский календарь.

  • KoreanLunisolarCalendar, представляющий корейский лунисолярный календарь.

  • PersianCalendar, представляющий персидский календарь.

  • TaiwanCalendar, представляющий календарь Тайваня.

  • TaiwanLunisolarCalendar, представляющий тайваньский лунисолярный календарь.

  • ThaiBuddhistCalendar, который представляет тайский буддийский календарь.

  • UmAlQuraCalendar, который представляет календарь Умм аль-Кура.

Календарь можно использовать одним из двух способов:

  • В качестве календаря, используемого определенной культурой. Каждый CultureInfo объект имеет текущий календарь, который является календарем, который в данный момент используется объектом. Строковые представления всех значений даты и времени автоматически отражают текущую культуру и текущий календарь этой культуры. Как правило, текущий календарь — это календарь по умолчанию культуры. CultureInfo Объекты также имеют необязательные календари, которые включают дополнительные календари, которые может использовать культура.

  • Как автономный календарь, независимый от конкретной культуры. В этом случае Calendar методы используются для выражения дат в виде значений, которые отражают календарь.

Обратите внимание, что шесть классов календарей — ChineseLunisolarCalendar, JapaneseLunisolarCalendarJulianCalendar, KoreanLunisolarCalendar, PersianCalendarи TaiwanLunisolarCalendar — можно использовать только в качестве автономных календарей. Они не используются ни одной культурой в качестве основного или дополнительного календаря.

Календари и культуры

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

В следующем примере иллюстрируются свойства CultureInfo.Calendar и CultureInfo.OptionalCalendars. Он создает CultureInfo объекты для культур Тайского (Таиланда) и японского (Японии) и отображает их стандартные и необязательные календари. Обратите внимание, что в обоих случаях календарь по умолчанию для данной культуры также включен в коллекцию CultureInfo.OptionalCalendars.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      // Create a CultureInfo for Thai in Thailand.
      CultureInfo th = CultureInfo.CreateSpecificCulture("th-TH");
      DisplayCalendars(th);

      // Create a CultureInfo for Japanese in Japan.
      CultureInfo ja = CultureInfo.CreateSpecificCulture("ja-JP");
      DisplayCalendars(ja);
   }

   static void DisplayCalendars(CultureInfo ci)
   {
      Console.WriteLine($"Calendars for the {ci.Name} culture:");

      // Get the culture's default calendar.
      Calendar defaultCalendar = ci.Calendar;
      Console.Write("   Default Calendar: {0}", GetCalendarName(defaultCalendar));

      if (defaultCalendar is GregorianCalendar)
         Console.WriteLine($" ({((GregorianCalendar) defaultCalendar).CalendarType})");
      else
         Console.WriteLine();

      // Get the culture's optional calendars.
      Console.WriteLine("   Optional Calendars:");
      foreach (var optionalCalendar in ci.OptionalCalendars) {
         Console.Write("{0,6}{1}", "", GetCalendarName(optionalCalendar));
         if (optionalCalendar is GregorianCalendar)
            Console.Write(" ({0})",
                          ((GregorianCalendar) optionalCalendar).CalendarType);

         Console.WriteLine();
      }
      Console.WriteLine();
   }

   static string GetCalendarName(Calendar cal)
   {
      return cal.ToString().Replace("System.Globalization.", "");
   }
}
// The example displays the following output:
//       Calendars for the th-TH culture:
//          Default Calendar: ThaiBuddhistCalendar
//          Optional Calendars:
//             ThaiBuddhistCalendar
//             GregorianCalendar (Localized)
//
//       Calendars for the ja-JP culture:
//          Default Calendar: GregorianCalendar (Localized)
//          Optional Calendars:
//             GregorianCalendar (Localized)
//             JapaneseCalendar
//             GregorianCalendar (USEnglish)
Imports System.Globalization

Public Module Example
    Public Sub Main()
        ' Create a CultureInfo for Thai in Thailand.
        Dim th As CultureInfo = CultureInfo.CreateSpecificCulture("th-TH")
        DisplayCalendars(th)

        ' Create a CultureInfo for Japanese in Japan.
        Dim ja As CultureInfo = CultureInfo.CreateSpecificCulture("ja-JP")
        DisplayCalendars(ja)
    End Sub

    Sub DisplayCalendars(ci As CultureInfo)
        Console.WriteLine("Calendars for the {0} culture:", ci.Name)

        ' Get the culture's default calendar.
        Dim defaultCalendar As Calendar = ci.Calendar
        Console.Write("   Default Calendar: {0}", GetCalendarName(defaultCalendar))

        If TypeOf defaultCalendar Is GregorianCalendar Then
            Console.WriteLine(" ({0})",
                              CType(defaultCalendar, GregorianCalendar).CalendarType)
        Else
            Console.WriteLine()
        End If

        ' Get the culture's optional calendars.
        Console.WriteLine("   Optional Calendars:")
        For Each optionalCalendar In ci.OptionalCalendars
            Console.Write("{0,6}{1}", "", GetCalendarName(optionalCalendar))
            If TypeOf optionalCalendar Is GregorianCalendar Then
                Console.Write(" ({0})",
                              CType(optionalCalendar, GregorianCalendar).CalendarType)
            End If
            Console.WriteLine()
        Next
        Console.WriteLine()
    End Sub

    Function GetCalendarName(cal As Calendar) As String
        Return cal.ToString().Replace("System.Globalization.", "")
    End Function
End Module
' The example displays the following output:
'       Calendars for the th-TH culture:
'          Default Calendar: ThaiBuddhistCalendar
'          Optional Calendars:
'             ThaiBuddhistCalendar
'             GregorianCalendar (Localized)
'       
'       Calendars for the ja-JP culture:
'          Default Calendar: GregorianCalendar (Localized)
'          Optional Calendars:
'             GregorianCalendar (Localized)
'             JapaneseCalendar
'             GregorianCalendar (USEnglish)

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

В следующем примере изменяется календарь, используемый культурными настройками арабской культуры (Саудовская Аравия). Сначала он создает экземпляр значения DateTime и отображает его, используя текущую культуру — которая в данном случае является английским (США) — и календарь текущей культуры (в данном случае — григорианский календарь). Затем он изменяет текущую культуру на арабскую (Саудовская Аравия) и отображает дату, используя календарь Um Al-Qura по умолчанию. Затем он вызывает CalendarExists метод, чтобы определить, поддерживается ли календарь Хиджри арабским языком (Саудовская Аравия). Так как календарь поддерживается, он изменяет текущий календарь на Хиджри и снова отображает дату. Обратите внимание, что в каждом случае дата отображается с помощью календаря текущей культуры.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      DateTime date1 = new DateTime(2011, 6, 20);

      DisplayCurrentInfo();
      // Display the date using the current culture and calendar.
      Console.WriteLine(date1.ToString("d"));
      Console.WriteLine();

      CultureInfo arSA = CultureInfo.CreateSpecificCulture("ar-SA");

      // Change the current culture to Arabic (Saudi Arabia).
      Thread.CurrentThread.CurrentCulture = arSA;
      // Display date and information about the current culture.
      DisplayCurrentInfo();
      Console.WriteLine(date1.ToString("d"));
      Console.WriteLine();

      // Change the calendar to Hijri.
      Calendar hijri = new HijriCalendar();
      if (CalendarExists(arSA, hijri)) {
         arSA.DateTimeFormat.Calendar = hijri;
         // Display date and information about the current culture.
         DisplayCurrentInfo();
         Console.WriteLine(date1.ToString("d"));
      }
   }

   private static void DisplayCurrentInfo()
   {
      Console.WriteLine($"Current Culture: {CultureInfo.CurrentCulture.Name}");
      Console.WriteLine($"Current Calendar: {DateTimeFormatInfo.CurrentInfo.Calendar}");
   }

   private static bool CalendarExists(CultureInfo culture, Calendar cal)
   {
      foreach (Calendar optionalCalendar in culture.OptionalCalendars)
         if (cal.ToString().Equals(optionalCalendar.ToString()))
            return true;

      return false;
   }
}
// The example displays the following output:
//    Current Culture: en-US
//    Current Calendar: System.Globalization.GregorianCalendar
//    6/20/2011
//
//    Current Culture: ar-SA
//    Current Calendar: System.Globalization.UmAlQuraCalendar
//    18/07/32
//
//    Current Culture: ar-SA
//    Current Calendar: System.Globalization.HijriCalendar
//    19/07/32
Imports System.Globalization
Imports System.Threading

Module Example
    Public Sub Main()
        Dim date1 As Date = #6/20/2011#

        DisplayCurrentInfo()
        ' Display the date using the current culture and calendar.
        Console.WriteLine(date1.ToString("d"))
        Console.WriteLine()

        Dim arSA As CultureInfo = CultureInfo.CreateSpecificCulture("ar-SA")

        ' Change the current culture to Arabic (Saudi Arabia).
        Thread.CurrentThread.CurrentCulture = arSA
        ' Display date and information about the current culture.
        DisplayCurrentInfo()
        Console.WriteLine(date1.ToString("d"))
        Console.WriteLine()

        ' Change the calendar to Hijri.
        Dim hijri As Calendar = New HijriCalendar()
        If CalendarExists(arSA, hijri) Then
            arSA.DateTimeFormat.Calendar = hijri
            ' Display date and information about the current culture.
            DisplayCurrentInfo()
            Console.WriteLine(date1.ToString("d"))
        End If
    End Sub

    Private Sub DisplayCurrentInfo()
        Console.WriteLine("Current Culture: {0}",
                          CultureInfo.CurrentCulture.Name)
        Console.WriteLine("Current Calendar: {0}",
                          DateTimeFormatInfo.CurrentInfo.Calendar)
    End Sub

    Private Function CalendarExists(ByVal culture As CultureInfo,
                                    cal As Calendar) As Boolean
        For Each optionalCalendar As Calendar In culture.OptionalCalendars
            If cal.ToString().Equals(optionalCalendar.ToString()) Then Return True
        Next
        Return False
    End Function
End Module
' The example displays the following output:
'    Current Culture: en-US
'    Current Calendar: System.Globalization.GregorianCalendar
'    6/20/2011
'    
'    Current Culture: ar-SA
'    Current Calendar: System.Globalization.UmAlQuraCalendar
'    18/07/32
'    
'    Current Culture: ar-SA
'    Current Calendar: System.Globalization.HijriCalendar
'    19/07/32

Даты и календари

За исключением конструкторов, которые включают параметр типа Calendar и позволяют элементам даты (то есть месяца, дня и года) отражать значения в указанном календаре, оба DateTime значения DateTimeOffset всегда основаны на григорианском календаре. Это означает, например, что DateTime.Year свойство возвращает год в григорианском календаре, а DateTime.Day свойство возвращает день месяца в григорианском календаре.

Это важно

Важно помнить, что существует разница между значением даты и его строковым представлением. Первый основан на григорианском календаре; второй основан на текущем календаре определенной культуры.

В следующем примере показано различие между DateTime свойствами и соответствующими Calendar методами. В примере текущий язык и региональные параметры — арабский (Египет), а текущий календарь — Ум аль-Кура. DateTime Значение задается на пятнадцатый день седьмого месяца 2011 года. Ясно, что это трактуется как грегорианская дата, так как эти же значения возвращаются DateTime.ToString(String, IFormatProvider) методом при использовании соглашений инвариантной культуры. Строковое представление даты, отформатируемой с помощью соглашений текущего языка и региональных параметров, равно 14.08.32, которая является эквивалентной датой в календаре Um Al Qura. Далее члены DateTime и Calendar используются для возврата дня, месяца и года DateTime значения. В каждом случае значения, возвращаемые DateTime членами, отражают значения в григорианском календаре, а значения, возвращаемые UmAlQuraCalendar членами, отражают значения в календаре Умм аль-Кура.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Make Arabic (Egypt) the current culture
      // and Umm al-Qura calendar the current calendar.
      CultureInfo arEG = CultureInfo.CreateSpecificCulture("ar-EG");
      Calendar cal = new UmAlQuraCalendar();
      arEG.DateTimeFormat.Calendar = cal;
      Thread.CurrentThread.CurrentCulture = arEG;

      // Display information on current culture and calendar.
      DisplayCurrentInfo();

      // Instantiate a date object.
      DateTime date1 = new DateTime(2011, 7, 15);

      // Display the string representation of the date.
      Console.WriteLine($"Date: {date1:d}");
      Console.WriteLine($"Date in the Invariant Culture: {date1.ToString("d", CultureInfo.InvariantCulture)}");
      Console.WriteLine();

      // Compare DateTime properties and Calendar methods.
      Console.WriteLine($"DateTime.Month property: {date1.Month}");
      Console.WriteLine($"UmAlQura.GetMonth: {cal.GetMonth(date1)}");
      Console.WriteLine();

      Console.WriteLine($"DateTime.Day property: {date1.Day}");
      Console.WriteLine($"UmAlQura.GetDayOfMonth: {cal.GetDayOfMonth(date1)}");
      Console.WriteLine();

      Console.WriteLine($"DateTime.Year property: {date1.Year:D4}");
      Console.WriteLine($"UmAlQura.GetYear: {cal.GetYear(date1)}");
      Console.WriteLine();
   }

   private static void DisplayCurrentInfo()
   {
      Console.WriteLine($"Current Culture: {CultureInfo.CurrentCulture.Name}");
      Console.WriteLine($"Current Calendar: {DateTimeFormatInfo.CurrentInfo.Calendar}");
   }
}
// The example displays the following output:
//    Current Culture: ar-EG
//    Current Calendar: System.Globalization.UmAlQuraCalendar
//    Date: 14/08/32
//    Date in the Invariant Culture: 07/15/2011
//
//    DateTime.Month property: 7
//    UmAlQura.GetMonth: 8
//
//    DateTime.Day property: 15
//    UmAlQura.GetDayOfMonth: 14
//
//    DateTime.Year property: 2011
//    UmAlQura.GetYear: 1432
Imports System.Globalization
Imports System.Threading

Module Example
    Public Sub Main()
        ' Make Arabic (Egypt) the current culture 
        ' and Umm al-Qura calendar the current calendar. 
        Dim arEG As CultureInfo = CultureInfo.CreateSpecificCulture("ar-EG")
        Dim cal As Calendar = New UmAlQuraCalendar()
        arEG.DateTimeFormat.Calendar = cal
        Thread.CurrentThread.CurrentCulture = arEG

        ' Display information on current culture and calendar.
        DisplayCurrentInfo()

        ' Instantiate a date object.
        Dim date1 As Date = #07/15/2011#

        ' Display the string representation of the date.
        Console.WriteLine("Date: {0:d}", date1)
        Console.WriteLine("Date in the Invariant Culture: {0}",
                          date1.ToString("d", CultureInfo.InvariantCulture))
        Console.WriteLine()

        ' Compare DateTime properties and Calendar methods.
        Console.WriteLine("DateTime.Month property: {0}", date1.Month)
        Console.WriteLine("UmAlQura.GetMonth: {0}",
                          cal.GetMonth(date1))
        Console.WriteLine()

        Console.WriteLine("DateTime.Day property: {0}", date1.Day)
        Console.WriteLine("UmAlQura.GetDayOfMonth: {0}",
                          cal.GetDayOfMonth(date1))
        Console.WriteLine()

        Console.WriteLine("DateTime.Year property: {0:D4}", date1.Year)
        Console.WriteLine("UmAlQura.GetYear: {0}",
                          cal.GetYear(date1))
        Console.WriteLine()
    End Sub

    Private Sub DisplayCurrentInfo()
        Console.WriteLine("Current Culture: {0}",
                          CultureInfo.CurrentCulture.Name)
        Console.WriteLine("Current Calendar: {0}",
                          DateTimeFormatInfo.CurrentInfo.Calendar)
    End Sub
End Module
' The example displays the following output:
'    Current Culture: ar-EG
'    Current Calendar: System.Globalization.UmAlQuraCalendar
'    Date: 14/08/32
'    Date in the Invariant Culture: 07/15/2011
'    
'    DateTime.Month property: 7
'    UmAlQura.GetMonth: 8
'    
'    DateTime.Day property: 15
'    UmAlQura.GetDayOfMonth: 14
'    
'    DateTime.Year property: 2011
'    UmAlQura.GetYear: 1432

Создание инстансов дат на основе календаря

Так как DateTime и DateTimeOffset значения основаны на григорианском календаре, необходимо вызвать перегруженный конструктор, включающий параметр типа Calendar , чтобы создать экземпляр значения даты, если вы хотите использовать значения дня, месяца или года из другого календаря. Можно также вызвать одну из перегрузок метода конкретного календаряCalendar.ToDateTime, чтобы создать экземпляр объекта DateTime на основе значений определенного календаря.

В следующем примере создается экземпляр одного DateTime значения путем передачи HebrewCalendar объекта DateTime конструктору и создания экземпляра HebrewCalendar.ToDateTime(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32) второго DateTime значения путем вызова метода. Так как два значения создаются с одинаковыми значениями из ивритского календаря, вызов DateTime.Equals метода показывает, что эти два DateTime значения равны.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      HebrewCalendar hc = new HebrewCalendar();

      DateTime date1 = new DateTime(5771, 6, 1, hc);
      DateTime date2 = hc.ToDateTime(5771, 6, 1, 0, 0, 0, 0);

      Console.WriteLine("{0:d} (Gregorian) = {1:d2}/{2:d2}/{3:d4} ({4}): {5}",
                        date1,
                        hc.GetMonth(date2),
                        hc.GetDayOfMonth(date2),
                        hc.GetYear(date2),
                        GetCalendarName(hc),
                        date1.Equals(date2));
   }

   private static string GetCalendarName(Calendar cal)
   {
      return cal.ToString().Replace("System.Globalization.", "").
                            Replace("Calendar", "");
   }
}
// The example displays the following output:
//    2/5/2011 (Gregorian) = 06/01/5771 (Hebrew): True
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim hc As New HebrewCalendar()

        Dim date1 As New Date(5771, 6, 1, hc)
        Dim date2 As Date = hc.ToDateTime(5771, 6, 1, 0, 0, 0, 0)

        Console.WriteLine("{0:d} (Gregorian) = {1:d2}/{2:d2}/{3:d4} ({4}): {5}",
                          date1,
                          hc.GetMonth(date2),
                          hc.GetDayOfMonth(date2),
                          hc.GetYear(date2),
                          GetCalendarName(hc),
                          date1.Equals(date2))
    End Sub

    Private Function GetCalendarName(cal As Calendar) As String
        Return cal.ToString().Replace("System.Globalization.", "").
                              Replace("Calendar", "")
    End Function
End Module
' The example displays the following output:
'   2/5/2011 (Gregorian) = 06/01/5771 (Hebrew): True

Представление дат в текущем календаре

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

В следующем примере показано, как текущий календарь влияет на строковое представление даты. Он изменяет текущую культуру на китайскую (традиционная, Тайвань) и создаёт экземпляр объекта, содержащего значение даты. Затем он отображает текущий календарь и дату, изменяет текущий календарь на TaiwanCalendar, а затем снова отображает текущий календарь и дату. При первом отображении даты она представлена в виде даты в григорианском календаре. Во второй раз оно отображается в виде даты в календаре Тайваня.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      // Change the current culture to zh-TW.
      CultureInfo zhTW = CultureInfo.CreateSpecificCulture("zh-TW");
      Thread.CurrentThread.CurrentCulture = zhTW;
      // Define a date.
      DateTime date1 = new DateTime(2011, 1, 16);

      // Display the date using the default (Gregorian) calendar.
      Console.WriteLine($"Current calendar: {zhTW.DateTimeFormat.Calendar}");
      Console.WriteLine(date1.ToString("d"));

      // Change the current calendar and display the date.
      zhTW.DateTimeFormat.Calendar = new TaiwanCalendar();
      Console.WriteLine($"Current calendar: {zhTW.DateTimeFormat.Calendar}");
      Console.WriteLine(date1.ToString("d"));
   }
}
// The example displays the following output:
//    Current calendar: System.Globalization.GregorianCalendar
//    2011/1/16
//    Current calendar: System.Globalization.TaiwanCalendar
//    100/1/16
Imports System.Globalization
Imports System.Threading

Module Example
    Public Sub Main()
        ' Change the current culture to zh-TW.
        Dim zhTW As CultureInfo = CultureInfo.CreateSpecificCulture("zh-TW")
        Thread.CurrentThread.CurrentCulture = zhTW
        ' Define a date.
        Dim date1 As Date = #1/16/2011#

        ' Display the date using the default (Gregorian) calendar.
        Console.WriteLine("Current calendar: {0}",
                          zhTW.DateTimeFormat.Calendar)
        Console.WriteLine(date1.ToString("d"))

        ' Change the current calendar and display the date.
        zhTW.DateTimeFormat.Calendar = New TaiwanCalendar()
        Console.WriteLine("Current calendar: {0}",
                          zhTW.DateTimeFormat.Calendar)
        Console.WriteLine(date1.ToString("d"))
    End Sub
End Module
' The example displays the following output:
'    Current calendar: System.Globalization.GregorianCalendar
'    2011/1/16
'    Current calendar: System.Globalization.TaiwanCalendar
'    100/1/16

Представление дат в календаре, отличном от текущего календаря

Чтобы представить дату с помощью календаря, который не является текущим календарем конкретной культуры, следует вызвать методы этого объекта Calendar. Например, методы Calendar.GetYear, Calendar.GetMonth и Calendar.GetDayOfMonth преобразуют год, месяц и день в значения, которые отражают определенный календарь.

Предупреждение

Поскольку некоторые календари не являются необязательными календарями в рамках какой-либо культуры, представление дат в этих календарях всегда требует вызова методов календаря. Это верно для всех календарей, производных от EastAsianLunisolarCalendar, JulianCalendarи PersianCalendar классов.

В следующем примере объект JulianCalendar используется для создания даты 9 января 1905 года в Юлианском календаре. Когда эта дата отображается с помощью календаря по умолчанию (грегорианская), она представлена как 22 января 1905 года. Вызовы отдельных JulianCalendar методов позволяют представить дату в календаре Джулиана.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      JulianCalendar julian = new JulianCalendar();
      DateTime date1 = new DateTime(1905, 1, 9, julian);

      Console.WriteLine("Date ({0}): {1:d}",
                        CultureInfo.CurrentCulture.Calendar,
                        date1);
      Console.WriteLine("Date in Julian calendar: {0:d2}/{1:d2}/{2:d4}",
                        julian.GetMonth(date1),
                        julian.GetDayOfMonth(date1),
                        julian.GetYear(date1));
   }
}
// The example displays the following output:
//    Date (System.Globalization.GregorianCalendar): 1/22/1905
//    Date in Julian calendar: 01/09/1905
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim julian As New JulianCalendar()
        Dim date1 As New Date(1905, 1, 9, julian)

        Console.WriteLine("Date ({0}): {1:d}",
                          CultureInfo.CurrentCulture.Calendar,
                          date1)
        Console.WriteLine("Date in Julian calendar: {0:d2}/{1:d2}/{2:d4}",
                          julian.GetMonth(date1),
                          julian.GetDayOfMonth(date1),
                          julian.GetYear(date1))
    End Sub
End Module
' The example displays the following output:
'    Date (System.Globalization.GregorianCalendar): 1/22/1905
'    Date in Julian calendar: 01/09/1905

Календари и диапазоны дат

Самая ранняя дата, поддерживаемая календарем, указывается свойством этого календаря Calendar.MinSupportedDateTime . GregorianCalendar Для класса эта дата — 1 января 0001 Г. Большинство других календарей в .NET поддерживают более позднюю дату. При попытке работать со значением даты и времени, предшествующим самой ранней поддерживаемой ArgumentOutOfRangeException дате календаря, возникает исключение.

Однако существует одно важное исключение. Значение по умолчанию (неинициализированное) объекта DateTime и объекта DateTimeOffset равно значению GregorianCalendar.MinSupportedDateTime. Если вы пытаетесь отформатировать эту дату в календаре, который не поддерживает 1 января 0001 г. C.E. и не предоставляет описатель формата, метод форматирования использует описатель формата "s" (шаблон даты и времени сортировки) вместо описателя формата "G" (общий шаблон даты и времени). В результате операция форматирования не выбрасывает ArgumentOutOfRangeException исключение. Вместо этого он возвращает неподдерживаемую дату. Это иллюстрируется в следующем примере, который отображает значение DateTime.MinValue, когда текущий язык и региональные параметры установлены на японский (Япония) с японским календарем и арабский (Египет) с календарем Умм аль-Кура. Он также устанавливает текущую языковую культуру на английский (Соединенные Штаты) и вызывает метод DateTime.ToString(IFormatProvider) с каждым из этих объектов CultureInfo. В каждом случае дата отображается с помощью шаблона сортировки даты и времени.

using System;
using System.Globalization;
using System.Threading;

public class Example
{
   public static void Main()
   {
      DateTime dat = DateTime.MinValue;

      // Change the current culture to ja-JP with the Japanese Calendar.
      CultureInfo jaJP = CultureInfo.CreateSpecificCulture("ja-JP");
      jaJP.DateTimeFormat.Calendar = new JapaneseCalendar();
      Thread.CurrentThread.CurrentCulture = jaJP;
      Console.WriteLine($"Earliest supported date by {GetCalendarName(jaJP)} calendar: {jaJP.DateTimeFormat.Calendar.MinSupportedDateTime:d}");
      // Attempt to display the date.
      Console.WriteLine(dat.ToString());
      Console.WriteLine();

      // Change the current culture to ar-EG with the Um Al Qura calendar.
      CultureInfo arEG = CultureInfo.CreateSpecificCulture("ar-EG");
      arEG.DateTimeFormat.Calendar = new UmAlQuraCalendar();
      Thread.CurrentThread.CurrentCulture = arEG;
      Console.WriteLine($"Earliest supported date by {GetCalendarName(arEG)} calendar: {arEG.DateTimeFormat.Calendar.MinSupportedDateTime:d}");
      // Attempt to display the date.
      Console.WriteLine(dat.ToString());
      Console.WriteLine();

      // Change the current culture to en-US.
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
      Console.WriteLine(dat.ToString(jaJP));
      Console.WriteLine(dat.ToString(arEG));
      Console.WriteLine(dat.ToString("d"));
   }

   private static string GetCalendarName(CultureInfo culture)
   {
      Calendar cal = culture.DateTimeFormat.Calendar;
      return cal.GetType().Name.Replace("System.Globalization.", "").Replace("Calendar", "");
   }
}
// The example displays the following output:
//       Earliest supported date by Japanese calendar: 明治 1/9/8
//       0001-01-01T00:00:00
//
//       Earliest supported date by UmAlQura calendar: 01/01/18
//       0001-01-01T00:00:00
//
//       0001-01-01T00:00:00
//       0001-01-01T00:00:00
//       1/1/0001
Imports System.Globalization
Imports System.Threading

Module Example
    Public Sub Main()
        Dim dat As Date = DateTime.MinValue

        ' Change the current culture to ja-JP with the Japanese Calendar.
        Dim jaJP As CultureInfo = CultureInfo.CreateSpecificCulture("ja-JP")
        jaJP.DateTimeFormat.Calendar = New JapaneseCalendar()
        Thread.CurrentThread.CurrentCulture = jaJP
        Console.WriteLine("Earliest supported date by {1} calendar: {0:d}",
                          jaJP.DateTimeFormat.Calendar.MinSupportedDateTime,
                          GetCalendarName(jaJP))
        ' Attempt to display the date.
        Console.WriteLine(dat.ToString())
        Console.WriteLine()

        ' Change the current culture to ar-EG with the Um Al Qura calendar.
        Dim arEG As CultureInfo = CultureInfo.CreateSpecificCulture("ar-EG")
        arEG.DateTimeFormat.Calendar = New UmAlQuraCalendar()
        Thread.CurrentThread.CurrentCulture = arEG
        Console.WriteLine("Earliest supported date by {1} calendar: {0:d}",
                          arEG.DateTimeFormat.Calendar.MinSupportedDateTime,
                          GetCalendarName(arEG))
        ' Attempt to display the date.
        Console.WRiteLine(dat.ToString())
        Console.WRiteLine()

        ' Change the current culture to en-US.
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
        Console.WriteLine(dat.ToString(jaJP))
        Console.WriteLine(dat.ToString(arEG))
        Console.WriteLine(dat.ToString("d"))
    End Sub

    Private Function GetCalendarName(culture As CultureInfo) As String
        Dim cal As Calendar = culture.DateTimeFormat.Calendar
        Return cal.GetType().Name.Replace("System.Globalization.", "").Replace("Calendar", "")
    End Function
End Module
' The example displays the following output:
'       Earliest supported date by Japanese calendar: 明治 1/9/8
'       0001-01-01T00:00:00
'       
'       Earliest supported date by UmAlQura calendar: 01/01/18
'       0001-01-01T00:00:00
'       
'       0001-01-01T00:00:00
'       0001-01-01T00:00:00
'       1/1/0001

Работа с эрами

Календари обычно делят даты на эры. Calendar Однако классы в .NET не поддерживают каждую эру, определенную календарем, и большинство Calendar классов поддерживают только одну эру. Только классы JapaneseCalendarJapaneseLunisolarCalendar поддерживают несколько эпох.

Это важно

Эра Рейва, новая эпоха в JapaneseCalendar и JapaneseLunisolarCalendar, начинается 1 мая 2019 года. Это изменение влияет на все приложения, использующие эти календари. Дополнительные сведения см. в этих статьях:

Эра в большинстве календарей обозначает чрезвычайно длительный период времени. Например, в григорианском календаре, текущая эра охватывает более двух тысячелетий. Два календаря JapaneseCalendar и JapaneseLunisolarCalendar, поддерживающие несколько эпох, не соответствуют этому. Эра соответствует периоду правления императора. Поддержка нескольких эпох, особенно когда верхний предел текущей эпохи неизвестен, представляет особые проблемы.

Эры и имена эпох

В .NET целые числа, представляющие эры, поддерживаемые определенной реализацией календаря, хранятся в обратном порядке в массиве Calendar.Eras . Текущая эра (которая является эрой с последним диапазоном времени) находится в нулевом индексе, а для Calendar классов, поддерживающих несколько эпох, каждый последовательный индекс отражает предыдущую эпоху. Статическое Calendar.CurrentEra свойство определяет индекс текущей эры в массиве Calendar.Eras ; это константа, значение которой всегда равно нулю. Отдельные Calendar классы также включают статические поля, возвращающие значение текущей эпохи. Они перечислены в следующей таблице.

Класс Calendar Поле текущей эры
ChineseLunisolarCalendar ChineseEra
GregorianCalendar ADEra
HebrewCalendar HebrewEra
HijriCalendar HijriEra
JapaneseLunisolarCalendar JapaneseEra
JulianCalendar JulianEra
KoreanCalendar KoreanEra
KoreanLunisolarCalendar GregorianEra
PersianCalendar PersianEra
ThaiBuddhistCalendar ThaiBuddhistEra
UmAlQuraCalendar UmAlQuraEra

Имя, соответствующее определенному номеру эпохи, можно получить, передав номер эпохи в метод DateTimeFormatInfo.GetEraName или DateTimeFormatInfo.GetAbbreviatedEraName. В следующем примере эти методы вызываются для получения сведений о поддержке эры GregorianCalendar в классе. В нем отображается дата григорианского календаря, соответствующая 1 января второго года текущей эпохи, а также дата григорианского календаря, которая соответствует 1 января второго года каждой поддерживаемой японской эпохи календаря.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      int year = 2;
      int month = 1;
      int day = 1;
      Calendar cal = new JapaneseCalendar();

      Console.WriteLine("\nDate instantiated without an era:");
      DateTime date1 = new DateTime(year, month, day, 0, 0, 0, 0, cal);
      Console.WriteLine("{0}/{1}/{2} in Japanese Calendar -> {3:d} in Gregorian",
                        cal.GetMonth(date1), cal.GetDayOfMonth(date1),
                        cal.GetYear(date1), date1);

      Console.WriteLine("\nDates instantiated with eras:");
      foreach (int era in cal.Eras) {
         DateTime date2 = cal.ToDateTime(year, month, day, 0, 0, 0, 0, era);
         Console.WriteLine("{0}/{1}/{2} era {3} in Japanese Calendar -> {4:d} in Gregorian",
                           cal.GetMonth(date2), cal.GetDayOfMonth(date2),
                           cal.GetYear(date2), cal.GetEra(date2), date2);
      }
   }
}
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim year As Integer = 2
        Dim month As Integer = 1
        Dim day As Integer = 1
        Dim cal As New JapaneseCalendar()

        Console.WriteLine("Date instantiated without an era:")
        Dim date1 As New Date(year, month, day, 0, 0, 0, 0, cal)
        Console.WriteLine("{0}/{1}/{2} in Japanese Calendar -> {3:d} in Gregorian",
                          cal.GetMonth(date1), cal.GetDayOfMonth(date1),
                          cal.GetYear(date1), date1)
        Console.WriteLine()

        Console.WriteLine("Dates instantiated with eras:")
        For Each era As Integer In cal.Eras
            Dim date2 As Date = cal.ToDateTime(year, month, day, 0, 0, 0, 0, era)
            Console.WriteLine("{0}/{1}/{2} era {3} in Japanese Calendar -> {4:d} in Gregorian",
                              cal.GetMonth(date2), cal.GetDayOfMonth(date2),
                              cal.GetYear(date2), cal.GetEra(date2), date2)
        Next
    End Sub
End Module

Кроме того, строка настраиваемого формата даты и времени "g" содержит имя эпохи календаря в строковом представлении даты и времени. Для получения дополнительной информации см. Строки пользовательского формата даты и времени.

Создайте экземпляр даты с учётом эры

Для двух Calendar классов, поддерживающих несколько эпох, дата, состоящая из определенного года, месяца и дня месяца, может быть неоднозначной. Например, все эры, поддерживаемые JapaneseCalendar, имеют годы, число которых равно 1. Как правило, если эра не указана, методы даты и времени и календаря предполагают, что значения относятся к текущей эре. Это верно для DateTime конструкторов и DateTimeOffset методов, которые включают параметры типа Calendar, а также методы JapaneseCalendar.ToDateTime и японского LunisolarCalendar.ToDateTime. В следующем примере создается экземпляр даты, представляющей 1 января второго года неопределенной эпохи. Если выполнить пример, когда эра Reiwa является текущей, дата интерпретируется как второй год эры Рейва. Эра, 令和, предшествует году в строке, возвращаемой DateTime.ToString(String, IFormatProvider) методом, и соответствует 1 января 2020 года в григорианском календаре. (Эра Reiwa начинается в 2019 году григорианского календаря.)

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
        var japaneseCal = new JapaneseCalendar();
        var jaJp = new CultureInfo("ja-JP");
        jaJp.DateTimeFormat.Calendar = japaneseCal;

        var date = new DateTime(2, 1, 1, japaneseCal);
        Console.WriteLine($"Gregorian calendar date: {date:d}");
        Console.WriteLine($"Japanese calendar date: {date.ToString("d", jaJp)}");
    }
}
Imports System.Globalization

Public Module Example
    Public Sub Main()
        Dim japaneseCal = New JapaneseCalendar()
        Dim jaJp = New CultureInfo("ja-JP")
        jaJp.DateTimeFormat.Calendar = japaneseCal

        Dim dat = New DateTime(2, 1, 1, japaneseCal)
        Console.WriteLine($"Gregorian calendar dat: {dat:d}")
        Console.WriteLine($"Japanese calendar dat: {dat.ToString("d", jaJp)}")
    End Sub
End Module

Однако если эра изменяется, намерение этого кода становится неоднозначным. Является ли дата предназначенной для обозначения второго года нашей эры, или она обозначает второй год периода «Хэйсэй»? Существует два способа избежать этой неоднозначности:

  • Создайте экземпляр значения даты и времени с помощью класса по умолчанию GregorianCalendar . Затем можно использовать японский календарь или японский календарь Lunisolar для строкового представления дат, как показано в следующем примере.

    using System;
    using System.Globalization;
    
    public class Example
    {
        public static void Main()
        {
            var japaneseCal = new JapaneseCalendar();
            var jaJp = new CultureInfo("ja-JP");
            jaJp.DateTimeFormat.Calendar = japaneseCal;
    
            var date = new DateTime(1905, 2, 12);
            Console.WriteLine($"Gregorian calendar date: {date:d}");
    
            // Call the ToString(IFormatProvider) method.
            Console.WriteLine($"Japanese calendar date: {date.ToString("d", jaJp)}");
    
            // Use a FormattableString object.
            FormattableString fmt = $"{date:d}";
            Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)}");
    
            // Use the JapaneseCalendar object.
            Console.WriteLine($"Japanese calendar date: {jaJp.DateTimeFormat.GetEraName(japaneseCal.GetEra(date))}" +
                              $"{japaneseCal.GetYear(date)}/{japaneseCal.GetMonth(date)}/{japaneseCal.GetDayOfMonth(date)}");
    
            // Use the current culture.
            CultureInfo.CurrentCulture = jaJp;
            Console.WriteLine($"Japanese calendar date: {date:d}");
        }
    }
    // The example displays the following output:
    //   Gregorian calendar date: 2/12/1905
    //   Japanese calendar date: 明治38/2/12
    //   Japanese calendar date: 明治38/2/12
    //   Japanese calendar date: 明治38/2/12
    //   Japanese calendar date: 明治38/2/12
    
    Imports System.Globalization
    
    Public Module Example
        Public Sub Main()
            Dim japaneseCal = New JapaneseCalendar()
            Dim jaJp = New CultureInfo("ja-JP")
            jaJp.DateTimeFormat.Calendar = japaneseCal
    
            Dim dat = New DateTime(1905, 2, 12)
            Console.WriteLine($"Gregorian calendar date: {dat:d}")
    
            ' Call the ToString(IFormatProvider) method.
            Console.WriteLine($"Japanese calendar date: {dat.ToString("d", jaJp)}")
    
            ' Use a FormattableString object.
            Dim fmt As FormattableString = $"{dat:d}"
            Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)}")
    
            ' Use the JapaneseCalendar object.
            Console.WriteLine($"Japanese calendar date: {jaJp.DateTimeFormat.GetEraName(japaneseCal.GetEra(dat))}" +
                              $"{japaneseCal.GetYear(dat)}/{japaneseCal.GetMonth(dat)}/{japaneseCal.GetDayOfMonth(dat)}")
    
            ' Use the current culture.
            CultureInfo.CurrentCulture = jaJp
            Console.WriteLine($"Japanese calendar date: {dat:d}")
        End Sub
    End Module
    ' The example displays the following output:
    '   Gregorian calendar date: 2/12/1905
    '   Japanese calendar date: 明治38/2/12
    '   Japanese calendar date: 明治38/2/12
    '   Japanese calendar date: 明治38/2/12
    '   Japanese calendar date: 明治38/2/12
    
    
    
  • Вызовите метод даты и времени, который явно указывает эру. К ним относятся следующие методы:

    В следующем примере используется три из этих методов для создания экземпляра даты и времени в эпоху Meiji, которая началась 8 сентября 1868 года и закончилась 29 июля 1912 года.

    using System;
    using System.Globalization;
    
    public class Example
    {
        public static void Main()
        {
            var japaneseCal = new JapaneseCalendar();
            var jaJp = new CultureInfo("ja-JP");
            jaJp.DateTimeFormat.Calendar = japaneseCal;
    
            // We can get the era index by calling DateTimeFormatInfo.GetEraName.
            int eraIndex = 0;
    
            for (int ctr = 0; ctr < jaJp.DateTimeFormat.Calendar.Eras.Length; ctr++)
               if (jaJp.DateTimeFormat.GetEraName(ctr) == "明治")
                  eraIndex = ctr;
            var date1 = japaneseCal.ToDateTime(23, 9, 8, 0, 0, 0, 0, eraIndex);
            Console.WriteLine($"{date1.ToString("d", jaJp)} (Gregorian {date1:d})");
    
            try {
                var date2 = DateTime.Parse("明治23/9/8", jaJp);
                Console.WriteLine($"{date2.ToString("d", jaJp)} (Gregorian {date2:d})");
            }
            catch (FormatException)
            {
                Console.WriteLine("The parsing operation failed.");
            }
    
            try {
                var date3 = DateTime.ParseExact("明治23/9/8", "gyy/M/d", jaJp);
                Console.WriteLine($"{date3.ToString("d", jaJp)} (Gregorian {date3:d})");
            }
            catch (FormatException)
            {
                Console.WriteLine("The parsing operation failed.");
            }
        }
    }
    // The example displays the following output:
    //   明治23/9/8 (Gregorian 9/8/1890)
    //   明治23/9/8 (Gregorian 9/8/1890)
    //   明治23/9/8 (Gregorian 9/8/1890)
    
    Imports System.Globalization
    
    Public Module Example
        Public Sub Main()
            Dim japaneseCal = New JapaneseCalendar()
            Dim jaJp = New CultureInfo("ja-JP")
            jaJp.DateTimeFormat.Calendar = japaneseCal
    
            ' We can get the era index by calling DateTimeFormatInfo.GetEraName.
            Dim eraIndex As Integer = 0
    
            For ctr As Integer = 0 To jaJp.DateTimeFormat.Calendar.Eras.Length - 1
                If jaJp.DateTimeFormat.GetEraName(ctr) = "明治" Then eraIndex = ctr
            Next
            Dim date1 = japaneseCal.ToDateTime(23, 9, 8, 0, 0, 0, 0, eraIndex)
            Console.WriteLine($"{date1.ToString("d", jaJp)} (Gregorian {date1:d})")
    
            Try
                Dim date2 = DateTime.Parse("明治23/9/8", jaJp)
                Console.WriteLine($"{date2.ToString("d", jaJp)} (Gregorian {date2:d})")
            Catch e As FormatException
                Console.WriteLine("The parsing operation failed.")
            End Try
    
            Try
                Dim date3 = DateTime.ParseExact("明治23/9/8", "gyy/M/d", jaJp)
                Console.WriteLine($"{date3.ToString("d", jaJp)} (Gregorian {date3:d})")
            Catch e As FormatException
                Console.WriteLine("The parsing operation failed.")
            End Try
        End Sub
    End Module
    ' The example displays the following output:
    '   明治23/9/8 (Gregorian 9/8/1890)
    '   明治23/9/8 (Gregorian 9/8/1890)
    '   明治23/9/8 (Gregorian 9/8/1890)
    

Подсказка

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

При указании эры в ToDateTime(Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32) методе укажите индекс эры в свойстве календаря Eras . Для календарей, эры которых подвергаются изменению, однако эти индексы не являются константными значениями; текущая эра находится на индексе 0, а самая старая эра находится в индексе Eras.Length - 1. Когда новая эра добавляется в календарь, индексы предыдущих эпох увеличиваются на один. Вы можете указать соответствующий индекс эры следующим образом:

  • Для дат в текущей эре всегда используйте свойство календаря CurrentEra .

  • Для дат в указанной эре используйте DateTimeFormatInfo.GetEraName метод для получения индекса, соответствующего указанному имени эпохи. Для этого необходимо, чтобы JapaneseCalendar был текущим календарем объекта CultureInfo, представляющего культуру ja-JP. (Этот метод работает также для JapaneseLunisolarCalendar, так как он поддерживает те же самые эпохи, что и JapaneseCalendar.) В предыдущем примере показан этот подход.

Календари, эры и диапазоны дат: смягчённые проверки диапазона

Очень похоже, что отдельные календари поддерживают диапазоны дат, эры в JapaneseCalendar и JapaneseLunisolarCalendar классах также поддерживают диапазоны. Ранее .NET использовал строгие проверки диапазона эры, чтобы убедиться, что дата конкретной эпохи находилась в пределах этого периода. То есть, если дата выходит за пределы диапазона указанной эпохи, метод вызывает ArgumentOutOfRangeException. В настоящее время .NET использует расслабленную проверку диапазона по умолчанию. Обновления для всех версий .NET ввели ослабленные проверки диапазона эры; попытка создать экземпляр даты, относящейся к эпохе, которая находится за пределами диапазона указанной эры, переполняется в следующую эру, и исключение не возникает.

Следующий пример пытается создать экземпляр даты в 65-м году эпохи Showa, которая началась 25 декабря 1926 года и закончилась 7 января 1989 года. Эта дата соответствует 9 января 1990 года, которая находится за пределами диапазона эпохи Showa в .JapaneseCalendar Как показано в выходных данных примера, дата, отображаемая примером, — 9 января 1990 года, во втором году эры Heisei.

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      var jaJp = new CultureInfo("ja-JP");
      var cal = new JapaneseCalendar();
      jaJp.DateTimeFormat.Calendar = cal;
      string showaEra = "昭和";

      var dt = cal.ToDateTime(65, 1, 9, 15, 0, 0, 0, GetEraIndex(showaEra));
      FormattableString fmt = $"{dt:d}";

      Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)}");
      Console.WriteLine($"Gregorian calendar date: {fmt}");

      int GetEraIndex(string eraName)
      {
         foreach (var ctr in cal.Eras)
            if (jaJp.DateTimeFormat.GetEraName(ctr) == eraName)
               return ctr;

         return 0;
      }
   }
}
// The example displays the following output:
//   Japanese calendar date: 平成2/1/9
//   Gregorian calendar date: 1/9/1990
Imports System.Globalization

Public Module Example
    Dim jaJp As CultureInfo
    Dim cal As Calendar

    Public Sub Main()
        jaJp = New CultureInfo("ja-JP")
        cal = New JapaneseCalendar()
        jaJp.DateTimeFormat.Calendar = cal
        Dim showaEra = "昭和"

        Dim dt = cal.ToDateTime(65, 1, 9, 15, 0, 0, 0, GetEraIndex(showaEra))
        Dim fmt As FormattableString = $"{dt:d}"
        Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)}")
        Console.WriteLine($"Gregorian calendar date: {fmt}")
    End Sub

    Private Function GetEraIndex(eraName As String) As Integer
        For Each ctr As Integer In cal.Eras
            If jaJp.DateTimeFormat.GetEraName(ctr) = eraName Then Return ctr
        Next
        Return 0
    End Function
End Module
' The example displays the following output:
'   Japanese calendar date: 平成2/1/9
'   Gregorian calendar date: 1/9/1990

Если ослабленные проверки диапазона нежелательны, можно восстановить строгие проверки диапазона несколькими способами, в зависимости от версии .NET, на которой работает ваше приложение.

  • .NET Core: Добавьте следующее в файл конфигурации.netcore.runtime.json :

    "runtimeOptions": {
      "configProperties": {
          "Switch.System.Globalization.EnforceJapaneseEraYearRanges": true
      }
    }
    
  • .NET Framework 4.6 или более поздней версии: Задайте следующий параметр AppContext в файлеapp.config :

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <runtime>
        <AppContextSwitchOverrides value="Switch.System.Globalization.EnforceJapaneseEraYearRanges=true" />
      </runtime>
    </configuration>
    
  • .NET Framework 4.5.2 или более ранней версии: Задайте следующее значение реестра:

    Ценность
    Ключ HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\AppContext
    запись Switch.System.Globalization.EnforceJapaneseEraYearRanges
    Тип REG_SZ
    Value правда

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

Unhandled Exception: System.ArgumentOutOfRangeException: Valid values are between 1 and 64, inclusive.
Parameter name: year
   at System.Globalization.GregorianCalendarHelper.GetYearOffset(Int32 year, Int32 era, Boolean throwOnError)
   at System.Globalization.GregorianCalendarHelper.ToDateTime(Int32 year, Int32 month, Int32 day, Int32 hour, Int32 minute, Int32 second, Int32 millisecond, Int32 era)
   at Example.Main()

Представление дат в календарях с несколькими эрами

Calendar Если объект поддерживает эры и является текущим календарем CultureInfo объекта, эра включается в строковое представление значения даты и времени для полной даты и времени, длинной даты и коротких шаблонов дат. В следующем примере отображаются эти шаблоны дат, когда текущая культура и язык — Япония (японский), а текущий календарь — японский календарь.

using System;
using System.Globalization;
using System.IO;
using System.Threading;

public class Example
{
   public static void Main()
   {
      StreamWriter sw = new StreamWriter(@".\eras.txt");
      DateTime dt = new DateTime(2012, 5, 1);

      CultureInfo culture = CultureInfo.CreateSpecificCulture("ja-JP");
      DateTimeFormatInfo dtfi = culture.DateTimeFormat;
      dtfi.Calendar = new JapaneseCalendar();
      Thread.CurrentThread.CurrentCulture = culture;

      sw.WriteLine("\n{0,-43} {1}", "Full Date and Time Pattern:", dtfi.FullDateTimePattern);
      sw.WriteLine(dt.ToString("F"));
      sw.WriteLine();

      sw.WriteLine("\n{0,-43} {1}", "Long Date Pattern:", dtfi.LongDatePattern);
      sw.WriteLine(dt.ToString("D"));

      sw.WriteLine("\n{0,-43} {1}", "Short Date Pattern:", dtfi.ShortDatePattern);
      sw.WriteLine(dt.ToString("d"));
      sw.Close();
    }
}
// The example writes the following output to a file:
//    Full Date and Time Pattern:                 gg y'年'M'月'd'日' H:mm:ss
//    平成 24年5月1日 0:00:00
//
//    Long Date Pattern:                          gg y'年'M'月'd'日'
//    平成 24年5月1日
//
//    Short Date Pattern:                         gg y/M/d
//    平成 24/5/1
Imports System.Globalization
Imports System.IO
Imports System.Threading

Module Example
    Public Sub Main()
        Dim sw As New StreamWriter(".\eras.txt")
        Dim dt As Date = #05/01/2012#

        Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture("ja-JP")
        Dim dtfi As DateTimeFormatInfo = culture.DateTimeFormat
        dtfi.Calendar = New JapaneseCalendar()
        Thread.CurrentThread.CurrentCulture = culture

        sw.WriteLine("{0,-43} {1}", "Full Date and Time Pattern:", dtfi.FullDateTimePattern)
        sw.WriteLine(dt.ToString("F"))
        sw.WriteLine()

        sw.WriteLine("{0,-43} {1}", "Long Date Pattern:", dtfi.LongDatePattern)
        sw.WriteLine(dt.ToString("D"))
        sw.WriteLine()

        sw.WriteLine("{0,-43} {1}", "Short Date Pattern:", dtfi.ShortDatePattern)
        sw.WriteLine(dt.ToString("d"))
        sw.WriteLine()
        sw.Close()
    End Sub
End Module
' The example writes the following output to a file:
'    Full Date and Time Pattern:                 gg y'年'M'月'd'日' H:mm:ss
'    平成 24年5月1日 0:00:00
'    
'    Long Date Pattern:                          gg y'年'M'月'd'日'
'    平成 24年5月1日
'    
'    Short Date Pattern:                         gg y/M/d
'    平成 24/5/1 

Предупреждение

Класс JapaneseCalendar является единственным классом календаря в .NET, который поддерживает даты более чем в одну эпоху и может быть текущим календарем объекта, в частности, объекта CultureInfo, представляющего японскую культуру (язык и региональные параметры CultureInfo) (Япония).

Для любого календаря настраиваемый форматный спецификатор 'g' включает эру в результирующей строке. В следующем примере используется строка настраиваемого формата MM-dd-y g, чтобы включить эру в результируемую строку, когда текущий календарь является григорианским календарем.

   DateTime dat = new DateTime(2012, 5, 1);
   Console.WriteLine($"{dat:MM-dd-yyyy g}");
// The example displays the following output:
//     05-01-2012 A.D.
Dim dat As Date = #05/01/2012#
Console.WriteLine("{0:MM-dd-yyyy g}", dat)
' The example displays the following output:
'     05-01-2012 A.D.      

В случаях, когда строковое представление даты выражается в календаре, который не является текущим календарем, класс Calendar предоставляет метод Calendar.GetEra, который можно использовать вместе с методами Calendar.GetYear, Calendar.GetMonth и Calendar.GetDayOfMonth для однозначного указания даты, а также эры, к которой она принадлежит. В следующем примере класс JapaneseLunisolarCalendar используется для предоставления иллюстрации. Однако обратите внимание, что включение понятного имени или сокращения вместо целого числа для эры в результирующей строке требует создания экземпляра DateTimeFormatInfo объекта и создания JapaneseCalendar текущего календаря. (Календарь JapaneseLunisolarCalendar не может быть текущим календарем какой-либо культуры, но в этом случае два календаря делят одни и те же эпохи.)

using System;
using System.Globalization;

public class Example
{
   public static void Main()
   {
      DateTime date1 = new DateTime(2011, 8, 28);
      Calendar cal = new JapaneseLunisolarCalendar();

      Console.WriteLine("{0} {1:d4}/{2:d2}/{3:d2}",
                        cal.GetEra(date1),
                        cal.GetYear(date1),
                        cal.GetMonth(date1),
                        cal.GetDayOfMonth(date1));

      // Display eras
      CultureInfo culture = CultureInfo.CreateSpecificCulture("ja-JP");
      DateTimeFormatInfo dtfi = culture.DateTimeFormat;
      dtfi.Calendar = new JapaneseCalendar();

      Console.WriteLine("{0} {1:d4}/{2:d2}/{3:d2}",
                        dtfi.GetAbbreviatedEraName(cal.GetEra(date1)),
                        cal.GetYear(date1),
                        cal.GetMonth(date1),
                        cal.GetDayOfMonth(date1));
   }
}
// The example displays the following output:
//       4 0023/07/29
//       平 0023/07/29
Imports System.Globalization

Module Example
    Public Sub Main()
        Dim date1 As Date = #8/28/2011#
        Dim cal As New JapaneseLunisolarCalendar()
        Console.WriteLine("{0} {1:d4}/{2:d2}/{3:d2}",
                          cal.GetEra(date1),
                          cal.GetYear(date1),
                          cal.GetMonth(date1),
                          cal.GetDayOfMonth(date1))

        ' Display eras
        Dim culture As CultureInfo = CultureInfo.CreateSpecificCulture("ja-JP")
        Dim dtfi As DateTimeFormatInfo = culture.DateTimeFormat
        dtfi.Calendar = New JapaneseCalendar()

        Console.WriteLine("{0} {1:d4}/{2:d2}/{3:d2}",
                          dtfi.GetAbbreviatedEraName(cal.GetEra(date1)),
                          cal.GetYear(date1),
                          cal.GetMonth(date1),
                          cal.GetDayOfMonth(date1))
    End Sub
End Module
' The example displays the following output:
'       4 0023/07/29
'       平 0023/07/29

В японских календарях первый год эпохи называется Ганнен (元年). Например, вместо Heisei 1 первый год эры Heisei можно охарактеризовать как Heisei Gannen. .NET использует это соглашение при форматировании дат и времени с применением следующих стандартных или настраиваемых строк формата, когда они используются с объектом CultureInfo, представляющим культуру Japanese-Japan ("ja-JP") в классе JapaneseCalendar.

Например, приведён пример с датой в первом году эры Эйсэй в системе JapaneseCalendar.

using System;
using System.Globalization;

public class Example
{
    public static void Main()
    {
         var enUs = new CultureInfo("en-US");
        var japaneseCal = new JapaneseCalendar();
        var jaJp = new CultureInfo("ja-JP");
        jaJp.DateTimeFormat.Calendar = japaneseCal;
        string heiseiEra = "平成";

        var date = japaneseCal.ToDateTime(1, 8, 18, 0, 0, 0, 0, GetEraIndex(heiseiEra));
        FormattableString fmt = $"{date:D}";
        Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)} (Gregorian: {fmt.ToString(enUs)})");

        int GetEraIndex(string eraName)
        {
           foreach (var ctr in japaneseCal.Eras)
              if (jaJp.DateTimeFormat.GetEraName(ctr) == eraName)
                 return ctr;

           return 0;
        }
    }
}
// The example displays the following output:
//    Japanese calendar date: 平成元年8月18日 (Gregorian: Friday, August 18, 1989)
Imports System.Globalization

Module Program
    Dim jaJp As CultureInfo
    Dim japaneseCal As Calendar

    Sub Main()
        Dim enUs = New CultureInfo("en-US")
        japaneseCal = New JapaneseCalendar()
        jaJp = New CultureInfo("ja-JP")
        jaJp.DateTimeFormat.Calendar = japaneseCal
        Dim heiseiEra = "平成"

        Dim dat = japaneseCal.ToDateTime(1, 8, 18, 0, 0, 0, 0, GetEraIndex(heiseiEra))
        Dim fmt As FormattableString = $"{dat:D}"
        Console.WriteLine($"Japanese calendar date: {fmt.ToString(jaJp)} (Gregorian: {fmt.ToString(enUs)})")
    End Sub

    Private Function GetEraIndex(eraName As String) As Integer
        For Each ctr In japaneseCal.Eras
            If jaJp.DateTimeFormat.GetEraName(ctr) = eraName Then
                Return ctr
            End If
        Next
        Return 0
    End Function
End Module
' The example displays the following output:
'    Japanese calendar date: 平成元年8月18日 (Gregorian: Friday, August 18, 1989)

Если это поведение нежелательно в операциях форматирования, можно восстановить предыдущее поведение, которое всегда представляет первый год эпохи как "1", а не "Gannen", выполнив следующие действия в зависимости от версии .NET:

  • .NET Core: Добавьте следующее в файл конфигурации.netcore.runtime.json :

    "runtimeOptions": {
      "configProperties": {
          "Switch.System.Globalization.FormatJapaneseFirstYearAsANumber": true
      }
    }
    
  • .NET Framework 4.6 или более поздней версии: Задайте следующий параметр AppContext в файлеapp.config :

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <runtime>
        <AppContextSwitchOverrides value="Switch.System.Globalization.FormatJapaneseFirstYearAsANumber=true" />
      </runtime>
    </configuration>
    
  • .NET Framework 4.5.2 или более ранней версии: Задайте следующее значение реестра:

    Ценность
    Ключ HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\AppContext
    вход Переключатель.Система.Глобализация.ФорматироватьЯпонскийПервыйГодКакЧисло
    Тип REG_SZ
    Value правда

При отключенной поддержке gannen в операциях форматирования в предыдущем примере отображаются следующие выходные данные:

Japanese calendar date: 平成1年8月18日 (Gregorian: Friday, August 18, 1989)

.NET также был обновлен таким образом, чтобы операции синтаксического анализа даты и времени поддерживали строки, содержащие год, представленные как "1" или "Ганнен". Хотя это не нужно сделать, можно восстановить предыдущее поведение, чтобы распознать только "1" как первый год эпохи. Это можно сделать следующим образом в зависимости от версии .NET:

  • .NET Core: Добавьте следующее в файл конфигурации.netcore.runtime.json :

    "runtimeOptions": {
      "configProperties": {
          "Switch.System.Globalization.EnforceLegacyJapaneseDateParsing": true
      }
    }
    
  • .NET Framework 4.6 или более поздней версии: Задайте следующий параметр AppContext в файлеapp.config :

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <runtime>
        <AppContextSwitchOverrides value="Switch.System.Globalization.EnforceLegacyJapaneseDateParsing=true" />
      </runtime>
    </configuration>
    
  • .NET Framework 4.5.2 или более ранней версии: Задайте следующее значение реестра:

    Ценность
    Ключ HKEY_LOCAL_MACHINE\Software\Microsoft\.NETFramework\AppContext
    запись Switch.System.Globalization.EnforceLegacyJapaneseDateParsing
    Тип REG_SZ
    Value правда

См. также