Выходная метка времени RFC 3339 в Java
Я хочу вывести временную метку со смещением PST (например, 2008-11-13T13:23:30-08:00). java.util.SimpleDateFormat
не выводит смещения часового пояса в формате час: минута, исключая двоеточие. Есть ли простой способ получить эту метку времени в Java?
// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp);
// prints "2008-11-13T12:23:30-0800" See the difference?
Также, SimpleDateFormat
не могу правильно разобрать пример выше. Это бросает ParseException
,
// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")
13 ответов
Начиная с Java 7, есть X
строка шаблона для часового пояса ISO8601. Для строк в формате, который вы описываете, используйте XXX
, Смотрите документацию.
Образец:
System.out.println(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX")
.format(new Date()));
Результат:
2014-03-31T14:11:29+02:00
Проверьте пакет времени Joda. Они делают форматирование даты RFC 3339 намного проще.
Пример Joda:
DateTime dt = new DateTime(2011,1,2,12,45,0,0, DateTimeZone.UTC);
DateTimeFormatter fmt = ISODateTimeFormat.dateTime();
String outRfc = fmt.print(dt);
Я потратил довольно много времени в поисках ответа на ту же проблему, и я нашел кое-что здесь: http://developer.android.com/reference/java/text/SimpleDateFormat.html
Предлагаемый ответ:
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZZZZZ").format(new Date());
Если вы заметили, я использую 5 'Z' вместо одного. Это дает вывод с двоеточием в смещении, например: "2008-11-13T12:23:30-08:00". Надеюсь, поможет.
Из "Отдела по выполнению задач" одним из решений является использование регулярных выражений для исправления строки после завершения SimpleDateFormat. Что-то вроде s/(\d{2})(\d{2})$/$1:$2/ в Perl.
Если вы хотя бы отдаленно заинтересованы в этом, я отредактирую этот ответ с помощью работающего кода Java.
Но да. Я тоже бьюсь над этой проблемой. RFC3339, я смотрю на тебя!
РЕДАКТИРОВАТЬ:
Это работает для меня
// As a private class member
private SimpleDateFormat rfc3339 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
String toRFC3339(Date d)
{
return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
}
Мы можем просто использовать класс ZonedDateTime и класс DateTimeFormatter для этого.
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssxxx");
ZonedDateTime z2 = ZonedDateTime.now(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS);
System.out.println("format =======> " + z2.format(format));
Вывод: формат =======> 30-03-2020T05:57:37+00:00
Проблема в том, что Z создает смещение часового пояса без двоеточия (:) в качестве разделителя.
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");
Не то, что именно вам нужно?
я пробовал этот формат и работал у меня
yyyy-MM-dd'T'HH:mm:ss'Z'
Я сделал класс InternetDateFormat для RFC3339.
Но комментарий исходного кода японский.
PS: я создал английское издание и немного рефакторинг.
Я нашел беспризорную PasteBin, которая помогла мне с этой проблемой: http://pastebin.com/y3TCAikc
На случай, если его содержимое позже будет удалено:
// I want 2008-11-13T12:23:30-08:00
String timestamp = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").format(new Date());
System.out.println(timestamp);
// prints "2008-11-13T12:23:30-0800" See the difference?
// Throws a ParseException
new SimpleDateFormat("yyyy-MM-dd'T'h:m:ssZ").parse("2008-11-13T13:23:30-08:00")
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'h:m:ss.SZ");
java.time
В
java.util
Date-Time API и их API форматирования,
SimpleDateFormat
устарели и подвержены ошибкам. Рекомендуется полностью отказаться от них и перейти на современный Date-Time API*.
Кроме того, ниже цитируется уведомление с домашней страницы Joda-Time:
Обратите внимание, что начиная с Java SE 8 и далее пользователям предлагается перейти на java.time (JSR-310) - основную часть JDK, заменяющую этот проект.
Решение с использованием
java.time
, современный API даты и времени: самый большой город в тихоокеанском часовом поясе - это Лос-Анджелес, чей часовой пояс называется America / Los_Angeles . С использованием
ZoneId.of("America/Los_Angeles")
, вы можете создать экземпляр, который был разработан для автоматической настройки смещения часового пояса при переходах на летнее время .
Если вам нужно смещение часового пояса, но не имя часового пояса, вы можете преобразовать
ZonedDateTime
в использование ZonedDateTime#toOffsetDateTime
. Некоторые другие варианты использования
OffsetDateTime
должны создать экземпляр Date-Time с фиксированным смещением часового пояса (например,
Instant.now().atOffset(ZoneOffset.of("+05:30"))
и для анализа строки даты и времени со смещением часового пояса.
Демо:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
public class Main {
public static void main(String[] args) {
ZoneId zoneIdLosAngeles = ZoneId.of("America/Los_Angeles");
ZonedDateTime zdtNowLosAngeles = ZonedDateTime.now(zoneIdLosAngeles);
System.out.println(zdtNowLosAngeles);
// With zone offset but without time zone name
OffsetDateTime odtNowLosAngeles = zdtNowLosAngeles.toOffsetDateTime();
System.out.println(odtNowLosAngeles);
// Truncated up to seconds
odtNowLosAngeles = odtNowLosAngeles.truncatedTo(ChronoUnit.SECONDS);
System.out.println(odtNowLosAngeles);
// ################ A winter date-time ################
ZonedDateTime zdtLosAngelesWinter = ZonedDateTime
.of(LocalDateTime.of(LocalDate.of(2021, 11, 20), LocalTime.of(10, 20)), zoneIdLosAngeles);
System.out.println(zdtLosAngelesWinter); // 2021-11-20T10:20-08:00[America/Los_Angeles]
System.out.println(zdtLosAngelesWinter.toOffsetDateTime()); // 2021-11-20T10:20-08:00
// ################ Parsing a date-time string with zone offset ################
String strDateTime = "2008-11-13T13:23:30-08:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt); // 2008-11-13T13:23:30-08:00
}
}
Результат пробного запуска:
2021-07-18T03:27:15.578028-07:00[America/Los_Angeles]
2021-07-18T03:27:15.578028-07:00
2021-07-18T03:27:15-07:00
2021-11-20T10:20-08:00[America/Los_Angeles]
2021-11-20T10:20-08:00
2008-11-13T13:23:30-08:00
Вы, должно быть, заметили, что я не использовал a для анализа строки даты и времени вашего вопроса. Это потому, что ваша строка даты и времени соответствует стандартам ISO-8601. Современный API даты и времени основан на ISO 8601 и не требует использования
DateTimeFormatter
объект явно, если строка даты и времени соответствует стандартам ISO 8601.
Узнайте больше о современном API даты и времени из Trail: Date Time .
* По любой причине, если вам нужно придерживаться Java 6 или Java 7, вы можете использовать ThreeTen-Backport, который поддерживает большую часть функций java.time для Java 6 и 7. Если вы работаете над проектом Android и своим Android API уровень по-прежнему не соответствует Java-8, проверьте API-интерфейсы Java 8+, доступные через десугаринг, и Как использовать ThreeTenABP в Android Project .
Использование библиотеки Google
new com.google.api.client.util.DateTime(new Date()).toStringRfc3339()
Я много тестировал с этим, у меня он работает хорошо ... В частности, когда дело доходит до синтаксического анализа (и для форматирования тоже), это самое близкое, что я нашел до сих пор
DateTimeFormatter rfc3339Formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
DateTimeFormatter rfc3339Parser = new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.appendValue(ChronoField.YEAR, 4)
.appendLiteral('-')
.appendValue(ChronoField.MONTH_OF_YEAR, 2)
.appendLiteral('-')
.appendValue(ChronoField.DAY_OF_MONTH, 2)
.appendLiteral('T')
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 2, 9, true) //2nd parameter: 2 for JRE (8, 11 LTS), 1 for JRE (17 LTS)
.optionalEnd()
.appendOffset("+HH:MM","Z")
.toFormatter()
.withResolverStyle(ResolverStyle.STRICT)
.withChronology(IsoChronology.INSTANCE);
Тестовые примеры на https://github.com/guyplusplus/RFC3339-DateTimeFormatter