Formatar Instantâneo para String


227

Estou tentando formatar um Instant para uma String usando o novo java 8 time-api e um padrão:

Instant instant = ...;
String out = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(instant);

Usando o código acima, recebo uma exceção que reclama um campo não suportado:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
    at java.time.Instant.getLong(Instant.java:608)
    at java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:298)
    ...

Respostas:


310

Fuso horário

Para formatar Instantum fuso horário é necessário. Sem um fuso horário, o formatador não sabe como converter o instante em campos de data e hora humanos e, portanto, lança uma exceção.

O fuso horário pode ser adicionado diretamente ao formatador usando withZone().

DateTimeFormatter formatter =
    DateTimeFormatter.ofLocalizedDateTime( FormatStyle.SHORT )
                     .withLocale( Locale.UK )
                     .withZone( ZoneId.systemDefault() );

Gerando String

Agora use esse formatador para gerar a representação String do seu Instant.

Instant instant = Instant.now();
String output = formatter.format( instant );

Despejar no console.

System.out.println("formatter: " + formatter + " with zone: " + formatter.getZone() + " and Locale: " + formatter.getLocale() );
System.out.println("instant: " + instant );
System.out.println("output: " + output );

Quando correr.

formatter: Localized(SHORT,SHORT) with zone: US/Pacific and Locale: en_GB
instant: 2015-06-02T21:34:33.616Z
output: 02/06/15 14:34

51
Obrigado!! Aliás, a exceção "campo não suportado" que aponta para, por exemplo, ano, é espetacularmente obtusa. Talvez essa situação deva ser detectada e uma exceção apontando diretamente para o ID da zona ausente no Instant seja lançada!
Davidbak 22/10/2015

1
Mais estranhamente, se você incluir .withZone (por exemplo, .withZone (ZoneId.of ("Z"))) e formatar um LocalDateTime, a zona será IGNORADA! Contanto que .withZone () esteja incluído, o mesmo formatador pode ser usado para Instant e LocalDateTime, sem afetar o tempo mostrado para o último.
Glenn

1
Por que é tão difícil aceitar o fato de o Instant ter um fuso horário GMT?
precisa saber é o seguinte

1
@KorayTugay Como os pedantes comentários do "Instant já são GMT" podem ser verdadeiros, mas estão longe de ser úteis ao enfrentar um rastreamento de exceção lançado porque formatar um Instant sem especificar um fuso horário não funciona. Teria sido bom se o formatador tivesse o padrão GMT, mas tudo bem.
Ti Strga

Agora isso lhe dá o yyyy-MM-dd hh:mm:ssformato:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun 25/03

39
public static void main(String[] args) {

    DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
            .withZone(ZoneId.systemDefault());

    System.out.println(DATE_TIME_FORMATTER.format(new Date().toInstant()));

}

3
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e por que resolve o problema melhoraria o valor a longo prazo da resposta.
Alexander Alexander

1
Embora esse trecho de código possa resolver a questão, incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
Rosário Pereira Fernandes

23
DateTimeFormatter.ISO_INSTANT.format(Instant.now())

Isso evita que você precise converter para o UTC. No entanto, algumas estruturas de tempo de outro idioma podem não suportar milissegundos, portanto, você deve

DateTimeFormatter.ISO_INSTANT.format(Instant.now().truncatedTo(ChronoUnit.SECONDS))

O que você quer dizer com "estruturas de tempo de outras línguas"? ISO_INSTANT.format () truncará automaticamente para segundos?
Guangtong Shen

Algumas estruturas esperam apenas o tempo de segundos, porque não seguem a convenção ISO completa e quebram quando há milissegundos como parte da sequência de entrada.
Archimedes Trajano

21

A Instantclasse não contém informações da Zona, apenas armazena o registro de data e hora em milissegundos da época UNIX, ou seja, 1 de janeiro de 1070 da UTC. Portanto, o formatador não pode imprimir uma data porque a data sempre é impressa para fuso horário concreto. Você deve definir o fuso horário como formatador e tudo ficará bem, assim:

Instant instant = Instant.ofEpochMilli(92554380000L);
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT).withLocale(Locale.UK).withZone(ZoneOffset.UTC);
assert formatter.format(instant).equals("07/12/72 05:33");
assert instant.toString().equals("1972-12-07T05:33:00Z");

4

Ou se você ainda deseja usar o formatador criado a partir do padrão, basta usar LocalDateTime em vez de Instant:

LocalDateTime datetime = LocalDateTime.now();
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(datetime)

4

Os instantes já estão no UTC e já possuem um formato de data padrão aaaa-MM-dd . Se você está satisfeito com isso e não quer mexer com fusos horários ou formatação, você também pode toString():

Instant instant = Instant.now();
instant.toString()
output: 2020-02-06T18:01:55.648475Z


Não quer o T e Z? (Z indica que esta data é UTC. Z significa "Zulu", também conhecido como "Desvio de hora zero", também conhecido como UTC):

instant.toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.663763


Deseja milissegundos em vez de nanossegundos? (Para que você possa inseri-lo em uma consulta sql):

instant.truncatedTo(ChronoUnit.MILLIS).toString().replaceAll("[TZ]", " ")
output: 2020-02-06 18:01:55.664

etc.


-3
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

Acredito que isso possa ajudar, talvez você precise usar algum tipo de variação de data local em vez de instantes

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.