Bagaimana cara mendapatkan Tanggal tanpa waktu di Jawa?

235

Melanjutkan dari pertanyaan Stack Overflow program Java untuk mendapatkan tanggal saat ini tanpa stempel waktu :

Apa cara paling efisien untuk mendapatkan objek Date tanpa waktu? Apakah ada cara lain selain keduanya?

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

Perbarui :

  1. Saya tahu tentang Joda-Time ; Saya hanya mencoba menghindari perpustakaan tambahan untuk tugas yang sederhana (saya pikir). Tetapi berdasarkan jawaban sejauh ini Joda-Time tampaknya sangat populer, jadi saya mungkin mempertimbangkannya.

  2. Dengan efisien , maksud saya saya ingin menghindari Stringpembuatan objek sementara seperti yang digunakan oleh method 1, sementara itu method 2tampak seperti peretasan bukan solusi.

Rosdi Kasim
sumber
1
Efisien? Apakah Anda memerlukan efisiensi lebih dari yang disediakan misalnya, oleh method1?
Johan Sjöberg
2
Apa yang Anda maksud dengan "efisien"? Tanggal pada dasarnya diketik lama, Anda tidak bisa benar-benar melakukan ini dalam memori kurang dari itu. Jika Anda maksud "nyaman", waktu JODA adalah cara untuk pergi.
milimoose
3
+1 Persis pertanyaan saya.
Alba Mendez
1
Saya suka metode 2. Buat metode statis di kelas utilitas dan gunakan saja. Saya sudah melakukan pendekatan ini selama bertahun-tahun.
Wilson Freitas
1
Mengenali "pembaruan 1" Anda: jika itu "tugas yang begitu sederhana", saya kira Sun tidak akan sampai pada API yang begitu menghebohkan dan tidak efisien, dan Anda (dan banyak orang lain) tidak akan menanyakan pertanyaan itu at all ;-)
Flávio Etrusco

Jawaban:

108

Apakah Anda benar - benar harus menggunakan java.util.Date? Saya benar - benar akan merekomendasikan Anda menggunakan Joda Time atau java.timepaket dari Java 8 sebagai gantinya. Secara khusus, saat Tanggal dan Kalender selalu mewakili instan tertentu dalam waktu, tanpa konsep seperti "hanya tanggal", Joda Time memang memiliki tipe yang mewakili ini ( LocalDate). Kode Anda akan jauh lebih jelas jika Anda dapat menggunakan tipe yang mewakili apa yang sebenarnya Anda coba lakukan.

Ada banyak, banyak alasan lain untuk menggunakan Joda Time atau java.timebukannya java.utiltipe bawaan - mereka umumnya API yang jauh lebih baik. Anda selalu dapat mengonversi ke / dari a java.util.Datedi batas kode Anda sendiri jika perlu, misalnya untuk interaksi basis data.

Jon Skeet
sumber
75
Dalam aplikasi perusahaan kami tidak selalu memiliki opsi untuk menambah / menggunakan perpustakaan lain. Saya menghargai pointer ke Joda Time, tapi itu benar-benar bukan jawaban untuk masalah asli mendapatkan porsi tanggal menggunakan Java standar. Terima kasih. Benarkan jawaban Chathuranga.
noogrub
3
@noogrub: Jawaban Chathugranga tidak menjawab pertanyaan awal, yang menanyakan tentang cara mendapatkan Dateobjek - jawaban itu memformat tanggal ke string, yang bukan hal yang sama. Pada dasarnya, menanyakan tanggal berapa Datepada adalah pertanyaan yang tidak berarti tanpa informasi lebih lanjut: zona waktu dan sistem kalender yang Anda gunakan.
Jon Skeet
7
"Dalam aplikasi perusahaan kami tidak selalu memiliki opsi untuk menambah / menggunakan perpustakaan lain". Betulkah ? Apakah Anda menyarankan Anda tidak dapat menggunakan lib pihak ketiga sama sekali?
Brian Agnew
3
Komentar @BrianAgnew noogrub tampaknya terkait dengan kendala non-teknologi, saya pikir
Jose_GD
3
Dari perspektif hari ini: " Joda-Time adalah perpustakaan tanggal dan waktu standar de facto untuk Java sebelum Java SE 8. Pengguna sekarang diminta untuk bermigrasi ke java.time (JSR-310)."
Drux
66

Inilah yang saya gunakan untuk mendapatkan tanggal hari ini dengan waktu yang ditentukan 00:00:00:

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

Date today = new Date();

Date todayWithZeroTime = formatter.parse(formatter.format(today));
Shobbi
sumber
28
Dalam hal apa ini berbeda dari "metode 1" yang sudah diusulkan dalam pertanyaan awal?
Chris
Tidak membahas di zona waktu apa ini terjadi (diserahkan ke zona waktu standar JVM yang sewenang-wenang).
Darrell Teague
58

Anda dapat menggunakan DateUtils.truncate dari pustaka Apache Commons.

Contoh:

DateUtils.truncate(new Date(), java.util.Calendar.DAY_OF_MONTH)
JoGo
sumber
3
Jika Anda akan menambahkan perpustakaan baru, biarkan itu menjadi Joda, bukan Apache Commons.
Dibbeke
6
+1 @Dibbeke Perbedaannya bukan hanya bahwa Anda akan menambahkan satu perpustakaan, bukan yang lain. Kadang-kadang orang tidak ingin mempelajari perpustakaan baru hanya untuk tugas sepele untuk memotong waktu dari kencan. Atau tidak ingin memiliki kode yang mencampur Tanggal / Kalender dengan tanggal Joda menggunakan kadang-kadang mantan dan kadang-kadang yang terakhir. Atau tidak mampu / membenarkan mengganti semua kode berbasis Tanggal / Kalender yang berfungsi baik dengan perpustakaan lain untuk tujuan sepele seperti itu. Meskipun menyarankan Joda tentu baik karena jelas lebih unggul dan hanya The Right Thing, terkadang kehidupan nyata muncul.
SantiBailors
Jenius! Bantu saya banyak
Thiesen
37

Apakah ada cara lain selain keduanya?

Ya ada.

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

waktu java

Java 8 dan yang lebih baru disertai dengan paket java.time baru . Lihat Tutorial . Sebagian besar fungsi java.time di-port-back ke Java 6 & 7 di ThreeTen-Backport dan selanjutnya diadaptasi ke Android di ThreeTenABP .

Mirip dengan Joda-Time , java.time menawarkan LocalDatekelas untuk mewakili nilai hanya tanggal tanpa waktu hari dan tanpa zona waktu.

Perhatikan bahwa zona waktu sangat penting untuk menentukan tanggal tertentu. Pada tengah malam di Paris, misalnya, tanggalnya masih "kemarin" di Montréal.

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

Secara default, java.time menggunakan standar ISO 8601 dalam menghasilkan representasi string dari nilai tanggal atau waktu-tanggal. (Kesamaan lain dengan Joda-Time.) Jadi cukup panggil toString()untuk menghasilkan teks seperti 2015-05-21.

String output = today.toString() ; 

Tentang java.time

The java.time kerangka dibangun ke Jawa 8 dan kemudian. Kelas-kelas ini menggantikan tua merepotkan warisan kelas tanggal-waktu seperti java.util.Date, Calendar, & SimpleDateFormat.

Proyek Joda-Time , sekarang dalam mode pemeliharaan , menyarankan migrasi ke kelas java.time .

Untuk mempelajari lebih lanjut, lihat Tutorial Oracle . Dan cari Stack Overflow untuk banyak contoh dan penjelasan. Spesifikasi adalah JSR 310 .

Di mana mendapatkan kelas java.time?

Proyek ThreeTen-Extra memperpanjang java.time dengan kelas tambahan. Proyek ini adalah ajang pembuktian untuk kemungkinan penambahan masa depan ke java.time. Anda mungkin menemukan beberapa kelas berguna di sini seperti Interval, YearWeek, YearQuarter, dan lebih .

Basil Bourque
sumber
1
Terima kasih telah menyebutkan zona waktu . Tidak terpikir oleh saya bahwa "hari apa ini" bukanlah konsep absolut.
ToolmakerSteve
@ToolmakerSteve Mendapatkan tanggal selalu melibatkan zona waktu. Tetapi masalahnya adalah jika Anda gagal menentukan zona waktu, zona waktu default JVM Anda saat ini secara otomatis diterapkan dalam menentukan tanggal. Selain itu, zona waktu default JVM saat ini dapat berubah kapan saja ! Kode apa pun di utas aplikasi mana pun dalam JVM dapat memanggil TimeZone.setDefaultselama runtime dan segera memengaruhi semua kode lain yang berjalan di JVM itu. Moral of the Story: Selalu tentukan zona waktu.
Basil Bourque
22

Cara yang paling mudah:

long millisInDay = 60 * 60 * 24 * 1000;
long currentTime = new Date().getTime();
long dateOnly = (currentTime / millisInDay) * millisInDay;
Date clearDate = new Date(dateOnly);
Roma
sumber
5
Bagi saya, ini saat ini: "Sabtu 19 Feb 01 : 00: 00 CET 2011". Jika Anda ingin menggunakannya, maka hanya dengan UTC.
Chris Lercher
4
Bukankah baris 3 long dateOnly = (currentTime / millisInDay) * millisInDay;sama dengan menulis long dateOnly = currentTime;?
Chris
5
Bukan, karena matematika bilangan bulat. Anggap saja lebih seperti Math.floor (currentTime / millisInDay) * millisInDay. Dia secara efektif mengatur waktu ke 00:00:00 dengan cara itu.
Nicholas Flynt
2
Solusi ini mungkin baik untuk sebagian besar aplikasi, tetapi diingatkan asumsi bahwa satu hari memiliki 60 * 60 * 24 * 1000 tidak selalu benar. Misalnya Anda dapat memiliki detik kabisat dalam beberapa hari.
Pierre-Antoine
1
Ini bisa dibilang cara yang paling tumpul dan tidak direkomendasikan dibandingkan metode 1 dan 2-line lainnya yang jelas dan ringkas.
Darrell Teague
22

Jawaban standar untuk pertanyaan ini adalah menggunakan Joda Time . API lebih baik dan jika Anda menggunakan formatters dan parser Anda dapat menghindari kurangnya keamanan thread SimpleDateFormat.

Menggunakan Joda berarti Anda cukup melakukan:

LocalDate d = new LocalDate();

Perbarui :: Menggunakan java 8 ini dapat dicapai menggunakan

LocalDate date = LocalDate.now();
Brian Agnew
sumber
Paket java.time baru di Java 8 juga menawarkan LocalDatekelas yang mirip dengan Joda-Time.
Basil Bourque
1
Idealnya Anda akan meneruskan DateTimeZonekepada konstruktor LocalDate itu. Menentukan tanggal saat ini tergantung pada zona waktu, karena Paris memulai tanggal baru lebih awal dari Montréal. Jika Anda menghilangkan zona waktu, zona waktu default JVM Anda diterapkan. Biasanya lebih baik untuk menentukan daripada mengandalkan default.
Basil Bourque
8

Ini adalah cara sederhana untuk melakukannya:

Calendar cal = Calendar.getInstance();
SimpleDateFormat dateOnly = new SimpleDateFormat("MM/dd/yyyy");
System.out.println(dateOnly.format(cal.getTime()));
Lembah kecil
sumber
4
Jawaban ini gagal menjawab pertanyaan. Memperoleh string yang diformat bukanlah tujuan.
Basil Bourque
7

Tidak masuk akal untuk berbicara tentang tanggal tanpa timestamp sehubungan dengan rutinitas Tanggal dalam runtime java standar, karena pada dasarnya peta turun ke milidetik tertentu dan bukan tanggal. Kata milidetik secara intrinsik memiliki waktu sehari yang melekat padanya yang membuatnya rentan terhadap masalah zona waktu seperti Waktu Musim Panas dan penyesuaian kalender lainnya. Lihat Mengapa mengurangi dua kali ini (tahun 1927) memberikan hasil yang aneh? untuk contoh yang menarik.

Jika Anda ingin menggunakan tanggal alih-alih milidetik, Anda perlu menggunakan yang lain. Untuk Java 8 ada serangkaian metode baru yang menyediakan persis apa yang Anda minta. Untuk Java 7 dan sebelumnya gunakan http://www.joda.org/joda-time/

Thorbjørn Ravn Andersen
sumber
3
Catatan: Pendekatan yang mengatakan "tanggal pada tengah malam" tidak menangani waktu musim panas dan beberapa zona waktu dengan baik.
Thorbjørn Ravn Andersen
Saya mengonfirmasinya, saya menambah tanggal satu hari di aplikasi saya, dan mengetahui hal ini dengan laporan bug dari pengguna di zona waktu dengan DST (negara saya tidak menggunakan DST). Pada hari DST dimulai, aplikasi saya menambahkan 11 jam, bukannya 12. Mungkin menggunakan siang hari sebagai jam untuk tanggal "tidak ada waktu" lebih baik?
Jose_GD
1
@ Jose_GD Paling-paling masih hack. Anda mungkin menemukan youtube.com/watch?v=-5wpm-gesOY menghibur.
Thorbjørn Ravn Andersen
@ Thorbjorn, Anda benar, hanya ingin menghindari JodaTime karena menambahkan perpustakaan hanya untuk satu fitur suara berlebihan bagi saya. Saya tahu tentang video itu, memang lucu.
Jose_GD
1
@ Jose_GD Intinya adalah bahwa ada kasus penggunaan kehidupan nyata yang sebenarnya di mana pendekatan Anda akan dianggap sebagai bug. Jika Anda menemukan satu, mungkin ada lebih ... Saya tidak tahu bagaimana Joda menangani ini, tetapi Anda bisa melihatnya. Perhatikan juga bahwa Java 8 membawa perpustakaan tanggal-waktu baru (berdasarkan pengalaman dengan Joda) yang mungkin ingin Anda lihat.
Thorbjørn Ravn Andersen
4

Jelas bukan cara yang paling benar, tetapi jika Anda hanya memerlukan solusi cepat untuk mendapatkan tanggal tanpa waktu dan Anda tidak ingin menggunakan perpustakaan pihak ketiga ini harus dilakukan

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

Saya hanya perlu tanggal untuk keperluan visual dan tidak bisa Joda jadi saya substring.

Bamz
sumber
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
blueberry0xff
sumber
3

Yah, sejauh yang saya tahu tidak ada cara yang lebih mudah untuk mencapai ini jika Anda hanya menggunakan JDK standar.

Anda dapat, tentu saja, meletakkan logika itu di method2 ke dalam fungsi statis di kelas helper, seperti yang dilakukan di sini di metode toBeginningOfTheDay

Kemudian Anda dapat mempersingkat metode kedua menjadi:

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

Atau, jika Anda benar-benar membutuhkan hari ini dalam format ini begitu sering, maka Anda bisa membungkusnya dengan metode pembantu statis lain, sehingga menjadikannya satu baris.

Enduriel
sumber
3

Jika semua yang Anda inginkan adalah melihat tanggal seperti "YYYY-MM-DD" tanpa semua kekacauan lainnya misalnya "Kamis 21 Mei 12:08:18 EDT 2015" maka gunakan saja java.sql.Date. Contoh ini mendapatkan tanggal saat ini:

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

Juga java.sql.Datemerupakan subkelas dari java.util.Date.

BigMac66
sumber
3

Jika Anda hanya memerlukan tanggal saat ini, tanpa waktu, opsi lain adalah:

DateTime.now().withTimeAtStartOfDay()
pengguna3037726
sumber
1
Pertanyaan tidak meminta waktu. Hasil Anda adalah objek tanggal-waktu yang memang memiliki waktu-hari, yang 00:00:00biasanya (dapat bervariasi berdasarkan zona waktu untuk anomali seperti DST ). Jadi, seperti yang dicatat oleh Jawaban lain, LocalDatekelas lebih tepat, dari Joda-Time (dengan asumsi Anda merujuk Joda-Time - yang harus Anda perhatikan secara eksplisit ketika mengutip kelas yang tidak dibundel dengan Java).
Basil Bourque
3

Gunakan LocalDate.now()dan ubah menjadi Dateseperti di bawah ini:

Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
Sahil Chhabra
sumber
1
Zona waktu default JVM saat ini dapat berubah setiap saat selama runtime. Kode apa pun di utas apa pun dari aplikasi apa pun dalam JVM dapat dipanggil TimeZone.setDefault. Kode Anda memanggil ZoneId.systemDefaultdua kali, yang pertama tersirat LocalDate.now()dan yang kedua eksplisit dengan atStartOfDay. Di antara kedua momen tersebut saat runtime, zona default saat ini dapat berubah. Saya sarankan menangkap zona menjadi variabel, dan lolos ke kedua metode.
Basil Bourque
2

Jika Anda memerlukan bagian tanggal hanya untuk tujuan gema, maka

Date d = new Date(); 
String dateWithoutTime = d.toString().substring(0, 10);
manish_s
sumber
1
Saya rasa ini bukan pertandingan persahabatan
Mark Lapasa
2

Bagaimana dengan ini?

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();
}
vitiello.antonio
sumber
1

Lihat waktu-Veyder . Ini adalah alternatif yang sederhana dan efisien untuk java.util dan Joda-time. Ini memiliki API intuitif dan kelas yang mewakili tanggal saja, tanpa cap waktu.

lonerook
sumber
1

Cara paling straigthforward yang memanfaatkan penuh TimeZone Database besar Java dan benar:

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

Ini adalah solusi bersih tanpa konversi ke string dan kembali, dan juga tidak menghitung ulang waktu beberapa kali saat Anda mengatur ulang setiap komponen waktu menjadi nol. Itu juga menggunakan% (modulus) daripada membagi diikuti oleh kalikan untuk menghindari operasi ganda.

Ini tidak memerlukan dependensi pihak ketiga, dan MENGHARGAI WAKTU DARI objek Kalender berlalu. Fungsi ini mengembalikan waktu pada pukul 12 pagi di zona waktu tanggal (Kalender) yang Anda lewati.

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;
}
Brent Larsen
sumber
Saya tidak begitu yakin akan menghargai summer tme (DST)?
Ole VV
0

Memilih untuk tidak menggunakan perpustakaan pihak ketiga sebanyak mungkin. Saya tahu bahwa cara ini disebutkan sebelumnya, tetapi ini cara bersih yang bagus:

  /*
    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;
}

Yah, tidak menggunakan GregorianCalendar mungkin merupakan opsi!

hehe
sumber
0

Saya baru saja membuat ini untuk aplikasi saya:

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 level 1, tidak ada perpustakaan eksternal. Itu menghormati siang hari dan zona waktu standar. Tidak ada manipulasi String, jadi saya pikir cara ini lebih efisien daripada CPU Anda, tetapi saya belum melakukan tes.

Elloco
sumber
0

Anda dapat menggunakan waktu joda.

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

dan Anda menelepon dengan:

Date date = new Date();
System.out.println("Without Time = " + dateWitoutTime(date) + "/n  With time = " + date);
Jesús Sánchez
sumber