Home > OS >  How do I format an integer with a specific set of digits?
How do I format an integer with a specific set of digits?

Time:12-09

I am writing a method that will take a java.time.LocalDate and produce a Julian date variant. The Julian date variant format is as follows:

CYYDDD

Where C is the century, YY is the 2 digit year and DDD is the 3 digit day-of-year. Today (December 8, 2021) translates into 121342.

I'm using a java.util.Formatter to format the values from the LocalDate as follows:

  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());
  }

The getYear() and getDayOfYear() methods both return an int value.

When I attempt to run this, I get the following exception:

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)

I don't understand what is wrong. Every example I've found indicates this format is valid.

This is sort of a secondary question, but does the formatter allow for leading characters (like leading zeros)? I can't seem to find information on doing that.

CodePudding user response:

The problem is that %.2d doesn't make sense, as that specifies the precision of fractional numbers (number of decimals after the point), while integers by definition do not have fractional values. You're probably thinking of d and d, but that only specifies the minimum width.

Instead, use java.time.DateTimeFormatter:

var date = LocalDate.of(2021, 12, 8);
var formatter = DateTimeFormatter.ofPattern("yyDDD");
System.out.println("1"   formatter.format(date));

If the century is fixed (always 1), then you can also use pattern "'1'yyDDD" and do away with the concatenation.

  •  Tags:  
  • java
  • Related