Che cos'è questo formato data? 2011-08-12T20: 17: 46.384Z


384

Ho la seguente data: 2011-08-12T20:17:46.384Z. Che formato è? Sto cercando di analizzarlo con Java 1.4 tramite DateFormat.getDateInstance().parse(dateStr)e sto ottenendo

java.text.ParseException: data non analizzabile: "2011-08-12T20: 17: 46.384Z"

Penso che dovrei usare SimpleDateFormat per l'analisi, ma devo prima conoscere la stringa di formato. Finora tutto ciò che ho è yyyy-MM-ddperché non so quale sia il Tsignificato di questa stringa - qualcosa legato al fuso orario? Questa stringa di data proviene dal lcmis:downloadedOntag mostrato nel tipo di supporto Cronologia download file CMIS .



3
@TomaszNurkiewicz, non lo è. ISO8601 non ha la Z alla fine.
t1gor,

5
ISO8601 consente una Z alla fine. Vedi il link sopra, cerca UTC.
Jonathan Rosenne,

2
@ t1gor Alla Zfine è l'abbreviazione di Zulue significa UTC . Questo formato fa sicuramente parte della raccolta ISO 8601 di formati di testo standard di data e ora. A proposito, questi formati standard sono usati di default nelle classi java.time .
Basil Bourque,

3
Cordiali saluti, le vecchie e problematiche classi data-ora come java.util.Date, java.util.Calendare java.text.SimpleDateFormatora sono legacy , soppiantate dalle classi java.time integrate in Java 8 e Java 9. Vedi Tutorial di Oracle .
Basil Bourque,

Risposte:


513

La T è solo un letterale per separare la data dall'ora e la Z significa "offset dell'ora zero" noto anche come "ora Zulu" (UTC). Se le tue stringhe hanno sempre una "Z" puoi usare:

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

O usando Joda Time , puoi usare ISODateTimeFormat.dateTime().


7
Perché abbiamo bisogno delle virgolette singole in giro Te Z?
Maroun,

7
@MarounMaroun: Fondamentalmente vogliamo quei personaggi letterali . Potrebbe non essere necessario per T(non ricordo come SimpleDateFormat gestisce gli identificatori sconosciuti) ma per Znoi vogliamo che sia il carattere 'Z' anziché "un valore di offset UTC" (es. "00").
Jon Skeet,

2
@nyedidikeke: nella pagina Wikipedia a cui ti sei collegato, mostra "Fuso orario zulu" per UTC. Non sono sicuro di cosa credi di correggere.
Jon Skeet,

9
@JonSkeet: potrebbe generare un dibattito non necessario; non contestando la tua risposta, ma intendendo attirare l'attenzione sulla Z che ha ottenuto la sua lettera iniziale da "zero offset UTC". La lettera Z è indicata come "Zulu" nell'alfabeto fonetico della NATO . A sua volta, l'approccio militare per riferirsi all'offset UTC zero è ancorato alla lettera Z che identificano come Zulu, guadagnandosi il loro nome in codice: fuso orario Zulu. È importante notare che la Z non ha perso il suo significato ed è ancora il designatore di zona per l'offset UTC zero poiché il fuso orario Zulu (da Z) è semplicemente un linguaggio codificato ereditato per riferirsi ad esso.
nyedidikeke,

2
@nyedidikeke: non sono ancora d'accordo sul fatto che qualcun altro si preoccuperà mai della distinzione in riferimento alla mia risposta, ma l'ho aggiornato. Non entrerò nei dettagli, poiché la storia è sostanzialmente irrilevante per la risposta.
Jon Skeet,

86

tl; dr

Il formato standard ISO 8601 viene utilizzato dalla stringa di input.

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

ISO 8601

Questo formato è definito dallo standard pratico sensibile, ISO 8601 .

La Tsepara la parte di data dalla parte ora del giorno. L' Zestremità indica UTC (ovvero un offset-da-UTC di zero ore-minuti-secondi). Lo Zsi pronuncia "Zulu" .

java.time

Le vecchie classi di data e ora in bundle con le prime versioni di Java si sono dimostrate mal progettate, confuse e problematiche. Evitali.

Invece, usa il framework java.time incorporato in Java 8 e versioni successive. Le classi java.time soppiantano sia le vecchie classi data-ora che la libreria Joda-Time di grande successo.

Le classi java.time utilizzano ISO 8601 per impostazione predefinita quando analizzano / generano rappresentazioni testuali di valori data-ora.

La Instantclasse rappresenta un momento sulla linea temporale in UTC con una risoluzione di nanosecondi . Quella classe può analizzare direttamente la stringa di input senza preoccuparsi di definire un modello di formattazione.

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

Tabella dei tipi di data e ora in Java, sia moderni che legacy


Informazioni su java.time

Il framework java.time è integrato in Java 8 e versioni successive. Queste classi soppiantare la vecchia fastidiosi legacy classi data-time come java.util.Date, Calendar, e SimpleDateFormat.

Il progetto Joda-Time , ora in modalità manutenzione , consiglia la migrazione alle classi java.time .

Per saperne di più, consulta il tutorial Oracle . E cerca Stack Overflow per molti esempi e spiegazioni. La specifica è JSR 310 .

Dove ottenere le classi java.time?

  • Java SE 8 , Java SE 9 e versioni successive
    • Built-in.
    • Parte dell'API Java standard con un'implementazione in bundle.
    • Java 9 aggiunge alcune funzionalità e correzioni minori.
  • Java SE 6 e Java SE 7
    • Gran parte della funzionalità java.time è trasferita su Java 6 e 7 in ThreeTen-Backport .
  • androide
    • Versioni successive di implementazioni di bundle Android delle classi java.time.
    • Per precedenza Android, il ThreeTenABP progetto si adatta ThreeTen-Backport (di cui sopra). Vedi Come usare ThreeTenABP… .

Tabella di quale libreria java.time utilizzare con quale versione di Java o Android

Il progetto ThreeTen-Extra estende java.time con classi aggiuntive. Questo progetto è un banco di prova per possibili aggiunte future a java.time. Si possono trovare alcune classi utili, come per esempio Interval, YearWeek, YearQuartere altro .


3
@star Lo "Zulu" deriva dalla tradizione militare e aeronautica in cui 25 lettere dell'alfabeto AZ (no "J"), ogni lettera con un nome pronunciabile, rappresentano la loro versione dei fusi orari . La zona "Zulu" è compensata di zero ore rispetto a UTC. Vedi questo e questo .
Basil Bourque,

27

Non sono sicuro dell'analisi Java, ma è ISO8601: http://en.wikipedia.org/wiki/ISO_8601


Questo è "27-01-2016T17: 44: 55UTC", anche ISO8601?
user1997292

Io non ci credo. È vicino ma UTC come suffisso non è consentito. Deve essere Z o un fuso orario, ad es. +0100. Z e UTC hanno lo stesso significato, però, in modo da cambiare l' UTC a Z sarebbe resa valida ISO 8601.
smparkes

9

Esistono altri modi per analizzarlo piuttosto che la prima risposta. Per analizzarlo:

(1) Se si desidera acquisire informazioni su data e ora, è possibile analizzarlo su un ZonedDatetime(dal momento che Java 8 ) o Date(vecchio) oggetto:

// 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);

o

// '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) Se non ti interessa la data e l'ora e vuoi solo trattare le informazioni come un momento in nanosecondi, puoi usare 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

Se state cercando una soluzione per Android, potete usare il codice seguente per ottenere i secondi di epoca dalla stringa di data / ora.

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;
}

Esempio di input: 2019-10-15T05: 51: 31.537979Z

Uscita campione: 1571128673


0

Puoi usare il seguente esempio.

    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);

Non dovresti mettere apostrofi attorno al Z. Ciò significa aspettarsi ma ignorare quella lettera. Ma quella lettera non dovrebbe essere ignorata. Quella lettera fornisce informazioni preziose, il fatto che la stringa fosse destinata a UTC, un offset di zero. Il tuo formato sta scartando questo fatto importante. Inoltre, non è necessario nemmeno preoccuparsi di definire questo modello di formattazione. Un formattatore per questo modello è incorporato.
Basil Bourque

-1

Questa tecnica traduce java.util.Date in formato UTC (o qualsiasi altro) e viceversa.

Definisci una classe in questo modo:

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;
}

}

Quindi usalo in questo modo:

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

o

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

Se lo desideri, puoi anche definire altri formati di data (non solo UTC)


Sia java.util.Dateil progetto Joda-Time sono stati soppiantati anni fa dalle moderne classi java.time definite in JSR 310. I consigli qui sono obsoleti.
Basil Bourque,

java.time è stato introdotto in Java 8. Questa domanda si riferisce specificamente a Java 1.4 e quindi ho deliberatamente evitato l'uso delle nuove classi. Questa soluzione si rivolge a basi di codice più vecchie. Suppongo che l'autore possa spostare la sua base di codice su Java 8, ma ciò non è sempre semplice, efficiente o necessario.
Gapmeister66,

-1

@ John-Skeet mi ha dato la chiave per risolvere il mio problema. Come programmatore più giovane questo piccolo problema è facile da perdere e difficile da diagnosticare. Quindi lo condivido nella speranza che possa aiutare qualcuno.

Il mio problema era che volevo analizzare la seguente stringa in contrasto con un timestamp da un JSON su cui non ho alcuna influenza e inserirla in variabili più utili. Ma continuavo a ricevere errori.

Quindi, dato quanto segue (prestare attenzione al parametro string all'interno di OfPattern ();

String str = "20190927T182730.000Z"

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

Errore:

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

Il problema? La Z alla fine del Pattern deve essere racchiusa in "Z" proprio come la "T". Passa "yyyyMMdd'T'HHmmss.SSSZ"a "yyyyMMdd'T'HHmmss.SSS'Z'"e funziona.

La rimozione completa della Z dal modello ha comportato errori.

Francamente, mi aspetto che una classe Java lo abbia anticipato.


1
Questo è già stato chiesto e risposto qui e qui . E la tua soluzione è sbagliata. Mentre Tè letterale e deve essere citato, Zè un offset (pari a zero) e deve essere analizzato come tale, altrimenti si otterranno risultati errati. Non so cosa vuoi dire che non è stato previsto, credo che lo sia.
Ole VV,

1
No, no, no, non ignorare il Z. Stai eliminando informazioni preziose. Elaborare un valore data-ora ignorando il fuso orario o offset da UTC è come elaborare una somma di denaro ignorando la valuta!
Basil Bourque,

1
Il Tsolo separa la parte di data dalla parte ora del giorno, e aggiunge alcun significato. L' Zaltra parte aggiunge sicuramente un significato.
Basil Bourque,

Ole, grazie per i collegamenti. Certamente leggerò quelli. E accetto che sicuramente potrei sbagliarmi da giovane. Tutto quello che sto dicendo è che avvolgere la Z tra virgolette singole come un carattere nel modello ha risolto l'errore. La mia critica è che chiunque abbia progettato una parte "di classe" della classe avrebbe potuto codificare intorno alla presenza o assenza di "Z" (o un fuso orario diff?) E "T" essere avvolti in "o no. Perché non è unico. Il formato con cui ho a che fare proviene da JSON da un'API commerciale analizzata in una stringa. Ma ho bisogno di analizzare tutto ciò nel calendario della data, ecc. Per renderli più utili.
spencemw,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.