Formatta Instant in String


227

Sto cercando di formattare un Instant to a String usando il nuovo java 8 time-api e uno schema:

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

Usando il codice sopra ottengo un'eccezione che lamenta un campo non supportato:

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

Risposte:


310

Fuso orario

Per formattare un Instantun fuso orario è richiesto. Senza un fuso orario, il formattatore non sa come convertire l'istante in campi data-ora umani e quindi genera un'eccezione.

Il fuso orario può essere aggiunto direttamente al formatter usando withZone().

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

Generare stringa

Ora usa quel formattatore per generare la rappresentazione String del tuo Instant.

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

Scarica alla 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 eseguito.

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
Grazie!! A proposito, l'eccezione "campo non supportato" che indica, ad esempio, l'anno, è incredibilmente ottusa. Forse questa situazione dovrebbe essere rilevata e dovrebbe essere generata un'eccezione che punta direttamente all'ID zona mancante nell'Istantaneo!
davidbak,

1
Più stranamente, se includi .withZone (ad es. .WithZone (ZoneId.of ("Z"))) e formatta un LocalDateTime, la zona è IGNORATA! Finché è incluso .withZone (), lo stesso formattatore può essere utilizzato sia per Instant che per LocalDateTime, senza influire sul tempo mostrato per quest'ultimo.
Glenn,

1
Perché è così difficile accettare il fatto che Instant abbia un fuso orario GMT?
Koray Tugay,

1
@KorayTugay Perché mentre i commenti "Instant is già GMT" pedanti potrebbero essere veri, sono tutt'altro che utili quando si trova una traccia di eccezione generata perché la formattazione di un Instant senza specificare un fuso orario non funziona. Sarebbe stato bello se il formatter fosse impostato su GMT, ma vabbè.
Ti Strga,

Ora questo ti dà il yyyy-MM-dd hh:mm:ssformato:DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss").withZone(ZoneId.of("Europe/Paris"));
WesternGun

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
Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo a come e perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Alexander

1
Sebbene questo frammento di codice possa risolvere la domanda, inclusa una spiegazione aiuta davvero a migliorare la qualità del tuo post. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Rosário Pereira Fernandes,

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

Questo ti evita di dover convertire in UTC. Tuttavia, alcuni framework temporali di altre lingue potrebbero non supportare i millisecondi, quindi dovresti farlo

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

Cosa intendi con "quadri temporali di altre lingue"? ISO_INSTANT.format () si troncerà automaticamente in secondi?
Guangtong Shen,

Alcuni framework prevedono solo il tempo che passa ai secondi perché non seguono la convenzione ISO completa e si rompono quando ci sono millisecondi come parte della stringa di input.
Archimede Trajano,

21

La Instantclasse non contiene informazioni sulla zona, memorizza solo la data e l'ora in millisecondi di epoca UNIX, ovvero 1 gennaio 1070 da UTC. Pertanto, il formatter non può stampare una data perché la data viene sempre stampata per un fuso orario concreto. Dovresti impostare il fuso orario su formattatore e tutto andrà bene, in questo modo:

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

O se vuoi ancora usare il formatter creato dal pattern puoi semplicemente usare LocalDateTime invece di Instant:

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

4

Gli istanti sono già in UTC e hanno già un formato data predefinito yyyy-MM-dd . Se sei soddisfatto di questo e non vuoi fare confusione con i fusi orari o la formattazione, puoi anche toString():

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


Non vuoi la T e la Z? (Z indica che questa data è UTC. Z sta per "Zulu" aka "Zero hour offset" aka UTC):

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


Vuoi millisecondi invece di nanosecondi? (Quindi puoi inserirlo in una query sql):

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

eccetera.


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

Credo che questo possa aiutare, potrebbe essere necessario utilizzare una sorta di variazione di localizzazione anziché istantanea

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.