วิธีลบ X วันจากวันที่โดยใช้ปฏิทิน Java


180

ใครรู้วิธีง่ายๆในการใช้ปฏิทิน Java เพื่อลบ X วันจากวันที่?

ฉันไม่สามารถค้นหาฟังก์ชั่นใด ๆ ที่อนุญาตให้ฉันลบ X วันจากวันที่ใน Java โดยตรง ใครบางคนชี้ให้ฉันไปในทิศทางที่ถูกต้อง?


FYI คลาสวันที่และเวลาที่ลำบากเช่นjava.util.Calendarตอนนี้เป็นแบบดั้งเดิมแทนที่ด้วยคลาสjava.time ดูการสอนโดยออราเคิล
Basil Bourque

คำตอบ:


309

นำมาจากเอกสารที่นี่ :

เพิ่มหรือลบจำนวนเวลาที่ระบุในฟิลด์ปฏิทินที่กำหนดตามกฎของปฏิทิน ตัวอย่างเช่นหากต้องการลบ 5 วันจากเวลาปัจจุบันของปฏิทินคุณสามารถทำได้โดยโทร:

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

1
เพียงแค่ระมัดระวังในการทำเช่นนี้เพราะมันจะไม่หมุนเหมือนที่คุณคาดหวัง
carson

1
คำตอบนี้มี upvotes มากมาย แต่ปลอดภัยไหมที่จะใช้? หรือนี่จะดีกว่า: stackoverflow.com/a/10796111/948268
Kuldeep Jain

44
คุณจะไม่ใช้Calendar.DAY_OF_MONTHในกรณีนี้เนื่องจากจะไม่จัดการม้วนระหว่างเดือนตามที่คุณต้องการ ใช้Calendar.DAY_OF_YEARแทน
อัลกอริทึม

4
สิ่งนี้ควรจะปลอดภัยแน่นอนเมื่อคุณเพิ่มมันไม่สำคัญว่ามันคือ DAY_OF_MONTH หรือ DAY_OF_YEAR stackoverflow.com/q/14065198/32453
rogerdpack

@carson มีปัญหาอะไรบ้างในแนวทางนี้
tatmanblue

38

คุณสามารถใช้addวิธีการและส่งผ่านจำนวนลบ อย่างไรก็ตามคุณสามารถเขียนวิธีที่ง่ายกว่าซึ่งไม่ใช้Calendarคลาสดังต่อไปนี้

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

สิ่งนี้ได้รับค่าการประทับเวลาของวันที่ (มิลลิวินาทีนับตั้งแต่ยุค) และเพิ่มจำนวนมิลลิวินาทีที่เหมาะสม คุณสามารถส่งจำนวนเต็มลบเพื่อให้พารามิเตอร์ days ทำการลบได้ นี่จะง่ายกว่าโซลูชันปฏิทิน "เหมาะสม":

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

โปรดทราบว่าการแก้ปัญหาทั้งสองนี้จะเปลี่ยนDateวัตถุที่ส่งผ่านเป็นพารามิเตอร์แทนที่จะส่งค่าใหม่Dateทั้งหมด ทั้งสองฟังก์ชั่นสามารถเปลี่ยนแปลงได้อย่างง่ายดายเพื่อทำอย่างอื่นหากต้องการ


3
อย่าเชื่อ. setTime และ .add เป็นวิธีการคงที่ของปฏิทิน คุณควรใช้ตัวแปรอินสแตนซ์ค
Edward

@Edward: คุณถูกต้องขอบคุณที่ชี้ให้เห็นความผิดพลาดของฉันฉันได้แก้ไขรหัสเพื่อให้มันทำงานได้อย่างถูกต้อง
Eli Courtwright

3
ระวังด้วยวิธีแรกเช่นเมื่อต้องจัดการกับวันที่มีฝนตกมันอาจล้มเหลว: stackoverflow.com/a/1006388/32453
rogerdpack

FYI คลาสวันที่และเวลาที่ลำบากเช่นjava.util.Calendarตอนนี้เป็นแบบดั้งเดิมแทนที่ด้วยคลาสjava.time ดูการสอนโดยออราเคิล
Basil Bourque

36

คำตอบของแอนสันจะทำงานได้ดีสำหรับกรณีที่เรียบง่าย แต่ถ้าคุณกำลังจะทำการคำนวณวันที่ใด ๆ ที่ซับซ้อนมากขึ้นผมอยากแนะนำให้ตรวจสอบจากJoda เวลา มันจะทำให้ชีวิตของคุณง่ายขึ้นมาก

FYI ใน Joda Time ที่คุณสามารถทำได้

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

1
@ShahzadImam ตรวจสอบDateTimeFormat มันจะช่วยให้คุณสามารถแปลงอินสแตนซ์ DateTime เป็นสตริงโดยใช้รูปแบบที่กำหนดเอง มันคล้ายกับคลาส java.text.DateFormat
Mike Deck

1
ในฐานะของ Java 8 พิจารณาใช้ java.time docs.oracle.com/javase/8/docs/api/java/time/ ......
toidiu

FYI โครงการJoda-Timeขณะนี้อยู่ในโหมดบำรุงรักษาโดยทีมงานให้คำแนะนำการย้ายถิ่นไปยังคลาสjava.time ดูการสอนโดยออราเคิล
Basil Bourque

19

TL; DR

LocalDate.now().minusDays( 10 )

ระบุเขตเวลาได้ดีกว่า

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

รายละเอียด

คลาสวันที่และเวลาเก่าที่มาพร้อมกับ Java เวอร์ชันแรก ๆ เช่นjava.util.Date/ .Calendarได้พิสูจน์แล้วว่ามีปัญหาสับสนและมีข้อบกพร่อง หลีกเลี่ยงพวกเขา

java.time

Java 8 และใหม่กว่าแทนที่คลาสเก่าเหล่านั้นด้วยเฟรมเวิร์ก java.time ใหม่ ดูการสอน กำหนดโดยJSR 310แรงบันดาลใจจากJoda เวลาและขยายโดยThreeTen-พิเศษโครงการ โครงการ ThreeTen-Backport back-ports คลาสไปยัง Java 6 & 7; โครงการ ThreeTenABP สำหรับ Android

คำถามนั้นคลุมเครือไม่ชัดเจนหากถามถึงวันที่อย่างเดียวหรือเป็นวันที่

LocalDate

สำหรับวันที่เท่านั้นโดยไม่มีเวลาให้ใช้LocalDateคลาส โปรดทราบว่าเขตเวลามีความสำคัญอย่างยิ่งในการกำหนดวันที่เช่น "วันนี้"

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

ZonedDateTime

ถ้าคุณหมายถึงวันที่เวลานั้นใช้Instantระดับที่จะได้รับสักครู่บนไทม์ไลน์ในUTC จากนั้นปรับเป็นเขตเวลาเพื่อรับZonedDateTimeวัตถุ

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

ตารางประเภทวันที่ - เวลาใน Java ทั้งทันสมัยและดั้งเดิม


เกี่ยวกับjava.time

java.timeกรอบถูกสร้างขึ้นใน Java 8 และต่อมา ชั้นเรียนเหล่านี้แย่งลำบากเก่ามรดกเรียนวันที่เวลาเช่นjava.util.Date, และCalendarSimpleDateFormat

Joda เวลาโครงการขณะนี้อยู่ในโหมดการบำรุงรักษาให้คำแนะนำแก่การโยกย้ายไปยังjava.timeชั้นเรียน

ต้องการเรียนรู้เพิ่มเติมโปรดดูที่ออราเคิลกวดวิชา และค้นหา Stack Overflow สำหรับตัวอย่างและคำอธิบายมากมาย สเปกJSR 310

คุณสามารถแลกเปลี่ยนวัตถุjava.timeโดยตรงกับฐานข้อมูลของคุณ ใช้ไดรเวอร์ JDBC ที่สอดคล้องกับJDBC 4.2หรือใหม่กว่า ไม่จำเป็นต้องใช้สตริงไม่จำเป็นต้องมีjava.sql.*คลาส

จะรับคลาส java.time ได้ที่ไหน?

  • Java SE 8 , Java SE 9 , Java SE 10และใหม่กว่า
    • Built-in
    • เป็นส่วนหนึ่งของ Java API มาตรฐานที่มีการใช้งานแบบรวม
    • Java 9 เพิ่มคุณสมบัติและการแก้ไขเล็กน้อย
  • Java SE 6และ Java SE 7
    • มากของการทำงาน java.time จะกลับรังเพลิง Java 6 และ 7 ในThreeTen-ย้ายกลับ
  • Android
    • การใช้งานชุดบันเดิล Android รุ่นต่อมาของคลาส java.time
    • สำหรับก่อนหน้านี้ Android (<26) ที่ThreeTenABPโครงการปรับThreeTen-ย้ายกลับ (ดังกล่าวข้างต้น) ดูวิธีการใช้ ThreeTenABP … .

โครงการThreeTen-Extraขยาย java.time ด้วยคลาสเพิ่มเติม โครงการนี้เป็นพื้นฐานที่พิสูจน์ได้สำหรับการเพิ่มเติมในอนาคตไปยัง java.time คุณอาจพบว่าการเรียนที่มีประโยชน์บางอย่างที่นี่เช่นInterval, YearWeek, YearQuarterและอื่น ๆ อีกมากมาย


นี่เป็นการปรับปรุงที่ดีกว่าตัวเลือกอื่น ๆ (มันยังใหม่กว่ามากและใช้วิธีการใหม่) หากคุณกำลังเยี่ยมชมปัญหานี้ในขณะนี้นี่คือวิธีที่จะไป
Shourya Bansal


5

แทนการเขียนของตัวเองaddDaysตามที่แนะนำโดยเอลีฉันชอบที่จะใช้DateUtilsจากอาปาเช่ มันมีประโยชน์โดยเฉพาะเมื่อคุณต้องใช้หลาย ๆ ที่ในโครงการของคุณ

API กล่าวว่า:

addDays(Date date, int amount)

เพิ่มจำนวนวันให้กับวันที่ส่งคืนวัตถุใหม่

โปรดทราบว่ามันส่งคืนDateวัตถุใหม่และไม่ทำการเปลี่ยนแปลงไปก่อนหน้านี้เอง


2

สามารถทำได้ง่าย ๆ ดังต่อไปนี้

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

คำตอบนี้เป็นคำแนะนำที่ไม่ดีโดยใช้คลาสวันที่เก่าที่แย่ซึ่งตอนนี้เป็นแบบดั้งเดิมแทนที่ด้วยคลาส java.time นอกจากนี้โค้ดนี้จะไม่สนใจปัญหาที่สำคัญของเขตเวลาโดยที่สมมติว่าเป็น 24 ชั่วโมง ปัญหาอื่นคือการใช้คลาสวันที่เพื่อแก้ปัญหาเฉพาะวันที่ การใช้LocalDateนั้นง่ายกว่าและเหมาะสมกว่ามาก
Basil Bourque

1

มีคนแนะนำ Joda Time ดังนั้น - ฉันใช้คลาส CalendarDateนี้http://calendardate.sourceforge.net

มันเป็นโครงการที่ค่อนข้างแข่งขันกับ Joda Time แต่พื้นฐานมากขึ้นใน 2 ชั้นเท่านั้น มันมีประโยชน์มากและทำงานได้ดีสำหรับสิ่งที่ฉันต้องการเนื่องจากฉันไม่ต้องการใช้แพคเกจที่ใหญ่กว่าโครงการของฉัน แตกต่างจากจาวาหน่วยที่เล็กที่สุดของมันคือวันดังนั้นมันจึงเป็นวันที่จริง ๆ (ไม่ต้องมีหน่วยเป็นมิลลิวินาที เมื่อคุณสร้างวันที่สิ่งที่คุณต้องทำเพื่อลบคือ myDay.addDays (-5) เพื่อย้อนกลับไป 5 วัน คุณสามารถใช้มันเพื่อค้นหาวันในสัปดาห์และสิ่งต่าง ๆ เช่นนั้น ตัวอย่างอื่น:

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

และ:

//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

ฉันเชื่อว่าวิธีที่ดีและสะอาดในการลบหรือเพิ่มหน่วยเวลา (เดือน, วัน, ชั่วโมง, นาที, วินาที, ... ) สามารถทำได้โดยใช้คลาสjava.time.Instant

ตัวอย่างการลบ 5 วันจากเวลาปัจจุบันและรับผลลัพธ์เป็นวันที่:

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

อีกตัวอย่างสำหรับการลบ 1 ชั่วโมงและเพิ่ม 15 นาที:

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

หากคุณต้องการความแม่นยำมากขึ้นอินสแตนซ์วัดได้สูงสุดนาโนวินาที วิธีการจัดการส่วน nanosecond:

minusNano()
plusNano()
getNano()

นอกจากนี้โปรดทราบว่าวันที่นั้นไม่ถูกต้องเท่า Instant


1
หรือขึ้นอยู่กับรสนิยมสั้นกว่าเล็กน้อย:Date.from(Instant.now().minus(5, ChronoUnit.DAYS))
Ole VV

1
ดี! คุณพูดถูก ฉันจริงปรับปรุงคำตอบที่จะใช้สิ่งนี้และยังแสดงการใช้งานของ java.time.Duration class ซึ่งในกรณีนี้ก็มีศักยภาพมาก
Yordan Boev

0

อีไลคอร์ทไรท์คำตอบที่สองนั้นผิดมันควรจะเป็น:

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

2
ชื่อของฟังก์ชันในโซลูชันของ Eli คือaddDays; ทางออกของเขาถูกต้อง daysหากคุณต้องการที่จะลบวันนับจากวันที่คุณผ่านในค่าลบสำหรับ
โทมัสอัพตัน

นั่นคือสิ่งที่โปรแกรมเมอร์ต้องระบุเมื่อสร้างฟังก์ชันใช่ไหม : P
user178973
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.