Utilizo Noda Time y tengo el siguiente código:

var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
    "yyyy-MM-dd HH:mm:ss z", 
    DateTimeZoneProviders.Tzdb);

var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);

Esto da como resultado un UnparsableValueException con el mensaje:

La fecha / hora local es ambigua en la zona horaria objetivo

El problema, según tengo entendido, es que esta hora específica puede ocurrir dos veces debido al horario de verano. A las 02:00, el reloj retrocede una hora hasta la 01:00. NodaTime no sabe a qué "versión" de 01:00 se refiere la cadena y, por lo tanto, se lanza la excepción.

Para mí, realmente no importa en qué versión del tiempo resulte el análisis, solo quiero evitar la excepción y obtener una fecha lo más cercana posible a la realidad. Una hora menos o más está bien. ¿Cuál sería la mejor forma de hacerlo?

La única forma en que puedo pensar es dividir la cadena y analizar las partes individualmente, y luego agregar una hora, pero eso se siente completamente mal. ¿Existe una solución mejor?

6
TheQ 14 feb. 2018 a las 13:07

2 respuestas

La mejor respuesta

La clase ZonedDateTimePattern tiene un Resolver propiedad. La función del solucionador es realizar el mapeo a la fecha / hora zonificada y manejar los tiempos saltados y ambiguos - tiempos que no se pueden mapear ya que ocurrirán nunca (salteados) o más de una vez (ambiguo) debido a DST.

El código fuente de ZonedDateTimePattern muestra que el El solucionador predeterminado es Resolvers.StrictResolver. Como ya ha descubierto, este resolutor genera una excepción si el mapeo es ambiguo o se omite.

Hay disponibles una variedad de resolutores. La mejor coincidencia para tu "¡solo dame una fecha y hora válidas, por favor!" es probable que el requisito sea LenientResolver que se comporta de la siguiente manera:

La ambigüedad se maneja devolviendo la ocurrencia anterior, y los tiempos omitidos se adelantan según la duración del intervalo.

Podemos especificar este resolutor agregando una llamada a WithResolver() en nuestra instancia ZonedDateTimePattern (la propiedad Resolver no tiene un establecedor público):

var pattern = ZonedDateTimePattern.CreateWithInvariantCulture(
    "yyyy-MM-dd HH:mm:ss z",
    DateTimeZoneProviders.Tzdb).WithResolver(Resolvers.LenientResolver);

var parsed = pattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);

Salida:

2017-11-05T01: 00: 00 América / Los_Angeles (-07)

5
Stephen Kennedy 14 feb. 2018 a las 21:01

Según https : //github.com/nodatime/nodatime/blob/2.2.x/src/NodaTime.Web/Markdown/2.0.x/zoneddatetime-patterns.md (o donde sea que se genere)

Si el patrón no contiene un especificador de desplazamiento ("o <...>"), la fecha y hora locales representadas por el texto se interpretan de acuerdo con el ZoneLocalMappingResolver asociado con el patrón. Se puede crear un nuevo patrón a partir de uno existente, solo con un resolutor diferente, utilizando el método WithResolver. Si el solucionador arroja una SkippedTimeException o AmbiguousTimeException, estos se convierten en resultados de UnparsableValueException. Tenga en cuenta que un patrón sin un especificador de desplazamiento siempre conducirá a una posible pérdida de datos cuando se utiliza con zonas horarias que no son un desplazamiento fijo único, debido a los problemas normales de las transiciones de zona horaria (normalmente para el horario de verano).

Sugerencia

var lenientpattern = ZonedDateTimePattern
                    .CreateWithInvariantCulture("yyyy-MM-dd HH:mm:ss z", DateTimeZoneProviders.Tzdb)
                    .WithResolver(Resolvers.LenientResolver); //or any of the other resolvers
var parsed = lenientpattern.Parse("2017-11-05 01:00:00 America/Los_Angeles");
Console.WriteLine(parsed.Value);
3
Martijn 14 feb. 2018 a las 11:28