Принуждение Java 8 LocalTime toString для сообщения о пропущенных значениях

У меня есть следующий вспомогательный метод datetime, который преобразует UTC-зону Java 8 Date в строку datetime:

public static String dateTimeString(Date date) {
    return date.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime().toString();
}

Желаемый результат состоит в том, чтобы всегда результирующая строка была отформатирована как:

ГГГГ-ММ-дд'Т'ЧЧ:мм:сс'Z'

Проблема в том, что Java 8 LocalTime#toString() намеренно удаляет компоненты времени, которые равны нулю. Так, например, если у меня есть экземпляр Date, который представляет 8 июня 2018 г. в 12:35:00 UTC. Тогда вывод этого метода выше: 2018-06-08'T'12:35'Z'. В то время как я хочу, чтобы он содержал любые обнуленные компоненты секунды/минуты/часа (например, 2018-06-08'T'12:35:00'Z').

Есть идеи?


person hotmeatballsoup    schedule 24.04.2018    source источник
comment
Очевидно, вы можете создать свой собственный DateTimeFormat, который форматирует его таким образом, за исключением того, что он не упущен. У меня нет другой идеи.   -  person Dreamspace President    schedule 24.04.2018
comment
Я бы принял это как решение @DreamspacePresident (+1) - есть идеи о том, как будет выглядеть этот код?   -  person hotmeatballsoup    schedule 24.04.2018
comment
Спасибо @OleV.V. (+1), однако в принятом ответе на этот вопрос используется DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss:SSS"), который не относится к зоне UTC.   -  person hotmeatballsoup    schedule 24.04.2018
comment
Хорошо, hotmeatballsoup, я отправил его с кодом в качестве ответа.   -  person Dreamspace President    schedule 24.04.2018
comment
@hotmeatballsoup Жаль, что вы приняли другой ответ, хотя он пришел через полчаса после моего. :П   -  person Dreamspace President    schedule 06.05.2018


Ответы (3)


private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssX");

public static String dateTimeString(Date date) {
    return date.toInstant().atOffset(ZoneOffset.UTC).format(formatter);
}

Просто используйте строку шаблона фиксированного формата, чтобы получить желаемый формат. Давай попробуем:

    System.out.println(dateTimeString(new Date(0)));
    System.out.println(dateTimeString(new Date(1_524_560_255_555L)));

Это печатает:

1970-01-01T00:00:00Z
2018-04-24T08:57:35Z
  • В первом примере часы, минуты и секунды печатаются, даже если они равны 0.
  • Во втором примере миллисекунды опущены, даже если они не равны нулю (вы видите, что указанное мной значение миллисекунд заканчивается на 555).

Все это говорит о том, что вывод соответствует формату ISO 8601, независимо от того, есть ли у вас 2018-06-08T12:35Z, 2018-06-08T12:35:00Z или даже 2018-06-08T12:35:00.000000000Z. Таким образом, вы можете еще раз проверить, работает ли исключение второго для ваших целей, прежде чем вы возьмете на себя труд определить свой собственный форматировщик.

Ссылка: Статья в Википедии: ISO 8601

person Ole V.V.    schedule 24.04.2018

Я не понимаю, почему вы изображаете вывод по умолчанию, заключая буквы в одинарные кавычки, когда фактический вывод Java вместо этого выглядит как 2018-06-08T12:35Z, но в любом случае, вот код, который его создает по желанию, без пропусков:

final LocalDateTime ldt = LocalDateTime.of(2018, 6, 8, 12, 35, 0);

final ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.of("Z"));

final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd'''T'''HH:mm:ss''X''", Locale.US);

System.err.println(dtf.format(zdt));

Выход:

2018-06-08'T'12:35:00'Z'

Лично я, вероятно, предпочел бы такой формат, содержащий миллис, предоставляющий информацию о часовом поясе, не требующий дополнительных знаний от пользователя и не содержащий лишних символов:

FORMAT: "yyyy-MM-dd HH:mm:ss'.'SSS Z"

OUTPUT: 2018-06-08 12:35:12.345 +0200
person Dreamspace President    schedule 24.04.2018
comment
Спасибо @Dreamspace Президент (+1)! Как/где я могу отформатировать это для зонирования UTC? - person hotmeatballsoup; 24.04.2018
comment
Лучшее, что я могу сделать, это GMT: заменить X в 4-строчном коде, 3-я строка, на OOOO, что изменит эту часть вывода с Z до GMT. В JavaDocs указано GMT+8; Гринвич+08:00; UTC-08:00, но я никогда не мог сделать это, чтобы сказать UTC, это всегда говорит GMT. - person Dreamspace President; 24.04.2018

Похоже, готового решения нет. Самый простой способ — написать собственный класс, расширяющий DateTimeFormatter и переопределите метод public String format(TemporalAccessor temporal), где вы вызовете исходный метод, а затем, при необходимости, измените выходную строку. См. флаги 'Z' для форматирования. Если этот флаг присутствует, вам нужно будет изменить исходный вывод.

person Michael Gantman    schedule 24.04.2018
comment
Класс DateTimeFormatter является окончательным, его нельзя расширять (подклассировать). Также проще определить собственную строку шаблона формата. - person Ole V.V.; 24.04.2018
comment
@Оле В.В. - Вы правы, я пропустил это. Затем вы можете иметь свой собственный класс, который будет содержать класс DateTimeFormatter, т.е. Класс обертки. И вы можете написать все методы DateTimeFormatter и делегировать их исходным, кроме public String format(TemporalAccessor temporal), где вам нужно будет внести изменения в исходный результат по мере необходимости. Немного больше работы, но это будет делать - person Michael Gantman; 24.04.2018