Estou tentando converter uma seqüência de caracteres formatada em ISO 8601 para um java.util.Date
.
Achei que o padrão yyyy-MM-dd'T'HH:mm:ssZ
era compatível com ISO8601 se usado com um Local (compare amostra).
No entanto, usando o java.text.SimpleDateFormat
, não consigo converter a String formatada corretamente 2010-01-01T12:00:00+01:00
. Eu tenho que convertê-lo primeiro para 2010-01-01T12:00:00+0100
, sem os dois pontos.
Então, a solução atual é
SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));
o que obviamente não é legal. Estou faltando alguma coisa ou há uma solução melhor?
Responda
Graças ao comentário de JuanZe, encontrei a magia Joda-Time , que também é descrita aqui .
Então, a solução é
DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));
Ou, mais simplesmente, use o analisador padrão por meio do construtor:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Para mim, isso é legal.
Respostas:
Infelizmente, os formatos de fuso horário disponíveis para SimpleDateFormat (Java 6 e versões anteriores) não são compatíveis com ISO 8601 . SimpleDateFormat entende seqüências de fuso horário como "GMT + 01: 00" ou "+0100", este último de acordo com a RFC # 822 .
Mesmo que o Java 7 tenha adicionado suporte para descritores de fuso horário de acordo com a ISO 8601, o SimpleDateFormat ainda não poderá analisar adequadamente uma sequência de datas completa, pois não possui suporte para partes opcionais.
Reformatar sua string de entrada usando o regexp é certamente uma possibilidade, mas as regras de substituição não são tão simples quanto na sua pergunta:
A solução mais fácil é possivelmente usar o conversor de tipo de dados no JAXB, pois o JAXB deve poder analisar a sequência de datas ISO8601 de acordo com a especificação do Esquema XML.
javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
lhe dará umCalendar
objeto e você pode simplesmente usar getTime (), se precisar de umDate
objeto.Você provavelmente poderia usar o Joda-Time também, mas não sei por que você deveria se preocupar com isso.
fonte
A maneira que é abençoada pela documentação do Java 7 :
Você pode encontrar mais exemplos na seção Exemplos em javadoc SimpleDateFormat .
UPD 13/02/2020: Existe uma maneira completamente nova de fazer isso no Java 8
fonte
java.time
estrutura no Java 8, inspirada no Joda-Time , substituindo as problemáticas classes java.util.Date, .Calendar e SimpleDateFormat.string1
estring2
não souber qual será o seu?Ok, esta pergunta já foi respondida, mas deixarei minha resposta de qualquer maneira. Isso pode ajudar alguém.
Estou procurando uma solução para Android (API 7).
javax.xml
não funcionarão na API do Android 7.Acabou implementando essa classe simples. Ele cobre apenas a forma mais comum de seqüências ISO 8601, mas isso deve ser suficiente em alguns casos (quando você tiver certeza de que a entrada estará nesse formato).
Nota de desempenho: eu instanciao sempre o novo SimpleDateFormat como forma de evitar um bug no Android 2.1. Se você está tão surpreso quanto eu, veja este enigma . Para outros mecanismos Java, você pode armazenar em cache a instância em um campo estático privado (usando ThreadLocal, para ser seguro para threads).
fonte
s = s.substring(0, 22) + s.substring(23);
- eu não ver o ponto em estejava.time
A API java.time (incorporada no Java 8 e posterior) facilita um pouco isso.
Se você souber que a entrada está no UTC , como o
Z
(para Zulu) no final, aInstant
classe poderá analisar.Se a sua entrada puder ser outro valor de deslocamento do UTC em vez do UTC indicado pelo
Z
(Zulu) no final, use aOffsetDateTime
classe para analisar.Em seguida, extraia um
Instant
e converta para umjava.util.Date
chamandofrom
.fonte
LocalDateTime
eZoneId
andatZone
. Este simples comentário de uma linha fará:java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
Date.from(Instant.parse("2014-12-12T10:39:40Z" ));
basta.OffsetDateTime
seria suficiente analisar o ISO8601 (que não contém informações de fuso horário, mas apenas um deslocamento).Instant
a análise. Embora não seja suficiente para esta questão em particular, é uma distinção importante que vale a pena destacar. Então eu adicionei um segundo exemplo de código. Opa, acabei de notar que essa não é originalmente minha resposta; Espero que Adam aprove.A biblioteca Jackson-databind também possui a classe ISO8601DateFormat que faz isso (implementação real em ISO8601Utils .
fonte
2015-08-11T13:10:00
. Eu entendoString index out of range: 19
. Observando o código, parece que ele exige que os milissegundos sejam especificados e o fuso horário. Esses devem ser opcionais.[yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]
. Em outras palavras, os milissegundos são opcionais, mas o fuso horário é obrigatório.new DateTime("2015-08-11T13:10:00").toDate()
tl; dr
Usando java.time
O novo pacote java.time no Java 8 e posterior foi inspirado no Joda-Time.
A
OffsetDateTime
classe representa um momento na linha do tempo com um deslocamento do UTC, mas não um fuso horário.A chamada
toString
gera uma sequência no formato ISO 8601 padrão:Para ver o mesmo valor pela lente do UTC, extraia
Instant
ou ajuste o deslocamento de+01:00
para00:00
.…ou…
Ajuste para um fuso horário, se desejar. Um fuso horário é um histórico de valores de deslocamento do UTC para uma região, com um conjunto de regras para lidar com anomalias, como horário de verão (DST). Portanto, aplique um fuso horário em vez de um mero deslocamento sempre que possível.
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
, eSimpleDateFormat
.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 .
Você pode trocar objetos java.time diretamente com seu banco de dados. Use um driver JDBC compatível com JDBC 4.2 ou posterior. Não há necessidade de strings, não há necessidade de
java.sql.*
classes.Onde obter as classes java.time?
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 .fonte
Para Java versão 7
Você pode seguir a documentação do Oracle: http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
X - é usado para o fuso horário ISO 8601
fonte
A solução DatatypeConverter não funciona em todas as VMs. O seguinte funciona para mim:
Descobri que o joda não funciona imediatamente (especificamente para o exemplo que eu dei acima com o fuso horário em uma data, que deve ser válida)
fonte
Acho que deveríamos usar
para data
2010-01-01T12:00:00Z
fonte
A partir do Java 8, existe uma maneira completamente nova e oficialmente suportada de fazer isso:
fonte
Z
como deslocamento, não precisamos especificar isso explicitamente. ApenasInstant i = Instant.parse(s);
. A string na pergunta tinha+01:00
, nesse casoDateTimeFormatter.ISO_INSTANT
, não funciona (pelo menos não no meu Java 11).ISO_OFFSET_DATE_TIME
para formatar datas com deslocamentos, como+01:00
( docs.oracle.com/javase/8/docs/api/java/time/format/… )Outra maneira muito simples de analisar os carimbos de data / hora ISO8601 é usar
org.apache.commons.lang.time.DateUtils
:fonte
java.time
Observe que no Java 8, você pode usar a classe java.time.ZonedDateTime e seu
parse(CharSequence text)
método estático .fonte
Instant
eZonedDateTime
são apropriados aqui, nãoZonedDateTime
.A solução alternativa para Java 7+ está usando SimpleDateFormat:
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
Este código pode analisar o formato ISO8601 como:
2017-05-17T06:01:43.785Z
2017-05-13T02:58:21.391+01:00
Mas no Java6,
SimpleDateFormat
não entende oX
caractere e lançaráIllegalArgumentException: Unknown pattern character 'X'
. Precisamos normalizar a data ISO8601 para o formato legível no Java 6 com
SimpleDateFormat
.Método acima para substituir [
Z
with+0000
] ou [+01:00
with+0100
] quando ocorrer um erro no Java 6 (você pode detectar a versão Java e substituir try / catch pela instrução if).fonte
Date
eSimpleDateFormat
são mal projetadas, confusas e com falhas. Agora eles são herdados, substituídos pelas classes java.time incorporadas no Java 8 e posterior. Para Java 6 e Java 7, grande parte da funcionalidade java.time é portada no projeto ThreeTen-Backport . É muito melhor adicionar essa biblioteca ao seu aplicativo do que usar essas classes herdadas. Solução one-line em java.time:OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Eu enfrentei o mesmo problema e resolvi-o pelo código a seguir.
Antes eu estava usando
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
Mas depois descobri que a principal causa da exceção foi a
yyyy-MM-dd'T'HH:mm:ss.SSSZ
,Então eu usei
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
Funcionou bem para mim .
fonte
Além disso, você pode usar a seguinte classe -
Link para o Java Doc - Hierarquia para pacote org.springframework.extensions.surf.maven.plugin.util
fonte
Java tem uma dúzia de maneiras diferentes de analisar uma data e hora, como demonstram as excelentes respostas aqui. Surpreendentemente, nenhuma das classes de tempo do Java implementa totalmente a ISO 8601!
Com o Java 8, eu recomendaria:
Isso manipulará exemplos no UTC e com um deslocamento, como "2017-09-13T10: 36: 40Z" ou "2017-09-13T10: 36: 40 + 01: 00". Isso servirá para a maioria dos casos de uso.
Mas ele não trata exemplos como "2017-09-13T10: 36: 40 + 01", que é uma data / hora ISO 8601 válida.
Ele também não trata apenas da data, por exemplo, "13/09/2017".
Se você precisar lidar com isso, sugiro usar um regex primeiro para farejar a sintaxe.
Há uma boa lista de ISO 8601 exemplos aqui com muitos casos de canto: https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ eu sou não conhece nenhuma classe Java que possa lidar com todas elas.
fonte
OffsetDateTime
fará e combina conceitualmente uma data e hora com um deslocamento melhor.OffsetDateTime
lida com os exemplos com os quais você lidaZonedDateTime
. Eu acredito que ele não lida com nenhum dos exemplos queZonedDateTime
não. Nesse sentido, não há melhora (mas também não é pior). Desculpe, eu não estava perfeitamente claro.O Apache Jackrabbit usa o formato ISO 8601 para datas persistentes e há uma classe auxiliar para analisá-las:
org.apache.jackrabbit.util.ISO8601
Vem com jackrabbit-jcr-commons .
fonte
Como outros usuários mencionaram, o Android não tem uma boa maneira de oferecer suporte à análise / formatação de datas ISO 8601 usando as classes incluídas no SDK. Eu escrevi esse código várias vezes, então finalmente criei um Gist que inclui uma classe DateUtils que oferece suporte à formatação e análise de datas ISO 8601 e RFC 1123. O Gist também inclui um caso de teste mostrando o que ele suporta.
https://gist.github.com/mraccola/702330625fad8eebe7d3
fonte
SimpleDateFormat para JAVA 1.7 possui um padrão legal para o formato ISO 8601.
Classe SimpleDateFormat
Aqui está o que eu fiz:
fonte
Z
na cadeia de formato não é ISO 8601 fuso horário, você deve usarX
(ouXX
ouXXX
) se quiser ISO 8601 fuso horárioFaça isso deste modo:
Aqui está a saída:
Qua 19 de outubro 15:15:36 CST 2016
fonte
Use string como
LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
fonte
Estou surpreso que nem mesmo uma biblioteca Java suporte todos os formatos de data ISO 8601, conforme https://en.wikipedia.org/wiki/ISO_8601 . O Joda DateTime estava suportando a maioria deles, mas não todos, e, portanto, adicionei uma lógica personalizada para lidar com todos eles. Aqui está a minha implementação.
fonte
Um pequeno teste que mostra como analisar uma data na ISO8601 e que LocalDateTime não processa DSTs.
fonte
java.util.Date
,java.util.Calendar
, ejava.text.SimpleDateFormat
são agora legado , suplantado pelos java.time classes internas em Java 8 e posterior. Consulte o Tutorial da Oracle .LocalDateTime
não lida com horário de verão (DST), pois não lida com um fuso horário. Para isso precisamosZonedDateTime
. PropondoDate
eSimpleDateFormat
é - IMHO ruim.Eu tinha uma necessidade semelhante: precisava ser capaz de analisar qualquer data compatível com ISO8601 sem conhecer o formato exato com antecedência e queria uma solução leve que também funcionasse no Android.
Quando pesquisei minhas necessidades, deparei-me com essa pergunta e notei que o AFAIU, nenhuma resposta se encaixava completamente nas minhas necessidades. Então, desenvolvi o jISO8601 e o empurrei na maven central.
Basta adicionar você
pom.xml
:e então você está pronto para ir:
Espera que ajude.
fonte
Para formatar apenas uma data como esta, o seguinte funcionou para mim em um aplicativo baseado em Java 6. Há uma
DateFormat
classeJacksonThymeleafISO8601DateFormat
no projeto thymeleaf que insere os dois pontos ausentes:https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java
Usei-o para compatibilidade de formato de data ECMAScript.
fonte
Cortesia da função base: @wrygiel.
Esta função pode converter o formato ISO8601 em Data Java, que pode manipular os valores de deslocamento. De acordo com a definição da ISO 8601, o deslocamento pode ser mencionado em diferentes formatos.
Esta classe possui métodos estáticos para converter
Amostras de cordas ISO8601
}
fonte
Isso pareceu funcionar melhor para mim:
Eu precisava converter para / para seqüências de datas JavaScript em Java. Eu encontrei os trabalhos acima com a recomendação. Havia alguns exemplos usando SimpleDateFormat próximos, mas eles não pareciam ser o subconjunto conforme recomendado por:
http://www.w3.org/TR/NOTE-datetime
e suportado por PLIST e JavaScript Strings e é isso que eu precisava.
Essa parece ser a forma mais comum de cadeia de caracteres ISO8601, e um bom subconjunto.
Os exemplos que eles dão são:
Eu também tenho uma versão rápida:
...
Eu não o comparei, mas acho que será bem rápido. Parece funcionar. :)
fonte
Eu acho que o que muita gente quer fazer é analisar as seqüências de datas JSON. Existe uma boa chance de você vir para esta página converter uma data JSON JavaScript em uma data Java.
Para mostrar a aparência de uma sequência de datas JSON:
A sequência de datas JSON é 2013-12-14T01: 55: 33.412Z.
As datas não são cobertas pelas especificações JSON, por exemplo, mas o acima é um formato ISO 8601 muito específico, enquanto o ISO_8601 é muito maior e esse é um mero subconjunto, embora muito importante.
Consulte http://www.json.org Consulte http://en.wikipedia.org/wiki/ISO_8601 Consulte http://www.w3.org/TR/NOTE-datetime
Por acaso, escrevi um analisador JSON e um analisador PLIST, que usam ISO-8601, mas não os mesmos bits.
Eu escrevi duas maneiras de fazer isso no meu projeto. Um padrão, um rápido.
Novamente, a sequência de datas JSON é uma implementação muito específica da ISO 8601 ....
(Postei a outra na outra resposta, que deve funcionar para datas PLIST, que são um formato ISO 8601 diferente).
A data JSON é a seguinte:
Os arquivos PLIST (ASCII não GNUNext) também usam a ISO 8601, mas não milissegundos, portanto ... nem todas as datas da ISO-8601 são iguais. (Pelo menos ainda não encontrei um que use milis e o analisador que vi pular o fuso horário OMG).
Agora, a versão rápida (você pode encontrá-la no Boon).
Observe que Reflection.toCharArray usa inseguro, se disponível, mas o padrão é string.toCharArray, se não estiver.
(Você pode tirá-lo do exemplo substituindo Reflection.toCharArray (string) por string.toCharArray ()).
O isJsonDate é implementado da seguinte maneira:
Enfim ... meu palpite é que muitas pessoas que vêm aqui .. podem estar procurando a JSON Date String e, embora seja uma data ISO-8601, é uma data muito específica que precisa de uma análise muito específica.
Consulte https://github.com/RichardHightower/boon O Boon possui um analisador PLIST (ASCII) e um analisador JSON.
O analisador JSON é o analisador Java JSON mais rápido que eu conheço.
Independentemente verificado pelos caras Gatling Performance.
https://github.com/gatling/json-parsers-benchmark
Possui o analisador JSON mais rápido para fluxos, leitores, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) e String.
Veja mais benchmarks em:
https://github.com/RichardHightower/json-parsers-benchmark
fonte
Instant.parse( "2013-12-14T01:55:33.412Z" )