如何比较两个date没有时间部分?
我想有一个compareTo方法忽略java.util.Date的时间部分。 我想有很多方法可以解决这个问题。 最简单的方法是什么?
更新:虽然当时Joda时间是一个很好的build议,但请尽可能使用Java 8+中的java.time
库。
我的select是使用乔达时间 ,这使得这非常简单:
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时间”几乎是所有关于java.util.Date
或java.util.Calendar
SO问题的基础,它是一个非常优秀的API,如果你使用date/时间做任何重要的事情 ,你应该真的如果可能,可以使用它。)
如果您绝对不得不使用内置的API,则应该使用适当的date并使用适当的时区创buildCalendar
实例。 然后,您可以将每个日历中的每个字段设置为小时,分,秒和毫秒为0,并比较结果时间。 肯定与Joda解决scheme相比,虽然:)
时区部分很重要: java.util.Date
总是基于UTC。 在大多数情况下,我已经对某个date感兴趣,这是某个特定时区的date。 这将迫使你使用Calendar
或乔达时间(除非你想自己考虑的时区,我不build议。)
Apache commons-lang几乎无处不在。 那么这个怎么样?
if (DateUtils.isSameDay(date1, date2)) { // it's same } else if (date1.before(date2)) { // it's before } else { // it's after }
如果你真的想使用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); } }
因为Joda会区分date和时间(请参见YearMonthDay和DateTime类),所以我最好直接使用java.util.Date
的Joda库插入。
但是,如果您确实希望使用java.util.Date
我会build议您编写一个实用程序方法; 例如
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(); }
对这个select的任何意见?
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); sdf.format(date1).equals(sdf.format(date2));
我也更喜欢Joda Time ,但是这里有一个select:
long oneDay = 24 * 60 * 60 * 1000 long d1 = first.getTime() / oneDay long d2 = second.getTime() / oneDay d1 == d2
编辑
我把UTC的东西放在下面,以防您需要比较UTC以外的特定时区的date。 如果你有这样的需要,那么我真的build议去乔达。
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
如果您只想比较两个date的月份,date和年份,以下代码适用于我:
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd"); sdf.format(date1).equals(sdf.format(date2));
感谢Rob。
已经提到apache commons-utils :
org.apache.commons.lang.time.DateUtils.truncate(date, Calendar.DAY_OF_MONTH)
给你date对象只包含date,没有时间,你可以比较它与Date.compareTo
如果您使用的是Java 8,则应该使用java.time.*
类来比较date – 它优先于各种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);
恐怕没有办法比较两种可以称之为“简单”或“简单”的date。
当比较两个时间实例的精度降低(例如,仅仅比较date)时,您必须始终考虑时区如何影响比较。
如果date1
指定发生在+2时区中的事件,而date2
指定发生在EST中的事件,则必须注意正确理解比较的含义。
你的目的是弄清楚这两个事件是否发生在他们各自的时区的同一日历date? 或者您是否需要知道这两个date是否属于特定时区(例如UTC或您本地的TZ)中的相同日历date。
一旦找出你想要比较的实际内容,只需要在适当的时间段内获得年份 – date三元组并进行比较即可。
乔达的时间可能会使实际的比较操作看起来更清晰,但比较的语义仍然是你需要弄清楚自己。
以下是此博客的解决scheme: 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.");
即你可以看到以毫秒为单位的时间差是否小于一天的时间长度。
如果你只是想比较没有时间的两个date,那么下面的代码可能会帮助你:
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 }
TL;博士
myJavaUtilDate1.toInstant() .atZone( ZoneId.of( "America/Montreal" ) ) .toLocalDate() .isEqual ( myJavaUtilDate2.toInstant() .atZone( ZoneId.of( "America/Montreal" ) ) .toLocalDate() )
避免遗留的date时间类
避免使用诸如Date
和Calendar
等麻烦的旧式遗留date时间类,现在由java.time类取代。
使用java.time
java.util.Date
表示UTC中时间轴上的某一时刻。 java.time中的等价物是Instant
。 您可以使用添加到旧类的新方法进行转换。
Instant instant1 = myJavaUtilDate1.toInstant(); Instant instant2 = myJavaUtilDate2.toInstant();
你想按date比较。 时区对确定date至关重要。 对于任何特定的时刻,date在全球各地按照地区而不同。 例如, 巴黎午夜过后的几分钟, 法国是一个新的一天,而在魁北克蒙特利尔仍然是“昨天”。
以America/Montreal
, Africa/Casablanca
, Pacific/Auckland
等continent/region
的格式指定适当的时区名称 。 切勿使用3-4字母缩写(如EST
或IST
因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId z = ZoneId.of( "America/Montreal" );
将ZoneId
应用于Instant
以获取ZonedDateTime
。
ZonedDateTime zdt1 = instant1.atZone( z ); ZonedDateTime zdt2 = instant2.atZone( z );
LocalDate
类代表没有时间和没有时区的只有date的值。 我们可以从ZonedDateTime
提取LocalDate
,从而有效地消除了每天的时间部分。
LocalDate localDate1 = zdt1.toLocalDate(); LocalDate localDate2 = zdt2.toLocalDate();
现在比较一下,使用isEqual
, isBefore
和isAfter
。
Boolean sameDate = localDate1.isEqual( localDate2 );
看到这个代码在IdeOne.com上运行 。
instant1:2017-03-25T04:13:10.971Z | instant2:2017-03-24T22:13:10.972Z
zdt1:2017-03-25T00:13:10.971-04:00 [America / Montreal] | zdt2:2017-03-24T18:13:10.972-04:00 [美国/蒙特利尔]
localDate1:2017-03-25 | localDate2:2017-03-24
sameDate:false
关于java.time
java.time框架内置于Java 8及更高版本中。 这些类取代了麻烦的旧的遗留date时间类,如java.util.Date
, Calendar
和SimpleDateFormat
。
Joda-Time项目现在处于维护模式 ,build议迁移到java.time类。
要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。
从何处获取java.time类?
- Java SE 8和SE 9及更高版本
- 内置。
- 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和SE 7
- 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
- Android的
- ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
- 请参阅如何使用ThreeTenABP …。
ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如Interval
, YearWeek
, YearQuarter
等等 。
`
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);
`
在Java 8中,您可以使用与Joda Time非常类似的LocalDate。
使用SimpleDateFormat的getDateInstance,我们可以比较没有时间的两个date对象。 执行下面的代码。
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)); }
使用http://mvnrepository.com/artifact/commons-lang/commons-lang
Date date1 = new Date(); Date date2 = new Date(); if (DateUtils.truncatedCompareTo(date1, date2, Calendar.DAY_OF_MONTH) == 0) // TRUE else // FALSE
只需检查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)
另一个简单的比较方法是基于这里的答案和我的导师指导
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,上面的代码失败了一些情况下(我想看看这些情况,请) ,他build议如下,据我所知:
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类已被弃用,因为它不适合国际化。 日历类是用来代替!
首先,请注意,此操作取决于时区。 因此,select是否要以UTC,计算机时区,自己喜欢的时区或在哪里进行。 如果你还不确定它的重要性,请看我的例子,在这个答案的底部。
由于你的问题是不是很清楚,我假设你有一个实例字段代表一个时间点和实施Comparable
,你想你的对象的自然顺序是date,但不是时间,那个领域。 例如:
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
类
我已经把你的实例字段的types从Date
为Instant
,Java 8中相应的类的自由。我保证将返回到下面的Date
的处理。 我还添加了一个时区常量。 您可以将其设置为ZoneOffset.UTC
或ZoneId.of("Europe/Stockholm")
或您认为合适的设置(将其设置为ZoneOffset
因为ZoneOffset
是ZoneOffset
的子类)。
我已经select使用Java 8类来展示解决scheme。 你问最简单的方法吧? :-)这是你要求的compareTo
方法:
public int compareTo(ArnesClass o) { LocalDate dateWithoutTime = when.atZone(arnesTimeZone).toLocalDate(); LocalDate otherDateWithoutTime = o.when.atZone(arnesTimeZone).toLocalDate(); return dateWithoutTime.compareTo(otherDateWithoutTime); }
如果你从不需要时间的一部分时间,那么声明LocalDate
并跳过所有转换当然更容易。 那么我们也不必担心时区了。
现在假设出于某种原因,你不能宣布你的when
字段是一个Instant
或者你想保持一个老式的Date
。 如果您仍然可以使用Java 8,只需将其转换为Instant
,然后按照以前那样进行操作:
LocalDate dateWithoutTime = when.toInstant().atZone(arnesTimeZone).toLocalDate();
同样为o.when
。
没有Java 8?
如果你不能使用java 8,有两个select:
- 使用旧的类之一,
Calendar
或SimpleDateFormat
解决它。 - 使用Java 8date和时间类的回溯到Java 6和7,然后按照上面的方法进行操作。 我在底部包含一个链接。 不要使用JodaTime。 当推荐的答案写成时,JodaTime可能是一个很好的build议; 但是JodaTime现在处于维护模式,所以ThreeTen backport是一个更好,更具前瞻性的select。
老式的方式
Adamski的答案显示了如何使用Calendar
类去除Date
的时间部分。 我build议您使用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)); }
这是受Rob的回答启发的 。
时区依赖关系
为什么我们必须select一个特定的时区? 假设我们要比较UTC的两次是3月24日0:00(午夜)和12:00(中午)。 如果你在CET(欧洲/巴黎)这样做,他们是3月24日上午1点和下午1点,也就是同一天。 在纽约(东部夏时制),他们是3月23日的20:00和3月24日的8:00,也就是不同日子。 所以它select哪个时区会有所不同。 如果你只是依靠计算机的默认设置,当有人试图在这个全球化世界的另一个地方的计算机上运行你的代码时,你可能会感到惊讶。
链接
连接到ThreeTen Backport,这是Java 8date和时间类到Java 6和7的反向链接: http : //www.threeten.org/threetenbp/ 。
我的主张:
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());
使用Apache共享你可以这样做:
import org.apache.commons.lang3.time.DateUtils DateUtils.truncatedEquals(first, second, Calendar.DAY_OF_MONTH)
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
这是解决这个问题最简单的方法。
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(); }
这将帮助您比较date而不考虑时间。
我通过时间戳比较解决了这个问题:
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 }
我避免使用乔达时间,因为在Android上使用了巨大的空间。 大小事项。 ;)
这对我来说是有效的:
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 }
如何DateUtil.daysBetween()
。 它是Java,它返回一个数字(以天为单位)。