Cómo: Permitir que los usuarios resuelvan horas ambiguas
Actualización: noviembre 2007
Una hora ambigua es aquella que se asigna a más de una hora universal coordinada (UTC). Se produce al retrasar los relojes, como en el cambio de horario de verano a horario estándar. Para tratar una hora ambigua, puede elegir una de las siguientes acciones:
Si la hora ambigua es un elemento de datos especificado por el usuario, puede dejar que el usuario resuelva la ambigüedad.
Haga una suposición sobre cómo se asigna la hora a la hora UTC. Por ejemplo, puede suponer que una hora ambigua siempre se expresa en la hora estándar de la zona horaria.
En este tema se muestra cómo permitir a un usuario resolver una hora ambigua.
Para permitir a un usuario resolver una hora ambigua
Obtenga la entrada de fecha y hora del usuario.
Llame al método IsAmbiguousTime para determinar si la hora es ambigua.
Si la hora es ambigua, llame al método GetAmbiguousTimeOffsets para recuperar una matriz de objetos TimeSpan. Cada elemento de la matriz contiene una diferencia respecto a la hora UTC a la que puede ser asignada la hora ambigua.
Permita al usuario seleccionar la diferencia deseada.
Obtenga la fecha y hora UTC restando a la hora local la diferencia seleccionada por el usuario.
Llame al método SpecifyKindstatic (Shared en Visual Basic .NET) para establecer la propiedad Kind del valor de fecha y hora UTC en DateTimeKind.Utc.
Ejemplo
En el ejemplo siguiente se pide al usuario que escriba un valor de fecha y hora y, si la hora es ambigua, le permite seleccionar la hora UTC a la que se asignará esta hora ambigua.
Private Sub GetUserDateInput()
' Get date and time from user
Dim inputDate As Date = GetUserDateTime()
Dim utcDate As Date
' Exit if date has no significant value
If inputDate = Date.MinValue Then Exit Sub
If TimeZoneInfo.Local.IsAmbiguousTime(inputDate) Then
Console.WriteLine("The date you've entered is ambiguous.")
Console.WriteLine("Please select the correct offset from Universal Coordinated Time:")
Dim offsets() As TimeSpan = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate)
For ctr As Integer = 0 to offsets.Length - 1
Dim zoneDescription As String
If offsets(ctr).Equals(TimeZoneInfo.Local.BaseUtcOffset) Then
zoneDescription = TimeZoneInfo.Local.StandardName
Else
zoneDescription = TimeZoneInfo.Local.DaylightName
End If
Console.WriteLine("{0}.) {1} hours, {2} minutes ({3})", _
ctr, offsets(ctr).Hours, offsets(ctr).Minutes, zoneDescription)
Next
Console.Write("> ")
Dim selection As Integer = CInt(Console.ReadLine())
' Convert local time to UTC, and set Kind property to DateTimeKind.Utc
utcDate = Date.SpecifyKind(inputDate - offsets(selection), DateTimeKind.Utc)
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())
Else
utcDate = inputDate.ToUniversalTime()
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString())
End If
End Sub
Private Function GetUserDateTime() As Date
Dim exitFlag As Boolean = False ' flag to exit loop if date is valid
Dim dateString As String
Dim inputDate As Date = Date.MinValue
Console.Write("Enter a local date and time: ")
Do While Not exitFlag
dateString = Console.ReadLine()
If dateString.ToUpper = "E" Then exitFlag = True
If Date.TryParse(dateString, inputDate) Then
exitFlag = true
Else
Console.Write("Enter a valid date and time, or enter 'e' to exit: ")
End If
Loop
Return inputDate
End Function
private void GetUserDateInput()
{
// Get date and time from user
DateTime inputDate = GetUserDateTime();
DateTime utcDate;
// Exit if date has no significant value
if (inputDate == DateTime.MinValue) return;
if (TimeZoneInfo.Local.IsAmbiguousTime(inputDate))
{
Console.WriteLine("The date you've entered is ambiguous.");
Console.WriteLine("Please select the correct offset from Universal Coordinated Time:");
TimeSpan[] offsets = TimeZoneInfo.Local.GetAmbiguousTimeOffsets(inputDate);
for (int ctr = 0; ctr < offsets.Length; ctr++)
{
Console.WriteLine("{0}.) {1} hours, {2} minutes", ctr, offsets[ctr].Hours, offsets[ctr].Minutes);
}
Console.Write("> ");
int selection = Convert.ToInt32(Console.ReadLine());
// Convert local time to UTC, and set Kind property to DateTimeKind.Utc
utcDate = DateTime.SpecifyKind(inputDate - offsets[selection], DateTimeKind.Utc);
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());
}
else
{
utcDate = inputDate.ToUniversalTime();
Console.WriteLine("{0} local time corresponds to {1} {2}.", inputDate, utcDate, utcDate.Kind.ToString());
}
}
private DateTime GetUserDateTime()
{
bool exitFlag = false; // flag to exit loop if date is valid
string dateString;
DateTime inputDate = DateTime.MinValue;
Console.Write("Enter a local date and time: ");
while (! exitFlag)
{
dateString = Console.ReadLine();
if (dateString.ToUpper() == "E")
exitFlag = true;
if (DateTime.TryParse(dateString, out inputDate))
exitFlag = true;
else
Console.Write("Enter a valid date and time, or enter 'e' to exit: ");
}
return inputDate;
}
El núcleo del código de ejemplo utiliza una matriz de objetos TimeSpan para indicar las posibles diferencias de la hora ambigua respecto a la hora UTC. Sin embargo, probablemente estas diferencias no resultan significativas para el usuario. Para aclarar el significado de las diferencias, el código también indica si una diferencia representa la hora estándar de la zona horaria local o del horario de verano. El código determina qué hora es la estándar y cuál pertenece al horario de verano comparando la diferencia con el valor de la propiedad BaseUtcOffset. Esta propiedad indica la diferencia entre la hora UTC y la hora estándar de la zona horaria.
En este ejemplo, todas las referencias a la zona horaria local se realizan a través de la propiedad TimeZoneInfo.Local; la zona horaria local nunca se asigna a una variable de objeto. Este es un procedimiento recomendado porque una llamada al método TimeZoneInfo.ClearCachedData invalida todos los objetos a los que la zona horaria local está asignada.
Compilar el código
Para este ejemplo se necesita:
Que se agregue al proyecto una referencia a System.Core.dll.
Que se importe el espacio de nombres System con la instrucción using (necesaria en código de C#).