Який це формат дати? 2011-08-12T20: 17: 46.384З


382

У мене є такі дати: 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 .



3
@TomaszNurkiewicz, це не так. Зрештою, ISO8601 не має Z.
t1gor

4
Норма ISO8601 допускає Z в кінці. Дивіться посилання вище, шукайте UTC.
Джонатан Розенн

2
@ t1gor Кінець Zв кінці короткий Zuluі означає UTC . Цей формат, безумовно, є частиною колекції ISO 8601 стандартних текстових форматів дати. До речі, ці стандартні формати використовуються за замовчуванням у класах java.time .
Василь Бурк

3
FYI, тривожні старі класи дату, такі як java.util.Date, java.util.Calendarі java.text.SimpleDateFormatтепер застарілі , замінені класами java.time, вбудованими в Java 8 та Java 9. Див. Підручник від Oracle .
Василь Бурк

Відповіді:


511

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?
Maroun

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 . І шукайте переповнення стека за багатьма прикладами та поясненнями. Специфікація - 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
    • Пізніші версії реалізації пакетів Android для класів java.time.
    • Для попереднього Android проект ThreeTenABP адаптується ThreeTen-Backport (згаданий вище). Див. Як користуватися ThreeTenABP… .

Таблиця, яку бібліотеку java.time використовувати в якій версії Java або Android

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


3
@star "Зулу" походить з військової та авіаційної традиції, де 25 літер алфавіту AZ (без "J"), кожна літера має вимовляючу назву, представляє свою версію часових поясів . Зона "зулу" - зсув нульових годин від UTC. Дивіться це і це .
Василь Бурк

27

Не впевнений у розборі Java, але це ISO8601: http://en.wikipedia.org/wiki/ISO_8601


Це "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");

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)


І проект, java.util.Dateі проект Joda-Time були витіснені років тому сучасними класами java.time, визначеними в JSR 310. Порада тут давно застаріла.
Василь Бурк

java.time був представлений на Java 8. Це питання спеціально стосується Java 1.4, і тому я навмисно уникав використання нових класів. Це рішення обслуговує старі кодові бази. Я припускаю, що автор може перенести свою кодову базу на Java 8, але це не завжди просто, ефективно чи потрібно.
Gapmeister66

-1

@ Джон-Скіт дав мені підказку, щоб вирішити мою власну проблему навколо цього. Як молодший програміст, це невелике питання легко пропустити і важко діагностувати. Тож я ділюсь ним у надії, що це комусь допоможе.

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

Отже, враховуючи наступне (зверніть увагу на параметр рядка всерединіPattern ();

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 передбачив це.


1
Про це вже запитували і відповіли тут і тут . І ваше рішення неправильне. Хоча Tце буквально і його потрібно цитувати, Zце зсув (дорівнює нулю) і його потрібно проаналізувати як таке, або ви отримаєте неправильні результати. Я не знаю, що ви маєте на увазі, що цього не передбачали, я вважаю, що так.
Оле ВВ

1
Ні, ні, ні, не ігноруйте Z. Ви відкидаєте цінну інформацію. Обробка значення дати та часу при ігноруванні часового поясу або зміщення з-за UTC - це як обробка грошей, ігнорування валюти!
Василь Бурк

1
TПросто відокремлює частину дати від частини часу в день, і не додає ніякого сенсу. З Zіншого боку, безумовно, додає сенсу.
Василь Бурк

Оле, дякую за посилання. Я, безумовно, прочитав їх. І я приймаю, що я, безумовно, можу помилитися як молодий. Все, що я кажу, полягає в тому, що загортання Z в одиничні лапки, як знаки в шаблоні, вирішило помилку. Моя критика полягає в тому, що той, хто сконструював "шаблонну" частину класу, міг закодувати навколо наявності або відсутності "Z" (чи різного часового поясу?) Та "T", оберненого "чи ні". Тому що вони не зробили його унікальним. Формат, з яким я маю справу, надходить від JSON з комерційного API, розібраного на рядок. Але мені потрібно проаналізувати все це в календарі дати та ін, щоб зробити їх кориснішими.
spencemw
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.