Cómo: Mostrar fechas en calendarios no gregorianos

Actualización: noviembre 2007

Los tipos DateTime y DateTimeOffset utilizan el calendario gregoriano como calendario predeterminado. Esto significa que al llamar al método ToString del valor de fecha y hora, se muestra la representación de cadena de esa fecha y hora en el calendario gregoriano, aunque esa fecha y hora se crearan con otro calendario. Esto se ilustra en el ejemplo siguiente, en el que se utilizan dos maneras diferentes de crear un valor de fecha y hora con el calendario persa, aunque se siguen mostrando esos valores de fecha y hora en el calendario gregoriano cuando se llama al método ToString. En este ejemplo se reflejan dos técnicas que se utilizan habitualmente, aunque son incorrectas, para mostrar la fecha en un calendario determinado.

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

Se pueden utilizar dos técnicas distintas para mostrar la fecha en un calendario determinado. La primera requiere que el calendario sea el calendario predeterminado de una determinada referencia cultural. La segunda se puede utilizar con cualquier calendario.

Para mostrar la fecha en el calendario predeterminado de una referencia cultural

  1. Cree instancias de un objeto de calendario derivado de la clase Calendar que representa el calendario que se va a utilizar.

  2. Cree instancias de un objeto CultureInfo que represente la referencia cultural cuyo formato se utilizará para mostrar la fecha.

  3. Llame al método Array.Exists<T> para determinar si el objeto de calendario es un miembro de la matriz devuelta por la propiedad CultureInfo.OptionalCalendars. Esto indica que el calendario puede actuar como calendario predeterminado del objeto CultureInfo. Si no es miembro de la matriz, siga las instrucciones que aparecen en la sección "Para mostrar la fecha en cualquier calendario".

  4. Asigne el objeto de calendario a la propiedad Calendar del objeto DateTimeFormatInfo devuelto por la propiedad CultureInfo.DateTimeFormat.

    Nota:

    La clase CultureInfo tiene también una propiedad Calendar. Sin embargo, es una propiedad de sólo lectura y constante, no cambia para reflejar el nuevo calendario predeterminado asignado a la propiedad DateTimeFormatInfo.Calendar.

  5. Llame al método ToString o ToString y pásele el objeto CultureInfo cuyo calendario predeterminado se modificó en el paso anterior.

Para mostrar la fecha en cualquier calendario

  1. Cree instancias de un objeto de calendario derivado de la clase Calendar que representa el calendario que se va a utilizar.

  2. Determine qué elementos de fecha y hora deben aparecer en la representación de cadena del valor de fecha y hora.

  3. Para cada elemento de fecha y hora que desee mostrar, llame al método del objeto Get. Los métodos siguientes están disponibles:

    • GetYear, para mostrar el año en el calendario adecuado.

    • GetMonth, para mostrar el mes en el calendario adecuado.

    • GetDayOfMonth, para mostrar el número del día del mes en el calendario adecuado.

    • GetHour, para mostrar la hora del día del mes en el calendario adecuado.

    • GetMinute, para mostrar los minutos de la hora en el calendario adecuado.

    • GetSecond, para mostrar los segundos del minuto en el calendario adecuado.

    • GetMilliseconds, para mostrar los milisegundos del segundo en el calendario adecuado.

Ejemplo

En el ejemplo se muestra una fecha utilizando dos calendarios diferentes. Se muestra la fecha después de definir el calendario hijri como calendario predeterminado para la referencia cultural ar-JO y se muestra la fecha con el calendario Persa, que no se admite como calendario opcional en la referencia cultural 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

Cada objeto CultureInfo puede admitir uno o varios calendarios, que se especifican mediante la propiedad OptionalCalendars. Uno de estos calendarios se establece como calendario predeterminado de la referencia cultural y es devuelto por la propiedad de sólo lectura CultureInfo.Calendar. Otro de los calendarios opcionales se puede establecer como valor predeterminado asignando un objeto Calendar que represente ese calendario a la propiedad DateTimeFormatInfo.Calendar devuelta por la propiedad CultureInfo.DateTimeFormat. Sin embargo, algunos calendarios, como el calendario persa representado por la clase PersianCalendar, no actúan como calendarios opcionales de cualquier referencia cultural.

En el ejemplo se define una clase de utilidad de calendario reutilizable, CalendarUtility, para administrar muchos de los detalles de la generación de la representación de cadena de una fecha mediante un calendario determinado. La clase CalendarUtility tiene los siguientes miembros:

  • Un constructor parametrizado cuyo único parámetro es un objeto Calendar en el que se va a representar una fecha. Éste se asigna a un campo privado de la clase.

  • CalendarExists, un método privado que devuelve un valor booleano que indica si el calendario representado por el objeto CalendarUtility es compatible con el objeto CultureInfo que se pasa al método como parámetro. El método contiene una llamada al método Array.Exists<T>, al que pasa la matriz CultureInfo.OptionalCalendars.

  • HasSameName, un método privado asignado al delegado Predicate<T> que se pasa como parámetro al método Array.Exists<T>. Los miembros de la matriz se pasan al método hasta que devuelve true. El método determina si el nombre de un calendario opcional es igual que el calendario representado por el objeto CalendarUtility.

  • DisplayDate, un método público sobrecargado al que se pasan dos parámetros: el valor DateTime o DateTimeOffset que se va a expresar en el calendario representado por el objeto CalendarUtility y la referencia cultural cuyas reglas de formato se van a utilizar. Su comportamiento a la hora de devolver la representación de cadena de una fecha depende de si el calendario de destino es compatible con la referencia cultural cuyas reglas de formato se van a utilizar.

Independientemente del calendario que se utilice para crear un valor DateTime o DateTimeOffset en este ejemplo, ese valor normalmente se expresa como una fecha gregoriana. Esto se debe a que los tipos DateTime y DateTimeOffset no conservan ninguna información del calendario. Internamente, se representan como el número de pasos transcurridos desde la medianoche del 1 de enero de 0001. La interpretación de ese número depende del calendario. En la mayoría de las referencias culturales, el calendario predeterminado es el calendario gregoriano.

Compilar el código

Este ejemplo requiere una referencia a System.Core.dll.

Compile el código de la línea de comandos mediante csc.exe o vb.exe. Para compilar el código de Visual Studio, póngalo en una plantilla de proyecto de aplicación de consola.

Vea también

Conceptos

Temas "Cómo..." sobre formatos