Estoy escribiendo un método que tomará java.time.LocalDate y producirá una variante de fecha juliana. El formato de la variante de fecha juliana es el siguiente:
CYYDDD
Donde C es el siglo, YY es el año de 2 dígitos y DDD es el día del año de 3 dígitos. Hoy (8 de diciembre de 2021) se traduce en 121342.
Estoy usando java.util.Formatter para formatear los valores de LocalDate de la siguiente manera:
private int calculateJDEDate(LocalDate date) { StringBuilder sb = new StringBuilder(); Formatter fmt = new Formatter(sb); // Format 2 digit year. fmt.format("%.2d", date.getYear()).close(); // fmt.format("1%1$.2d%2$.3d", date.getYear(), date.getDayOfYear()).close(); return Integer.parseInt(sb.toString()); } Los métodos getYear() y getDayOfYear() devuelven un valor int.
Cuando intento ejecutar esto, obtengo la siguiente excepción:
Exception in thread "main" java.util.IllegalFormatPrecisionException: 2 at java.base/java.util.Formatter$FormatSpecifier.checkInteger(Formatter.java:3138) at java.base/java.util.Formatter$FormatSpecifier.<init>(Formatter.java:2874) at java.base/java.util.Formatter.parse(Formatter.java:2713) at java.base/java.util.Formatter.format(Formatter.java:2655) at java.base/java.util.Formatter.format(Formatter.java:2609) at com.fossfloors.f55hubdt.Main.calculateJDEDate(Main.java:104) at com.fossfloors.f55hubdt.Main.calculateDateData(Main.java:96) at com.fossfloors.f55hubdt.Main.lambda$0(Main.java:129) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) at java.base/java.util.stream.LongPipeline$1$1.accept(LongPipeline.java:177) at java.base/java.util.stream.Streams$RangeLongSpliterator.forEachRemaining(Streams.java:228) at java.base/java.util.Spliterator$OfLong.forEachRemaining(Spliterator.java:763) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.forEachOrdered(ReferencePipeline.java:502) at com.fossfloors.f55hubdt.Main.main(Main.java:128)No entiendo lo que está mal. Cada ejemplo que he encontrado indica que este formato es válido.
Esta es una especie de pregunta secundaria, pero ¿el formateador permite caracteres iniciales (como ceros iniciales)? Parece que no puedo encontrar información sobre cómo hacerlo.
El problema es que %.2d no tiene sentido, ya que especifica la precisión de los números fraccionarios (número de decimales después del punto), mientras que los enteros, por definición, no tienen valores fraccionarios. Probablemente esté pensando en %02d y %03d , pero eso solo especifica el ancho mínimo.
En su lugar, use java.time.DateTimeFormatter :
var date = LocalDate.of(2021, 12, 8); var formatter = DateTimeFormatter.ofPattern("yyDDD"); System.out.println("1" + formatter.format(date)); Si el siglo es fijo (siempre 1), también puede usar el patrón "'1'yyDDD" y eliminar la concatenación.