Search code examples
javadatetime-formatdatetime-parsingsecondszoneddatetime

ZonedDateTime ignores 00 for ss part


I am trying to convert string value "2018-10-11T12:00:00Z"; to ZonedDateTime. If I use the default ZonedDateTime.parse(zonedDateTime) then ss portion i.e. 00 is removed and I get "2018-10-11T12:00Z" as output.

Can you please help how to retain 00 as SS part.

String zonedDateTime = "2018-10-11T12:00:00Z";

ZonedDateTime z =  ZonedDateTime.parse(zonedDateTime);
System.out.println(z);  // return 2018-10-11T12:00Z

ZonedDateTime z1 =  ZonedDateTime.parse (zonedDateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ") );

System.out.println(z1);  // Exception : Text '2018-10-11T12:00:00Z' could not be parsed at index 19

Solution

  • Printing the seconds

    When you just print a ZonedDateTime using System.out.println, you are implicitly calling its toString method. When the seconds and fraction of second are 0, toString leaves them out. To print them anyway, use a formatter for formatting (as opposed to using one for parsing):

        DateTimeFormatter formatterWithSeconds = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX");
        System.out.println("z with seconds: " + z.format(formatterWithSeconds));
    

    Output is:

    z with seconds: 2018-10-11T12:00:00Z

    The important distinction here is between the ZonedDateTime object and its string representation. The ZonedDateTimeobject always contains seconds and nanoseconds, also when they are 0. The string representation may or may not include them. The one-arg ZonedDateTime.parse has parsed the 00 seconds. BTW, it accepts strings both with and without seconds.

    Use Instant or OffsetDateTime

    As an aside, since your string contains an offset (Z) and no time zone (like Africa/Nairobi), an OffsetDateTime matches more precisely as representation. The code will work fine if you just search/replace ZonedDateTime with OffsetDateTime throughout since the APIs are similar.

    If the offset is always Z (for “Zulu time zone” or offset 0 from UTC), use Instant:

        String instantString = "2018-10-11T12:00:00Z";
        Instant i = Instant.parse(instantString);
        System.out.println("As Instant: " + i);
    

    I have given your String variable a name that is more appropriate for this snippet; it’s still the same string. Output:

    As Instant: 2018-10-11T12:00:00Z

    Curiously Instant.toString does print the seconds even when they are 0.

    Please read more about the correct type to use in the answer by @Basil Bourque.

    What went wrong in your code? Pattern letter for parsing Z

    // Exception : Text '2018-10-11T12:00:00Z' could not be parsed at index 19
    

    The problem here is not with the seconds, nor with the ss. Index 19 is where the Z is in your string. The two-arg ZonedDateTime.parse objects because pattern letter Z does not match a Z in the date-time string. If you do need to supply a format pattern string for parsing Z, use uppercase X (one or more of them depending on how a non-zero offset looks). From the documentation of pattern letters:

      Symbol  Meaning                     Presentation      Examples
      ------  -------                     ------------      -------
       X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15
       Z       zone-offset                 offset-Z          +0000; -0800; -08:00
    

    Links