La letra “L” del patrón de mes de DateTimeFormatter falla

Noté que java.time.format.DateTimeFormatter no puede analizarse como se esperaba. Vea abajo:

 import java.time.LocalDate; import java.time.format.DateTimeFormatter; public class Play { public static void tryParse(String d,String f) { try { LocalDate.parse(d, DateTimeFormatter.ofPattern(f)); System.out.println("Pass"); } catch (Exception x) {System.out.println("Fail");} } public static void main(String[] args) { tryParse("26-may-2015","dd-L-yyyy"); tryParse("26-May-2015","dd-L-yyyy"); tryParse("26-may-2015","dd-LLL-yyyy"); tryParse("26-May-2015","dd-LLL-yyyy"); tryParse("26-may-2015","dd-M-yyyy"); tryParse("26-May-2015","dd-M-yyyy"); tryParse("26-may-2015","dd-MMM-yyyy"); tryParse("26-May-2015","dd-MMM-yyyy"); } } 

Solo el último bash con tryParse("26-May-2015","dd-MMM-yyyy"); pasará”. Según la documentación, LLL debería poder analizar el formato textual. Tampoco la sutil diferencia de la mayúscula ‘M’ frente a la minúscula ‘m’.

Esto es realmente molesto, ya que no puedo analizar las cadenas formateadas de forma predeterminada por Oracle DB

 SELECT TO_DATE(SYSDATE,'DD-MON-YYYY') AS dt FROM DUAL; 

Del mismo modo, para el siguiente progtwig:

 import java.time.LocalDate; import java.time.format.DateTimeFormatter; public class Play { public static void output(String f) { LocalDate d = LocalDate.now(); Locale l = Locale.US; // Locale l = Locale.forLanguageTag("ru"); System.out.println(d.format(DateTimeFormatter.ofPattern(f,l))); } public static void main(String[] args) { output("dd-L-yyyy"); output("dd-LLL-yyyy"); output("dd-M-yyyy"); output("dd-MMM-yyyy"); } } 

Me sale por debajo de la salida:

 28-5-2015 28-5-2015 28-5-2015 28-May-2015 

Claramente, el especificador de formato L no trata nada textual, me parece numérico …

Sin embargo, si cambio la Locale.forLanguageTag("ru") regional a Locale.forLanguageTag("ru") , obtengo el siguiente resultado:

 28-5-2015 28-Май-2015 28-5-2015 28-мая-2015 

Todo realmente interesante, ¿no estás de acuerdo?

Las preguntas que tengo son:

  • ¿Es razonable para mí esperar que cada uno de los debe funcionar?
  • ¿Deberíamos al menos enviar algunos de estos como un error?
  • ¿Entiendo mal el uso del especificador de patrón L ?

Citando una parte de la documentación que percibí como ‘es importante’:

Texto: el estilo de texto se determina en función del número de letras de patrón utilizadas. Menos de 4 letras de patrón usarán la forma corta. Exactamente 4 letras de patrón usarán la forma completa. Exactamente 5 letras de patrón usarán la forma estrecha. Las letras de patrón ‘L’, ‘c’ y ‘q’ especifican la forma independiente de los estilos de texto .

Número: si el recuento de letras es uno, el valor se genera usando la cantidad mínima de dígitos y sin relleno. De lo contrario, el recuento de dígitos se usa como el ancho del campo de salida, con el valor cero acolchado según sea necesario. Las siguientes letras de patrón tienen restricciones en el recuento de letras. Solo se puede especificar una letra de ‘c’ y ‘F’. Se pueden especificar hasta dos letras de ‘d’, ‘H’, ‘h’, ‘K’, ‘k’, ‘m’ y ‘s’. Se pueden especificar hasta tres letras de ‘D’.

Número / texto: si el recuento de letras de patrón es 3 o más, use las reglas de Texto arriba . De lo contrario, use las reglas numéricas de arriba.

ACTUALIZAR

He hecho dos presentaciones a Oracle:

  • Solicitud de corrección de errores para el problema LLL (texto de formulario largo): JDK-8114833 (original oracle ID de revisión: JI-9021661)
  • Solicitud de mejora para el problema de análisis de minúsculas: ID de revisión: 0 (¿eso también es un error?)

Nombre del mes “independiente”

Creo que “L” está destinado a los idiomas que usan una palabra diferente para el mes en sí contra la forma en que se usa en una fecha. Por ejemplo:

 Locale russian = Locale.forLanguageTag("ru"); asList("MMMM", "LLLL").forEach(ptrn -> System.out.println(ptrn + ": " + ofPattern(ptrn, russian).format(Month.MARCH)) ); 

Salida:

 MMMM: марта LLLL: Март 

No debería haber ninguna razón para usar ‘L’ en lugar de ‘M’ al analizar una fecha.

Intenté lo siguiente para ver qué configuraciones regionales admiten el formato de nombre de mes independiente:

 Arrays.stream(Locale.getAvailableLocales()) .collect(partitioningBy( loc -> "3".equals(Month.MARCH.getDisplayName(FULL_STANDALONE, loc)), mapping(Locale::getDisplayLanguage, toCollection(TreeSet::new)) )).entrySet().forEach(System.out::println); 

Los siguientes idiomas obtienen un nombre de mes autónomo específico de la localidad de ‘LLLL’:

Catalán, chino, croata, checo, finlandés, griego, húngaro, italiano, lituano, noruego, polaco, rumano, ruso, eslovaco, turco, ucraniano

Todos los demás idiomas obtienen “3” como nombre independiente para marzo.

De acuerdo con los javadocs:

Las letras de patrón ‘L’, ‘c’ y ‘q’ especifican la forma independiente de los estilos de texto.

Sin embargo, no pude encontrar mucho sobre lo que se supone que es la forma “independiente”. Al mirar el código, veo que al usar ‘L’ selecciona TextStyle.SHORT_STANDALONE y de acuerdo con ese javadoc:

Texto breve para uso independiente, generalmente una abreviatura. Por ejemplo, el lunes de día de la semana podría generar “Mon”.

Sin embargo, no es así como parece funcionar. Incluso con tres letras obtengo un resultado numérico de este código:

 DateTimeFormatter pattern = DateTimeFormatter.ofPattern ("dd-LLL-yyyy"); System.out.println (pattern.format (LocalDate.now ())); 

Editar

Tras una investigación más exhaustiva, parece (hasta donde puedo decir) que las versiones “autónomas” de estos códigos son para cuando desee cargar sus propios datos independientes de la configuración regional, presumiblemente utilizando DateTimeFormatterBuilder . Como tal, por defecto DateTimeFormatter no tiene entradas cargadas para TextStyle.SHORT_STANDALONE .