Java OffsetDateTime.parse() добавляет дополнительные нули к времени

Следующие коды возвращают OffsetDateTime, например 2021-06-30T23:59:59.009966667Z, с добавлением 2 дополнительных нулей. У меня в форматтере 7 цифр, но он все равно возвращает 9 цифр. Почему?

import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter;

public class HelloWorld{

       public static void main(String []args){
 DateTimeFormatter MAIN_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnn XXX");
 String dbData = "2021-06-30 23:59:59.9966667 +00:00";
 OffsetDateTime time = OffsetDateTime.parse(dbData, MAIN_FORMATTER);
 System.out.println(time.toString());
 }

}

1 ответ

Следующие коды возвращают OffsetDateTime, например 2021-06-30T23:59:59.009966667Z, с добавлением 2 дополнительных нулей. У меня в форматтере 7 цифр, но он все равно возвращает 9 цифр. Почему?

Вы получите тот же результат даже для одного или любого количества s, меньших или равных. Однако, если вы превысите 7, вы получите исключение, например

      Exception in thread "main" java.time.format.DateTimeParseException:
               Text '2021-06-30 23:59:59.9966667 +00:00' could not be parsed at index 20

Причина этого DateTimeFormatter считает количество цифр в шаблоне, и если оно меньше или равно количеству цифр после ., он будет использовать дополнительный, чтобы компенсировать это, но если количество s превышает количество цифр, он не будет иметь никакого представления, для чего эти дополнительные s.

Это касается не только, но и большинства (если не всех) символов. Вы можете понять это из следующего примера:

      import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDate1 = "2020/2/2";
        String strDate2 = "2020/02/02";

        // Notice the single M and d
        DateTimeFormatter dtfCorrectForBothDateStrings = DateTimeFormatter.ofPattern("uuuu/M/d", Locale.ENGLISH);
        System.out.println(LocalDate.parse(strDate2, dtfCorrectForBothDateStrings));
        System.out.println(LocalDate.parse(strDate1, dtfCorrectForBothDateStrings));

        // Notice the two M's and d's
        DateTimeFormatter dtfCorrectOnlyForSecondDateString = DateTimeFormatter.ofPattern("uuuu/MM/dd", Locale.ENGLISH);
        System.out.println(LocalDate.parse(strDate2, dtfCorrectOnlyForSecondDateString));
        System.out.println(LocalDate.parse(strDate1, dtfCorrectOnlyForSecondDateString));
    }
}

Выход:

      2020-02-02
2020-02-02
2020-02-02
Exception in thread "main" java.time.format.DateTimeParseException: Text '2020/2/2' could not be parsed at index 5
    at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2051)
    at java.base/java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1953)
    at java.base/java.time.LocalDate.parse(LocalDate.java:429)
    at Main.main(Main.java:16)

Почему это дает мне .009966667 и нет ?

Символ, nобозначает нано-секунды и 9966667 наносекунды равны 0.009966667 второй.

      public class Main {
    public static void main(String[] args) {
        int nanos = 9966667;
        System.out.println(nanos + " nanoseconds = " + ((double) nanos / 1_000_000_000) + " second");
    }
}

Выход:

      9966667 nanoseconds = 0.009966667 second

Как это работает?

Sобозначает долю секунды и разбирается как 0.9966667 второй.

Примечание по реализации:

Группирует цифры доли секунды в ближайшее кратное 3 (т.е. милли, микро и нано), например

  • за .99, вывод будет .990, и
  • для, вывод будет .996, и
  • за .9966, вывод будет .996600, и
  • за .9966667, вывод будет .996666700.

Ниже приводится отрывок из OffsetDateTime#toString:

На выходе будет один из следующих форматов ISO-8601:

  • уууу-ММ-дд'Т'ЧЧ: ммXXXXX
  • уууу-ММ-дд'Т'ЧЧ: мм: ссXXXXX
  • uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX
  • uuuu-MM-dd'T'HH: мм:ss.SSSSSSXXXXX
  • uuuu-MM-dd'T'HH: мм:ss.SSSSSSSSSXXXXX

Финальная демонстрация (включающая все, что было обсуждено выше):

      import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2021-06-30 23:59:59.9966667 +00:00";

        System.out.println(OffsetDateTime.parse(strDateTime,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.nnnnnnn XXX", Locale.ENGLISH)));

        System.out.println(OffsetDateTime.parse(strDateTime,
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS XXX", Locale.ENGLISH)));
    }
}

Выход:

      2021-06-30T23:59:59.009966667Z
2021-06-30T23:59:59.996666700Z
Другие вопросы по тегам