Java Tarihi ve Takvim Karşılaştırması


364

Birisi lütfen mevcut "en iyi uygulama" Dateve Calendartürleri hakkında tavsiye verebilir .

Yeni kod yazarken, her zaman iyilik etmek en iyisidir Calendarüzerinde Dateveya orada şartlar nerede Datedaha uygun veri türü nedir?



2
Bilginize, gibi zahmetli eski tarih-saat sınıfları java.util.Date, java.util.Calendarve java.text.SimpleDateFormatsupplanted şimdi mirası, java.time sınıfları. Java.time işlevinin çoğu , ThreeTen-Backport projesinde Java 6 ve Java 7'ye geri yüklenmiştir . ThreeTenABP projesinde daha önceki Android için daha da uyarlandı . Bkz . ThreeTenABP nasıl kullanılır… .
Basil Bourque

2
FYI, Joda-Time projesi (başka bir yorumda bahsedilmiştir) şimdi bakım modundadır ve ekip java.time sınıflarına geçişi tavsiye etmektedir . Oracle'ın Öğreticisine bakın .
Basil Bourque

Yanıtlar:


377

Tarih daha basit bir sınıftır ve temel olarak geriye dönük uyumluluk nedeniyle vardır. Belirli tarihler ayarlamanız veya tarih aritmetiği yapmanız gerekiyorsa, bir Takvim kullanın. Takvimler ayrıca yerelleştirmeyi de ele alır. Tarihin önceki tarih düzenleme işlevleri kullanımdan kaldırılmıştır.

Şahsen ya milisaniye cinsinden zamanı uzun (ya da uygunsa Uzun) ya da bir seçenek olduğunda Takvim'i kullanma eğilimindeyim.

Hem Tarih hem de Takvim değiştirilebilir, bu da bir API'de kullanıldığında sorunlar sunma eğilimindedir.


5
Bilginize gibi korkunç zahmetli eski tarih-saat sınıfları java.util.Date, java.util.Calendarve java.text.SimpleDateFormatşimdi mirası supplanted, java.time sonra Java 8 ve yerleşik sınıflara. Oracle'ın Öğreticisine bakın .
Basil Bourque

67

Yeni kod için en iyi yol (politikanız üçüncü taraf koduna izin veriyorsa) Joda Time kitaplığını kullanmaktır .

Hem Tarih hem de Takvim'de , yeni kod için iyi çözümler olmayan pek çok tasarım sorunu var.


7
İkinci kez joda zamanı kullanma önerisi. Kullanımı ve anlaşılması daha kolaydır ve kullanabileceğiniz çok daha fazla işlevsellik sunar.
Jeroen van Bergen

30
Joda Time'ın standart JDK sınıflarıyla kullanılıp kullanılmayacağı hakkında tartışma için bkz. Stackoverflow.com/questions/589870/…
Jonik

3
Aşağı oyları hak edip etmediğini bilmiyorum, ama soruyu cevaplamıyor. Bir yorum olarak daha iyi olabilir.
IcedDante

7
Soru, Date ve Calendar'ın bir projeye tek bir satıcı bağımlılığı riski ekleyen bir üçüncü taraf kitaplığı kullanmama ile ilgili olmasıydı.
Arşimet Trajano

3
Java.time paketi Java 8 ile kullanıma sunulana kadar "en iyi yol" OLDU
DaBlick

58
  • Dateve Calendargerçekten aynı temel kavramdır (her ikisi de bir anı temsil eder ve altta yatan bir longdeğerin etrafını sarar ).

  • Kişi , haftanın günü ve günün saati gibi şeyler hakkında somut gerçekler sunduğu gibi Calendar, aslında olduğundan daha kırılmışDate olduğunu iddia edebilirken , timeZonemülkünü değiştirirseniz , beton boşluklara dönüşür! Her iki nesne de bu nedenle yıl-ay-gün veya günün saati deposu olarak gerçekten kullanışlı değildir .

  • CalendarSadece verildiğinde Dateve TimeZonenesnelerde sizin için hesaplamalar yapacak bir hesap makinesi olarak kullanın . Bir uygulamada özellik yazarken kullanımından kaçının.

  • Görüntüleme Dizeleri oluşturmak SimpleDateFormatiçin TimeZoneve ile birlikte kullanın Date.

  • Maceraperest hissediyorsanız, Joda-Time'ı kullanın, ancak gereksiz bir şekilde karmaşık IMHO olmasına rağmen ve yakında herhangi bir olayda JSR-310 tarih API'sının yerini alacaktır.

  • Daha önce, tarih hesaplamaları için başlık altında YearMonthDaykullanan kendi sınıfınızı yuvarlamanın zor olmadığını cevapladım Calendar. Öneri için reddedildim, ancak hala geçerli olduğuna inanıyorum çünkü Joda-Time (ve JSR-310 ) çoğu kullanım durumu için gerçekten çok karmaşık.


1
JSR310 için bir zaman dilimi var mı? Java 7'de olacaktı, ama şimdi böyle olmadığını düşünüyorum.
Brian Agnew

@Brian - bu posta listesinde kesinlikle çok sessiz gitti!
oxbow_lakes

Sadece kontrol ediyoruz, Hareketsiz kaldı, yani 18 ayda bir kilometre taşı taslağı yayınlamadılar :-(
Brian Agnew

Posta listesindeki en son yorum Temmuz ve Stephen tarafından yapılmıştır, bu yüzden proje muhtemelen hala
ilerliyor

Kabul. Date'i değişmez bir nesne olarak güvenli bir şekilde ve Tarihleri ​​değiştirmek için Takvim'i nasıl kullanacağınızı biliyorsanız, çoğu kişi güvende olmalıdır. Çok iş parçacıklı kodda SimpleDateFormat kullanırken dikkatli olun.
cwash

25

Tarih, bir tarih nesnesini depolamak için en iyisidir. Bu ısrarcı, Serialize olan ...

Takvim Tarihleri ​​düzenlemek için en iyisidir.

Not: biz de bazen java.lang.Long Tarih üzerinde uzun, çünkü Tarih değiştirilebilir ve bu nedenle iş parçacığı güvenli değildir. Bir Date nesnesinde, ikisi arasında geçiş yapmak için setTime () ve getTime () kullanın. Örneğin, uygulamada sabit bir Tarih (örnekler: sıfır 1970/01/01 veya 2099/12/31 olarak ayarladığınız bir uygulama END_OF_TIME; bunlar, null değerleri başlangıç ​​ve bitiş zamanı olarak değiştirmek için çok yararlıdır, özellikle veritabanında kalmaya devam ettiğinizde, SQL null'lara özgüdür).


Değişmez hakkında java.lang.Long
alıyoruz

17

Mümkünse genellikle Date kullanıyorum. Değişken olmasına rağmen, mutasyoncular aslında kullanımdan kaldırılmıştır. Sonunda temel olarak tarih / saati temsil edecek uzun bir süre sarar. Tersine, değerleri değiştirmek zorunda kalsam Takvimler'i kullanırdım.

Bunu şu şekilde düşünebilirsiniz: StringBuffer'ı yalnızca kolayca yönetebileceğiniz ve ardından toString () yöntemini kullanarak Dizelere dönüştürmeniz gerektiğinde kullanın. Aynı şekilde Takvim'i yalnızca geçici verileri işlemem gerektiğinde kullanıyorum.

En iyi uygulama için, etki alanı modelinin dışında mümkün olduğunca değişmez nesneleri kullanma eğilimindeyim . Herhangi bir yan etki olasılığını önemli ölçüde azaltır ve sizin için bir JUnit testi yerine derleyici tarafından yapılır. Bu tekniği sınıfınızda özel final alanları oluşturarak kullanırsınız .

Ve StringBuffer benzetmesine geri dönüyorum. Takvim ve Tarih arasında nasıl dönüşüm yapacağınızı gösteren bazı kodlar

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);

Evet, değişmez nesneler tarih-saat çalışması için mantıklıdır. Java.time yerini sınıfları Date/ CalendarDeğişken olmayan objeler desen kullanın.
Basil Bourque

Bu doğru olabilir, ancak 2010'da değil.
Archimedes Trajano

Evet. Ancak şu anda bu sayfayı okuyan binlerce kişi var, şu ana kadar 150.000'in üzerinde. Benim yorumum onlar için bir not, senin bir eleştiri değil.
Basil Bourque

Biliyorum, bu yüzden diğer cevabı iptal ettim. Bununla birlikte, hala yukarıdaki cevaba ihtiyaç duyan eski JDK'larla uğraşması gereken bazı insanlar var.
Arşimet Trajano

1
Aslında, Java 6 ve 7 için ThreeTen-Backport projemiz var. Bu, java.time işlevselliğinin çoğunu neredeyse aynı API ile getirir . Bu yüzden bu korkunç eski tarih-saat sınıflarını kullanmaya gerek yoktur.
Basil Bourque

15

Dates zaman içinde değişmez noktalar olarak kullanılmalıdır; Calendars değiştirilebilir, ve bir son tarih bulmak için diğer sınıflarla işbirliği gerekiyorsa geçilebilir ve değiştirilebilir. Onlara benzer düşünün Stringve StringBuildernasıl kullanılmaları gerektiğini düşündüğümü anlayacaksınız.

(Ve evet, Date'in teknik olarak değişmez olmadığını biliyorum, ancak niyet, değişmez olmamalı ve hiçbir şey kullanımdan kaldırılan yöntemleri çağırmıyorsa, öyle.)


Evet, değişmez nesneler tarih-saat çalışması için mantıklıdır. Java.time yerini sınıfları Date/ CalendarDeğişken olmayan objeler desen kullanın. Özellikle, Instantbirinci cümledeki java.util.Dateve ZonedDateTimecümledeki Calendar/ GregorianCalendar.
Basil Bourque

15

tl; Dr.

mevcut "en iyi uygulamayı" tavsiye eder DateveCalendar

en iyisi her zaman lehine olan CalendaraşırıDate

Bu eski sınıflardan tamamen kaçının . Kullanım java.time yerine sınıfları.

Java'da hem modern hem de eski tüm tarih-saat türlerinin tablosu

ayrıntılar

Ortomala tarafından cevap Lokni çağdaş kullanarak önermek doğru java.time oldukça zahmetli eski eski tarih-saat sınıfları (daha sınıflar Date, Calendarvb.) Ancak bu Cevap yanlış sınıfı eşdeğer olarak önermektedir (bu Cevap hakkındaki yorumuma bakın).

Java.time kullanma

Java.time sınıfları , eski tarih-saat sınıfları, gece ve gündüz farkı üzerinde büyük bir gelişmedir. Eski sınıflar kötü tasarlanmış, kafa karıştırıcı ve zahmetlidir. Mümkün olduğunca eski sınıflardan kaçınmalısınız. Ancak eski / yeniye / yenisinden dönüştürmeniz gerektiğinde, eski sınıflara eklenen yeni yöntemleri çağırarak bunu yapabilirsiniz .

Dönüştürme hakkında daha fazla bilgi için, başka bir Soruya cevap ve nifty şemasına bakın , java.util'i dönüştürün. .

Yığın Taşması aranması, java.time kullanımıyla ilgili yüzlerce örnek Soru ve Cevap verir. Ama işte kısa bir özet.

Instant

Mevcut anı bir ile alın Instant. InstantSınıfı zaman çizelgesinde bir anı temsil UTC çözünürlüğe sahip nanosaniye (ondalık kesir dokuz (9) haneye kadar).

Instant instant = Instant.now();

ZonedDateTime

Aynı anda , belirli bir bölgenin duvar saati süresinin merceğinden aynı anda görmek için , bir saat dilimi ( ZoneId) uygulayın ZonedDateTime.

Saat dilimi

Bir belirtme uygun bir zaman dilimi adı biçiminde continent/regiongibi America/Montreal, Africa/Casablancaya da Pacific/Auckland. Hiçbir zaman gibi 3-4 harfli bir kısaltma kullanın ESTveya ISToldukları gibi değil , gerçek zaman dilimleri, değil standardize ve hatta benzersiz değil (!).

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

dengelemek

Saat dilimi, bir bölgenin UTC'den uzaklığındaki değişiklik geçmişidir . Ama bazen sadece tam bölge olmayan bir ofset verilir. Bu durumda OffsetDateTimesınıfı kullanın .

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

Bir zaman diliminin kullanılması, sadece bir ofsetin kullanılması tercih edilir.

LocalDateTime

Local…Sınıflardaki “Yerel” , belirli bir yer değil, herhangi bir yer anlamına gelir . Yani adı karşı sezgisel olabilir.

LocalDateTime, LocalDateve LocalTimeofset veya saat dilimi hakkında herhangi bir bilgi içermemesi. Onlar do Yani değil gerçek anları temsil, bunlar değil puan cetvelinde. Şüphe veya karmaşa, kullandığınızda ZonedDateTimeyerine LocalDateTime. Daha fazla tartışma için Yığın Taşması'nda arama yapın.

Teller

Tarih ve saat nesnelerini, değerlerini temsil eden dizelerle sınırlamayın. Bir tarih-saat nesnesi almak için bir dizeyi ayrıştırabilir ve bir tarih-saat nesnesinden bir dize oluşturabilirsiniz. Ama dize asla tarih-zamanın kendisi değildir.

Java.time sınıflarında varsayılan olarak kullanılan standart ISO 8601 biçimleri hakkında bilgi edinin .


Hakkında java.time

Java.time çerçevesi daha sonra Java 8 ve yerleşiktir. Bu sınıflar zahmetli eski yerini mirası gibi tarih-saat sınıfları java.util.Date, Calendar& SimpleDateFormat.

Artık bakım modunda olan Joda-Time projesi java.time sınıflarına geçişi tavsiye ediyor .

Daha fazla bilgi için Oracle Eğiticisine bakın . Ve birçok örnek ve açıklama için Stack Overflow'da arama yapın. Spesifikasyon JSR 310'dur .

JDBC 4.2 veya sonraki bir sürümüyle uyumlu bir JDBC sürücüsü kullanarak , java.time nesnelerini doğrudan veritabanınızla değiştirebilirsiniz. Dizelere veya java.sql. * Sınıflarına gerek yoktur.

Java.time sınıflarını nereden edinebilirsiniz?

Hangi Java veya Android sürümüyle kullanılacak java.time kütüphanesinin tablosu

ThreeTen-Ekstra proje ek sınıfları ile java.time uzanır. Bu proje, java.time'a gelecekteki olası eklemeler için bir kanıt zeminidir. Burada bazı yararlı sınıfları gibi bulabilir Interval, YearWeek, YearQuarter, ve daha .


10

Java 8 ile yeni java.time paketi kullanılmalıdır.

Nesneler değiştirilemez, saat dilimleri ve gün ışığından yararlanma dikkate alınır.

Bunun gibi ZonedDateTimeeski bir nesneden nesne oluşturabilirsiniz java.util.Date:

    Date date = new Date();
    ZonedDateTime zonedDateTime = date.toInstant().atZone(ZoneId.systemDefault());

Java.time sınıfları önermek güzel. Ama önermek kötü LocalDateTime. Bu sınıf, UTC'den ve saat dilimi ile ilgili tüm bilgileri bilerek kaybeder. Böylece bu sınıf UTC'deki gibi eşdeğer değildirDate ve Calendaratanmış bir saat dilimi vardır. Bkz benim cevap ve şık diyagramı , başka Sorununa neyi “java.time” türüne java.util.Date dönüştürme? .
Basil Bourque

9

Her zaman Joda-time'ı savunuyorum . İşte nedeni.

  1. API tutarlı ve sezgiseldir. Java.util.Date/Calendar API'larının aksine
  2. java.text.SimpleDateFormat vb. aksine, iş parçacığı sorunlarından muzdarip değildir (Standart tarih / saat biçimlendirmesinin iş parçacığı için güvenli olmadığını fark etmemeyle ilgili birçok müşteri sorunu gördüm)
  3. Java 8 için planlanan yeni Java tarih / saat API'larının ( JSR310) temelidir. Böylece çekirdek Java API'ları olacak API'ları kullanacaksınız.

DÜZENLEME: Java 8'e geçiş yapabiliyorsanız, Java 8 ile sunulan Java tarih / saat sınıfları artık tercih edilen çözümdür


3
En son baktığımda, ikisi de Stephen Colebourne tarafından yazılsa bile , JODA ve JSR-310 çok farklı görünüyordu . Bununla birlikte, JODA, JSR-310'un da çözdüğü tarih-saat problemlerinin karmaşıklığını tanıtacaktır
oxbow_lakes

2
Soru, Date ve Calendar'ın bir projeye tek bir satıcı bağımlılığı riski ekleyen bir üçüncü taraf kitaplığı kullanmama ile ilgili olmasıydı.
Arşimet Trajano

2
Ben en iyi uygulamayı sadece bu sınıfları kullanmak değil korumak
Brian Agnew

3
Java.util.Date ve Calendar sınıflarıyla ilgili bilinen sorunlar göz önüne alındığında, Joda-Time'ı (veya JSR 310) önermek bana uygun ve sorumlu görünüyor. Bir tat ya da estetik tarzdan bahsetmiyoruz. Birisi kırmızı arabayı mı yoksa gümüş arabayı mı almaları gerektiğini sorduysa ve kırmızı arabanın patlak bir lastiğe ve gümüş arabanın yanmış bir radyatöre sahip olduğunu biliyorsam, bir araba seçmeli miyim yoksa taksi çağırmayı önerir miyim? Bu sorunun cevabı, Sun / Oracle'ın bile bu çöpleri geride bırakmaya ve yeni bir araba satın almaya karar verdiği için bugünlerde açıkça görülmelidir: JSR 310: Tarih ve Saat API'sı.
Basil Bourque

1
FYI, Joda-Time projesi şu anda bakım modunda ve java.time sınıflarına geçişi tavsiye ediyor . Oracle'ın Öğreticisine bakın .
Basil Bourque

8

Partide biraz geç, ancak Java'nın JDK 8'de yeni bir Date Time API'sı var. JDK sürümünüzü yükseltmek ve standardı benimsemek isteyebilirsiniz. Artık dağınık tarih / takvim yok, artık 3. parti kavanoz yok.


1

Tarih yeniden geliştirilmelidir. Uzun bir tamsayı olmak yerine, yılı, ayı, tarihi, saati, dakikayı, saniyeyi ayrı alanlar olarak tutmalıdır. Bu tarihin ilişkilendirildiği takvimi ve saat dilimini saklamak bile iyi olabilir.

Doğal sohbetimizde, 1 Kasım 2013 13:00 NY Saatinde bir randevu ayarladıysanız, bu bir DateTime. Bu bir takvim DEĞİLDİR. Bu yüzden Java'da da bu şekilde sohbet edebilmeliyiz.

Tarih uzun bir tamsayı olarak saklandığında (1 Ocak 1970'ten beri mili saniye cinsinden), geçerli tarihinin hesaplanması takvime bağlıdır. Farklı takvimler farklı tarihler verir. Bu, mutlak bir zaman verme olasılığından kaynaklanmaktadır (örneğin, Big Bang'den 1 trilyon saniye sonra). Ancak çoğu zaman, yıl, ay vb. İçeren bir nesne gibi uygun bir konuşma şekline de ihtiyacımız var.

Java'da bu 2 hedefi uzlaştırmak için yeni gelişmeler olup olmadığını merak ediyorum. Belki de java bilgim çok eski.


Aynı anı zamanında saklayabilmeniz, ancak farklı takvim sistemlerine göre farklı saat / dakika / gün / hafta / yıl / foo bildirebilmeniz bir güçtür, bir zayıflık değildir. (Karmaşık) gerçekliği yansıtır.
ThrawnCA

Gerçekten de Dateyeniden geliştirildi; java.time.Instantsınıf ile değiştirilir . Ve Calendar/ GregorianCalendaryerine java.time.ZonedDateTimesınıf eklendi.
Basil Bourque


0

Takvim'i, zaman içinde hareket etmek gibi tarihler üzerinde bazı özel işlemlere ihtiyaç duyduğumda kullanıyorum, ancak Tarih İhtiyaçlarınızı uyarlamak için tarihi biçimlendirmeniz gerektiğinde yararlı buluyorum, son zamanlarda Locale'in çok sayıda yararlı işlem ve yöntem olduğunu keşfettim. Şu anda Locale kullanıyorum!


FYI, zahmetli Calendarve Datedersler yıllar önce java.time dersleri ile tamamlandı. Hiç kullanmaya gerek yok Dateveya Calendar. Ve Localetarih-saat nesnelerinin anlamları ile ilgisi yoktur. A Locale, yalnızca bir tarih-saat nesnesinin değerini temsil etmek için metin oluştururken yerelleştirmede kullanılacak insan dilini ve kültürel normları belirtmek için kullanılır.
Basil Bourque
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.