JavaRush /Blog Java /Random-PL /Intuicyjna, solidna biblioteka do pracy z godzinami i dat...
theGrass
Poziom 24
Саратов

Intuicyjna, solidna biblioteka do pracy z godzinami i datami jest wreszcie dostępna w Javie (część 1).

Opublikowano w grupie Random-PL
Java ma     wreszcie intuicyjny i niezawodny sposób pracy z datami i godzinami. Zasady dotyczące daty i godziny mają fundamentalne znaczenie w wielu zastosowaniach. Różne rzeczy, takie jak daty urodzenia, daty wynajmu, godziny wydarzeń i godziny otwarcia sklepów, są oparte na datach i godzinach, ale Java SE nie zapewnia wygodnego sposobu pracy z nimi. Począwszy od Java SE 8 , dostępny był zestaw pakietów Java.time , które udostępniają dobrze zorganizowany interfejs API do pracy z datami i godzinami.
Tło
    Kiedy po raz pierwszy pojawiła się Java , w wersji 1.0 , jedyną klasą do pracy z datami i godzinami była java.util.Date . Pierwszą rzeczą, którą zauważyli twórcy, było to, że nie reprezentuje ona „daty”. W rzeczywistości reprezentuje moment, z dokładnością do milisekund, mierzony od daty 1 stycznia 1970 r. Jednak biorąc pod uwagę fakt, że metoda toString() Date wyświetla datę i godzinę w strefie czasowej określonej w ustawieniach Java komputera , niektórzy programiści błędnie doszli do wniosku, że Date może współpracować ze strefami czasowymi. Naprawienie tej klasy okazało się na tyle trudne (lub tak leniwe), że w wersji 1.1 musieliśmy dodać nową klasę - java.util.Calendar . Niestety klasa Calendar okazała się niewiele lepsza od Date . Oto mała lista istniejących problemów w jego realizacji:
  • Zmienny. Klasy takie jak data i godzina powinny być niezmienne.
  • Przesunięcia. Lata w dacie zaczynają się od roku 1900, miesiące w obu klasach zaczynają się od zera.
  • Nazwy. Data nie jest w rzeczywistości „datą”, a Kalendarz nie jest kalendarzem.
  • Formatowanie. Formatowanie działa tylko z datą, a nie z kalendarzem i nie jest bezpieczne dla wątków.
    W 2001 roku powstał projekt Joda-Time . Jego cel był prosty – stworzyć wysokiej jakości bibliotekę do pracy z datami i godzinami w Javie . Zajęło to trochę czasu, ale ostatecznie wypuszczono wersję 1.0 , która szybko stała się bardzo popularna i szeroko stosowana. Z biegiem czasu programiści coraz częściej domagali się, aby biblioteka o podobnej wygodzie była dostarczana w ramach JDK . Przy udziale Michaela Nascimento Santosa z Brazylii ruszył projekt JSR-310 , będący oficjalnym procesem tworzenia i integracji nowego API do pracy z datami i godzinami w JDK .
Recenzja
Nowe API Java.time zawiera 5 pakietów:
  • java.time - pakiet podstawowy zawierający obiekty do przechowywania wartości
  • java.time.chrono - zapewnia dostęp do różnych kalendarzy
  • java.time.format - formatowanie i rozpoznawanie daty i godziny
  • java.time.temporal - biblioteki niskiego poziomu i zaawansowana funkcjonalność
  • java.time.zone - klasy do pracy ze strefami czasowymi
    Większość programistów będzie głównie używać pakietu podstawowego i formatowania, a być może Java.time.temporal . Tak więc, mimo że dodano 68 nowych typów, programiści będą używać tylko około jednej trzeciej z nich.
Daktyle
    Klasa LocalDate jest jedną z najważniejszych w nowym API . Zawiera niezmienną wartość reprezentującą datę. Nie można ustawić czasu ani strefy czasowej. Nazwa „lokalny” może być Ci znana z Joda-Time i pierwotnie pochodzi z normy ISO-8601 . Oznacza to właśnie brak strefy czasowej. Zasadniczo LocalDate to opis daty, na przykład „5 kwietnia 2014 r.”. Rzeczywisty czas tej daty będzie się różnić w zależności od Twojej strefy czasowej. Przykładowo w Australii data ta będzie 10 godzin wcześniejsza niż w Londynie i 18 godzin wcześniej niż w San Francisco. Klasa LocalDate posiada wszystkie powszechnie potrzebne metody: LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)     W naszym przykładzie widzimy datę utworzoną metodą fabryczną (wszystkie konstruktory są prywatne). Następnie prosimy obiekt o pewne dane. Należy pamiętać, że wyliczenia Month i DayOfWeek mają na celu zwiększenie czytelności i niezawodności kodu. W poniższym przykładzie zobaczymy jak zmodyfikować datę. Ponieważ klasa jest niezmienna, wynikiem będą nowe obiekty, ale oryginalny pozostanie taki, jaki był. LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09     Są to stosunkowo proste zmiany, ale często trzeba dokonać bardziej skomplikowanych modyfikacji daty. Istnieje do tego specjalny mechanizm w API java.time – TemporalAdjuster . Jego celem jest udostępnienie wbudowanego narzędzia umożliwiającego manipulację datami, na przykład uzyskanie obiektu odpowiadającego ostatniemu dniu miesiąca. Niektóre z nich są zawarte w interfejsie API , ale możesz dodać własne. Używanie modyfikatorów jest bardzo łatwe, ale wymaga statycznego importu: import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));     używanie modyfikatorów znacznie upraszcza kod. Nikt nie chce widzieć wielu ręcznych manipulacji datami. Jeśli w Twoim projekcie kilkakrotnie dochodzi do manipulacji datami, napisz własny modyfikator, a Twój zespół będzie mógł go użyć jako już napisanego i przetestowanego komponentu.
Czas i data jako wartości
    Warto poświęcić trochę czasu na zrozumienie, co sprawia, że ​​LocalDate jest wartością. Wartości to proste typy danych, które są całkowicie wymienne; gdy są równe, tożsamość obiektów staje się bez znaczenia. Klasycznym przykładem klasy wartości jest String . Porównujemy ciągi za pomocą równości() i nie obchodzi nas, czy obiekty są identyczne w porównaniu z operatorem == . Większość klas służących do pracy z datami i godzinami to także wartości. Zatem porównywanie ich za pomocą operatora == jest złym pomysłem, jak stwierdzono w dokumentacji. Jeśli chcesz dowiedzieć się więcej, zapoznaj się z moją najnowszą definicją VALJO , która przedstawia ścisły zestaw reguł, których muszą przestrzegać obiekty wartościujące w Javie , w tym niezmienność, metody fabryczne i właściwą definicję równości() , hashCode , toString() , i porównajTo.() .
Alternatywne kalendarze
    Klasa LocalDate , podobnie jak wszystkie główne klasy w java.time , jest powiązana z jednym kalendarzem – zgodnie z opisem w normie ISO-8601 . Norma 8601 opisuje ogólnoświatowy standardowy kalendarz, znany również jako kalendarz gregoriański. Rok standardowy obejmuje 365 dni, rok przestępny - 366. Co czwarty rok jest rokiem przestępnym, chyba że jest podzielny przez 100 lub jest podzielny przez 400. Rok poprzedzający pierwszy rok nowej ery jest uważany za zerowy dla ułatwienia obliczeń. Pierwszą konsekwencją tego, że jest to system domyślny, jest to, że wyniki nie zawsze odpowiadają wynikom obliczonym przy użyciu GregorianCalendar . Klasa GregorianCalendar ma wbudowany przełącznik do systemu juliańskiego dla wszystkich dat przed 15 października 1582 r. W systemie juliańskim co czwarty rok był rokiem przestępnym, bez wyjątku. Pytanie brzmi, skoro przejście z jednego systemu do drugiego jest faktem historycznym, dlaczego Java.time tego nie modeluje? Tak, ponieważ różne kraje przeszły na system gregoriański w różnym czasie, a biorąc pod uwagę tylko datę przejścia w Watykanie, otrzymamy nieprawidłowe dane dla większości pozostałych krajów. Na przykład Imperium Brytyjskie, łącznie z koloniami w Ameryce Północnej, przeszło na kalendarz gregoriański 14 września 1752 roku, prawie 200 lat później. Rosja zmieniła swój kalendarz dopiero 14 lutego 1918 roku, a transformacja Szwecji jest ogólnie niejasną sprawą. W rezultacie faktyczne znaczenie dat przed 1918 rokiem znacznie się różni w zależności od okoliczności. Autorzy kodu LocalDate podjęli całkowicie racjonalną decyzję, aby w ogóle nie modelować przejścia z kalendarza juliańskiego na gregoriański, aby uniknąć rozbieżności. Drugą konsekwencją stosowania ISO-8601 jako kalendarza domyślnego we wszystkich klasach podstawowych jest to, że do obsługi pozostałych kalendarzy wymagany jest dodatkowy zestaw klas. Interfejs Chronology stanowi podstawę pracy z alternatywnymi kalendarzami, umożliwiając znalezienie żądanego kalendarza według nazwy regionalnej. Java 8 zawiera 4 dodatkowe kalendarze – tajski buddyjski, Mingguo (tajwański), japoński i islamski. Do innych kalendarzy mogą być dołączone programy. Każdy kalendarz ma specjalną klasę dat, taką jak ThaiBuddhistDate , MinguoDate , JapaneseDate i HijrahDate . Używanie ich w bardzo wysoce zlokalizowanych zastosowaniach, takich jak aplikacje dla rządu japońskiego, ma sens. Dodatkowy interfejs ChronoLocalDate jest używany jako podstawowa abstrakcja czterech powyższych klas wraz z LocalDate, co pozwala na pisanie kodu niezależnego od użytego typu kalendarza. Chociaż taka abstrakcja istnieje, nie zaleca się jej stosowania. Zrozumienie, dlaczego ta abstrakcja nie jest zalecana, jest ważne dla zrozumienia działania całego interfejsu API Java.time . Konkluzja jest taka, że ​​większość kodu napisanego bez odniesienia do konkretnego kalendarza okazuje się nie działać. Na przykład nie można być pewnym, czy rok ma 12 miesięcy, ale niektórzy programiści dodają 12 miesięcy i myślą, że dodali cały rok. Nie możesz być pewien, że wszystkie miesiące mają w przybliżeniu tę samą liczbę dni - w kalendarzu koptyjskim jest 12 miesięcy po 30 dni i 1 miesiąc po pięć lub sześć dni. Nie można też mieć pewności, że liczba następnego roku będzie o 1 większa od aktualnej, ponieważ w kalendarzu japońskim lata liczone są od ogłoszenia kolejnego cesarza (w tym przypadku nawet 2 dni tego samego miesiąca mogą należeć do różnych lat). Jedynym sposobem na napisanie wysokiej jakości działającego kodu, który współpracuje z kilkoma kalendarzami jednocześnie, jest to, że rdzeń kodu, który wykonuje wszystkie operacje na datach i godzinach, musi być napisany przy użyciu standardowego kalendarza i tylko podczas wprowadzania/wypisywania dat czy należy go konwertować na inne systemy kalendarzy. Oznacza to, że zaleca się używanie LocalDate do przechowywania i wszelkich manipulacji datami w aplikacji. I tylko podczas lokalizowania dat wejściowych i wyjściowych należy używać ChronoLocalDate , który zwykle jest uzyskiwany z klasy kalendarza przechowywanej w profilu użytkownika. To prawda, że ​​​​większość aplikacji nie wymaga tak poważnej lokalizacji. Jeśli potrzebujesz bardziej szczegółowego wyjaśnienia wszystkiego, co opisano w tym rozdziale, zapraszamy do dokumentacji klasy ChronoLocalDate .      Ciąg dalszy artykułu      Artykuł oryginalny
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION