Java'da zaman olmadan nasıl bir Tarih alabilirim?


235

Geçerli tarihi zaman damgası olmadan almak için Yığın Taşması sorusu Java programından devam :

Bir Date nesnesini zaman olmadan almanın en etkili yolu nedir? Bu ikisinden başka bir yol var mı?

// Method 1
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateWithoutTime = sdf.parse(sdf.format(new Date()));

// Method 2
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
dateWithoutTime = cal.getTime();

Güncelleme :

  1. Hakkında biliyordum Joda-Time'ı ; Ben sadece böyle bir basit (bence) görev için ek kütüphane kaçınmaya çalışıyorum. Ama şimdiye kadar verilen cevaplara dayanarak Joda-Time son derece popüler görünüyor, bu yüzden bunu düşünebilirim.

  2. By verimli , ben geçici nesne önlemek istiyorum demek Stringtarafından kullanılan oluşturulmasını method 1arada method 2yerine çözümün kesmek gibi görünüyor.


1
Verimli? Örneğin, method1 tarafından sağlanandan daha fazla verimliliğe mi ihtiyacınız var?
Johan Sjöberg

2
"Verimli" ile ne demek istiyorsun? Tarih temelde uzun bir yazımdır, bunu bundan daha az bellekte yapamazsınız. "Uygun" demek istiyorsan, JODA zamanı gitmenin yoludur.
millimoose

3
+1 Kesinlikle sahip olduğum soru.
Alba Mendez

1
Yöntem 2'yi seviyorum. Bir yardımcı program sınıfında statik bir yöntem oluşturun ve sadece kullanın. Yıllardır bu yaklaşım benim.
Wilson Freitas

1
"Güncelleme 1" inizi nitelendirmek: "bu kadar basit bir görev" olsaydı, sanırım Sun böylesine korkunç ve verimsiz bir API'ye gelmezdi ve siz (ve diğer birçok kişi) bu soruyu sormazdı hiç ;-)
Flávio Etrusco

Yanıtlar:


108

Kesinlikle Do sahip kullanımına java.util.Date? Ben ediyorum iyice kullanmanızı öneririz Joda Saat veya java.timeyerine Java 8'den paketi. Özellikle, Tarih ve Takvim her zaman belirli bir anı temsil ederken , "sadece bir tarih" gibi bir kavramı yoktur, Joda Time'ın bunu temsil eden bir türü vardır ( LocalDate). Gerçekte yapmaya çalıştığınız şeyi temsil eden türleri kullanabiliyorsanız, kodunuz daha açık olacaktır.

Joda Time'ı kullanmak için veya java.timeyerleşik java.utiltürler yerine başka birçok neden var - bunlar genellikle çok daha iyi API'lardır. java.util.DateGerekirse her zaman kendi kodunuzun sınırlarında a / 'dan dönüştürebilirsiniz , örneğin veritabanı etkileşimi için.


75
Kurumsal uygulamalarda her zaman başka kitaplıklar ekleme / kullanma seçeneğimiz yoktur. Joda Time'a olan işaretçiyi takdir ediyorum, ancak standart Java'yı kullanarak tarih bölümünü almanın orijinal sorununun bir cevabı değil. Teşekkürler. Chathuranga'nın cevabını onaylıyor.
noogrub

3
@noogrub: Chathugranga'nın cevabı, bir Datenesnenin nasıl alınacağını soran orijinal soruya cevap vermez - bu cevap, bir tarihi bir dizeye formatlar , aynı şey değildir. Temel olarak, a'nın hangi tarihte Dateolduğunu sormak, daha fazla bilgi içermeyen anlamsız bir sorudur: kullandığınız saat dilimi ve takvim sistemi.
Jon Skeet

7
"Kurumsal uygulamalarda her zaman başka kütüphaneler ekleme / kullanma seçeneğimiz yoktur". Gerçekten mi ? Üçüncü taraf kütüphanelerini hiç kullanamayacağınızı mı düşünüyorsunuz?
Brian Agnew

3
@BrianAgnew noogrub'ın yorumu teknik olmayan kısıtlamalarla ilgili gibi görünüyor, sanırım
Jose_GD

3
Bugünün bakış açısından: " Joda-Time , Java SE 8'den önce Java için fiili standart tarih ve saat kütüphanesidir. Kullanıcılardan şimdi java.time'a (JSR-310) geçmeleri istenir."
Drux

66

Bugünün tarihini şu şekilde ayarlanmış olarak alıyorum 00:00:00:

DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));

28
Bu, orijinal soruda zaten önerilen "yöntem 1" den ne şekilde farklıdır?
Chris

Bunun hangi saat diliminde oluştuğunu ele almaz (JVM'nin keyfi varsayılan saat dilimine bırakılır).
Darrell Teague

58

Sen kullanabilirsiniz DateUtils.truncate Apache Commons kütüphaneden.

Misal:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)

3
Yeni bir kütüphane ekleyecekseniz, Apache Commons yerine Joda olsun.
Dibbeke

6
+1 @Dibbeke Fark sadece bir kütüphane yerine başka bir kütüphane eklemeniz değil. Bazen sadece yeni bir kütüphaneyi, bir tarihten itibaren zamanı kısaltmanın önemsiz görevi için öğrenmek istemez. Ya da bazen Tarih ve Takvimi Joda tarihleriyle karıştırarak bazen eskisini, bazen ikincisini kullanarak kod istemez. Ya da bu kadar önemsiz bir amaç için iyi çalışan Tarih / Takvim tabanlı kodu başka bir kütüphaneyle değiştirmeyi göze alamaz / haklı gösteremezsiniz.
Joda'yı

Genius! Bana çok yardımcı oldu
Thiesen

37

Bu ikisinden başka bir yol var mı?

Evet var.

LocalDate.now( 
    ZoneId.of( "Pacific/Auckland" ) 
)

java.time

Java 8 ve üstü, yerleşik yeni java.time paketi ile birlikte gelir . Bkz. Öğretici . Çok java.time işlevselliği Java 6 ve 7 geri-taşındıktan ThreeTen-backport ve ayrıca içinde Android'e uyarlanmıştır ThreeTenABP .

Joda-Time'a benzer şekilde , java.time, LocalDategünün saati ve saat dilimi olmadan salt tarih değerini temsil eden bir sınıf sunar .

Saat diliminin belirli bir tarihi belirlemek için kritik olduğunu unutmayın . Örneğin, Paris'te gece yarısının inişinde, tarih Montréal'de hala “dün”.

LocalDate today = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;

Varsayılan olarak, java.time, tarih veya tarih-saat değerinin dize ile temsil edilmesinde ISO 8601 standardını kullanır . (Joda-Time ile bir başka benzerlik.) Öyleyse toString()benzer metin üretmek için arayın 2015-05-21.

String output = today.toString() ; 

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 .

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

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 .


1
Saat diliminden bahsettiğiniz için teşekkürler . Bana, "hangi gün" olduğu mutlak bir kavram değildi.
ToolmakerSteve

@ToolmakerSteve Tarihin alınması her zaman bir saat dilimi içerir. Ancak işin püf noktası, bir saat dilimi belirtmezseniz, JVM'nizin geçerli varsayılan saat diliminin tarihi belirlemede otomatik olarak uygulanmasıdır. Bunun da ötesinde, JVM'nin geçerli varsayılan saat dilimi her an değişebilir ! JVM içindeki herhangi bir uygulamanın iş parçacığındaki herhangi bir kod, TimeZone.setDefaultçalışma zamanı sırasında arayabilir ve bu JVM'de çalışan diğer tüm kodları hemen etkileyebilir. Hikayenin Ahlakı: Her zaman bir saat dilimi belirtin.
Basil Bourque

22

En basit yol:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);

5
Benim için şu anda: "Cts 19 Şubat 01 : 00: 00 CET 2011". Bunu kullanmak istiyorsanız, sadece UTC ile.
Chris Lercher

4
3. satır long dateOnly = (currentTime / millisInDay) * millisInDay;yazmakla aynı şey değil long dateOnly = currentTime;mi?
Chris

5
Tamsayı matematik yüzünden değil. Daha çok Math.floor (currentTime / millisInDay) * millisInDay gibi düşünün. Zamanı etkili bir şekilde bu şekilde 00:00:00 olarak ayarlıyor.
Nicholas Flynt

2
Bu çözüm muhtemelen çoğu uygulama için iyidir, ancak bir günün 60 * 60 * 24 * 1000 olduğu varsayımı her zaman doğru değildir. Örneğin, bazı günlerde artık saniyeleriniz olabilir.
Pierre-Antoine

1
Bu tartışmasız diğer 1 ve 2 hatlı açık ve özlü yöntemlere göre en geniş ve tavsiye edilmeyen yoldur.
Darrell Teague

22

Bu soruların standart cevabı Joda Time'ı kullanmaktır . API daha iyidir ve biçimlendiricileri ve ayrıştırıcıları kullanıyorsanız, sezgisel olmayan iplik güvenliği eksikliğinden kaçınabilirsiniz SimpleDateFormat.

Joda kullanmak, şunları yapabileceğiniz anlamına gelir:

LocalDate d = new LocalDate();

Güncelleme :: Java 8 kullanarak bu elde edilebilir

LocalDate date = LocalDate.now();

Java 8'deki yeni java.time paketi de LocalDateJoda-Time'a benzer bir sınıf sunuyor .
Basil Bourque

1
İdeal DateTimeZoneolarak bu LocalDate yapıcısına geçersiniz . Paris Montréal'den önce yeni bir tarihe başladığı için, geçerli tarihi belirlemek saat dilimine bağlıdır. Saat dilimini atlarsanız, JVM'nizin varsayılan saat dilimi uygulanır. Genellikle belirtmek, varsayılana güvenmekten daha iyidir.
Basil Bourque

8

Bunu yapmanın basit bir yolu:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));

4
Bu cevap soruyu yanıtlayamıyor. Biçimlendirilmiş bir dize elde etmek hedef değildi.
Basil Bourque

7

Temelde bir tarihe değil, belirli bir milisaniyeye eşlendiği için standart java çalışma zamanındaki Tarih yordamlarına ilişkin zaman damgası olmadan bir tarih hakkında konuşmak mantıklı değildir. Bahsedilen milisaniyenin kendiliğinden günün saati vardır, bu da onu Yaz Saati Uygulaması ve diğer takvim ayarlamaları gibi saat dilimi sorunlarına karşı savunmasız hale getirir. Bkz. Bunları neden iki kez çıkarmak (1927'de) garip bir sonuç veriyor? ilginç bir örnek için.

Milisaniye yerine tarihlerle çalışmak istiyorsanız, başka bir şey kullanmanız gerekir. Java 8 için tam olarak ne istediğinizi sağlayan yeni bir yöntem kümesi vardır. Java 7 ve öncesi için http://www.joda.org/joda-time/ adresini kullanın.


3
Not: "Gece yarısı tarihi" diyen bu yaklaşımlar, yaz saati uygulaması ve birden fazla saat dilimini iyi işlemez.
Thorbjørn Ravn Andersen

Bunu onaylıyorum, uygulamamda tarihleri ​​bir gün artırıyordum ve bunu DST ile saat diliminde (ülkem DST kullanmıyor) kullanıcılardan bir hata raporu ile öğrendim. DST başlar gün benim app 12 yerine 11 saat ekler. Belki de bir "no time" tarihi için saat olarak öğlen kullanmak daha iyidir?
Jose_GD

1
@Jose_GD En iyisi hala bir hack. Youtube.com/watch?v=-5wpm-gesOY eğlenceli bulabilirsiniz .
Thorbjørn Ravn Andersen

@ Thorbjorn, haklısın, sadece JodaTime'den kaçınmak istedin çünkü benim için sadece bir özellik sesi için bir kütüphane ekledi. Gerçekten komik olan videoyu biliyordum.
Jose_GD

1
@Jose_GD Buradaki nokta, yaklaşımınızın bir hata olarak değerlendirileceği gerçek bir gerçek yaşam kullanım durumu olmasıydı. Eğer bir tane bulursanız, daha fazlası olabilir ... Joda'nın bunu nasıl ele aldığını bilmiyorum, ama bir bakabilirsiniz. Ayrıca Java 8'in, incelemek isteyebileceğiniz yeni bir tarih-saat kütüphanesi (Joda ile ilgili deneyimlere dayanarak) getirdiğini unutmayın.
Thorbjørn Ravn Andersen

4

Kesinlikle en doğru yol değil, ancak tarihi zaman olmadan almak için hızlı bir çözüme ihtiyacınız varsa ve bir üçüncü taraf kütüphanesi kullanmak istemiyorsanız, bunu yapmalısınız

    Date db = db.substring(0, 10) + db.substring(23,28);

Yalnızca görsel amaçlı tarihe ihtiyacım vardı ve Joda'yı bulamadım.


4
// 09/28/2015
System.out.println(new SimpleDateFormat("MM/dd/yyyy").format(Calendar.getInstance().getTime()));

// Mon Sep 28
System.out.println( new Date().toString().substring(0, 10) );

// 2015-09-28
System.out.println(new java.sql.Date(System.currentTimeMillis()));

// 2015-09-28
// java 8
System.out.println( LocalDate.now(ZoneId.of("Europe/Paris")) ); // rest zones id in ZoneId class

3

Bildiğim kadarıyla, sadece standart JDK kullanıyorsanız bunu başarmanın daha kolay bir yolu yoktur.

Elbette, yöntem2'deki bu mantığı, burada toBeginningOfTheDay yönteminde yapıldığı gibi, yardımcı bir sınıftaki statik bir işleve koyabilirsiniz.

Ardından ikinci yöntemi kısaltabilirsiniz:

Calendar cal = Calendar.getInstance();
Calendars.toBeginningOfTheDay(cal);
dateWithoutTime = cal.getTime();

Ya da, şimdiki günü bu formatta gerçekten çok sık ihtiyacınız varsa, o zaman başka bir statik yardımcı yöntemle tamamlayabilir ve böylece tek katmanlı hale getirebilirsiniz.


3

İstediğiniz tarih, "YYYY-AA-GG" gibi diğer tüm dağınıklığı görmeden görmekse, örneğin "21 Mayıs Per 12:08:18 EDT 2015" kullanın java.sql.Date. Bu örnek geçerli tarihi alır:

new java.sql.Date(System.currentTimeMillis());

Ayrıca java.sql.Datebir alt sınıfıdır java.util.Date.


3

Sadece şu andaki tarihe ihtiyacınız varsa, zaman olmadan, başka bir seçenek:

DateTime.now().withTimeAtStartOfDay()

1
Soru günün herhangi bir saatini istemedi. Sonuç, gerçekten bir zamana sahip bir tarih-zaman nesnesidir, o zaman 00:00:00genellikle ( DST gibi anomaliler için zaman dilimine göre değişebilir ). Bu nedenle, diğer Yanıtların belirttiği gibi, LocalDatesınıf Joda-Time'dan daha uygundur (Joda-Time'a atıfta bulunduğunuzu varsayarsak - Java ile paketlenmemiş sınıflara atıfta bulunurken açıkça belirtmeniz gerekir).
Basil Bourque

3

Kullanın LocalDate.now()ve Dateaşağıdaki gibi dönüştürün :

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());

1
JVM'nin geçerli varsayılan saat dilimi çalışma zamanı sırasında herhangi bir anda değişebilir. JVM içindeki herhangi bir uygulamanın herhangi bir iş parçacığında herhangi bir kod çağırabilir TimeZone.setDefault. Kodunuz ZoneId.systemDefaultiki kez çağırıyor , birincisi örtük LocalDate.now()ve ikincisi açık atStartOfDay. Çalışma zamanında bu iki an arasında, geçerli varsayılan bölge değişebilir. Bölgeyi bir değişkene yakalamanızı ve her iki yönteme de geçmenizi öneririm.
Basil Bourque

2

Tarih kısmına sadece yankılama amaçlı ihtiyacınız varsa, o zaman

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);

1
Bunun i18n dostu olduğunu düşünmüyorum
Mark Lapasa

2

Peki buna ne dersin?

public static Date formatStrictDate(int year, int month, int dayOfMonth) {
    Calendar calendar = Calendar.getInstance();
    calendar.set(year, month, dayOfMonth, 0, 0, 0);
    calendar.set(Calendar.MILLISECOND, 0);
    return calendar.getTime();
}

1

Veyder-time kontrol edin . Hem java.util hem de Joda-time için basit ve etkili bir alternatiftir. Sezgisel bir API ve zaman damgaları olmadan yalnızca tarihleri ​​temsil eden sınıflara sahiptir.


1

Java'nın devasa TimeZone Veritabanından tam olarak yararlanmanın en doğru yolu ve doğru:

long currentTime = new Date().getTime();
long dateOnly = currentTime + TimeZone.getDefault().getOffset(currentTime);

1

Burada, dize ve geri dönüşümü olmayan temiz bir çözümdür ve ayrıca zamanın her bileşenini sıfırladığınız için zamanı birkaç kez yeniden hesaplamaz. Ayrıca kullanır% bölme yerine (modül) ve ardından çift işlemden kaçınmak için çarpma kullanır.

Herhangi bir üçüncü taraf bağımlılığı gerektirmez ve iletilen Calender nesnesinin TIMEZONE'UNU TAKİP EDİR. Bu işlev, geçtiğiniz tarihin (Takvim) saat diliminde saat 12: 00'de anı döndürür.

public static Calendar date_only(Calendar datetime) {
    final long LENGTH_OF_DAY = 24*60*60*1000;
    long millis = datetime.getTimeInMillis();
    long offset = datetime.getTimeZone().getOffset(millis);
    millis = millis - ((millis + offset) % LENGTH_OF_DAY);
    datetime.setTimeInMillis(millis);
    return datetime;
}

Ben yaz tme (DST) saygı olacağını ikna değil mi?
Ole VV

0

Üçüncü taraf kitaplıklarını mümkün olduğunca kullanmamayı tercih edin. Bu yoldan daha önce bahsedildiğini biliyorum, ama burada güzel ve temiz bir yol var:

  /*
    Return values:
    -1:    Date1 < Date2
     0:    Date1 == Date2
     1:    Date1 > Date2

    -2:    Error
*/
public int compareDates(Date date1, Date date2)
{
    SimpleDateFormat sdf = new SimpleDateFormat("ddMMyyyy");

    try
    {
        date1 = sdf.parse(sdf.format(date1));
        date2 = sdf.parse(sdf.format(date2));
    }
    catch (ParseException e) {
        e.printStackTrace();
        return -2;
    }

    Calendar cal1 = new GregorianCalendar();
    Calendar cal2 = new GregorianCalendar();

    cal1.setTime(date1);
    cal2.setTime(date2);

    if(cal1.equals(cal2))
    {
        return 0;
    }
    else if(cal1.after(cal2))
    {
        return 1;
    }
    else if(cal1.before(cal2))
    {
        return -1;
    }

    return -2;
}

Pekala, GregorianCalendar kullanmamak belki bir seçenektir!


0

Ben sadece benim app için yaptım:

public static Date getDatePart(Date dateTime) {
    TimeZone tz = TimeZone.getDefault();
    long rawOffset=tz.getRawOffset();
    long dst=(tz.inDaylightTime(dateTime)?tz.getDSTSavings():0);
    long dt=dateTime.getTime()+rawOffset+dst; // add offseet and dst to dateTime
    long modDt=dt % (60*60*24*1000) ;

    return new Date( dt
                    - modDt // substract the rest of the division by a day in milliseconds
                    - rawOffset // substract the time offset (Paris = GMT +1h for example)
                    - dst // If dayLight, substract hours (Paris = +1h in dayLight)
    );
}

Android API seviye 1, harici kütüphane yok. Gün ışığına ve varsayılan saat dilimine saygılıdır. Hayır String manipülasyonu bu yüzden bu şekilde sizinkinden daha verimli CPU olduğunu düşünüyorum ama herhangi bir test yapmadım.


0

Joda zamanını kullanabilirsiniz.

private Date dateWitoutTime(Date date){
 return new LocalDate(date).toDate()
}

ve şununla ara:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
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.