Мгновенный формат в строку


227

Я пытаюсь отформатировать Instant в строку, используя новый Java-API time 8 и шаблон:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

Используя приведенный выше код, я получаю исключение, которое жалуется на неподдерживаемое поле:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
    at java.time.Instant.getLong(Instant.java:608)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

Ответы:


310

Часовой пояс

Для форматирования часового пояса требуется. Без часового пояса средство форматирования не знает, как преобразовать мгновенное в человеческое поле даты и времени, и поэтому выдает исключение.Instant

Часовой пояс можно добавить непосредственно в форматтер с помощью withZone().

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

Генерация строки

Теперь используйте этот форматер для генерации строкового представления вашего Instant.

Instant instant = Instant.now();
String output = formatter.format( instant );

Дамп на консоль.

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

Когда беги.

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

51
Спасибо!! Кстати, исключение «неподдерживаемое поле», указывающее, например, год, является чрезвычайно тупым. Возможно, эта ситуация должна быть обнаружена, и должно быть сгенерировано исключение, указывающее непосредственно на идентификатор отсутствующей зоны в Instant!
Давидбак

1
Более странно, если вы включите .withZone (например, .withZone (ZoneId.of ("Z"))) и отформатируете LocalDateTime, зона будет игнорироваться! Таким образом, если включен .withZone (), один и тот же форматер можно использовать как для Instant, так и для LocalDateTime, не влияя на время, указанное для последнего.
Гленн

1
Почему так трудно принять тот факт, что Instant имеет часовой пояс, который является GMT?
Корай Тугай

1
@KorayTugay Поскольку педантичные комментарии «Мгновенное уже по Гринвичу» могут быть правдой, они далеко не полезны при обнаружении трассировки исключения, поскольку форматирование Мгновенного режима без указания часового пояса не работает. Было бы неплохо, если бы форматировщик по умолчанию выбрал GMT, ну да ладно.
Ти Стрга

Теперь это дает вам yyyy-MM-dd hh:mm:ssформат:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

39
public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

3
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, как и почему он решает проблему, улучшит долгосрочную ценность ответа.
Александр

1
Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
Росарио Перейра Фернандес

23
DateTimeFormatter.ISO_INSTANT.format(Instant.now())

Это избавляет вас от необходимости конвертировать в UTC. Однако временные рамки некоторых других языков могут не поддерживать миллисекунды, поэтому вам следует

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

Что вы подразумеваете под «временными рамками какого-то другого языка»? Будет ли ISO_INSTANT.format () автоматически обрезаться до секунд?
Guangtong Shen

Некоторые фреймворки ожидают, что только время дойдет до секунд, потому что они не соблюдают полное соглашение ISO и прерываются, когда есть миллисекунды как часть входной строки.
Архимед Траяно

21

InstantКласс не содержит информации о зоне, он только хранит временные метки в миллисекундах от UNIX эпохи, то есть 1 января 1070 от UTC. Таким образом, средство форматирования не может печатать дату, потому что дата всегда печатается для конкретного часового пояса. Вы должны установить часовой пояс для форматирования, и все будет хорошо, как это:

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

4

Или, если вы все еще хотите использовать средство форматирования, созданное из шаблона, вы можете просто использовать LocalDateTime вместо Instant:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

4

Инстансы уже в UTC и уже имеют формат даты по умолчанию yyyy-MM-dd . Если вы довольны этим и не хотите связываться с часовыми поясами или форматированием, вы также можете toString()это сделать:

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


Не хотите T и Z? (Z указывает, что эта дата - UTC. Z обозначает "Zulu" или "Смещение нулевого часа" или UTC):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


Хотите миллисекунды вместо наносекунд? (Так что вы можете добавить его в SQL-запрос):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

и т.п.


-3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

Я считаю, что это может помочь, вам может понадобиться использовать какое-то изменение локальной даты вместо мгновенного

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.