¿`uuuu` versus `yyyy` en códigos de patrón de formato `DateTimeFormatter` en Java?

Resuelto Basil Bourque asked hace 8 años • 4 respuestas

La DateTimeFormatterdocumentación de la clase dice sobre sus códigos de formato para el año:

u año año 2004; 04

y año de era 2004; 04

Año: el recuento de letras determina el ancho mínimo del campo por debajo del cual se utiliza el relleno. Si el número de letras es dos, se utiliza una forma reducida de dos dígitos. Para imprimir, esto genera los dos dígitos más a la derecha. Para el análisis, se utilizará el valor base de 2000, lo que dará como resultado un año dentro del rango de 2000 a 2099 inclusive. Si el recuento de letras es inferior a cuatro (pero no dos), entonces el signo solo se genera para años negativos según SignStyle.NORMAL. De lo contrario, el signo se genera si se excede el ancho del pad, según SignStyle.EXCEEDS_PAD.

Ninguna otra mención de “era”.

Entonces, ¿cuál es la diferencia entre estos dos códigos, uversus y, yearversusyear-of-era ?

¿Cuándo debería usar algo como este patrón uuuu-MM-ddy cuándo?yyyy-MM-dd cuando trabajo con fechas en Java?

Parece que el código de ejemplo escrito por aquellos que conocen el usouuuu , pero ¿por qué?

Otras clases de formato, como la heredada, SimpleDateFormatsolo tienen yyyy, por lo que no estoy seguro de por qué java.time trae esto uuuucomo "año de era".

Basil Bourque avatar Dec 16 '16 11:12 Basil Bourque
Aceptado

Dentro del alcance de java.time-paquete, podemos decir:

  • Es más seguro utilizar "u" en lugar de "y" porque, DateTimeFormatterde lo contrario, insistirá en tener una era en combinación con "y" (= año de era). Por lo tanto, el uso de "u" evitaría algunas posibles excepciones inesperadas en el formato/análisis estricto. Vea también esta publicación SO . Otra cosa menor que mejora con el símbolo "u" en comparación con "y" es imprimir/analizar años gregorianos negativos (en el pasado).

  • De lo contrario, podemos afirmar claramente que el uso de "u" en lugar de "y" rompe hábitos arraigados en la programación Java . Tampoco está intuitivamente claro que "u" denota algún tipo de año porque a) la primera letra de la palabra inglesa "year" no concuerda con este símbolo y b) SimpleDateFormatha usado "u" para un propósito diferente desde Java. 7 ( ISO-día-número-de-semana ). La confusión está garantizada... ¿para siempre?

  • También deberíamos ver que usar eras (símbolo "G") en el contexto de ISO es en general peligroso si consideramos fechas históricas . Si se utiliza "G" con "u", ambos campos no están relacionados entre sí. Y si se usa "G" con "y", entonces el formateador está satisfecho pero aún usa el calendario gregoriano proléptico cuando la fecha histórica exige diferentes calendarios y manejo de fechas.

Información de contexto:

Al desarrollar e integrar JSR 310 ( java.timepaquetes), los diseñadores decidieron utilizar Common Locale Data Repository (CLDR) /LDML-spec como base de los símbolos de patrón en DateTimeFormatter. El símbolo "u" ya estaba definido en CLDR como año gregoriano proléptico, por lo que este significado se adoptó para el nuevo JSR-310 (pero no por SimpleDateFormatrazones de compatibilidad con versiones anteriores).

Sin embargo, esta decisión de seguir CLDR no fue del todo consistente porque JSR-310 también había introducido nuevos símbolos de patrón que no existían y aún no existen en CLDR; consulte también este antiguo billete CLDR . CLDR cambió el símbolo sugerido "I" a "VV" y finalmente lo superó JSR-310, incluidos los nuevos símbolos "x" y "X" . Pero "n" y "N" todavía no existen en CLDR, y dado que este ticket antiguo está cerrado, no está nada claro si CLDR alguna vez lo admitirá en el sentido de JSR-310. Además, el ticket no menciona el símbolo "p" (instrucción de relleno en JSR-310, pero no definida en CLDR). Por lo tanto, todavía no tenemos un acuerdo perfecto entre las definiciones de patrones en diferentes bibliotecas e idiomas.

Y sobre "y": Tampoco debemos pasar por alto el hecho de que CLDR asocia este año de era con al menos algún tipo de año mixto juliano/gregoriano y no con el año proléptico gregoriano como lo hace JSR-310 (dejando la rareza de aparte de los años negativos). Así que aquí tampoco hay un acuerdo perfecto entre CLDR y JSR-310.

Meno Hochschild avatar Dec 16 '2016 11:12 Meno Hochschild

En la sección de javadoc Patrones para formatear y analizar , se DateTimeFormatterenumeran los siguientes 3 símbolos relevantes:

Symbol  Meaning        Presentation  Examples
------  -------        ------------  -------
 G       era            text          AD; Anno Domini; A
 u       year           year          2004; 04
 y       year-of-era    year          2004; 04

Sólo a modo de comparación, estos otros símbolos son bastante fáciles de entender:

 D       day-of-year    number        189
 d       day-of-month   number        10
 E       day-of-week    text          Tue; Tuesday; T

Los day-of-year, day-of-monthy day-of-weekson obviamente el día dentro del alcance dado (año, mes, semana).

Entonces, year-of-erasignifica el año dentro del alcance dado (era), y justo encima se eramuestra con un valor de ejemplo de AD(el otro valor, por supuesto, es BC).

yeares el año firmado0 , donde año es 1 BC, año -1es 2 BC, y así sucesivamente.

Para ilustrar: ¿Cuándo fue asesinado Julio César ?

  • 15 de marzo de 44 a. C. (usando el patrón MMMM d, y GG)
  • 15 de marzo, -43 (usando el patrón MMMM d, u)

Por supuesto, la distinción sólo importará si el año es cero o negativo, y como eso es raro, a la mayoría de las personas no les importa, aunque debería.

Conclusión: Si usas ytambién deberías usar G. Dado Gque rara vez se utiliza, el símbolo del año correcto es u, no y; de lo contrario, un año no positivo se mostrará incorrectamente.

Esto se conoce como programación defensiva :

La programación defensiva es una forma de diseño defensivo destinado a garantizar el funcionamiento continuo de una pieza de software en circunstancias imprevistas .


Tenga en cuenta que DateTimeFormatteres consistente con SimpleDateFormat:

Letter  Date or Time Component  Presentation  Examples
------  ----------------------  ------------  --------
G       Era designator          Text          AD
y       Year                    Year          1996; 96

Los años negativos siempre han sido un problema y ahora lo solucionaron agregando u.

Andreas avatar Dec 16 '2016 06:12 Andreas

Larga historia corta

  1. Para el 99 % de los propósitos puedes lanzar una moneda, no habrá diferencia si usas yyyyo uuuu(o si usas yyo uupara un año de 2 dígitos).
  2. Depende de lo que quieras que suceda en caso de que ocurra un año antes del 1 EC (1 AD). La cuestión es que en el 99 % de los programas ese año nunca se producirá.

Otras dos respuestas ya han presentado los hechos de cómo uy yfuncionan muy bien, pero todavía sentí que faltaba algo, así que estoy contribuyendo con la respuesta un poco más basada en opiniones.

Para formatear

Suponiendo que no espera un año antes de que se formatee 1 CE, lo mejor que puede hacer es verificar esta suposición y reaccionar adecuadamente en caso de que se rompa. Por ejemplo, según las circunstancias y los requisitos, puede imprimir un mensaje de error o generar una excepción. Un camino de falla muy suave podría ser usar un patrón con y(año de era) y G(era) en este caso y un patrón con cualquiera de los dos uo yen el caso normal de la era actual. Tenga en cuenta que si está imprimiendo la fecha actual o la fecha en que se compiló su programa, puede estar seguro de que es en la era común y puede optar por omitir la verificación.

Para analizar

En muchos (¿la mayoría?) de los casos, analizar también significa validar, lo que significa que no tiene garantías de cómo se verá su cadena de entrada. Normalmente proviene del usuario o de otro sistema. Un ejemplo: una cadena de fecha es 2018-09-29. Aquí la elección entre uuuuy yyyydebería depender de lo que desee que suceda en caso de que la cadena contenga un año 0 o negativo (por ejemplo, 0000-08-17o -012-11-13). Suponiendo que esto sería un error, la respuesta inmediata es: usar yyyypara que se lance una excepción en este caso. Aún más fino: use uuuuy después del análisis realice una verificación del rango de la fecha analizada. Este último enfoque permite tanto una validación más precisa como un mejor mensaje de error en caso de un error de validación.

Caso especial (ya mencionado por Meno Hochschild): si su formateador usa un estilo de resolución estricto y contiene ywithout G, el análisis siempre fallará porque, estrictamente hablando, el año de la era es ambiguo sin era: 1950 podría significar 1950 EC o 1950 BCE (1950 BC). Entonces, en este caso necesita u(o proporcionar una era predeterminada, esto es posible a través de DateTimeFormatterBuilder).

Una larga historia resumida otra vez

La verificación explícita del rango de sus fechas, específicamente de sus años, es mejor que confiar en la elección entre uuuuy yyyypara detectar años muy tempranos inesperados.

Anonymous avatar Aug 13 '2018 10:08 Anonymous