Después de haber visto que la tarea no se puede archieved con la ayuda del marco/Silverlight WP7, escribí una pequeña ayuda que hace el trabajo:
public static class DateTimeHelper
{
/// <summary>
/// Tries to parse the given datetime string that is not annotated with a timezone
/// information but known to be in the CET/CEST zone and returns a DateTime struct
/// in UTC (so it can be converted to the devices local time). If it could not be
/// parsed, result contains the current date/time in UTC.
/// </summary>
public static bool TryParseCetCest(string s, string format, IFormatProvider provider, DateTimeStyles style, out DateTime result)
{
// Parse datetime, knowing it is in CET/CEST timezone. Parse as universal as we fix it afterwards
if (!DateTime.TryParseExact(s, format, provider, style, out result))
{
result = DateTime.UtcNow;
return false;
}
result = DateTime.SpecifyKind(result, DateTimeKind.Utc);
// The boundaries of the daylight saving time period in CET and CEST (_not_ in UTC!)
// Both DateTime structs are of kind 'Utc', to be able to compare them with the parsing result
DateTime DstStart = LastSundayOf(result.Year, 3).AddHours(2);
DateTime DstEnd = LastSundayOf(result.Year, 10).AddHours(3);
// Are we inside the daylight saving time period?
if (DstStart.CompareTo(result) <= 0 && result.CompareTo(DstEnd) < 0)
result = result.AddHours(-2); // CEST = UTC+2h
else
result = result.AddHours(-1); // CET = UTC+1h
return true;
}
/// <summary>
/// Returns the last sunday of the given month and year in UTC
/// </summary>
private static DateTime LastSundayOf(int year, int month)
{
DateTime firstOfNextMonth = new DateTime(year, month + 1, 1, 0, 0, 0, DateTimeKind.Utc);
return firstOfNextMonth.AddDays(firstOfNextMonth.DayOfWeek == DayOfWeek.Sunday ? -7 :
(-1 * (int)firstOfNextMonth.DayOfWeek));
}
}
el truco consistía en analizar que sin la bandera DateTimeStyles.AssumeUniversal (esto hace suponer TryParseExact
la fecha es UTC y devolver la fecha convertida/ajustarse a local), respecifying como la hora UTC y luego, manualmente ajustándolo al actu al equivalente UTC.
Sigue las reglas de DST que se pueden encontrar here. Lo probé con los 4 casos límite justo antes/después del inicio/final del horario de verano. Eso demostró nuevamente la importancia de las pruebas: tuve que cambiar el operador <
en DstStart.CompareTo(result) < 0
a <=
para que produjera el resultado correcto.
Tenía la sensación de que estoy reinventando la rueda aquí (lo que odio hacer), pero no quería utilizar una biblioteca dedicada para este trabajo simple. Eché un vistazo a Noda Time, que es un gran proyecto, pero creo que no es necesario para esto.
Espero poder ahorrarle a alguien un poco de tiempo con este pequeño ayudante. Intencionalmente no es genérico para todas las zonas horarias (si lo necesita, use una lib como Noda Time en su lugar), pero para estos casos en los que solo tiene una zona horaria fija, como en mi caso.
posible duplicado de [Creación de un DateTime en un huso horario específico en C# fx 3.5] (http://stackoverflow.com/questions/246498/creating-a-datetime-in-a-specific-time-zone-in -c-fx-3-5) –
@Michael Haren: No, no es un duplicado. Eché un vistazo a esto antes de hacer esta pregunta y no me ayudó con mi problema específico. –
quizás no sea un duplicado, pero pensé que sería útil –