วิธีเปรียบเทียบวันที่สองวันโดยไม่มีส่วนเวลาได้อย่างไร


202

ฉันต้องการมีวิธีการ comparTo ที่ละเว้นส่วนเวลาของ java.util.Date ฉันเดาว่ามีหลายวิธีในการแก้ปัญหานี้ วิธีที่ง่ายที่สุดคืออะไร

คำตอบ:


212

ปรับปรุง: ในขณะที่ Joda Time เป็นคำแนะนำที่ดีในเวลานั้นให้ใช้java.timeไลบรารีจาก Java 8+ แทนหากเป็นไปได้


ความชอบของฉันคือการใช้Joda Timeซึ่งทำให้ง่ายอย่างไม่น่าเชื่อ:

DateTime first = ...;
DateTime second = ...;

LocalDate firstDate = first.toLocalDate();
LocalDate secondDate = second.toLocalDate();

return firstDate.compareTo(secondDate);

แก้ไข: ตามที่ระบุไว้ในความคิดเห็นหากคุณใช้DateTimeComparator.getDateOnlyInstance()มันง่ายยิ่งขึ้น :)

// TODO: consider extracting the comparator to a field.
return DateTimeComparator.getDateOnlyInstance().compare(first, second);

("ใช้ Joda Time" เป็นพื้นฐานของคำถาม SO เกือบทั้งหมดที่ถามเกี่ยวกับjava.util.Dateหรือjava.util.Calendarมันเป็น API ที่เหนือกว่าอย่างทั่วถึงหากคุณกำลังทำอะไรที่สำคัญกับวันที่ / เวลาคุณควรใช้ถ้าคุณสามารถทำได้)

หากคุณถูกบังคับให้ใช้ API ในตัวคุณควรสร้างอินสแตนซ์Calendarด้วยวันที่ที่เหมาะสมและใช้เขตเวลาที่เหมาะสม จากนั้นคุณสามารถตั้งค่าแต่ละฟิลด์ในแต่ละปฏิทินเป็นชั่วโมงนาทีวินาทีและมิลลิวินาทีเป็น 0 และเปรียบเทียบเวลาผลลัพธ์ เหนอะหนะแน่นอนเมื่อเทียบกับวิธีการแก้ปัญหา Joda :)

โซนเวลาส่วนหนึ่งเป็นสิ่งสำคัญ: java.util.Dateจะเสมอขึ้นอยู่กับเวลา UTC ในกรณีส่วนใหญ่ที่ผมได้รับความสนใจในวันที่ที่ได้รับวันที่ในเขตเวลาที่เฉพาะเจาะจง โดยตัวของมันเองจะบังคับให้คุณใช้Calendarหรือ Joda Time (เว้นแต่คุณต้องการบัญชีสำหรับเขตเวลาด้วยตัวคุณเองซึ่งฉันไม่แนะนำ)

การอ้างอิงด่วนสำหรับนักพัฒนา Android

//Add joda library dependency to your build.gradle file
dependencies {
     ...
     implementation 'joda-time:joda-time:2.9.9'
}

โค้ดตัวอย่าง (ตัวอย่าง)

DateTimeComparator dateTimeComparator = DateTimeComparator.getDateOnlyInstance();

Date myDateOne = ...;
Date myDateTwo = ...;

int retVal = dateTimeComparator.compare(myDateOne, myDateTwo);

if(retVal == 0)
   //both dates are equal
else if(retVal < 0)
   //myDateOne is before myDateTwo
else if(retVal > 0)
   //myDateOne is after myDateTwo

28
Altough อย่างที่ Jon บอกว่า "Use Joda Time" เป็นพื้นฐานของคำถาม SO เกือบทั้งหมดที่ถามเกี่ยวกับ java.util.Date หรือ java.util.Calendar ฉันคิดเสมอว่าสิ่งแรกที่ดีที่สุดคือให้คำตอบที่เป็นรูปธรรมตามคำถามของผู้ใช้ที่ น้อยที่สุดที่จะแสดงว่ายากที่จะสามารถทำวิธี java และหลังจากนั้นแนะนำการใช้ Joda ...
JuanZe

13
@JuanZe: นั่นต้องใช้วิธีการทำสิ่งที่ถูกต้องใน API ที่เจ็บปวดซึ่งนิยามโดยเจ็บปวด ฉันอยากจะใช้เวลาที่ทำอะไรบางอย่างมีประสิทธิผลมากขึ้น :)
จอน Skeet

1
@ MetroidFan2002: LocalDate เป็นตัวเลือกที่ดีกว่า DateMidnight เนื่องจากมีความชัดเจนมากกว่าและทุกวันไม่มีเที่ยงคืน ...
Jon Skeet

2
@dertoni: แน่นอน - ในบราซิลเมื่อนาฬิกาเดินหน้าต่อไปเนื่องจากการปรับเวลาตามฤดูกาลซึ่งเกิดขึ้นในช่วงเริ่มต้นของวัน ... นาฬิกาจะอ่าน 23:59:58, 23:59:59, 01:00 : 00, 01:00:01 และอื่น ๆ
Jon Skeet

8
จะดีกว่าไหมถ้าใช้DateTimeComparator.getDateOnlyInstance ()
Emil

125

Apache Commons-langเกือบแพร่หลายแล้ว แล้วเรื่องนี้ล่ะ

if (DateUtils.isSameDay(date1, date2)) {
    // it's same
} else if (date1.before(date2)) {
   // it's before
} else {
   // it's after
}

เวอร์ชัน 2.6 รวมฟังก์ชัน truncatedCompareTo ฟังก์ชันcommons.apache.org/proper/commons-lang/javadocs/api-2.6/org/ ......
ผู้ใช้ shonky linux

2
Sadly ไม่ทนต่อวันที่ว่าง
Pavel Niedoba

ผู้ชายทุกวันนี้เรามี Java 8 stackoverflow.com/a/35411693/259237
André

ฉันไม่แนะนำให้ใช้ก่อนหน้านี้ด้วยวิธีนี้เพราะถ้าวัตถุวันที่แรกหรือวันที่สองไม่ได้รับการถ่ายทอดจาก Timestamp และมี Mileeconds และอีกวัตถุหนึ่งเป็นวัตถุวันที่ปกติคุณจะมีปัญหาเพราะวันที่จากร้าน datestamp ในส่วนอื่น ของวัตถุ miliseconds ให้ความแตกต่างแม้ว่าวันที่ทั้งสองเท่ากัน
Zini

น่าเสียดายที่ Apache ไม่ได้ใช้อุปกรณ์ Android มากกว่า 1.3 พันล้านเครื่องและเป็นห้องสมุดขนาดใหญ่ที่ต้องพึ่งพากรณีใช้เพียงครั้งเดียว ฉันจะต้องการอย่างอื่น: /
milosmns

58

หากคุณต้องการใช้ java.util.Date จริงๆคุณจะทำสิ่งนี้:

public class TimeIgnoringComparator implements Comparator<Date> {
  public int compare(Date d1, Date d2) {
    if (d1.getYear() != d2.getYear()) 
        return d1.getYear() - d2.getYear();
    if (d1.getMonth() != d2.getMonth()) 
        return d1.getMonth() - d2.getMonth();
    return d1.getDate() - d2.getDate();
  }
}

หรือใช้ปฏิทินแทน (แนะนำให้ใช้เนื่องจาก getYear () และเลิกใช้แล้ว)

public class TimeIgnoringComparator implements Comparator<Calendar> {
  public int compare(Calendar c1, Calendar c2) {
    if (c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)) 
        return c1.get(Calendar.YEAR) - c2.get(Calendar.YEAR);
    if (c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)) 
        return c1.get(Calendar.MONTH) - c2.get(Calendar.MONTH);
    return c1.get(Calendar.DAY_OF_MONTH) - c2.get(Calendar.DAY_OF_MONTH);
  }
}

1
ในวิธีที่สองคุณลืมอัปเดตข้อมูลอ้างอิงบางส่วนของคุณตั้งแต่ d1, d2 ถึง c1, c2
stivlo

1
หลังจากแก้ไขรายละเอียดรหัสของคุณได้ดี: ฉันได้ทดสอบหน่วยอย่างกว้างขวางแล้ว ฉันได้เพิ่มขั้นตอนในการสร้างปฏิทินจากวันที่และใช้รหัสของคุณในโครงการ github ที่เพิ่งสร้างใหม่org.obliquid.helpersขอบคุณ
stivlo

น่ารักน่าใช้มากโดยไม่ต้องใช้ไลบรารีภายนอก
4gus71n

1
วิธีการเหล่านี้ทั้งหมดเลิกใช้แล้ว สิ่งนี้มีผลกระทบอะไรบ้าง?
Pranav Mahajan

36

การตั้งค่าของฉันคือการใช้ห้องสมุดJoda ที่แทรกjava.util.Dateโดยตรงเนื่องจาก Joda สร้างความแตกต่างระหว่างวันที่และเวลา (ดูชั้น YearMonthDayและDateTime )

อย่างไรก็ตามหากคุณต้องการใช้java.util.Dateฉันขอแนะนำให้เขียนวิธีอรรถประโยชน์ เช่น

public static Date setTimeToMidnight(Date date) {
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( date );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

1
Joda-Time YearMonDay เลิกใช้งานใน LocalDate แล้ว นอกจากนี้รหัสในปฏิทินจะมีปัญหาหากเขตเวลาไม่มีเที่ยงคืน 00:00 เนื่องจากประหยัดเวลากลางวัน
JodaStephen

1
วิธีนี้ใช้ไม่ได้ 100% มีกรณีการใช้งานที่ฉันทำอย่างนั้นและ calendar.getTime () จะยังคงกลับเวลาด้วยชั่วโมงที่กำหนดเป็นวันที่พารามิเตอร์ ดีที่สุดเพื่อล้างฟิลด์และตั้งค่าเฉพาะปีเดือนและวัน
Jonathan Drapeau

31

ความคิดเห็นเกี่ยวกับทางเลือกนี้?

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));

1
ฉันไม่คิดว่ามันจะใช้ได้แม้ว่าการเปลี่ยนมาใช้ Strings เป็นความคิดที่ดี ==ผู้ประกอบการไม่จำเป็นต้องกลับมาtrueเทียบเท่า Strings (การใช้equals()) คุณไม่สามารถใช้โอเปอเรเตอร์การเปรียบเทียบอื่น ๆ ที่คุณกล่าวถึงอย่างแน่นอน
Harto

1
อ่าใช่ - ทับทิมของฉันทำลายจาวาของฉัน! สามารถแปลงสตริงเป็น ints แม้ว่าสำหรับ <,> ฯลฯ
Robert Brown

การใช้ Joda นั้นเป็นวิธีที่ดี แต่นี่มันช่างยอดเยี่ยม!
Arne Evertsson

สิ่งนี้ไม่ได้ผลสำหรับทุกคน แต่มันง่ายและเบามาก ทางเลือกที่ดีเมื่อไม่มี libs อื่น ๆ
Jacob Marble เมื่อ

sdf.format(date1).compareTo(sdf.format(date2));สำหรับการสั่งซื้อของวันที่คุณยังอาจจะใช้
Ole VV

18

หากคุณต้องการเปรียบเทียบเฉพาะเดือนวันและปีของวันที่สองรหัสต่อไปนี้ใช้งานได้สำหรับฉัน:

SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
sdf.format(date1).equals(sdf.format(date2));

ขอบคุณ Rob


13

ฉันชอบJoda Timeเหมือนกัน แต่นี่เป็นอีกทางเลือก:

long oneDay = 24 * 60 * 60 * 1000
long d1 = first.getTime() / oneDay
long d2 = second.getTime() / oneDay
d1 == d2

แก้ไข

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

long oneDay = 24 * 60 * 60 * 1000
long hoursFromUTC = -4 * 60 * 60 * 1000 // EST with Daylight Time Savings
long d1 = (first.getTime() + hoursFromUTC) / oneDay
long d2 = (second.getTime() + hoursFromUTC) / oneDay
d1 == d2

ฉันบอกว่าฉันควรใช้ Joda Time แต่นั่นเป็นจุดที่ดี ฉันหันไปใช้กลวิธีต่ำเช่นนี้เมื่อฉันไม่สนใจ TZ จริงๆ
Daniel C. Sobral

แผนกสามารถหลีกเลี่ยงได้:Math.abs(second.getTime() - first.getTime()) < 1000L*60*60*24
Vadzim

@Vadzim < oneDayทำให้
Daniel C. Sobral

2
@Vadzim จะตรวจสอบเฉพาะวันที่น้อยกว่า 1 วัน ไม่ได้หมายความว่าพวกเขาอยู่ในวันเดียวกัน
arahant

@ arahant ใช่ นี่อาจจะเพียงพอเมื่อวันที่ที่สองถูกจัดเรียงในเวลาเที่ยงคืนเสมอ
Vadzim

12

TL; DR

myJavaUtilDate1.toInstant()
               .atZone( ZoneId.of( "America/Montreal" ) )
               .toLocalDate()
               .isEqual (
                   myJavaUtilDate2.toInstant()
                                  .atZone( ZoneId.of( "America/Montreal" ) )
                                  .toLocalDate()
               )

หลีกเลี่ยงคลาสวันและเวลาดั้งเดิม

หลีกเลี่ยงคลาสวัน - เวลาเก่าที่ลำบากเช่นDate&Calendarแทนที่ด้วยคลาส java.time

ใช้ java.time

A java.util.Dateแสดงถึงช่วงเวลาบนเส้นเวลาใน UTC เทียบเท่าใน java.time Instantคือ คุณสามารถแปลงโดยใช้วิธีการใหม่ที่เพิ่มเข้ามาในคลาสเดิม

Instant instant1 = myJavaUtilDate1.toInstant();
Instant instant2 = myJavaUtilDate2.toInstant();

คุณต้องการเปรียบเทียบตามวันที่ เขตเวลามีความสำคัญในการกำหนดวันที่ สำหรับช่วงเวลาใด ๆ วันที่จะแตกต่างกันไปทั่วโลกตามโซน ตัวอย่างเช่นสองสามนาทีหลังเที่ยงคืนในปารีสฝรั่งเศสเป็นวันใหม่ในขณะที่ยังคง "เมื่อวาน" ในMontréalQuébecมอนทรีออควิเบก

ระบุชื่อโซนเวลาที่เหมาะสมในรูปแบบของcontinent/regionเช่นAmerica/Montreal, หรือAfrica/Casablanca Pacific/Aucklandอย่าใช้ตัวย่อ 3-4 ตัวอักษรเช่นESTหรือISTเพราะไม่ใช่เขตเวลาจริงไม่ใช่แบบมาตรฐานและไม่ซ้ำกัน (!)

ZoneId z = ZoneId.of( "America/Montreal" );

สมัครZoneIdไปที่จะได้รับInstantZonedDateTime

ZonedDateTime zdt1 = instant1.atZone( z );
ZonedDateTime zdt2 = instant2.atZone( z );

LocalDateชั้นหมายถึงค่าวันเท่านั้นโดยไม่ต้องเวลาของวันและไม่มีโซนเวลา เราสามารถแยกส่วน a LocalDateจากZonedDateTimeและกำจัดส่วนเวลาได้อย่างมีประสิทธิภาพ

LocalDate localDate1 = zdt1.toLocalDate();
LocalDate localDate2 = zdt2.toLocalDate();

ตอนนี้เปรียบเทียบโดยใช้วิธีการเช่นisEqual, และisBeforeisAfter

Boolean sameDate = localDate1.isEqual( localDate2 );

ดูรหัสนี้ทำงานอยู่ที่ IdeOne.com

ทันที 1: 2017-03-25T04: 13: 10.971Z | instant2: 2017-03-24T22: 13: 10.972Z

zdt1: 2017-03-25T00: 13: 10.971-04: 00 [อเมริกา / มอนทรีออล] | zdt2: 2017-03-24T18: 13: 10.972-04: 00 [อเมริกา / มอนทรีออล]

ท้องถิ่นวันที่ 1: 2017-03-25 | localDate2: 2017-03-24

sameDate: false


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

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

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

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

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

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

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


7

อาปาเช่คอมมอนส์กล่าวถึงแล้ว:

org.apache.commons.lang.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH)

ให้วัตถุวันที่ที่มีเฉพาะวันที่โดยไม่มีเวลาและคุณสามารถเปรียบเทียบได้ Date.compareTo


6

ฉันกลัวว่าจะไม่มีวิธีเปรียบเทียบวันที่สองวันที่อาจเรียกว่า "ง่าย" หรือ "ง่าย"

เมื่อเปรียบเทียบอินสแตนซ์สองช่วงเวลากับความแม่นยำที่ลดลง (เช่นการเปรียบเทียบวันที่) คุณจะต้องคำนึงว่าเขตเวลามีผลต่อการเปรียบเทียบอย่างไร

หากdate1กำลังระบุเหตุการณ์ที่เกิดขึ้นในเขตเวลา +2 และdate2กำลังระบุเหตุการณ์ที่เกิดขึ้นใน EST เช่นคุณต้องระมัดระวังเพื่อให้เข้าใจถึงผลกระทบของการเปรียบเทียบอย่างเหมาะสม

คุณมีจุดประสงค์เพื่อพิจารณาว่าเหตุการณ์ทั้งสองเกิดขึ้นในวันที่ปฏิทินเดียวกันในเขตเวลาของตนเองหรือไม่? หรือคุณจำเป็นต้องทราบว่าวันที่สองวันตรงกับวันที่ปฏิทินเดียวกันในเขตเวลาที่ระบุหรือไม่ (UTC หรือ TZ ในพื้นที่ของคุณเป็นต้น)

เมื่อคุณทราบว่าจริง ๆ แล้วคุณกำลังพยายามเปรียบเทียบมันเป็นเรื่องของการสามวันเดือนปีในโซนเวลาที่เหมาะสมและทำการเปรียบเทียบ

เวลาของ Joda อาจทำให้การเปรียบเทียบที่แท้จริงดูสะอาดกว่า แต่ความหมายของการเปรียบเทียบยังคงเป็นสิ่งที่คุณต้องเข้าใจด้วยตัวเอง


6

หากคุณกำลังใช้ Java 8 คุณควรใช้java.time.*คลาสเพื่อเปรียบเทียบวันที่ - ซึ่งเป็นที่ต้องการของคลาสต่างๆjava.util.*คลาส

เช่น; https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html

LocalDate date1 = LocalDate.of(2016, 2, 14);
LocalDate date2 = LocalDate.of(2015, 5, 23);
date1.isAfter(date2);

5

หากคุณต้องการเปรียบเทียบเพียงสองวันที่ไม่มีเวลารหัสต่อไปนี้อาจช่วยคุณได้:

final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Date dLastUpdateDate = dateFormat.parse(20111116);
Date dCurrentDate = dateFormat.parse(dateFormat.format(new Date()));
if (dCurrentDate.after(dLastUpdateDate))
{
   add your logic
}

นั่นเป็นเช่นเดียวกับคำตอบของร็อบ ฉันคิดว่าวิธีแก้ปัญหาของ Jornนั้นดีกว่าเพราะมันไม่ได้เกี่ยวข้องกับการเดินทางไปยังสายอักขระและควรทำสิ่งเดียวกันให้สำเร็จ
เปียห์

4

นี่คือทางออกจากบล็อกนี้: http://brigitzblog.blogspot.com/2011/10/java-compare-dates.html

long milliseconds1 = calendar1.getTimeInMillis();
long milliseconds2 = calendar2.getTimeInMillis();
long diff = milliseconds2 - milliseconds1;
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("Time in days: " + diffDays  + " days.");

นั่นคือคุณสามารถดูว่าความแตกต่างของเวลาเป็นมิลลิวินาทีน้อยกว่าความยาวของหนึ่งวัน


4
ตัวอย่างนั้นจะตรวจสอบว่าทั้งสองวันอยู่ภายใน 24 ชั่วโมงของกันและกัน แต่ไม่จำเป็นว่าพวกเขาทั้งสองในวันเดียวกันคือว่ามันเป็นไปได้ที่จะขยายเที่ยงคืน จะเป็นการดีกว่าที่จะแบ่งมิลลิวินาทีทั้งสองชุดด้วย MILLIS_IN_DAY และเปรียบเทียบผลลัพธ์ แต่จะมีความแน่นอนสำหรับ UTC ไม่ใช่เวลาท้องถิ่น
รูปา

4

`

SimpleDateFormat sdf= new SimpleDateFormat("MM/dd/yyyy")

   Date date1=sdf.parse("03/25/2015");



  Date currentDate= sdf.parse(sdf.format(new Date()));

   return date1.compareTo(currentDate);

`


3

ฉันไม่รู้ว่ามันเป็นความคิดใหม่หรืออย่างอื่น แต่ฉันแสดงให้คุณเห็นว่าฉันทำ

SimpleDateFormat dtf = new SimpleDateFormat("dd/MM/yyyy");
Date td_date = new Date();
String first_date = dtf.format(td_date);    //First seted in String 
String second_date = "30/11/2020";          //Second date you can set hear in String

String result = (first_date.equals(second_date)) ? "Yes, Its Equals":"No, It is not Equals";
System.out.println(result);

3

เพียงตรวจสอบ DAY_OF_YEAR ร่วมกับคุณสมบัติ YEAR

boolean isSameDay = 
firstCal.get(Calendar.YEAR) == secondCal.get(Calendar.YEAR) &&
firstCal.get(Calendar.DAY_OF_YEAR) == secondCal.get(Calendar.DAY_OF_YEAR)

แก้ไข:

ตอนนี้เราสามารถใช้พลังของฟังก์ชั่นการขยาย Kotlin

fun Calendar.isSameDay(second: Calendar): Boolean {

    return this[Calendar.YEAR] == second[Calendar.YEAR] && this[Calendar.DAY_OF_YEAR] == second[Calendar.DAY_OF_YEAR]
}

fun Calendar.compareDatesOnly(other: Calendar): Int {

    return when {
        isSameDay(other) -> 0
        before(other) -> -1
        else -> 1
    }
}

มันผิดเพราะวันที่ที่มีปีแตกต่างกันอาจมีวันเดียวกันของปีเช่น 2015-01-01 และ 2016-01-01
เนลสัน eldoro

@nelsoneldoro ขอบคุณสำหรับความคิดเห็นของคุณลืมที่จะเพิ่มการตรวจสอบสำหรับปีตอนนี้มันควรจะโอเค
Simon K. Gerges


2
public Date saveDateWithoutTime(Date date) {
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( date );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.HOUR, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    return calendar.getTime();
}

วิธีนี้จะช่วยคุณเปรียบเทียบวันที่โดยไม่คำนึงถึงเวลา


1

การใช้ getDateInstance ของ SimpleDateFormat เราสามารถเปรียบเทียบอ็อบเจกต์วันที่สองอันโดยไม่มีเวลา ดำเนินการรหัสด้านล่าง

public static void main(String[] args) {        
        Date date1  = new Date();
        Date date2  = new Date();
        DateFormat dfg = SimpleDateFormat.getDateInstance(DateFormat.DATE_FIELD);
        String dateDtr1 = dfg.format(date1);
        String dateDtr2 = dfg.format(date2);
        System.out.println(dateDtr1+" : "+dateDtr2);
        System.out.println(dateDtr1.equals(dateDtr2));  

    }


1

อีกวิธีการเปรียบเทียบแบบง่ายตามคำตอบที่นี่และคำแนะนำที่ปรึกษาของฉัน

public static int compare(Date d1, Date d2) {
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.setTime(d1);
    c1.set(Calendar.MILLISECOND, 0);
    c1.set(Calendar.SECOND, 0);
    c1.set(Calendar.MINUTE, 0);
    c1.set(Calendar.HOUR_OF_DAY, 0);
    c2.setTime(d2);
    c2.set(Calendar.MILLISECOND, 0);
    c2.set(Calendar.SECOND, 0);
    c2.set(Calendar.MINUTE, 0);
    c2.set(Calendar.HOUR_OF_DAY, 0);
    return c1.getTime().compareTo(c2.getTime());
  }

แก้ไข : ตาม @Jonathan Drapeau โค้ดด้านบนล้มเหลวในบางกรณี(ฉันต้องการดูกรณีเหล่านั้นโปรด)และเขาแนะนำสิ่งต่อไปนี้ตามที่ฉันเข้าใจ:

public static int compare2(Date d1, Date d2) {
    Calendar c1 = Calendar.getInstance();
    Calendar c2 = Calendar.getInstance();
    c1.clear();
    c2.clear();
    c1.set(Calendar.YEAR, d1.getYear());
    c1.set(Calendar.MONTH, d1.getMonth());
    c1.set(Calendar.DAY_OF_MONTH, d1.getDay());
    c2.set(Calendar.YEAR, d2.getYear());
    c2.set(Calendar.MONTH, d2.getMonth());
    c2.set(Calendar.DAY_OF_MONTH, d2.getDay());
    return c1.getTime().compareTo(c2.getTime());
}

โปรดสังเกตว่าคลาส Date เลิกใช้แล้วเนื่องจากไม่สามารถแก้ไขได้ในระดับสากล ใช้คลาสปฏิทินแทน!


วิธีนี้ใช้ไม่ได้ 100% มีกรณีการใช้งานที่ฉันทำอย่างนั้นและ calendar.getTime () จะยังคงกลับเวลาด้วยชั่วโมงที่กำหนดเป็นวันที่พารามิเตอร์ ดีที่สุดเพื่อล้างฟิลด์และตั้งค่าเฉพาะปีเดือนและวัน
Jonathan Drapeau

@JonathanDrapeau ฟังดูเหมือนว่าคุณอาจจะเจอกับการที่ไม่เลือกโซนเวลาที่ชัดเจน แน่นอนดีกว่าให้เขตเวลาที่ชัดเจนกว่าการใช้เลิกใช้วิธีการของgetXxx Date
Ole VV

1

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

เนื่องจากคำถามของคุณไม่ชัดเจนเกี่ยวกับเรื่องนี้ฉันถือว่าคุณมีคลาสที่มีฟิลด์อินสแตนซ์ที่แสดงถึงเวลาและการนำไปใช้Comparableและคุณต้องการให้การเรียงลำดับวัตถุตามธรรมชาติเป็นวันที่ แต่ไม่ใช่เวลา ของฟิลด์นั้น ตัวอย่างเช่น:

public class ArnesClass implements Comparable<ArnesClass> {

    private static final ZoneId arnesTimeZone = ZoneId.systemDefault();

    private Instant when;

    @Override
    public int compareTo(ArnesClass o) {
        // question is what to put here
    }

}

Java 8 java.timeคลาส

ผมได้เอาเสรีภาพของการเปลี่ยนแปลงประเภทของข้อมูลเช่นของคุณจากDateการInstantที่ระดับที่สอดคล้องกันใน Java 8. ฉันสัญญาว่าจะกลับไปรักษาDateด้านล่าง ฉันได้เพิ่มค่าคงที่ของเขตเวลาด้วย คุณอาจจะตั้งค่าให้ZoneOffset.UTCหรือZoneId.of("Europe/Stockholm")หรือสิ่งที่คุณหาที่เหมาะสม (การตั้งค่าไปยังZoneOffsetงานเพราะZoneOffsetเป็น subclass ของZoneId)

ฉันเลือกที่จะแสดงวิธีแก้ปัญหาโดยใช้คลาส Java 8 คุณถามหาวิธีที่ง่ายที่สุดใช่มั้ย :-) นี่คือcompareToวิธีการที่คุณขอ:

public int compareTo(ArnesClass o) {
    LocalDate dateWithoutTime = when.atZone(arnesTimeZone).toLocalDate();
    LocalDate otherDateWithoutTime = o.when.atZone(arnesTimeZone).toLocalDate();
    return dateWithoutTime.compareTo(otherDateWithoutTime);
}

หากคุณไม่เคยต้องใช้เวลาส่วนหนึ่งของwhenมันเป็นหลักสูตรที่ง่ายต่อการประกาศและข้าม Conversion ทั้งหมด จากนั้นเราไม่ต้องกังวลเกี่ยวกับเขตเวลาอีกต่อไปเช่นกันwhenLocalDate

ตอนนี้คิดว่าด้วยเหตุผลบางอย่างที่คุณไม่สามารถประกาศของคุณwhenภาคสนามหรือคุณต้องการที่จะให้มันสมัยเก่าInstant Dateหากคุณยังคงสามารถใช้ Java 8 เพียงแปลงเป็นให้Instantทำดังนี้ก่อน:

    LocalDate dateWithoutTime = when.toInstant().atZone(arnesTimeZone).toLocalDate();

o.whenในทำนองเดียวกันสำหรับ

ไม่มี Java 8 ใช่ไหม

หากคุณไม่สามารถใช้ java 8 มีสองตัวเลือก:

  1. แก้ได้โดยใช้หนึ่งในชั้นเรียนเก่าอย่างใดอย่างหนึ่งหรือCalendarSimpleDateFormat
  2. ใช้ backport ของคลาสวันที่และเวลาของ Java 8 กับ Java 6 และ 7 จากนั้นทำตามขั้นตอนด้านบน ฉันรวมลิงค์ที่ด้านล่าง ห้ามใช้ JodaTime JodaTime อาจเป็นคำแนะนำที่ดีเมื่อคำตอบแนะนำให้เขียน แต่ตอนนี้ JodaTime อยู่ในโหมดบำรุงรักษาดังนั้น ThreeTen backport จึงเป็นตัวเลือกที่ดีกว่าและปลอดภัยกว่าในอนาคต

วิธีที่ล้าสมัย

คำตอบของ Adamskiแสดงให้คุณเห็นว่าจะตัดเวลาออกอย่างไรDateโดยใช้Calendarคลาส ฉันขอแนะนำให้คุณใช้getInstance(TimeZone)เพื่อรับCalendarอินสแตนซ์สำหรับเขตเวลาที่คุณต้องการ เป็นทางเลือกที่คุณอาจจะใช้ความคิดจากช่วงครึ่งหลังของคำตอบของ Jorn

การใช้SimpleDateFormatเป็นวิธีการใช้งานทางอ้อมCalendarเนื่องจากSimpleDateFormatมีCalendarวัตถุ อย่างไรก็ตามคุณอาจพบว่ามีปัญหาน้อยกว่าการใช้Calendarโดยตรง:

private static final TimeZone arnesTimeZone = TimeZone.getTimeZone("Europe/Stockholm");
private static final DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
static {
    formatter.setTimeZone(arnesTimeZone);
}

private Date when;

@Override
public int compareTo(ArnesClass o) {
    return formatter.format(when).compareTo(formatter.format(o.when));
}

นี้ได้รับแรงบันดาลใจจากคำตอบของร็อบ

การพึ่งพาเขตเวลา

ทำไมเราต้องเลือกเขตเวลาที่เฉพาะเจาะจง สมมติว่าเราต้องการเปรียบเทียบสองครั้งใน UTC คือ 24 มีนาคม 0:00 (เที่ยงคืน) และ 12:00 (เที่ยง) หากคุณทำเช่นนั้นใน CET (พูดยุโรป / ปารีส) พวกเขาคือ 1 น. และ 13.00 น. ในวันที่ 24 มีนาคมนั่นคือวันเดียวกัน ในนิวยอร์ก (เวลาตามฤดูกาลตะวันออก) พวกเขาคือ 20:00 น. ในวันที่ 23 มีนาคมและ 8:00 น. ในวันที่ 24 มีนาคมนั่นคือไม่ใช่วันที่เดียวกัน ดังนั้นจึงสร้างความแตกต่างซึ่งคุณเลือกโซนเวลา หากคุณพึ่งการเริ่มต้นของคอมพิวเตอร์คุณอาจประหลาดใจเมื่อมีคนพยายามเรียกใช้รหัสของคุณบนคอมพิวเตอร์ในที่อื่นในโลกยุคโลกาภิวัตน์นี้

ลิงค์

เชื่อมโยงไปยัง ThreeTen ย้ายกลับ, ย้ายกลับของ Java 8 วันที่และเวลาเรียนชวาที่ 6 และ 7: http://www.threeten.org/threetenbp/


0

ข้อเสนอของฉัน:

    Calendar cal = Calendar.getInstance();
    cal.set(1999,10,01);   // nov 1st, 1999
    cal.set(Calendar.AM_PM,Calendar.AM);
    cal.set(Calendar.HOUR,0);
    cal.set(Calendar.MINUTE,0);
    cal.set(Calendar.SECOND,0);
    cal.set(Calendar.MILLISECOND,0);

    // date column in the Thought table is of type sql date
    Thought thought = thoughtDao.getThought(date, language);

    Assert.assertEquals(cal.getTime(), thought.getDate());

0

การใช้ Apache คอมมอนส์คุณสามารถทำได้:

import org.apache.commons.lang3.time.DateUtils

DateUtils.truncatedEquals(first, second, Calendar.DAY_OF_MONTH)

0
public static Date getZeroTimeDate(Date fecha) {
    Date res = fecha;
    Calendar calendar = Calendar.getInstance();

    calendar.setTime( fecha );
    calendar.set(Calendar.HOUR_OF_DAY, 0);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    calendar.set(Calendar.MILLISECOND, 0);

    res = calendar.getTime();

    return res;
}

Date currentDate = getZeroTimeDate(new Date());// get current date   

นี่เป็นวิธีที่ง่ายที่สุดในการแก้ปัญหานี้


0

ฉันแก้ไขได้โดยเปรียบเทียบโดยการประทับเวลา:

    Calendar last = Calendar.getInstance();

    last.setTimeInMillis(firstTimeInMillis);

    Calendar current = Calendar.getInstance();

    if (last.get(Calendar.DAY_OF_MONTH) != current.get(Calendar.DAY_OF_MONTH)) {
        //not the same day
    }

ฉันหลีกเลี่ยงการใช้ Joda Time เพราะบน Android ใช้พื้นที่มาก เรื่องขนาด ;)


0

โซลูชันอื่นที่ใช้ Java 8 และค้นหาทันใจกำลังใช้เมธอดtruncatedTo

ส่งคืนสำเนาของ Instant นี้ถูกตัดเหลือหน่วยที่ระบุ

ตัวอย่าง:

@Test
public void dateTruncate() throws InterruptedException {
    Instant now = Instant.now();
    Thread.sleep(1000*5);
    Instant later = Instant.now();
    assertThat(now, not(equalTo(later)));
    assertThat(now.truncatedTo(ChronoUnit.DAYS), equalTo(later.truncatedTo(ChronoUnit.DAYS)));
}

0
// Create one day 00:00:00 calendar
int oneDayTimeStamp = 1523017440;
Calendar oneDayCal = Calendar.getInstance();
oneDayCal.setTimeInMillis(oneDayTimeStamp * 1000L);
oneDayCal.set(Calendar.HOUR_OF_DAY, 0);
oneDayCal.set(Calendar.MINUTE, 0);
oneDayCal.set(Calendar.SECOND, 0);
oneDayCal.set(Calendar.MILLISECOND, 0);

// Create current day 00:00:00 calendar
Calendar currentCal = Calendar.getInstance();
currentCal.set(Calendar.HOUR_OF_DAY, 0);
currentCal.set(Calendar.MINUTE, 0);
currentCal.set(Calendar.SECOND, 0);
currentCal.set(Calendar.MILLISECOND, 0);

if (oneDayCal.compareTo(currentCal) == 0) {
    // Same day (excluding time)
}

ขอบคุณ! มีคำตอบอื่น ๆ อีกไม่กี่อย่างที่ใช้วิธีการเดียวกันแล้ว - แม้ว่าฉันจะเห็นว่าตอนนี้คุณกำลังเปรียบเทียบวัตถุในปฏิทินโดยตรงในขณะที่พวกเขาส่วนใหญ่เปรียบเทียบ getTime ()
รูปี

-2

นี่คือสิ่งที่ได้ผลสำหรับฉัน:

var Date1 = new Date(dateObject1.toDateString()); //this sets time to 00:00:00
var Date2 = new Date(dateObject2.toDateString()); 
//do a normal compare
if(Date1 > Date2){ //do something }

2
การเปรียบเทียบ "ปกติ" ของคุณจะไม่ได้รวบรวมใน Java ถ้ามันจะมันจะเปรียบเทียบการอ้างอิงวัตถุ แต่ไม่ได้รับอนุญาต
stivlo

ฉันแก้ไขเพื่อเพิ่ม Markdown แต่ stivlo นั้นถูกต้อง ฉันไม่รู้ว่าโค้ดนั้นทำงานอย่างไรสำหรับคุณ
Pops

นี่อาจเป็น js
Andrey Luiz

-2

DateUtil.daysBetween()วิธีการเกี่ยวกับ มันคือ Java และมันจะคืนค่าตัวเลข (ต่างกันเป็นวัน)

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