1

I am fetching datetime from oracle db and parsing in java-11 using ZonedDateTime as below:

  1. oracle --> 1/19/2020 06:09:46.038631 PM

    java ZonedDateTime 0/p --> 2020-01-19T18:09:46.038631Z[UTC]

  2. oracle --> 1/19/2011 4:00:00.000000 AM

    java ZonedDateTime o/p --> 2011-01-19T04:00Z[UTC] (So, here the 0s are truncated by default. However, my requirement is to have consistent fixed length o/p like #1.)

expected java ZonedDateTime o/p --> 2011-01-19T04:00:00.000000Z[UTC]

However, I didnt find any date api methods to achieve above expected o/p. Instead of manipulating string, is there any way to preserve the trailing 0s with fixed length. We have consistent ZonedDateTime type in application, so we do not prefer to change that.

Arvind Kumar Avinash
  • 62,771
  • 5
  • 54
  • 92
deval.techie
  • 43
  • 1
  • 4
  • 1
    How do you print it? With `System.out::println`? You should use a formatter to output the formatted output of your `ZonedDateTime`. – MC Emperor Sep 17 '20 at 05:20
  • I want to write it to file with desired format – deval.techie Sep 17 '20 at 09:50
  • 1
    @deval.techie - Write the value of `String output`, as shown in the [answer](https://stackoverflow.com/a/63936229/10819573), into the file. – Arvind Kumar Avinash Sep 17 '20 at 12:10
  • Just use [`ZonedDateTime.format()`](https://docs.oracle.com/javase/10/docs/api/java/time/ZonedDateTime.html#format(java.time.format.DateTimeFormatter)) with a `DateTimeFormatter` specifying your desired number of decimals. – Ole V.V. Sep 17 '20 at 17:42
  • Two possibly related questions, [OffsetDateTime is not showing milisecond if the string contains 000 \[duplicate\]](https://stackoverflow.com/questions/62890384/offsetdatetime-is-not-showing-milisecond-if-the-string-contains-000) and [String to ZonedDateTime is changing format](https://stackoverflow.com/questions/50120213/string-to-zoneddatetime-is-changing-format). – Ole V.V. Sep 19 '20 at 06:14

1 Answers1

2

We have consistent ZonedDateTime type in application, so we do not prefer to change that.

Why do you think 2011-01-19T04:00Z[UTC] is inconsistent? A date-time object is supposed to hold (and provide methods/functions to operate with) only the date, time, and time-zone information. It is not supposed to store any formatting information; otherwise, it will violate the Single-responsibility principle. The formatting should be handled by a formating class e.g. DateTimeFormatter (for modern date-time API), DateFormat (for legacy java.util date-time API) etc.

Every class is supposed to override the toString() function; otherwise, Object#toString will be returned when its object will be printed. A ZonedDateTime has date, time and time-zone information. Given below is how its toString() for time-part has been implemented:

@Override
public String toString() {
    StringBuilder buf = new StringBuilder(18);
    int hourValue = hour;
    int minuteValue = minute;
    int secondValue = second;
    int nanoValue = nano;
    buf.append(hourValue < 10 ? "0" : "").append(hourValue)
        .append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
    if (secondValue > 0 || nanoValue > 0) {
        buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
        if (nanoValue > 0) {
            buf.append('.');
            if (nanoValue % 1000_000 == 0) {
                buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
            } else if (nanoValue % 1000 == 0) {
                buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
            } else {
                buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
            }
        }
    }
    return buf.toString();
}

As you can see, the second and nano parts are included in the returned string only when they are greater than 0. It means that you need to use a formatting class if you want these (second and nano) zeros in the output string. Given below is an example:

    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    import java.time.format.DateTimeFormatterBuilder;
    import java.util.Locale;

    public class Main {
        public static void main(String[] args) {
            String input = "1/19/2011 4:00:00.000000 AM";

            // Formatter for input string
            DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
                                                .parseCaseInsensitive()
                                                .appendPattern("M/d/u H:m:s.n a")
                                                .toFormatter(Locale.ENGLISH);

            ZonedDateTime zdt = LocalDateTime.parse(input, inputFormatter).atZone(ZoneOffset.UTC);

            // Print `zdt` in default format i.e. the string returned by `zdt.toString()`
            System.out.println(zdt);

            // Formatter for input string
            DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.nnnnnnz");
            String output = zdt.format(outputFormatter);
            System.out.println(output);
        }
    }

Output:

2011-01-19T04:00Z
2011-01-19T04:00:00.000000Z

Food for thought:

public class Main {
    public static void main(String[] args) {
        double d = 5.0000;
        System.out.println(d);
    }
}

What output do you expect from the code given above? Does 5.0 represent a value different from 5.0000? How will you print 5.0000? [Hint: Check String#format, NumberFormat, BigDecimal etc.]

Arvind Kumar Avinash
  • 62,771
  • 5
  • 54
  • 92
  • thanks a lot Arvind. I wasnt aware abt the exact pattern. it works correctly. – deval.techie Sep 18 '20 at 10:07
  • Actually, "uuuu-MM-dd'T'HH:mm:ss.nnnnnnz" was causing length issue..e,g, for 0's it was givng perfect 6 digits for nanos in o/p but for nonzeros with 6 digit at source date, its giving 9 digits output for nanos by adding 3 0s. So, i have little modiefied the patterns which gives consistent result for my expected output : "uuuu-MM-dd'T'HH:mm:ss.SSSSSS'Z['z']'" . The generated string o/p : "2020-04-14T15:51:58.109932Z[UTC]" – deval.techie Sep 21 '20 at 09:05