Bagaimana cara mengurangi X hari dari tanggal menggunakan kalender Java?


180

Adakah yang tahu cara sederhana menggunakan kalender Java untuk mengurangi X hari dari tanggal?

Saya belum dapat menemukan fungsi yang memungkinkan saya untuk secara langsung mengurangi X hari dari tanggal di Jawa. Bisakah seseorang mengarahkan saya ke arah yang benar?


FYI, kelas tanggal-waktu lama bermasalah seperti java.util.Calendarsekarang warisan , digantikan oleh kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque

Jawaban:


309

Diambil dari dokumen di sini :

Menambahkan atau mengurangi jumlah waktu yang ditentukan ke bidang kalender yang diberikan, berdasarkan aturan kalender. Misalnya, untuk mengurangi 5 hari dari waktu kalender saat ini, Anda dapat mencapainya dengan menelepon:

Calendar calendar = Calendar.getInstance(); // this would default to now
calendar.add(Calendar.DAY_OF_MONTH, -5).

1
Berhati-hatilah dalam melakukan ini karena tidak selalu berjalan seperti yang Anda harapkan.
Carson

1
Jawaban ini memiliki banyak pembaruan, tetapi apakah aman digunakan? atau ini lebih baik: stackoverflow.com/a/10796111/948268
Kuldeep Jain

44
Anda tidak akan menggunakan Calendar.DAY_OF_MONTHdalam hal ini karena tidak akan menangani gulungan antara bulan seperti yang Anda inginkan. Gunakan Calendar.DAY_OF_YEARsebaliknya
algoritma

4
Ini harus aman, tampaknya ketika Anda menambahkannya tidak masalah apakah itu DAY_OF_MONTH atau DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack

@carson apa saja masalah dengan pendekatan ini?
tatmanblue

38

Anda dapat menggunakan addmetode ini dan memberikannya angka negatif. Namun, Anda juga bisa menulis metode yang lebih sederhana yang tidak menggunakan Calendarkelas seperti berikut ini

public static void addDays(Date d, int days)
{
    d.setTime( d.getTime() + (long)days*1000*60*60*24 );
}

Ini mendapatkan nilai cap waktu tanggal (milidetik sejak zaman) dan menambahkan jumlah milidetik yang tepat. Anda bisa melewati bilangan bulat negatif untuk parameter hari untuk melakukan pengurangan. Ini akan lebih sederhana daripada solusi kalender yang "tepat":

public static void addDays(Date d, int days)
{
    Calendar c = Calendar.getInstance();
    c.setTime(d);
    c.add(Calendar.DATE, days);
    d.setTime( c.getTime().getTime() );
}

Perhatikan bahwa kedua solusi ini mengubah Dateobjek yang dilewatkan sebagai parameter daripada mengembalikan yang sama sekali baru Date. Salah satu fungsi dapat dengan mudah diubah untuk melakukannya dengan cara lain jika diinginkan.


3
Jangan percaya .setTime dan .add adalah metode Kalender statis. Anda harus menggunakan variabel instan c.
Edward

@ Edward: Anda benar, terima kasih telah menunjukkan kesalahan saya, saya telah memperbaiki kode sehingga sekarang harus berfungsi dengan baik.
Eli Courtwright

3
Hati-hati dengan cara pertama, misalnya ketika berhadapan dengan hari leapyear, mungkin gagal: stackoverflow.com/a/1006388/32453
rogerdpack

FYI, kelas tanggal-waktu lama bermasalah seperti java.util.Calendarsekarang warisan , digantikan oleh kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque

36

Jawaban Anson akan bekerja dengan baik untuk kasus sederhana, tetapi jika Anda akan melakukan perhitungan tanggal yang lebih kompleks saya akan merekomendasikan memeriksa Joda Time . Itu akan membuat hidup Anda lebih mudah.

FYI di Joda Time bisa Anda lakukan

DateTime dt = new DateTime();
DateTime fiveDaysEarlier = dt.minusDays(5);

1
@ShahzadImam, periksa DateTimeFormat . Ini akan memungkinkan Anda untuk mengonversi instance DateTime ke string menggunakan format sewenang-wenang. Ini sangat mirip dengan kelas java.text.DateFormat.
Mike Deck

1
Pada Java 8 pertimbangkan untuk menggunakan java.time docs.oracle.com/javase/8/docs/api/java/time/…
toidiu

FYI, proyek Joda-Time sekarang dalam mode pemeliharaan , dengan tim menyarankan migrasi ke kelas java.time . Lihat Tutorial oleh Oracle .
Basil Bourque

19

tl; dr

LocalDate.now().minusDays( 10 )

Lebih baik menentukan zona waktu.

LocalDate.now( ZoneId.of( "America/Montreal" ) ).minusDays( 10 )

Detail

Kelas tanggal-waktu lama yang dibundel dengan versi awal Java, seperti java.util.Date/.Calendar , telah terbukti menyusahkan, membingungkan, dan cacat. Hindari mereka.

waktu java

Java 8 dan yang lebih baru menggantikan kelas-kelas lama dengan kerangka kerja java.time baru. Lihat Tutorial . Didefinisikan oleh JSR 310 , terinspirasi oleh Joda-Time , dan diperpanjang oleh ThreeTen-Extra . Proyek ThreeTen-Backport mendukung kelas-kelas ke Java 6 & 7; proyek ThreeTenABP ke Android.

Pertanyaannya tidak jelas, tidak jelas apakah hanya meminta tanggal saja atau tanggal saja.

LocalDate

Untuk kencan saja, tanpa waktu, gunakan LocalDatekelas. Perhatikan bahwa zona waktu sangat penting dalam menentukan tanggal seperti "hari ini".

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

ZonedDateTime

Jika Anda bermaksud menentukan tanggal, maka gunakan Instantkelas untuk mendapatkan momen di timeline dalam UTC . Dari sana, sesuaikan ke zona waktu untuk mendapatkan ZonedDateTimeobjek.

Instant now = Instant.now();  // UTC.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
ZonedDateTime tenDaysAgo = zdt.minusDays( 10 );

Tabel tipe waktu-tanggal di Jawa, baik yang modern maupun yang lama.


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 .

Anda dapat bertukar objek java.time secara langsung dengan database Anda. Gunakan driver JDBC yang sesuai dengan JDBC 4.2 atau yang lebih baru. Tidak perlu untuk string, tidak perlujava.sql.* kelas.

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 .


Ini merupakan peningkatan yang jauh lebih baik daripada opsi lain (ini juga jauh lebih baru dan menggunakan metode baru). Jika Anda mengunjungi masalah ini sekarang, Ini adalah cara untuk pergi.
Shourya Bansal


5

Daripada menulis sendiri addDaysseperti yang disarankan oleh Eli, saya lebih suka menggunakan DateUtilsdari Apache . Ini berguna terutama ketika Anda harus menggunakannya di banyak tempat di proyek Anda.

API mengatakan:

addDays(Date date, int amount)

Menambahkan beberapa hari ke tanggal mengembalikan objek baru.

Perhatikan bahwa ia mengembalikan yang baru Date objek dan tidak membuat perubahan ke yang sebelumnya itu sendiri.


2

Hal ini dapat dilakukan dengan mudah dengan cara berikut

Calendar calendar = Calendar.getInstance();
        // from current time
        long curTimeInMills = new Date().getTime();
        long timeInMills = curTimeInMills - 5 * (24*60*60*1000);    // `enter code here`subtract like 5 days
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

        // from specific time like (08 05 2015)
        calendar.set(Calendar.DAY_OF_MONTH, 8);
        calendar.set(Calendar.MONTH, (5-1));
        calendar.set(Calendar.YEAR, 2015);
        timeInMills = calendar.getTimeInMillis() - 5 * (24*60*60*1000);
        calendar.setTimeInMillis(timeInMills);
        System.out.println(calendar.getTime());

Jawaban ini keliru, menggunakan kelas tanggal waktu lama yang mengerikan yang sekarang merupakan warisan, digantikan oleh kelas java.time. Juga, kode ini mengabaikan masalah krusial zona waktu, dengan naif mengasumsikan 24 jam sehari. Masalah lain adalah menggunakan kelas tanggal-waktu untuk memecahkan masalah hanya tanggal. Penggunaannya LocalDatejauh lebih sederhana dan lebih tepat.
Basil Bourque

1

Seseorang merekomendasikan Joda Time jadi - Saya telah menggunakan kelas CalendarDate ini http://calendardate.sourceforge.net

Ini adalah proyek yang agak bersaing untuk Joda Time, tetapi jauh lebih mendasar di hanya 2 kelas. Ini sangat berguna dan bekerja sangat baik untuk apa yang saya butuhkan karena saya tidak ingin menggunakan paket yang lebih besar dari proyek saya. Tidak seperti rekan-rekan Java, unit terkecilnya adalah hari jadi itu benar-benar tanggal (tidak harus turun ke milidetik atau sesuatu). Setelah Anda membuat tanggal, yang Anda lakukan untuk mengurangi adalah sesuatu seperti myDay.addDays (-5) untuk kembali 5 hari. Anda dapat menggunakannya untuk menemukan hari dalam seminggu dan hal-hal seperti itu. Contoh lain:

CalendarDate someDay = new CalendarDate(2011, 10, 27);
CalendarDate someLaterDay = today.addDays(77);

Dan:

//print 4 previous days of the week and today
String dayLabel = "";
CalendarDate today = new CalendarDate(TimeZone.getDefault());
CalendarDateFormat cdf = new CalendarDateFormat("EEE");//day of the week like "Mon"
CalendarDate currDay = today.addDays(-4);
while(!currDay.isAfter(today)) {
    dayLabel = cdf.format(currDay);
    if (currDay.equals(today))
        dayLabel = "Today";//print "Today" instead of the weekday name
    System.out.println(dayLabel);
    currDay = currDay.addDays(1);//go to next day
}

1

Saya percaya cara yang bersih dan menyenangkan untuk melakukan pengurangan atau penambahan unit waktu (bulan, hari, jam, menit, detik, ...) dapat dicapai dengan menggunakan kelas java.time.Instant .

Contoh untuk mengurangi 5 hari dari waktu sekarang dan mendapatkan hasilnya sebagai Tanggal:

new Date(Instant.now().minus(5, ChronoUnit.DAYS).toEpochMilli());

Contoh lain untuk mengurangi 1 jam dan menambahkan 15 menit:

Date.from(Instant.now().minus(Duration.ofHours(1)).plus(Duration.ofMinutes(15)));

Jika Anda membutuhkan akurasi lebih, Instance mengukur hingga nanodetik. Metode memanipulasi bagian nanodetik:

minusNano()
plusNano()
getNano()

Juga, ingatlah, Tanggal itu tidak seakurat Instan.


1
Atau tergantung selera, sedikit lebih pendek:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Ole VV

1
Bagus! Kamu benar. Saya benar-benar memperbarui jawaban untuk menggunakan ini dan juga menunjukkan penggunaan kelas java.time.Duration, yang dalam hal ini juga sangat kuat.
Yordan Boev

0

Solusi kedua Eli Courtwright salah, seharusnya:

Calendar c = Calendar.getInstance();
c.setTime(date);
c.add(Calendar.DATE, -days);
date.setTime(c.getTime().getTime());

2
Nama fungsi dalam solusi Eli adalah addDays; solusinya benar. Jika Anda ingin mengurangi hari dari tanggal, Anda memberikan nilai negatif untuk days.
Thomas Upton

Ya, itu adalah sesuatu yang harus ditentukan oleh programmer ketika membuat fungsi, bukan? : P
user178973
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.