Java 8 dodała nowy interfejs API java.time do pracy z datami i godzinami ( JSR 310 ).
Mam datę i godzinę jako ciąg (np "2014-04-08 12:30"
.). Jak mogę uzyskać LocalDateTime
instancję z podanego ciągu?
Po zakończeniu pracy z LocalDateTime
obiektem: jak mogę przekonwertować LocalDateTime
instancję z powrotem na ciąg o takim samym formacie, jak pokazano powyżej?
ZonedDateTime
raczej niżLocalDateTime
. Nazwa jest sprzeczna z intuicją;Local
oznacza dowolną lokalizację w ogóle zamiast strefę określonym czasie. Jako takiLocalDateTime
obiekt nie jest powiązany z linią czasu. Aby mieć znaczenie, aby uzyskać określony moment na linii czasu, musisz zastosować strefę czasową.LocalDateTime
vsZonedDateTime
vsOffsetDateTime
vsInstant
vsLocalDate
vsLocalTime
, jak zachować spokój, dlaczego jest tak skomplikowane i jak zrobić to dobrze na pierwszy strzał.LocalDateTime
prawdopodobnie zostałby nazwanyZonelessOffsetlessDateTime
.Odpowiedzi:
Analiza daty i godziny
Aby utworzyć
LocalDateTime
obiekt z łańcucha, możesz użyćLocalDateTime.parse()
metody statycznej . Wymaga ciągu iDateTimeFormatter
parametru jako parametru.DateTimeFormatter
Jest używany do określenia wzoru data / czas.Formatowanie daty i godziny
Aby utworzyć sformatowany ciąg znaków na
LocalDateTime
obiekcie, możesz użyćformat()
metody.Zauważ, że niektóre powszechnie używane formaty daty / godziny są wstępnie zdefiniowane jako stałe w
DateTimeFormatter
. Na przykład: użycieDateTimeFormatter.ISO_DATE_TIME
do sformatowaniaLocalDateTime
instancji z góry spowoduje powstanie ciągu"1986-04-08T12:30:00"
.Te
parse()
iformat()
są dostępne dla wszystkich metod / obiektów czasowych związanych data (npLocalDate
lubZonedDateTime
)źródło
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
format()
klasę LocalDateTime zamiast instancji? Przynajmniej tak zrobiłem: pomyliłemDateTime
siędateTime
w powyższym przykładzie.Można również użyć
LocalDate.parse()
alboLocalDateTime.parse()
na zasadzieString
bez zapewniając jej wzoru, jeśliString
jest w formacie ISO-8601 .na przykład,
Wyjście ,
i używaj
DateTimeFormatter
tylko wtedy, gdy masz do czynienia z innymi wzorcami dat.Na przykład w poniższym przykładzie dd MMM uuuu reprezentuje dzień miesiąca (dwie cyfry), trzy litery nazwy miesiąca (styczeń, luty, mar, ...) i czterocyfrowy rok:
Wynik
pamiętaj również, że
DateTimeFormatter
obiekt jest dwukierunkowy; może zarówno analizować dane wejściowe, jak i formatować dane wyjściowe.Wynik
(zobacz pełną listę wzorców formatowania i analizy formatowania daty )
źródło
2018-08-09 12:00:08
ale kiedy analizuję, widzę, żeT
jest dodawany, którego nie potrzebuję. Czy jest na to sposób?yyyy-MM-dd hh:mm:ss
do analizy i formatowania. Symbol T będzie zawsze wyświetlany w domyślnym formacie (ISO-8061), ale możesz używać własnych wzorów.Obie powyższe odpowiedzi bardzo dobrze wyjaśniają pytanie dotyczące wzorów ciągów. Jednak w przypadku pracy z ISO 8601 nie ma potrzeby składania wniosku,
DateTimeFormatter
ponieważ LocalDateTime jest już na to przygotowany:Konwertuj LocalDateTime na ciąg strefy czasowej ISO8601
Konwertuj z ciągu ISO8601 z powrotem na LocalDateTime
źródło
Przetwarzanie ciągu z datą i godziną w określonym momencie (Java nazywa to „
Instant
”) jest dość skomplikowane. Java radzi sobie z tym w kilku iteracjach. Najnowszy,java.time
ijava.time.chrono
obejmuje prawie wszystkie potrzeby (z wyjątkiem Dylatacji Czasu :)).Jednak ta złożoność wprowadza wiele zamieszania.
Kluczem do zrozumienia parsowania daty jest:
Dlaczego Java ma tak wiele sposobów na parsowanie daty
... i dlaczego jest
LocalDateTime
,ZonedDateTime
i in. takie skomplikowaneIstnieją strefy czasowe . Strefa czasowa jest w zasadzie „paskiem” * [1] powierzchni Ziemi, którego władze przestrzegają tych samych zasad co do tego, kiedy ma przesunięcie czasowe. Obejmuje to zasady dotyczące czasu letniego.
Strefy czasowe zmieniają się w czasie dla różnych obszarów, głównie na podstawie tego, kto kogo zwycięża. Z czasem zasady jednej strefy czasowej również się zmieniają .
Istnieją przesunięcia czasowe. Nie jest to to samo, co strefy czasowe, ponieważ strefa czasowa może być np. „Praga”, ale ma przesunięcie czasu letniego i zimowego.
Jeśli otrzymasz znacznik czasu ze strefą czasową, przesunięcie może się różnić w zależności od tego, w której części roku się znajduje. Podczas godziny przestępnej znacznik czasu może oznaczać 2 różne czasy, więc bez dodatkowych informacji nie można go wiarygodnie nawrócony.
Uwaga: Przez znacznik czasu rozumiem „ciąg znaków zawierający datę i / lub godzinę, opcjonalnie ze strefą czasową i / lub przesunięciem czasu”.
Kilka stref czasowych może współdzielić to samo przesunięcie czasowe dla niektórych okresów. Na przykład strefa czasowa GMT / UTC jest taka sama jak strefa czasowa „Londyn”, gdy nie obowiązuje przesunięcie czasu letniego.
Aby było to nieco bardziej skomplikowane (ale nie jest to zbyt ważne w przypadku użycia):
2040-12-31 24:00:00
Może to być prawidłowa data i godzina). Wymaga to regularnych aktualizacji metadanych używanych przez systemy do prawidłowej konwersji daty. Np. W systemie Linux otrzymujesz regularne aktualizacje pakietów Java, w tym te nowe dane.Aktualizacje nie zawsze zachowują poprzednie zachowanie zarówno dla historycznych, jak i przyszłych znaczników czasu. Może się więc zdarzyć, że parsowanie dwóch znaczników czasu wokół zmiany strefy czasowej w porównaniu z nimi może dać różne wyniki, gdy uruchomione zostaną różne wersje oprogramowania. Dotyczy to również porównywania między strefą czasową dotkniętą chorobą a inną strefą czasową.
Jeśli spowoduje to błąd w oprogramowaniu, rozważ użycie znacznika czasu, który nie ma tak skomplikowanych reguł, jak na przykład znacznik czasu UNIX .
Z powodu 7 w przypadku przyszłych dat nie możemy przekonwertować dat dokładnie. Na przykład bieżące parsowanie
8524-02-17 12:00:00
może być wyłączone o kilka sekund od przyszłego parsowania.Interfejsy API JDK do tego ewoluowały wraz ze współczesnymi potrzebami
java.util.Date
nieco naiwne podejście, zakładając, że jest tylko rok, miesiąc, dzień i godzina. To szybko nie wystarczyło.java.sql.Date
, z własnymi ograniczeniami.Calendar
API.Jak sobie z tym poradzić w Javie
java.time
Określ, do jakiego typu parsować znacznik czasu
Kiedy konsumujesz ciąg znacznika czasu, musisz wiedzieć, jakie informacje zawiera. To jest kluczowy punkt. Jeśli nie uda ci się tego zrobić, możesz uzyskać tajemnicze wyjątki, takie jak „Nie można utworzyć błyskawicznego” lub „Brak przesunięcia strefy” lub „nieznany identyfikator strefy” itp.
Czy zawiera datę i godzinę?
Czy ma przesunięcie czasowe?
Przesunięcie czasu jest
+hh:mm
częścią. Czasami+00:00
może być zastąpiony przezZ
„czas Zulu”,UTC
jako koordynowany czas uniwersalny lubGMT
jako czas uniwersalny Greenwich. Ustawiają one także strefę czasową.Dla tych znaczników czasu używasz
OffsetDateTime
.Czy ma strefę czasową?
Dla tych znaczników czasu używasz
ZonedDateTime
.Strefa jest określona przez
Lista stref czasowych jest tworzona przez „bazę danych TZ” , wspieraną przez ICAAN.
Zgodnie z
ZoneId
javadoc, identyfikator strefy można również jakoś określić jakoZ
i offset. Nie jestem pewien, jak to mapuje do prawdziwych stref. Jeśli znacznik czasu, który ma tylko TZ, wpada w godzinę przestępną zmiany przesunięcia czasowego, to jest on niejednoznaczny, a interpretacja jest przedmiotemResolverStyle
, patrz poniżej.Jeśli nie ma żadnego , wówczas brakujący kontekst jest przyjmowany lub zaniedbywany. I konsument musi zdecydować. Dlatego musi zostać przeanalizowany jako
LocalDateTime
i przekonwertowanyOffsetDateTime
przez dodanie brakujących informacji:Duration
) lub gdy nie wiesz i nie ma to tak naprawdę znaczenia (np. Rozkład jazdy autobusów lokalnych).Informacje o niepełnym wymiarze godzin
LocalDate
,LocalTime
,OffsetTime
,MonthDay
,Year
, lubYearMonth
z niego.Jeśli masz pełne informacje, możesz uzyskać
java.time.Instant
. Jest to również wewnętrznie wykorzystywane do konwersji międzyOffsetDateTime
iZonedDateTime
.Dowiedz się, jak to przeanalizować
Istnieje obszerna dokumentacja, w
DateTimeFormatter
której można parsować ciąg znacznika czasu i formatować go.The wstępnie utworzone
DateTimeFormatter
s powinien obejmować więcejmniej wszystkie standardowe formaty datownik. Na przykładISO_INSTANT
można parsować2011-12-03T10:15:30.123457Z
.Jeśli masz jakiś specjalny format, możesz utworzyć własny DateTimeFormatter (który jest również analizatorem składni).
Polecam zajrzeć do kodu źródłowego
DateTimeFormatter
i zainspirować się, jak zbudować taki przy użyciuDateTimeFormatterBuilder
. Podczas gdy tam jesteś, sprawdź również,ResolverStyle
który kontroluje, czy analizator składni jest LENIENT, SMART czy STRICT dla formatów i niejednoznacznych informacji.TemporalAccessor
Teraz częstym błędem jest wchodzenie w złożoność
TemporalAccessor
. Wynika to ze sposobu, w jaki programiści byli przyzwyczajeni do pracySimpleDateFormatter.parse(String)
. Racja,DateTimeFormatter.parse("...")
daje ciTemporalAccessor
.Ale dzięki wiedzy z poprzedniej sekcji możesz wygodnie parsować wybrany typ:
Tak naprawdę nie potrzebujesz
DateTimeFormatter
ani jednego, ani drugiego. Typy, które chcesz przeanalizować, mająparse(String)
metody.Jeżeli chodzi o
TemporalAccessor
, możesz go użyć, jeśli masz niejasne pojęcie o tym, jakie informacje znajdują się w ciągu i chcesz zdecydować w czasie wykonywania.Mam nadzieję, że rzuciłem trochę zrozumienia na twoją duszę :)
Uwaga: Istnieje backport
java.time
do Java 6 i 7: ThreeTen-Backport . Na Androida ma ThreeTenABP .[1] Nie tylko to, że nie są paskami, ale są też dziwne skrajności. Na przykład niektóre sąsiednie wyspy Pacyfiku mają strefy czasowe +14: 00 i -11: 00. Oznacza to, że będąc na jednej wyspie, jest 1 maja 3 po południu, na innej wyspie jeszcze nie jest jeszcze 30 kwietnia 12 po południu (jeśli poprawnie policzyłem :))
źródło
UZYSKAJ BIEŻĄCY CZAS UTC W WYMAGANYM FORMACIE
źródło
Uważam, że wspaniale jest obejmować wiele wariantów formatu daty i godziny, takich jak ten:
źródło