比较两个java.util.Dates以查看它们是否在同一天
我需要比较两个Date
(例如date1
和date2
),并提出一个boolean sameDay
是真实的两个Date
共享同一天,如果不是。
我怎样才能做到这一点? 这里似乎有一个混乱的旋风……如果可能的话,我想避免在JDK以外的其他依赖。
澄清:如果date1
和date2
共享同一年份,月份和date,则sameDay
为true,否则为false。 我意识到这需要了解一个时区的知识……只要我知道行为是什么,那么通过一个时区将是很好的,但我可以住在格林尼治标准时间或当地时间。
再次澄清:
date1 = 2008 Jun 03 12:56:03 date2 = 2008 Jun 03 12:59:44 => sameDate = true date1 = 2009 Jun 03 12:56:03 date2 = 2008 Jun 03 12:59:44 => sameDate = false date1 = 2008 Aug 03 12:00:00 date2 = 2008 Jun 03 12:00:00 => sameDate = false
Calendar cal1 = Calendar.getInstance(); Calendar cal2 = Calendar.getInstance(); cal1.setTime(date1); cal2.setTime(date2); boolean sameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
请注意,“同一天”并不像在不同时区可能涉及时听起来那么简单。 上面的代码将在这两个date计算相对于它运行的计算机使用的时区的一天。 如果这不是你所需要的,那么在你决定了“同一天”的意思之后,你必须把相关的时区传递给Calendar.getInstance()
调用。
是的,Joda时间的LocalDate
会使整个事情变得更加简单和容易(虽然涉及时区的困难也会存在)。
怎么样:
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); return fmt.format(date1).equals(fmt.format(date2));
如果需要,您还可以将时区设置为SimpleDateFormat。
我使用“apache commons lang”包来做到这一点(即org.apache.commons.lang.time.DateUtils)
boolean samedate = DateUtils.isSameDay(date1, date2); //Takes either Calendar or Date objects
您可以通过计算每个date的Julian日数然后比较这些date来避免外部依赖性和使用Calendar的性能问题:
public static boolean isSameDay(Date date1, Date date2) { // Strip out the time part of each date. long julianDayNumber1 = date1.getTime() / MILLIS_PER_DAY; long julianDayNumber2 = date2.getTime() / MILLIS_PER_DAY; // If they now are equal then it is the same day. return julianDayNumber1 == julianDayNumber2; }
乔达时间
至于添加依赖项,恐怕java.util.Date&.Calendar真的太糟糕了,我对任何新项目做的第一件事就是添加Joda-Time库。 在Java 8中,您可以使用受Joda-Time启发的新的java.time包。
Joda-Time的核心是DateTime
类。 与java.util.Date不同,它理解其分配的时区( DateTimeZone
)。 从juDate转换时,分配一个区域。
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" ); DateTime dateTimeQuébec = new DateTime( date , zone );
LocalDate
validation两个date时间是否在同一date的一种方法是转换为LocalDate
对象。
该转换取决于分配的时区。 要比较LocalDate
对象,它们必须已经被转换为相同的区域。
这是一个小实用的方法。
static public Boolean sameDate ( DateTime dt1 , DateTime dt2 ) { LocalDate ld1 = new LocalDate( dt1 ); // LocalDate determination depends on the time zone. // So be sure the date-time values are adjusted to the same time zone. LocalDate ld2 = new LocalDate( dt2.withZone( dt1.getZone() ) ); Boolean match = ld1.equals( ld2 ); return match; }
更好的是另一个参数,指定时区,而不是假定应该使用第一个DateTime对象的时区。
static public Boolean sameDate ( DateTimeZone zone , DateTime dt1 , DateTime dt2 ) { LocalDate ld1 = new LocalDate( dt1.withZone( zone ) ); // LocalDate determination depends on the time zone. // So be sure the date-time values are adjusted to the same time zone. LocalDate ld2 = new LocalDate( dt2.withZone( zone ) ); return ld1.equals( ld2 ); }
string表示
另一种方法是创build每个date时间的date部分的string表示,然后比较string。
同样,指定的时区是至关重要的。
DateTimeFormatter formatter = ISODateTimeFormat.date(); // Static method. String s1 = formatter.print( dateTime1 ); String s2 = formatter.print( dateTime2.withZone( dt1.getZone() ) ); Boolean match = s1.equals( s2 ); return match;
时间跨度
广义的解决scheme是定义一个时间跨度,然后询问跨度是否包含您的目标。 这个例子代码是Joda-Time 2.4。 请注意,“午夜”相关课程已被弃用。 而是使用withTimeAtStartOfDay
方法。 Joda-Time提供了三种types来表示不同时间段的时间间隔,时间段和持续时间。
使用“半开放”的方法,其中跨度的开始是包容和结束排他。
目标的时区可能与区间的时区不同。
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); DateTime target = new DateTime( 2012, 3, 4, 5, 6, 7, timeZone ); DateTime start = DateTime.now( timeZone ).withTimeAtStartOfDay(); DateTime stop = start.plusDays( 1 ).withTimeAtStartOfDay(); Interval interval = new Interval( start, stop ); boolean containsTarget = interval.contains( target );
java.time
Java 8和更高版本带有java.time框架。 受JSR 310定义的Joda-Time的启发,并由ThreeTen-Extra项目扩展。 参见教程 。
Joda-Time的制造商已经指示我们尽快转移到java.time。 与此同时,乔达时代继续作为一个积极维护的项目。 但是,期待未来的工作只发生在java.time和ThreeTen-Extra而不是Joda-Time。
简要总结java.time … Instant
是UTC中时间轴上的一个时刻。 应用时区( ZoneId
)以获取ZonedDateTime
对象。 要离开时间线,为了获得date时间的模糊的不确定的想法,使用“本地”类: LocalDateTime
, LocalDate
, LocalTime
。
本答案的Joda-Time部分讨论的逻辑适用于java.time。
旧的java.util.Date类具有用于转换为java.time的新的toInstant
方法。
Instant instant = yourJavaUtilDate.toInstant(); // Convert into java.time type.
确定一个date需要一个时区。
ZoneId zoneId = ZoneId.of( "America/Montreal" );
我们将该时区对象应用于Instant
以获取ZonedDateTime
。 从中我们提取仅限date的值( LocalDate
),因为我们的目标是比较date(而不是小时,分钟等)。
ZonedDateTime zdt1 = ZonedDateTime.ofInstant( instant , zoneId ); LocalDate localDate1 = LocalDate.from( zdt1 );
对我们需要比较的第二个java.util.Date
对象做同样的事情。 我只是使用当前的时刻。
ZonedDateTime zdt2 = ZonedDateTime.now( zoneId ); LocalDate localDate2 = LocalDate.from( zdt2 );
使用特殊的isEqual
方法来testing相同的date值。
Boolean sameDate = localDate1.isEqual( localDate2 );
private boolean isSameDay(Date date1, Date date2) { Calendar calendar1 = Calendar.getInstance(); calendar1.setTime(date1); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date2); boolean sameYear = calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR); boolean sameMonth = calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH); boolean sameDay = calendar1.get(Calendar.DAY_OF_MONTH) == calendar2.get(Calendar.DAY_OF_MONTH); return (sameDay && sameMonth && sameYear); }
Java 8
如果您在项目中使用Java 8并比较java.sql.Timestamp
,则可以使用LocalDate
类:
sameDate = date1.toLocalDateTime().toLocalDate().equals(date2.toLocalDateTime().toLocalDate());
如果你正在使用java.util.Date
,看看Istvan的答案是不太模糊的。
将date转换为Java 8 java.time.LocalDate ,如此处所示 。
LocalDate localDate1 = date1.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); LocalDate localDate2 = date2.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); // compare dates assertTrue("Not on the same day", localDate1.equals(localDate2));
除了Binil Thomas的解决scheme
public static boolean isOnSameDay(Timestamp... dates) { SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd"); String date1 = fmt.format(dates[0]); for (Timestamp date : dates) { if (!fmt.format(date).equals(date1)) { return false; } } return true; }
用法
isOnSameDay(date1,date2,date3 ...); //or isOnSameDay(mydates);
对于Android用户:
您可以使用DateUtils.isToday(dateMilliseconds)
来检查给定date是否为当天。
API参考: https : //developer.android.com/reference/android/text/format/DateUtils.html#isToday(long)
public static boolean validSearchRange(String start, String end){ SimpleDateFormat dateFormat = new SimpleDateFormat(clientDateFormat); try { Date start_date = dateFormat.parse(start); Date end_date = dateFormat.parse(end); return !start_date.after(end_date); } catch (ParseException e) { e.printStackTrace(); } return false; }
您可以应用与SimpleDateFormat解决scheme相同的逻辑,而不依赖于SimpleDateFormat
date1.getFullYear()*10000 + date1.getMonth()*100 + date1.getDate() == date2.getFullYear()*10000 + date2.getMonth()*100 + date2.getDate()