Qual é esse formato de data? 2011-08-12T20: 17: 46.384Z

384

Eu tenho a seguinte data: 2011-08-12T20:17:46.384Z. Que formato é esse? Estou tentando analisá-lo com Java 1.4 via DateFormat.getDateInstance().parse(dateStr)e estou recebendo

java.text.ParseException: Data imperceptível: "2011-08-12T20: 17: 46.384Z"

Eu acho que eu deveria estar usando SimpleDateFormat para análise, mas eu tenho que saber a seqüência de formato primeiro. Tudo o que tenho até agora é yyyy-MM-ddporque não sei o que Tsignifica essa string - algo relacionado ao fuso horário? Essa sequência de datas é proveniente da lcmis:downloadedOntag mostrada no tipo de mídia do histórico de downloads Arquivos CMIS .

Sarah Vessels
fonte
43
É ISO 8601
Tomasz Nurkiewicz
3
@TomaszNurkiewicz, não é. ISO8601 não tem o Z no final.
t1gor
4
A gama ISO8601 permite um Z no final. Veja o link acima, procure pelo UTC.
Jonathan Rosenne
2
@ t1gor O Zfinal é curto Zulue significa UTC . Esse formato certamente faz parte da coleção ISO 8601 de formatos de texto padrão de data e hora. A propósito, esses formatos padrão são usados ​​por padrão nas classes java.time .
Basil Bourque
3
FYI, os incômodos aulas em tempo data antigas, tais como java.util.Date, java.util.Calendare java.text.SimpleDateFormatestão agora legado , suplantado pelos java.time classes internas em Java 8 & Java 9. Consulte Tutorial pela Oracle .
Basil Bourque

Respostas:

513

AT é apenas um literal para separar a data da hora e Z significa "deslocamento da hora zero", também conhecido como "hora do Zulu" (UTC). Se suas strings sempre tiverem um "Z", você poderá usar:

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

Ou usando o Joda Time , você pode usar ISODateTimeFormat.dateTime().

Jon Skeet
fonte
7
Por que precisamos de aspas simples Te Z?
Maroun
7
@MarounMaroun: Basicamente, queremos esses caracteres literais . Pode não ser necessário para T(não me lembro como o SimpleDateFormat lida com especificadores desconhecidos), mas Zqueremos que seja o caractere 'Z' em vez de "um valor de deslocamento UTC" (por exemplo, "00").
Jon Skeet
2
@nyedidikeke: na página da Wikipedia a que você vinculou, mostra "Fuso horário do Zulu" para UTC. Não tenho certeza do que você acredita que está corrigindo.
Jon Skeet
9
@ JonSkeet: pode gerar um debate desnecessário; não contestando sua resposta, mas pretendendo chamar a atenção para o Z que recebeu sua letra inicial de "deslocamento zero do UTC". A letra Z é referida como "Zulu" no alfabeto fonético da OTAN . Por sua vez, a abordagem militar para se referir ao deslocamento zero do UTC está ancorada na letra Z, que eles identificam como Zulu, ganhando seu nome codificado: fuso horário do Zulu. É importante observar que o Z não perdeu seu significado e ainda é o designador da zona para o deslocamento do zero no UTC, pois o fuso horário Zulu (de Z) é simplesmente uma linguagem codificada herdada para se referir a ele.
Neyedidikeke
2
@nyedidikeke: Eu ainda discordo se alguém mais vai se importar com a distinção com referência à minha resposta, mas eu a atualizei. Não vou entrar em todos os detalhes, pois a história é amplamente irrelevante para a resposta.
precisa
86

tl; dr

O formato ISO 8601 padrão é usado pela sua sequência de entrada.

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

ISO 8601

Este formato é definido pela norma prática sensata ISO 8601 .

O Tsepara a parte da data da parte da hora do dia. O Zfinal significa UTC (ou seja, um deslocamento do UTC de zero horas-minutos-segundos). O Zé pronunciado "Zulu" .

java.time

As antigas classes de data e hora incluídas nas versões mais antigas do Java provaram ser mal projetadas, confusas e problemáticas. Evite-os.

Em vez disso, use a estrutura java.time incorporada no Java 8 e posterior. As classes java.time substituem as classes antigas de data e hora e a biblioteca Joda-Time de grande sucesso.

As classes java.time usam o ISO 8601 por padrão ao analisar / gerar representações textuais de valores de data e hora.

A Instantclasse representa um momento na linha do tempo no UTC com uma resolução de nanossegundos . Essa classe pode analisar diretamente sua sequência de entrada sem se preocupar em definir um padrão de formatação.

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

Tabela de tipos de data e hora em Java, modernos e herdados


Sobre java.time

A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como java.util.Date, Calendar, e SimpleDateFormat.

O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .

Para saber mais, consulte o Tutorial do Oracle . E procure Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .

Onde obter as classes java.time?

  • Java SE 8 , Java SE 9 e posterior
    • Construídas em.
    • Parte da API Java padrão com uma implementação em pacote configurável.
    • O Java 9 adiciona alguns recursos e correções menores.
  • Java SE 6 e Java SE 7
    • Grande parte da funcionalidade java.time é portada para Java 6 e 7 no ThreeTen-Backport .
  • Android
    • Versões posteriores das implementações de pacote configurável do Android das classes java.time.
    • Para anteriormente Android, o ThreeTenABP projeto adapta ThreeTen-Backport (mencionados acima). Consulte Como usar o ThreeTenABP… .

Tabela de qual biblioteca java.time a ser usada com qual versão do Java ou Android

O projeto ThreeTen-Extra estende o java.time com classes adicionais. Este projeto é um campo de prova para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como Interval, YearWeek, YearQuarter, e mais .

Basil Bourque
fonte
3
@star O "Zulu" vem da tradição militar e da aviação, onde 25 letras do alfabeto AZ (sem "J"), cada letra com um nome pronunciável, representa sua versão dos fusos horários . A zona "Zulu" é zero horas de diferença em relação ao UTC. Veja isso e isso .
Basil Bourque
27

Não tenho certeza sobre a análise de Java, mas isso é ISO8601: http://en.wikipedia.org/wiki/ISO_8601

smparkes
fonte
Também é "2016-01-27T17: 44: 55UTC", ISO8601?
precisa saber é o seguinte
Eu não acredito nisso. Está próximo, mas o UTC como sufixo não é permitido. Tem que ser Z ou um deslocamento de fuso horário, por exemplo, +0100. Z e UTC têm o mesmo significado, embora, assim mudando o UTC para Z renderia válida ISO 8601.
smparkes
9

Existem outras maneiras de analisá-lo, em vez da primeira resposta. Para analisá-lo:

(1) Se você deseja obter informações sobre data e hora, é possível analisá-las em um objeto ZonedDatetime(desde Java 8 ) ou Date(antigo):

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

ou

// '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 você não se importa com a data e a hora e apenas deseja tratar as informações como um momento em nanossegundos, pode usar 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
fonte
1

Se vocês estão procurando uma solução para Android, podem usar o código a seguir para obter os segundos da época da sequência do carimbo de data / hora.

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

Entrada de amostra: 2019-10-15T05: 51: 31.537979Z

Saída de amostra: 1571128673

Rahul Raveendran
fonte
0

Você pode usar o exemplo a seguir.

    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);
Salih Kesepara
fonte
Você não deve colocar apóstrofos ao redor do Z. Isso significa esperar, mas ignorar essa carta. Mas essa carta não deve ser ignorada. Essa carta fornece informações valiosas, o fato de que a string foi projetada para o UTC, um deslocamento de zero. Seu formato está descartando esse fato importante. Além disso, não há necessidade de se preocupar em definir esse padrão de formatação. Um formatador para este padrão é construído em.
manjericão Bourque
-1

Essa técnica converte java.util.Date para o formato UTC (ou qualquer outro) e vice-versa.

Defina uma classe assim:

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

}

Em seguida, use-o assim:

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

ou

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

Você também pode definir outros formatos de data se precisar (e não apenas o UTC)

Gapmeister66
fonte
Tanto java.util.Dateo projeto quanto o Joda-Time foram suplantados anos atrás pelas modernas classes java.time definidas no JSR 310. A recomendação aqui está desatualizada há muito tempo.
Basil Bourque
O java.time foi introduzido no Java 8. Essa pergunta faz referência específica ao Java 1.4 e, portanto, evitei deliberadamente o uso das classes mais recentes. Esta solução atende a bases de código mais antigas. Suponho que o autor possa mover sua base de código para o Java 8, mas isso nem sempre é direto, eficiente ou necessário.
precisa saber é o seguinte
-1

@ John-Skeet me deu a pista para corrigir meu próprio problema em torno disso. Como programador mais jovem, esse pequeno problema é fácil de perder e difícil de diagnosticar. Então, eu estou compartilhando na esperança de ajudar alguém.

Meu problema foi que eu queria analisar a seguinte sequência restringindo um carimbo de data / hora de um JSON sobre o qual não tenho influência e colocá-lo em variáveis ​​mais úteis. Mas eu continuava recebendo erros.

Portanto, considerando o seguinte (preste atenção ao parâmetro string dentro dePattern ();

String str = "20190927T182730.000Z"

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

Erro:

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

O problema? O Z no final do Padrão precisa ser envolto em 'Z', assim como o 'T'. Mude "yyyyMMdd'T'HHmmss.SSSZ"para "yyyyMMdd'T'HHmmss.SSS'Z'"e funciona.

Remover o Z do padrão também levou a erros.

Francamente, eu esperaria que uma classe Java tivesse antecipado isso.

spencemw
fonte
11
Isso já foi solicitado e respondido aqui e aqui . E sua solução está errada. Enquanto Té um literal e precisa ser citado, Zé um deslocamento (de zero) e precisa ser analisado como tal, ou você obterá resultados incorretos. Não sei o que você quer dizer com não foi antecipado, acredito que sim.
Ole VV
11
Não, não, não, não ignore o Z. Você está descartando informações valiosas. Processar um valor de data e hora enquanto ignora o fuso horário ou compensar o UTC é como processar uma quantia de dinheiro enquanto ignora a moeda!
Basil Bourque
11
O Tmeramente separa a parte da data da parte da hora do dia e não adiciona significado. Por Zoutro lado, definitivamente acrescenta significado.
Basil Bourque
Ole, obrigado pelos links. Certamente vou ler aqueles. E aceito que certamente poderia estar errado quando jovem. Tudo o que estou dizendo é que envolver o Z entre aspas simples como um caractere no padrão resolveu o erro. Minha crítica é que quem projetou parte "padrão" da classe poderia ter codificado em torno da presença ou ausência de 'Z' (ou um fuso horário diferente?) E 'T' sendo envolvido '' ou não. Porque eles não são únicos. O formato com o qual estou lidando vem do JSON de uma API comercial analisada em uma string. Mas eu preciso analisar tudo isso no calendário de data e etc, para torná-los mais úteis.
Spencemw 28/09/19