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 .



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().


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 .


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


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

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


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

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)


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.