C#idiomatic C#
how-to-display-dates-in-non-gregorian-calendarsstandard/base-types

Core library

How to: Display Dates in Non-Gregorian Calendars

Learn more about: How to: Display Dates in Non-Gregorian Calendars

  • page standard/base-types/how-to-display-dates-in-non-gregorian-calendars
  • updated 03/30/2017

The System.DateTime and System.DateTimeOffset types use the Gregorian calendar as their default calendar. This means that calling a date and time value's ToString method displays the string representation of that date and time in the Gregorian calendar, even if that date and time was created using another calendar. This is illustrated in the following example, which uses two different ways to create a date and time value with the Persian calendar, but still displays those date and time values in the Gregorian calendar when it calls the System.DateTime.ToString method. This example reflects two commonly used but incorrect techniques for displaying the date in a particular calendar.

sample · csharpsamples/snippets/csharp/VS_Snippets_CLR/Formatting.HowTo.Calendar/cs/Calendar1.cs1

csharp
// <Snippet2>
using System;
using System.Globalization;

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

      // Display the date using the Gregorian calendar.
      Console.WriteLine($"Using the system default culture: {dateValue1.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: {dateValue1.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(dateValue1, jc));
      // Display a DateTimeOffset value.
      Console.WriteLine(hijriUtil.DisplayDate(dateValue2, 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: {dateValue1.ToString("d", ic)}");
      // Display a Date value.
      Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic));
      // Display a DateTimeOffset value.
      Console.WriteLine(persianUtil.DisplayDate(dateValue2, 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 {this.thisCalendar.GetType().Name} calendar...");
         culture.DateTimeFormat.Calendar = this.thisCalendar;
         return dateToDisplay.ToString(specifier, culture);
      }
      else
      {
         Console.WriteLine($"Displaying date in unsupported {thisCalendar.GetType().Name} calendar...");

         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
// </Snippet2>

public class AdditionalSnippets
{
   public static void BadDate()
   {
      // <Snippet1>
      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
      // </Snippet1>
   }
}

sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR/Formatting.HowTo.Calendar/vb/Calendar1.vb1

vb
' Visual Basic .NET Document
Option Strict On

' <Snippet2>
Imports System.Globalization

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

        ' Display the date using the Gregorian calendar.
        Console.WriteLine("Using the system default culture: {0}", _
                          dateValue1.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}", _
                          dateValue1.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(dateValue1, jc))
        ' Display a DateTimeOffset value.
        Console.WriteLine(hijriUtil.DisplayDate(dateValue2, 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}", _
                          dateValue1.ToString("d", ic))
        ' Display a Date value.
        Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic))
        ' Display a DateTimeOffset value.
        Console.WriteLine(persianUtil.DisplayDate(dateValue2, 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
' </Snippet2>

Module AdditionalSnippets
    Public Sub BadDate()
        ' <Snippet1>
        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
        ' </Snippet1>
    End Sub
End Module

Two different techniques can be used to display the date in a particular calendar. The first requires that the calendar be the default calendar for a particular culture. The second can be used with any calendar.

To display the date for a culture's default calendar

  1. Instantiate a calendar object derived from the System.Globalization.Calendar class that represents the calendar to be used.

  2. Instantiate a System.Globalization.CultureInfo object representing the culture whose formatting will be used to display the date.

  3. Call the System.Array.Exists method to determine whether the calendar object is a member of the array returned by the System.Globalization.CultureInfo.OptionalCalendars property. This indicates that the calendar can serve as the default calendar for the System.Globalization.CultureInfo object. If it is not a member of the array, follow the instructions in the "To Display the Date in Any Calendar" section.

  4. Assign the calendar object to the System.Globalization.DateTimeFormatInfo.Calendar property of the System.Globalization.DateTimeFormatInfo object returned by the System.Globalization.CultureInfo.DateTimeFormat property.

  5. Call either the System.DateTime.ToString or the System.DateTime.ToString method, and pass it the System.Globalization.CultureInfo object whose default calendar was modified in the previous step.

To display the date in any calendar

  1. Instantiate a calendar object derived from the System.Globalization.Calendar class that represents the calendar to be used.

  2. Determine which date and time elements should appear in the string representation of the date and time value.

  3. For each date and time element that you want to display, call the calendar object's Get… method. The following methods are available:

Example

The example displays a date using two different calendars. It displays the date after defining the Hijri calendar as the default calendar for the ar-JO culture, and displays the date using the Persian calendar, which is not supported as an optional calendar by the fa-IR culture.

sample · csharpsamples/snippets/csharp/VS_Snippets_CLR/Formatting.HowTo.Calendar/cs/Calendar1.cs2

csharp
// <Snippet2>
using System;
using System.Globalization;

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

      // Display the date using the Gregorian calendar.
      Console.WriteLine($"Using the system default culture: {dateValue1.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: {dateValue1.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(dateValue1, jc));
      // Display a DateTimeOffset value.
      Console.WriteLine(hijriUtil.DisplayDate(dateValue2, 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: {dateValue1.ToString("d", ic)}");
      // Display a Date value.
      Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic));
      // Display a DateTimeOffset value.
      Console.WriteLine(persianUtil.DisplayDate(dateValue2, 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 {this.thisCalendar.GetType().Name} calendar...");
         culture.DateTimeFormat.Calendar = this.thisCalendar;
         return dateToDisplay.ToString(specifier, culture);
      }
      else
      {
         Console.WriteLine($"Displaying date in unsupported {thisCalendar.GetType().Name} calendar...");

         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
// </Snippet2>

public class AdditionalSnippets
{
   public static void BadDate()
   {
      // <Snippet1>
      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
      // </Snippet1>
   }
}

sample · vbsamples/snippets/visualbasic/VS_Snippets_CLR/Formatting.HowTo.Calendar/vb/Calendar1.vb2

vb
' Visual Basic .NET Document
Option Strict On

' <Snippet2>
Imports System.Globalization

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

        ' Display the date using the Gregorian calendar.
        Console.WriteLine("Using the system default culture: {0}", _
                          dateValue1.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}", _
                          dateValue1.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(dateValue1, jc))
        ' Display a DateTimeOffset value.
        Console.WriteLine(hijriUtil.DisplayDate(dateValue2, 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}", _
                          dateValue1.ToString("d", ic))
        ' Display a Date value.
        Console.WriteLine(persianUtil.DisplayDate(dateValue1, ic))
        ' Display a DateTimeOffset value.
        Console.WriteLine(persianUtil.DisplayDate(dateValue2, 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
' </Snippet2>

Module AdditionalSnippets
    Public Sub BadDate()
        ' <Snippet1>
        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
        ' </Snippet1>
    End Sub
End Module

Each System.Globalization.CultureInfo object can support one or more calendars, which are indicated by the System.Globalization.CultureInfo.OptionalCalendars property. One of these is designated as the culture's default calendar and is returned by the read-only System.Globalization.CultureInfo.Calendar property. Another of the optional calendars can be designated as the default by assigning a System.Globalization.Calendar object that represents that calendar to the System.Globalization.DateTimeFormatInfo.Calendar property returned by the System.Globalization.CultureInfo.DateTimeFormat property. However, some calendars, such as the Persian calendar represented by the System.Globalization.PersianCalendar class, do not serve as optional calendars for any culture.

The example defines a reusable calendar utility class, CalendarUtility, to handle many of the details of generating the string representation of a date using a particular calendar. The CalendarUtility class has the following members:

  • A parameterized constructor whose single parameter is a System.Globalization.Calendar object in which a date is to be represented. This is assigned to a private field of the class.

  • CalendarExists, a private method that returns a Boolean value indicating whether the calendar represented by the CalendarUtility object is supported by the System.Globalization.CultureInfo object that is passed to the method as a parameter. The method wraps a call to the System.Array.Exists method, to which it passes the System.Globalization.CultureInfo.OptionalCalendars array.

  • HasSameName, a private method assigned to the System.Predicate delegate that is passed as a parameter to the System.Array.Exists method. Each member of the array is passed to the method until the method returns true. The method determines whether the name of an optional calendar is the same as the calendar represented by the CalendarUtility object.

  • DisplayDate, an overloaded public method that is passed two parameters: either a System.DateTime or System.DateTimeOffset value to express in the calendar represented by the CalendarUtility object; and the culture whose formatting rules are to be used. Its behavior in returning the string representation of a date depends on whether the target calendar is supported by the culture whose formatting rules are to be used.

Regardless of the calendar used to create a System.DateTime or System.DateTimeOffset value in this example, that value is typically expressed as a Gregorian date. This is because the System.DateTime and System.DateTimeOffset types do not preserve any calendar information. Internally, they are represented as the number of ticks that have elapsed since midnight of January 1, 0001. The interpretation of that number depends on the calendar. For most cultures, the default calendar is the Gregorian calendar.