Что это за формат даты? 2011-08-12T20: 17: 46.384Z

385

У меня есть следующие даты: 2011-08-12T20:17:46.384Z. Какой это формат? Я пытаюсь разобрать его с помощью Java 1.4 через, DateFormat.getDateInstance().parse(dateStr)и я получаю

java.text.ParseException: Неразборчивая дата: "2011-08-12T20: 17: 46.384Z"

Я думаю, что я должен использовать SimpleDateFormat для синтаксического анализа, но я должен сначала знать строку формата. Все, что у меня есть для этого, так это yyyy-MM-ddпотому, что я не знаю, что Tозначает эта строка - что-то, связанное с часовым поясом? Эта строка даты взята из lcmis:downloadedOnтега, отображаемого в типе носителя истории загрузки файлов CMIS .

Сара Весселс
источник
44
Это ISO 8601
Томаш Нуркевич
3
@ TomaszNurkiewicz, это не так. ISO8601 не имеет Z в конце.
t1gor
5
ISO8601 позволяет Z в конце. Смотрите ссылку выше, ищите UTC.
Джонатан Розен
2
@ t1gor Zв конце коротка для Zuluи средства UTC . Этот формат, безусловно, является частью набора стандартных текстовых форматов даты и времени ISO 8601 . Кстати, эти стандартные форматы по умолчанию используются в классах java.time .
Василий Бурк
3
К вашему сведению, проблемные старые классы даты и времени, такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormatтеперь унаследованные , вытеснены классами java.time, встроенными в Java 8 и Java 9. См. Руководство Oracle .
Василий Бурк

Ответы:

513

Буква T - это просто литерал для отделения даты от времени, а буква Z означает «смещение нулевого часа», также известное как «время Зулу» (UTC). Если ваши строки всегда имеют «Z», вы можете использовать:

SimpleDateFormat format = new SimpleDateFormat(
    "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));

Или используя Joda Time , вы можете использовать ISODateTimeFormat.dateTime().

Джон Скит
источник
7
Зачем нам нужны одиночные кавычки вокруг Tи Z?
Марун
7
@MarounMaroun: В основном нам нужны эти буквальные символы. Это может быть необязательно для T(я не могу вспомнить, как SimpleDateFormat обрабатывает неизвестные спецификаторы), но Zмы хотим, чтобы это был символ «Z», а не «значение смещения UTC» (например, «00»).
Джон Скит
2
@nyedidikeke: На странице Википедии, на которую вы ссылаетесь, отображается «часовой пояс Зулу» для UTC. Я не уверен, что ты веришь, что исправляешь.
Джон Скит
9
@JonSkeet: это может привести к ненужным дебатам; не оспаривая ваш ответ, но намеревался привлечь внимание к букве Z, получившей начальную букву от «нулевого смещения UTC». Буква Z в фонетическом алфавите НАТО называется «зулу» . В свою очередь, военный подход к нулевому смещению UTC закреплен на букве Z, которую они идентифицируют как зулу, получив зашифрованное имя: часовой пояс зулу. Важно отметить, что Z не утратил своего значения и все еще является указателем зоны для нулевого смещения UTC, поскольку часовой пояс Зулу (от Z) - просто унаследованный кодированный язык, чтобы ссылаться на него.
nyedidikeke
2
@nyedidikeke: Я все еще не согласен с тем, будет ли кто-либо еще заботиться о различии со ссылкой на мой ответ, но я обновил его. Я не собираюсь вдаваться во все детали, поскольку история в целом не имеет отношения к ответу.
Джон Скит
86

ТЛ; др

Стандартный формат ISO 8601 используется вашей входной строкой.

Instant.parse ( "2011-08-12T20:17:46.384Z" ) 

ISO 8601

Этот формат определяется разумным практическим стандартом ISO 8601 .

TОтделяет часть даты из части времени в день. В Zконце означает UTC (то есть смещение от UTC, равное нулю часов, минут и секунд). ZЭто произносится как «Zulu» .

java.time

Старые классы даты и времени, включенные в ранние версии Java, оказались плохо спроектированными, запутанными и хлопотными. Избежать их.

Вместо этого используйте инфраструктуру java.time, встроенную в Java 8 и более поздние версии . Классы java.time вытесняют как старые классы даты и времени, так и очень успешную библиотеку Joda-Time.

Классы java.time по умолчанию используют ISO 8601 при разборе / генерации текстовых представлений значений даты и времени.

InstantКласс представляет собой момент на шкале времени в формате UTC с разрешением наносекунд . Этот класс может напрямую анализировать вашу входную строку, не заботясь об определении шаблона форматирования.

Instant instant = Instant.parse ( "2011-08-12T20:17:46.384Z" ) ;

Таблица типов даты и времени в Java, как современных, так и устаревших


О java.time

Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date, Calendar, и SimpleDateFormat.

Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, смотрите Oracle Tutorial . И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310 .

Где взять классы java.time?

  • Java SE 8 , Java SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API с комплексной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android

Таблица какой библиотеки java.time использовать с какой версией Java или Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .

Базилик Бурк
источник
3
@star «Зулу» происходит из военной и авиационной традиции, где 25 букв алфавита AZ (без «J»), каждая из которых имеет произносимое имя, представляют свою версию часовых поясов . Зона "Зулу" смещена на 0 часов относительно UTC. Смотрите это и это .
Василий Бурк
27

Не уверен насчет разбора Java, но это ISO8601: http://en.wikipedia.org/wiki/ISO_8601

smparkes
источник
Это тоже "2016-01-27T17: 44: 55UTC", ISO8601?
user1997292
Я не верю в это. Это близко, но UTC как суффикс не допускается. Это должно быть Z или смещение часового пояса, например, +0100. Z и UTC имеют одинаковое значение, поэтому изменение UTC на Z приведет к действительному ISO 8601.
smparkes
9

Есть и другие способы разбора, а не первый ответ. Чтобы разобрать его:

(1) Если вы хотите получить информацию о дате и времени, вы можете проанализировать ее для ZonedDatetime(начиная с Java 8 ) или Date(старого) объекта:

// ZonedDateTime's default format requires a zone ID(like [Australia/Sydney]) in the end.
// Here, we provide a format which can parse the string correctly.
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2011-08-12T20:17:46.384Z", dtf);

или

// 'T' is a literal.
// 'X' is ISO Zone Offset[like +01, -08]; For UTC, it is interpreted as 'Z'(Zero) literal.
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX";

// since no built-in format, we provides pattern directly.
DateFormat df = new SimpleDateFormat(pattern);

Date myDate = df.parse("2011-08-12T20:17:46.384Z");

(2) Если вам не важны дата и время и вы просто хотите обрабатывать информацию как момент в наносекундах, вы можете использовать Instant:

// The ISO format without zone ID is Instant's default.
// There is no need to pass any format.
Instant ins = Instant.parse("2011-08-12T20:17:46.384Z");
VeryLazyBoy
источник
1

Если вы, ребята, ищете решение для Android, вы можете использовать следующий код, чтобы получить секунды эпохи из строки метки времени.

public static long timestampToEpochSeconds(String srcTimestamp) {
    long epoch = 0;

    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            Instant instant = Instant.parse(srcTimestamp);
            epoch = instant.getEpochSecond();
        } else {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'", Locale.getDefault());
            sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
            Date date = sdf.parse(srcTimestamp);
            if (date != null) {
                epoch = date.getTime() / 1000;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return epoch;
}

Пример ввода: 2019-10-15T05: 51: 31.537979Z

Пример вывода: 1571128673

Рахул Равеендран
источник
0

Вы можете использовать следующий пример.

    String date = "2011-08-12T20:17:46.384Z";

    String inputPattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

    String outputPattern = "yyyy-MM-dd HH:mm:ss";

    LocalDateTime inputDate = null;
    String outputDate = null;


    DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern, Locale.ENGLISH);
    DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern, Locale.ENGLISH);

    inputDate = LocalDateTime.parse(date, inputFormatter);
    outputDate = outputFormatter.format(inputDate);

    System.out.println("inputDate: " + inputDate);
    System.out.println("outputDate: " + outputDate);
Салих Кесепара
источник
Вы не должны ставить апострофы во всем Z. Это значит ожидать, но игнорировать это письмо. Но это письмо не следует игнорировать. Это письмо предоставляет ценную информацию, тот факт, что строка была предназначена для UTC, смещение нуля. Ваш формат игнорирует этот важный факт. Кроме того, нет необходимости даже беспокоиться об определении этого шаблона форматирования.
Василий Бурк,
-1

Этот метод переводит java.util.Date в формат UTC (или любой другой) и обратно.

Определите класс следующим образом:

import java.util.Date;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

public class UtcUtility {

public static DateTimeFormatter UTC = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZoneUTC();


public static Date parse(DateTimeFormatter dateTimeFormatter, String date) {
    return dateTimeFormatter.parseDateTime(date).toDate();
}

public static String format(DateTimeFormatter dateTimeFormatter, Date date) {
    return format(dateTimeFormatter, date.getTime());
}

private static String format(DateTimeFormatter dateTimeFormatter, long timeInMillis) {
    DateTime dateTime = new DateTime(timeInMillis);
    String formattedString = dateTimeFormatter.print(dateTime);
    return formattedString;
}

}

Тогда используйте это так:

Date date = format(UTC, "2020-04-19T00:30:07.000Z")

или

String date = parse(UTC, new Date())

Вы также можете определить другие форматы даты, если вам требуется (не только UTC)

Gapmeister66
источник
И java.util.Dateпроект Joda-Time, и проект Joda-Time были вытеснены несколько лет назад современными классами java.time, определенными в JSR 310. Советы здесь давно устарели.
Василий Бурк
java.time был представлен в Java 8. Этот вопрос специально относится к Java 1.4, и поэтому я намеренно избегал использования более новых классов. Это решение обслуживает старые базы кода. Я предполагаю, что автор мог бы переместить свою кодовую базу в Java 8, но это не всегда просто, эффективно или необходимо.
Gapmeister66
-1

@ Джон-Скит дал мне подсказку, чтобы решить мою проблему вокруг этого. Будучи молодым программистом, эту маленькую проблему легко упустить и ее трудно диагностировать. Так что я делюсь этим в надежде, что это кому-нибудь поможет.

Моя проблема заключалась в том, что я хотел проанализировать следующую строку, противоречащую отметке времени из JSON, на которую я не имею никакого влияния, и поместить ее в более полезные переменные. Но я продолжал получать ошибки.

Поэтому, учитывая следующее (обратите внимание на строковый параметр внутри ofPattern ();

String str = "20190927T182730.000Z"

LocalDateTime fin;
fin = LocalDateTime.parse( str, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ") );

Ошибка:

Exception in thread "main" java.time.format.DateTimeParseException: Text 
'20190927T182730.000Z' could not be parsed at index 19

Проблема? Буква Z в конце шаблона должна быть заключена в букву «Z», как и буква «T». Перейдите "yyyyMMdd'T'HHmmss.SSSZ"на "yyyyMMdd'T'HHmmss.SSS'Z'"и это работает.

Удаление Z из шаблона в целом также привело к ошибкам.

Честно говоря, я ожидал бы, что класс Java предвидит это.

spencemw
источник
1
Об этом уже спрашивали и отвечали здесь и здесь . И ваше решение неверно. Хотя Tлитерал и должен быть Zзаключен в кавычки, является смещением (нуля) и должен быть проанализирован как таковой, иначе вы получите неправильные результаты. Я не знаю, что вы имеете в виду, что это не ожидалось, я верю, что это произошло.
Оле В.В.
1
Нет, нет, не игнорируйте Z. Вы отбрасываете ценную информацию. Обработка значения даты и времени при игнорировании часового пояса или смещения от UTC аналогична обработке суммы денег при игнорировании валюты!
Базилик Бурк
1
TПросто отделяет часть даты от части времени в день, и не добавляет никакого смысла. С Zдругой стороны, определенно добавляет смысл.
Базилик Бурк
Оле, спасибо за ссылки. Я, конечно, читаю их. И я признаю, что я, конечно, мог быть неправ, будучи молодым. Я всего лишь говорю, что завершение Z в одинарные кавычки, как символ в шаблоне, решило ошибку. Моя критика заключается в том, что тот, кто спроектировал «шаблонную» часть класса, мог кодировать наличие или отсутствие «Z» (или другого часового пояса?) И «Т», заключенных в «или нет». Потому что они не уникальны. Формат, с которым я имею дело, прибывает из JSON из коммерческого API, проанализированного в строку. Но мне нужно разобрать все это в календаре даты и т. Д., Чтобы сделать их более полезными.
Spencemw