Próbuję przeanalizować następującą datę, aby uzyskać błąd w czasie wykonywania:
java.time.format.DateTimeParseException: Text '2019-11-21-05:00' could not be parsed, unparsed text found at index 10
Mój wkład:
String inpDate = "2019-11-20-05:00"
Próbowałem również następujących formatów daty, ale bez powodzenia.
yyyy-MM-ddZ
yyyy-MM-dd Z
Kod:
public static final String DATE_FORMAT = "yyyy-MM-dd";
public static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
LocalDate localDate = LocalDate.parse(inpDate, dateFormatter);
return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Jak mogę sprawić, aby moje dane wejściowe zostały poprawnie przeanalizowane?
3 odpowiedzi
Użyj następującego formatu:
public static final String DATE_FORMAT = "yyyy-MM-ddZZZZZ";
Ma 5 razy literę „Z”. Aby przeanalizować przesunięcie strefy czasowej za pomocą dwukropka, musisz 5 razy podać literę „Z”. Może to być nieco ukryte w dokumentacji Javadoc.
Z Javadoc:
Przesunięcie Z: formatuje przesunięcie na podstawie liczby liter wzorca.
Jedna, dwie lub trzy litery powodują wyświetlenie godziny i minuty bez dwukropka, np. „+0130”. Wyjście będzie '+0000', gdy przesunięcie wynosi zero.
Cztery litery wytwarzają pełną formę zlokalizowanego przesunięcia, odpowiednik czterech liter offset-o. Wyjście będzie odpowiedniego tekstu zlokalizowanego tekstu, jeśli przesunięcie jest zero.
Pięć liter to godzina, minuta, z opcjonalną sekundą, jeśli jest różna od zera, z dwukropkiem.
Wyprowadza 'Z', jeśli przesunięcie wynosi zero. Sześć lub więcej liter generuje IllegalArgumentException.
String inpDate = "2019-11-20-05:00";
System.out.println(LocalDate.parse(inpDate, DateTimeFormatter.ofPattern("yyyy-MM-dd-hh:mm")));
Wydrukuje 2019-11-20.
To łatwiejsze niż myślisz. Formater, którego potrzebujesz, jest wbudowany. Nie musisz więc walczyć z pisaniem własnego ciągu wzorca formatu.
String inpDate = "2019-11-20-05:00";
LocalDate localDate = LocalDate.parse(inpDate, DateTimeFormatter.ISO_OFFSET_DATE);
System.out.println(Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
Wyjście w mojej strefie czasowej:
śr 20 lis 00:00:00 EST 2019
Zakładam, że dokonujesz konwersji tylko na Date
, ponieważ potrzebujesz go do starszego interfejsu API, którego nie możesz teraz uaktualnić do java.time. W przeciwnym razie nie powinieneś używać Date
, ale trzymaj się nowoczesnego API.
Początek dnia w Twojej strefie czasowej czy przesunięcie podane w ciągu znaków?
Edytuj: Basil Bourque w komentarzu zadał to bardzo kompetentne pytanie:
Być może byłoby to bardziej zgodne z intencją wydawcy tego ciąg wejściowy, aby uzyskać pierwszą chwilę dnia, jak widać w tym przesunięciu 5 godzin za UTC. Czy można analizować jako
OffsetDateTime
z domyślną porą dnia do pierwszej chwili dnia (00:00:00)? (A następnie przekonwertuj najava.util.Date
, jeśli jest to wymagane).
To zdecydowanie prawda. Zdecydowałem się podać kod, który daje wynik, który moim zdaniem próbował uzyskać kod w pytaniu. Jeśli rozumiemy 2019-11-20-05:00
jako nieokreślony czas w przedziale półotwartym od 2019-11-20T00:00-05:00 do 2019-11-21T00:00-05:00, to dla niektórych przesunięć i niektórych domyślnych strefy czasowe wynik z powyższego fragmentu kodu będzie faktycznie leżeć poza tym interwałem (zazwyczaj przed nim, w skrajnych przypadkach może również przypadać po nim). Tak więc jest to zgodne z pytaniem (jeśli dobrze zrozumiałem) i nieprawdziwe w stosunku do wydawcy oryginalnego ciągu. Jeśli zamiast tego chcemy rozpocząć dzień od przesunięcia UTC podanego w ciągu, zrobiłbym to tak:
TemporalAccessor parsed = DateTimeFormatter.ISO_OFFSET_DATE.parse(inpDate);
Instant startOfDayAtSpecifiedOffset = LocalDate.from(parsed)
.atStartOfDay(ZoneOffset.from(parsed))
.toInstant();
System.out.println(Date.from(startOfDayAtSpecifiedOffset));
Wyjście w mojej strefie czasowej:
śr 20 lis 06:00:00 CET 2019
W listopadzie jestem na offsecie +01:00, dlatego tutaj jest godzina 06:00, kiedy dzień zaczyna się o offsecie -05:00. Aby zilustrować, że wybór strefy czasowej lub przesunięcia może mieć duże znaczenie, oto wynik uruchomienia drugiego fragmentu z domyślną strefą czasową Pacyfik/Kiritimati:
śr 20 lis 19:00:00 LINT 2019
Lub w strefie czasowej Pacyfik/Pago_Pago:
wt lis 19 18:00:00 SST 2019
Więc ostrożnie wybierz to, czego naprawdę chcesz.
Co poszło nie tak w swoim kodzie?
Po pierwsze, LocalDate.parse()
i podobne metody parsowania nalegają na parsowanie całego łańcucha lub wyrzucą wyjątek, który widziałeś wspominając o unparsed text found at index (some index)
(możesz użyć przeciążonej metody DateTimeFormatter.parse(CharSequence, ParsePosition)
do parsowania tylko jak to możliwe ciągu bez tego wyjątku).
Po drugie, jeden Z
w ciągu wzorca formatu pasuje do przesunięcia bez dwukropka, więc -0500
, a nie -05:00
.
Link: Dokumentacja DateTimeFormatter.parse(CharSequence, ParsePosition)
Podobne pytania
Nowe pytania
java
Java to język programowania wysokiego poziomu. Użyj tego tagu, jeśli masz problemy z używaniem lub zrozumieniem samego języka. Ten tag jest rzadko używany samodzielnie i jest najczęściej używany w połączeniu z [spring], [spring-boot], [jakarta-ee], [android], [javafx], [hadoop], [gradle] i [maven].
05:00
to pora dnia, potrzebujesz wielkich literHH
jako godziny dnia. Ale prawdopodobnie tak nie jest. Biorę-05:00
za przesunięcie UTC. Data bez pory dnia i z przesunięciem jest osobliwa, ale czasami jest używana, nie bardzo rozumiem po co.