2017-04-26 26 views
7

Próbuję zapewnić, że wywołanie toString() na moim obiekcie będzie zgodne z formatem ISO-8601.ZonedDateTime toString kompatybilność z ISO 8601

Dokumentacja dla państw toString() metoda:

... Wyjście jest zgodny z ISO-8601, czy offset i ID są samo

Czy to znaczy, że istnieje sytuacji, w której wywołanie będzie zwracać coś innego niż zdt.getZone().getRules().getOffset(zdt.toInstant()) ?

To nie wydaje się mieć sensu.

Czy ktoś może podać przykład, w którym przesunięcie i identyfikator nie są takie same (np. Gdzie toString() nie jest zgodny z ISO-8601), aby lepiej zrozumieć opis w dokumentacji.

Dziękuję.

Odpowiedz

12

Jest to kompletny opis:

* Outputs this date-time as a {@code String}, such as 
* {@code 2007-12-03T10:15:30+01:00[Europe/Paris]}. 
* <p> 
* The format consists of the {@code LocalDateTime} followed by the {@code ZoneOffset}. 
* If the {@code ZoneId} is not the same as the offset, then the ID is output. 
* The output is compatible with ISO-8601 if the offset and ID are the same. 

Specyfikacja Javadoc odnosi się do przypadku, w którym ZonedDateTime jest wykonana z ZoneOffset zamiast nazwany ZoneId, a tym samym, gdy przesunięcie i ID są takie same:

System.out.println(ZonedDateTime.now(ZoneId.of("Europe/Paris"))); 
// 2017-04-26T15:13:12.006+02:00[Europe/Paris] 

System.out.println(ZonedDateTime.now(ZoneOffset.ofHours(2))); 
// 2017-04-26T15:13:12.016+02:00 

Jak widać, w drugim przypadku, gdy stosuje się ZoneOffset sformatować toString() pomija kwadratowy przekrój uchwytu na końcu. Pomijając tę ​​sekcję, wynik jest zgodny z ISO-8601.

boolean iso8601Compatible = zdt.getZone() instanceof ZoneOffset; 

celu zagwarantowania ISO-8601 wykorzystanie wyjścia kompatybilny toOffsetDateTime():

String isoCompatible = zdt.toOffsetDateTime().toString(); 

lub formatyzatora.

+4

"lub formater": [DataTimeFormatter.ISO_OFFSET_DATE_TIME] (http://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_OFFSET_DATE_TIME) przywodzi na myśl. –

0

Zgodnie z oficjalnej dokumentacji:

Uzyskanie offsetu przez chwilę jest prosta, ponieważ istnieje dokładnie jedna ważna offsetu dla każdej chwili. Natomiast uzyskanie offsetu dla lokalnej daty i godziny nie jest proste. Istnieją trzy przypadki:

  • Normalny, z jednym poprawnym przesunięciem. Przez znaczną większość roku stosuje się zwykły przypadek, w którym występuje jeden poprawny offset dla lokalnej daty i godziny.
  • Luka, z zerowymi poprawnymi przesunięciami. Dzieje się tak, gdy zegary przeskakują naprzód, zazwyczaj ze względu na zmianę czasu letniego na zimowy z "zimowego" na "letni". W luce występują lokalne wartości daty i czasu bez poprawnego przesunięcia.
  • Nakładanie, z dwoma poprawnymi przesunięciami. Dzieje się tak, gdy zegary są cofane, zazwyczaj ze względu na zmianę jesiennej zmiany dziennej z "lata" na "zimę". W zakładce występują lokalne wartości daty i czasu z dwoma poprawnymi przesunięciami.

Tak więc drugi i trzeci przypadek to sytuacje, w których toString() nie będzie zgodne z ISO-8601.

+0

Pytanie dotyczyło 'ZonedDateTime', a nie' LocalDateTime'. 'ZonedDateTime' jednoznacznie identyfikuje jedną chwilę, więc nie widzę problemu? Z drugiej strony masz rację, że 'LocalDateTime' i strefa czasowa (' ZoneId') razem nie zawsze jednoznacznie identyfikują jedną chwilę, jak wyjaśnisz w przypadku 2 i 3. –

+0

@ OleV.V. odpowiedziałeś na moje pytanie, mój przyjacielu. 'toString()' nie będzie zgodne z normą ISO-8601 w sytuacjach, gdy nie można zidentyfikować unikatowego Instant. – VivekRatanSinha

+3

Chociaż ta informacja jest interesująca, niestety jest to zła odpowiedź na pytanie. Przerwy i nakładanie się w tym przypadku nie mają nic wspólnego z ISO-8601. – JodaStephen

1

Przykład pod numerem the documentation to 2007-12-03T10:15:30+01:00[Europe/Paris]. Nie dzieje się to w zgodzie z ISO, ponieważ ISO-8601 nie obejmuje części [Europe/Paris]. Zostało to dodane przez deweloperów java.time w kompromis między uzyskaniem jak najbardziej zbliżonego do standardowego i wciąż udowadniającego informację o strefie czasowej w jednoznaczny sposób.

Prawdziwe pytanie może w rzeczywistości być odwrotne: jeśli ZonedDateTime.toString() zawiera informacje o strefie czasowej, której ISO nie zawiera, gdy jest wynik w pełni zgodny z ISO? Co oznacza "jeśli przesunięcie i identyfikator są takie same"? Tutaj musimy pamiętać, że ZoneOffset jest podklasą ZoneID i może być używany jako identyfikator strefy w ZonedDateTime. W tym przypadku przesunięcie i identyfikator są takie same. W przeciwnym razie nie są. W konkretnym przykładzie ZonedDateTime.now(ZoneOffset.ofHours(+2)).toString() może produkować 2017-04-26T15:04:59.828+02:00. Jest to w pełni zgodne z ISO, ponieważ strefa jest podana jako +02:00, która jest taka sama jak przesunięcie. Również ZonedDateTime.now(ZoneOffset.UTC).toString() daje coś w formacie 2017-04-26T13:04:59.828Z. Ponieważ Z liczy się jako przesunięcie, jest to również kompatybilne.

Myślę, że w większości przypadków nie będzie to zbyt przydatne. Jeśli twoja strefa jest tylko przesunięciem, zwykle wolisz używać OffsetDateTime przez ZonedDateTime, a jeśli tak, to oczywiście nie przejmujesz się tym, czy ZonedDateTime.toString() jest zgodny z ISO, czy nie.

0

Lubię powyżej ostatniego komentarza JodaStephen 'lub formatyzatora', ponieważ użycie formatyzatora jest bardziej niezawodne, niezależnie od danych. Powodem jest OffsetDateTime toString() pomiń część drugiego urządzenia, gdy nie ma wartości na drugiej jednostce i poniżej, więc kończy się na rrrr-MM-ddTHH: mmZ zamiast rrrr-MM-ddTHH: mm: ssZ . Może to powodować problemy, jeśli inny system oczekuje formatu statycznego i nie ma zdolności adaptacyjnych.

Poniżej znajduje się kod, którego użyłem do symulacji obu przypadków, w których nie ma części czasowej i jest ona dostępna.

/** 
* This function is design to convert Date object from other system to ISO dateTime String 
* which will be sent to another system. and using formatter to lock up the format 
* @param date java.util.Date 
* @return 'yyyy-MM-ddTHH:mm:ssZ' format ISO dateTime string 
*/ 
public String formatIsoUtcDateTime(Date date) { 
    if(null == date) { 
     return null; 
    } 
    return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC")) 
         .format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")); 
} 

// no time portion with using formatter 
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); 
Date date = sdf.parse("20171010"); 
System.out.println(formatIsoUtcDateTime(date)); 

// no time portion with using OffsetDateTime toString 
System.out.println(ZonedDateTime.ofInstant(date.toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString()); 

// just current date and probably has at least millisecond, using formatter 
System.out.println(formatIsoUtcDateTime(new Date())); 

// just current date and probably has at least millisecond, using OffsetDateTime toString 
// this will print yyyy-MM-ddTHH:mm:ss.SSSZ format 
System.out.println(ZonedDateTime.ofInstant(new Date().toInstant(), ZoneId.of("UTC")).toOffsetDateTime().toString()); 
Powiązane problemy