Data Java a kalendarz

364

Czy ktoś mógłby doradzić na temat obecnych najlepszych praktyk Datei Calendartypów.

Podczas pisania nowego kodu, jest to najlepiej zawsze faworyzują Calendarnad Datelub istnieją okoliczności, w których Datejest bardziej odpowiedni typ danych?

Marty Pitt
źródło
28
Czas Joda: joda-time.sourceforge.net
R. Martinho Fernandes
2
FYI, kłopotliwego starych klas date-time, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz Legacy, wyparta przez java.time klas. Wiele funkcji java.time zostało przeniesionych z powrotem do Java 6 i Java 7 w projekcie ThreeTen-Backport . Dalsze dostosowanie do wcześniejszego Androida w projekcie ThreeTenABP . Zobacz Jak korzystać z ThreeTenABP… .
Basil Bourque,
2
Do Twojej wiadomości, projekt Joda-Time (wspomniany w innym komentarzu) jest teraz w trybie konserwacji , a zespół doradza migrację do klas java.time . Zobacz samouczek Oracle .
Basil Bourque,

Odpowiedzi:

377

Data jest prostszą klasą i jest tam głównie ze względu na kompatybilność wsteczną. Jeśli chcesz ustawić określone daty lub wykonać arytmetykę dat, użyj kalendarza. Kalendarze obsługują również lokalizację. Poprzednie funkcje manipulowania datą w Data były już nieaktualne.

Osobiście używam albo czasu w milisekundach jako długiego (lub odpowiednio Długiego) lub Kalendarza, kiedy jest wybór.

Zarówno data, jak i kalendarz są zmienne, co może powodować problemy podczas korzystania z interfejsu API.

Cletus
źródło
5
Do Twojej wiadomości, strasznie kłopotliwe stare klasy daty i czasu, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz spuścizną , wyparte przez klasy java.time wbudowane w Javę 8 i nowsze wersje . Zobacz samouczek Oracle .
Basil Bourque,
67

Najlepszym sposobem na nowy kod (jeśli Twoje zasady zezwalają na kod innej firmy) jest użycie biblioteki Joda Time .

Zarówno Date, jak i Calendar mają tak wiele problemów projektowych, że żadne z nich nie jest dobrym rozwiązaniem dla nowego kodu.

dmeister
źródło
7
Popieram sugestię wykorzystania czasu Joda. Jest łatwiejszy w użyciu i zrozumieniu oraz oferuje znacznie więcej funkcji, z których możesz korzystać.
Jeroen van Bergen,
30
Aby dowiedzieć się, czy użyć Joda Time, czy trzymać się standardowych klas JDK, zobacz stackoverflow.com/questions/589870/…
Jonik 10.09 o
3
Nie wiem, czy to zasługuje na negatywne opinie, ale nie odpowiada na pytanie. Może być lepszy jako komentarz.
IcedDante,
7
Ponieważ pytanie dotyczyło użycia daty i kalendarza, a nie korzystania z biblioteki innej firmy, która dodaje ryzyko zależności od jednego dostawcy do projektu.
Archimedes Trajano,
3
BYŁO to „najlepszy sposób”, dopóki pakiet java.time nie został udostępniony w Javie 8.
DaBlick
58
  • Datei Calendarsą tak naprawdę tą samą podstawową koncepcją (obie reprezentują moment w czasie i są owijane wokół podstawowej longwartości).

  • Można argumentować, że Calendartak naprawdę jest jeszcze bardziej zepsuty niżDate jest, ponieważ wydaje się, że oferuje konkretne fakty o takich rzeczach, jak dzień tygodnia i pora dnia, natomiast jeśli zmienisz jego timeZonewłaściwość, beton zamieni się w blanszange! Z tego powodu żadne obiekty nie są tak naprawdę przydatne jako magazyn roku-miesiąca-dnia lub pory dnia .

  • Używaj Calendartylko jako kalkulatora, który, jeśli zostanie podany Datei TimeZoneobiekty, wykona dla ciebie obliczenia. Unikaj jego używania do wpisywania właściwości w aplikacji.

  • Używaj SimpleDateFormatrazem z TimeZonei Datedo generowania ciągów wyświetlania.

  • Jeśli masz ochotę na przygodę, użyj Joda-Time, chociaż jest to niepotrzebnie skomplikowane IMHO i wkrótce zostanie zastąpione przez interfejs API daty JSR-310.

  • Odpowiedziałem wcześniej, że nie jest trudno rzucić własną YearMonthDayklasę, która używa Calendarpod maską do obliczania daty. Nie podobała mi się ta sugestia, ale nadal uważam, że jest ona ważna, ponieważ Joda-Time (i JSR-310 ) są naprawdę zbyt skomplikowane w większości przypadków użycia.

oxbow_lakes
źródło
1
Czy istnieje ramy czasowe dla JSR310? To miało być w Javie 7, ale myślę, że teraz tak nie jest.
Brian Agnew,
@Brian - na tej liście mailowej z pewnością zrobiło się bardzo cicho!
oxbow_lakes,
Tylko sprawdzam, to już nieaktywne, co oznacza, że nie zostały opublikowane projekt kamień milowy w 18 miesięcy :-(
Brian Agnew
Najnowszy komentarz do listy mailingowej pochodzi z lipca i autorstwa Stephena, więc projekt prawdopodobnie nadal tyka
oxbow_lakes 10.09.2009
Zgoda. Jeśli wiesz, jak bezpiecznie używać Data jako niezmiennego obiektu i Kalendarza do manipulowania datami, większość ludzi powinna być bezpieczna. Zachowaj ostrożność podczas używania SimpleDateFormat w kodzie wielowątkowym.
cwash
25

Data jest najlepsza do przechowywania obiektu daty. Jest to utrwalony, zserializowany ...

Kalendarz jest najlepszy do manipulowania datami.

Uwaga: czasem preferujemy także java.lang.Long nad Date, ponieważ Date jest zmienna i dlatego nie jest bezpieczna dla wątków. W obiekcie Date użyj setTime () i getTime (), aby przełączać się między nimi. Na przykład stała data w aplikacji (przykłady: zero 1970/01/01 lub aplikacyjny END_OF_TIME ustawiony na 2099/12/31; są one bardzo przydatne do zastąpienia wartości zerowych jako godziny rozpoczęcia i zakończenia, szczególnie gdy utrzymujesz je w bazie danych, ponieważ SQL jest tak specyficzny dla zer.

KLE
źródło
Rozumiem, że zajmujesz się niezmiennymjava.lang.Long
pjp
17

Zazwyczaj używam Data, jeśli to możliwe. Chociaż można go modyfikować, mutatory są w rzeczywistości przestarzałe. Na koniec zasadniczo zawija długi, który reprezentuje datę / godzinę. I odwrotnie, użyłbym kalendarzy, gdybym musiał manipulować wartościami.

Możesz myśleć o tym w ten sposób: używasz StringBuffer tylko wtedy, gdy potrzebujesz Ciągów, którymi możesz łatwo manipulować, a następnie przekształcić je w Ciągi za pomocą metody toString (). W ten sam sposób korzystam z Kalendarza tylko wtedy, gdy muszę manipulować danymi czasowymi.

Najlepszą praktyką jest używanie obiektów niezmiennych jak najwięcej poza modelem domeny . Znacząco zmniejsza ryzyko wystąpienia jakichkolwiek skutków ubocznych i jest to wykonywane przez kompilator, a nie przez test JUnit. Korzystasz z tej techniki, tworząc prywatne pola końcowe w swojej klasie.

I wracając do analogii StringBuffer. Oto kod, który pokazuje, jak konwertować kalendarz i datę

String s = "someString"; // immutable string
StringBuffer buf = new StringBuffer(s); // mutable "string" via StringBuffer
buf.append("x");
assertEquals("someStringx", buf.toString()); // convert to immutable String

// immutable date with hard coded format.  If you are hard
// coding the format, best practice is to hard code the locale
// of the format string, otherwise people in some parts of Europe
// are going to be mad at you.
Date date =     new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2001-01-02");

// Convert Date to a Calendar
Calendar cal = Calendar.getInstance();
cal.setTime(date);

// mutate the value
cal.add(Calendar.YEAR, 1);

// convert back to Date
Date newDate = cal.getTime();

// 
assertEquals(new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse("2002-01-02"), newDate);
Archimedes Trajano
źródło
Tak, niezmienne obiekty mają sens w pracy z datą i godziną. W java.time klas, które wyparły Date/ Calendarużywać obiektów niezmienny wzorzec.
Basil Bourque,
To może być prawda, ale nie w 2010 roku.
Archimedes Trajano,
Tak. Ale tysiące ludzi czyta teraz tę stronę , jak dotąd ponad 150 000. Mój komentarz jest dla nich notatką, a nie krytyką.
Basil Bourque,
Wiem, dlatego głosowałem za drugą odpowiedzią. Jednak wciąż są ludzie, którzy muszą cierpieć z powodu starszych pakietów JDK, które również potrzebują powyższej odpowiedzi.
Archimedes Trajano,
1
W rzeczywistości dla Java 6 i 7 mamy projekt ThreeTen-Backport . Daje to większość funkcji java.time z praktycznie takim samym API. Nie ma więc potrzeby korzystania z tych okropnych klas czasu i daty.
Basil Bourque,
15

Dates powinny być używane jako niezmienne punkty w czasie; Calendars są zmienne i mogą być przekazywane i modyfikowane, jeśli musisz współpracować z innymi klasami, aby ustalić ostateczną datę. Rozważ je analogicznie, Stringa StringBuilderzrozumiesz, jak uważam, że powinny być używane.

(I tak, wiem, że Data nie jest technicznie niezmienna, ale intencją jest, aby nie była zmienna, a jeśli nic nie wywołuje przestarzałych metod, to tak jest.)

Andrzej Doyle
źródło
Tak, niezmienne obiekty mają sens w pracy z datą i godziną. W java.time klas, które wyparły Date/ Calendarużywać obiektów niezmienny wzorzec. W szczególności Instantzastępuje java.util.Datei ZonedDateTimezastępuje Calendar/ GregorianCalendar.
Basil Bourque,
15

tl; dr

doradzać w zakresie bieżącej „najlepszej praktyki” wokół DateiCalendar

jest to najlepiej zawsze faworyzują CalendarponadDate

Unikaj całkowicie tych klas starszych . Zamiast tego użyj klas java.time .

Tabela wszystkich typów daty i godziny w Javie, zarówno nowoczesnych, jak i starszych

Detale

Odpowiedz przez Ortomala Lokni słusznie sugerują, stosując nowoczesne java.time klas zamiast kłopotliwych starych klas legacy-czasowych (data Date, Calendaritd). Ale ta odpowiedź sugeruje, że niewłaściwa klasa jest równoważna (patrz mój komentarz do tej odpowiedzi).

Korzystanie z java.time

Klasy java.time to znaczna poprawa w stosunku do starszych klas data-godzina, różnica między dniem i nocą. Stare klasy są źle zaprojektowane, zagmatwane i kłopotliwe. W miarę możliwości powinieneś unikać starych klas. Ale kiedy musisz przekonwertować na / ze starej / nowej, możesz to zrobić, wywołując nowe metody add do starych klas.

Aby uzyskać więcej informacji na temat konwersji, zobacz mój Odpowiedź i sprytny diagram na inne pytanie. Konwertuj java.util.Date na jaki typ „java.time”? .

Przeszukiwanie stosu przepełnienia daje wiele setek przykładowych pytań i odpowiedzi na temat korzystania z java.time. Ale tutaj jest krótkie streszczenie.

Instant

Uzyskaj aktualny moment dzięki Instant. InstantKlasa reprezentuje moment na osi czasu w UTC z rozdzielczością nanosekund (do dziewięciu (9) cyfr ułamka dziesiętnego).

Instant instant = Instant.now();

ZonedDateTime

Aby zobaczyć ten sam jednoczesny moment przez soczewkę zegara ściennego z określonego regionu , zastosuj strefę czasową ( ZoneId), aby uzyskać ZonedDateTime.

Strefa czasowa

Określ prawidłową nazwę strefy czasowej w formacie continent/region, takie jak America/Montreal, Africa/Casablancalub Pacific/Auckland. Nigdy nie używaj 3-4 literowego skrótu, takiego jak ESTlub, ISTponieważ nie są to prawdziwe strefy czasowe, nie są znormalizowane, a nawet unikalne (!).

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone();

Offsetowy

Strefa czasowa to historia zmian regionu w przesunięciu względem UTC . Ale czasami dostajesz tylko przesunięcie bez pełnej strefy. W takim przypadku użyj OffsetDateTimeklasy.

ZoneOffset offset = ZoneOffset.parse( "+05:30" );
OffsetDateTime odt = instant.atOffset( offset );

Użycie strefy czasowej jest lepsze niż zwykłe przesunięcie.

LocalDateTime

„Lokalny” w Local…klasach oznacza dowolną lokalizację, a nie określoną lokalizację. Więc nazwa może być sprzeczna z intuicją.

LocalDateTime, LocalDatei LocalTimecelowo brakuje jakichkolwiek informacji o przesunięciu lub strefie czasowej. Więc oni nie reprezentują rzeczywistych momentów, są one nie punkty na osi czasu. W razie wątpliwości lub zamieszania użyj ZonedDateTimeraczej niż LocalDateTime. Przeszukaj stos przepełnienia, aby uzyskać więcej dyskusji.

Smyczki

Nie należy łączyć obiektów daty i godziny z łańcuchami reprezentującymi ich wartość. Możesz przeanalizować ciąg, aby uzyskać obiekt daty i godziny, i możesz wygenerować ciąg z obiektu daty i godziny. Ale ciąg nigdy nie jest samą datą i godziną.

Dowiedz się o standardowych formatach ISO 8601 , używanych domyślnie w klasach java.time.


O java.time

Środowisko java.time jest wbudowane w Javę 8 i nowsze wersje . Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , teraz w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj stos przepełnienia dla wielu przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Korzystając ze sterownika JDBC zgodnego z JDBC 4.2 lub nowszym, możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Nie potrzeba ciągów ani klas java.sql. *.

Gdzie można uzyskać klasy java.time?

Tabela, z której biblioteki java.time należy korzystać, w której wersji Java lub Android

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
10

W Javie 8 należy użyć nowego pakietu java.time .

Obiekty są niezmienne, brane są pod uwagę strefy czasowe i oszczędność światła dziennego.

Możesz utworzyć ZonedDateTimeobiekt ze starego java.util.Dateobiektu, takiego jak ten:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());
Ortomala Lokni
źródło
Dobrze jest zasugerować klasy java.time. Ale źle sugerować LocalDateTime. Klasa ta celowo traci wszelkie informacje o przesunięciu względem UTC i strefie czasowej. Ta klasa nie jest równoważna jak Datew UTC i Calendarma przypisaną strefę czasową. Zobacz moją odpowiedź i fajny diagram na inne pytanie. Konwertuj java.util.Date na jaki typ „java.time”? .
Basil Bourque,
9

Zawsze opowiadam się za czasem Jody . Dlatego.

  1. interfejs API jest spójny i intuicyjny. W przeciwieństwie do interfejsów API java.util.Date/Calendar
  2. nie ma problemów z wątkami , w przeciwieństwie do java.text.SimpleDateFormat itp. (Widziałem wiele problemów klientów związanych z nieświadomością, że standardowe formatowanie daty / godziny nie jest bezpieczne dla wątków)
  3. jest to podstawa nowych interfejsów API daty / godziny Java ( JSR310 , zaplanowanych dla Java 8. Zatem będziesz używać interfejsów API, które staną się podstawowymi interfejsami API Java.

EDYCJA: Klasy daty / godziny Java wprowadzone w Javie 8 są teraz preferowanym rozwiązaniem, jeśli można przeprowadzić migrację do Java 8

Brian Agnew
źródło
3
Kiedy ostatnio patrzyłem, JODA i JSR-310 wyglądały zupełnie inaczej, nawet jeśli oba są napisane przez Stephena Colebourne. To powiedziawszy, JODA zapozna cię ze złożonością problemów związanych z datą i czasem, które JSR-310 rozwiązuje również
oxbow_lakes 10.09.2009
2
Ponieważ pytanie dotyczyło użycia daty i kalendarza, a nie korzystania z biblioteki innej firmy, która dodaje ryzyko zależności od jednego dostawcy do projektu.
Archimedes Trajano,
2
Utrzymuję, że najlepszą praktyką jest po prostu nie korzystać z tych zajęć
Brian Agnew,
3
Biorąc pod uwagę znane problemy z klasami java.util.Date i Calendar, sugerowanie Joda-Time (lub JSR 310) wydaje mi się odpowiednie i odpowiedzialne. Nie mówimy o kwestii smaku lub stylu estetycznego. Gdyby ktoś zapytał, czy powinien wziąć czerwony samochód, czy srebrny samochód, a wiedziałem, że czerwony samochód ma zepsutą oponę, a srebrny samochód ma zepsuty radiator, czy powinienem wybrać samochód, czy powinienem wezwać taksówkę? Odpowiedź na to pytanie powinna obecnie wydawać się oczywista, ponieważ nawet Sun / Oracle zdecydowało się zostawić tych śmieci i kupić nowy samochód: JSR 310: API Data i godzina.
Basil Bourque,
1
Do Twojej wiadomości, projekt Joda-Time jest teraz w trybie konserwacji , doradzając migrację do klas java.time . Zobacz samouczek Oracle .
Basil Bourque,
8

Trochę późno na imprezie, ale Java ma nowy interfejs API Data Time w JDK 8. Możesz zaktualizować swoją wersję JDK i zastosować standard. Nigdy więcej niechlujnej daty / kalendarza, żadnych słoików innych firm.

Silviu Burcea
źródło
1

Data powinna zostać ponownie opracowana. Zamiast być długim intergerem, powinien zawierać rok, miesiąc, datę, godzinę, minutę, sekundę jako osobne pola. Może być nawet dobrze przechowywać kalendarz i strefę czasową, z którą ta data jest powiązana.

W naszej naturalnej rozmowie, jeśli umówimy się na spotkanie w dniu 1 listopada 2013 r. O godzinie 13.00 czasu nowojorskiego, jest to data i godzina. To NIE jest kalendarz. Powinniśmy być w stanie rozmawiać w ten sposób również w Javie.

Gdy data jest przechowywana jako długa liczba całkowita (w miliardach sekund od 1 stycznia 1970 roku lub coś takiego), obliczenie jej bieżącej daty zależy od kalendarza. Różne kalendarze podadzą inną datę. Wynika to z możliwości podania czasu bezwzględnego (np. 1 bilion sekund po Wielkim Wybuchu). Ale często potrzebujemy również wygodnego sposobu rozmowy, takiego jak obiekt podsumowujący rok, miesiąc itp.

Zastanawiam się, czy istnieją nowe postępy w Javie w celu pogodzenia tych 2 celów. Może moja wiedza java jest za stara.

użytkownik 2835562
źródło
Fakt, że możesz przechowywać tę samą chwilę w czasie, ale raportować inną godzinę / minutę / dzień / tydzień / rok / foo w oparciu o różne systemy kalendarza, jest mocną stroną, a nie słabością. Odzwierciedla (złożoną) rzeczywistość.
ThrawnCA
Rzeczywiście Datezostał ponownie opracowany; zastąpiony przez java.time.Instantklasę. I Calendar/ GregorianCalendarzostał zastąpiony przez java.time.ZonedDateTimeklasę.
Basil Bourque,
0

Btw „data” jest zwykle oznaczana jako „przestarzała / przestarzała” (nie wiem dokładnie dlaczego) - coś tam jest napisane tam Java: Dlaczego konstruktor daty jest przestarzały i czego mam używać zamiast tego?

Wygląda na to, że jest to problem konstruktora - tylko przez nową datę (int rok, int miesiąc, int dzień) , zalecany sposób to przez kalendarz i ustaw parametry osobno .. ( Calendar cal = Calendar.getInstance (); )

xxxvodnikxxx
źródło
0

Korzystam z Kalendarza, gdy potrzebuję określonych operacji w datach, takich jak przemieszczanie się w czasie, ale Data jest dla mnie pomocna, gdy musisz sformatować datę w celu dostosowania swoich potrzeb, niedawno odkryłem, że Locale ma wiele przydatnych operacji i metod. Korzystam teraz z ustawień regionalnych!

Brian Nelson
źródło
Do Twojej wiadomości, kłopotliwe Calendari Datezajęcia zostały wyparte lata temu przez zajęcia java.time . Nie trzeba nigdy używać Datelub Calendar. I Localenie ma nic wspólnego ze znaczeniem obiektów daty i godziny. A Localesłuży tylko do określenia języka ludzkiego i norm kulturowych, które mają być używane podczas lokalizacji podczas generowania tekstu reprezentującego wartość obiektu daty i godziny.
Basil Bourque,