【发布时间】:2011-09-30 11:18:15
【问题描述】:
我想比较两个java.util.Date 对象的日期部分。我怎样才能做到这一点?我不想分别比较日期、月份和年份。
提前致谢!
【问题讨论】:
-
感谢查尔斯的编辑 :)
-
我在stackoverflow.com/questions/1363307/… 回答了类似的问题
标签: java date calendar date-comparison
我想比较两个java.util.Date 对象的日期部分。我怎样才能做到这一点?我不想分别比较日期、月份和年份。
提前致谢!
【问题讨论】:
标签: java date calendar date-comparison
commons-lang DateUtils 为这个问题提供了一个很好的解决方案:
这样,您可以在一行中比较两个 Date 实例,而忽略您想要的 Date 的每个部分。
Date date1 = new Date(2011, 8, 30, 13, 42, 15);
Date date2 = new Date(2011, 8, 30, 15, 23, 46);
int compareTo = DateUtils.truncatedCompareTo(date1, date2,
Calendar.DAY_OF_MONTH);
在本例中,compareTo 的值为 0。
【讨论】:
Date 只是一个瞬间。当您对其应用日历和时区时,它仅在日期方面真正“意味着”任何东西。因此,如果您想坚持使用标准 Java API,您应该真正关注 Calendar - 您可以创建一个具有正确 Date 和时区的 Calendar 对象,然后将时间组件设置为 0。
但是,最好使用Joda Time 开头,它的LocalDate 类型更准确地反映了您感兴趣的内容。
【讨论】:
setTime() 方法设置日期。这就是问题的不可避免的根源。此外,我使用的比较函数将日期作为其参数,而不是日历。所以,需要一些与日期有关的东西。总之,非常感谢!
使用 Calendar.set() 与 Calendar.HOUR_OF_DAY、Calendar.MINUTE、Calendar.SECOND 和 Calendar.MILLISECOND 将所有这些字段设置为 0。
这个重复问题的答案会很有用:Resetting the time part of a timestamp in Java
【讨论】:
java.sql.* 包
在下面找到使用 Joda Time 并支持时区的解决方案。
因此,您将在 JVM 中当前配置的时区中获取日期和时间(到 currentDate 和 currentTime)。
请注意,Joda Time 不支持闰秒。因此,您可能会偏离真实值大约 26 或 27 秒。这可能要在未来 50 年内才能解决,届时累积误差将接近 1 分钟,人们会开始关心它。
另请参阅:https://en.wikipedia.org/wiki/Leap_second
/**
* This class splits the current date/time (now!) and an informed date/time into their components:
* <lu>
* <li>schedulable: if the informed date/time is in the present (now!) or in future.</li>
* <li>informedDate: the date (only) part of the informed date/time</li>
* <li>informedTime: the time (only) part of the informed date/time</li>
* <li>currentDate: the date (only) part of the current date/time (now!)</li>
* <li>currentTime: the time (only) part of the current date/time (now!)</li>
* </lu>
*/
public class ScheduleDateTime {
public final boolean schedulable;
public final long millis;
public final java.util.Date informedDate;
public final java.util.Date informedTime;
public final java.util.Date currentDate;
public final java.util.Date currentTime;
public ScheduleDateTime(long millis) {
final long now = System.currentTimeMillis();
this.schedulable = (millis > -1L) && (millis >= now);
final TimeZoneUtils tz = new TimeZoneUtils();
final java.util.Date dmillis = new java.util.Date( (millis > -1L) ? millis : now );
final java.time.ZonedDateTime zdtmillis = java.time.ZonedDateTime.ofInstant(dmillis.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdmillis = java.util.Date.from(tz.tzdate(zdtmillis));
final java.util.Date ztmillis = new java.util.Date(tz.tztime(zdtmillis));
final java.util.Date dnow = new java.util.Date(now);
final java.time.ZonedDateTime zdtnow = java.time.ZonedDateTime.ofInstant(dnow.toInstant(), java.time.ZoneId.systemDefault());
final java.util.Date zdnow = java.util.Date.from(tz.tzdate(zdtnow));
final java.util.Date ztnow = new java.util.Date(tz.tztime(zdtnow));
this.millis = millis;
this.informedDate = zdmillis;
this.informedTime = ztmillis;
this.currentDate = zdnow;
this.currentTime = ztnow;
}
}
public class TimeZoneUtils {
public java.time.Instant tzdate() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tzdate(zdtime);
}
public java.time.Instant tzdate(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final java.time.Instant instant = zddate.toInstant();
return instant;
}
public long tztime() {
final java.time.ZonedDateTime zdtime = java.time.ZonedDateTime.now();
return tztime(zdtime);
}
public long tztime(java.time.ZonedDateTime zdtime) {
final java.time.ZonedDateTime zddate = zdtime.truncatedTo(java.time.temporal.ChronoUnit.DAYS);
final long millis = zddate.until(zdtime, java.time.temporal.ChronoUnit.MILLIS);
return millis;
}
}
【讨论】:
LocalDate ld =
myUtilDate.toInstant()
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate() ;
您正在使用麻烦的旧旧日期时间类。避开他们。
改为使用java.time 类。这些取代了旧的类以及 Joda-Time 库。
将您的java.util.Date 转换为Instant。
Instant 类代表UTC 中时间轴上的一个时刻,分辨率为nanoseconds。
Instant instant = myUtilDate.toInstant();
应用时区。时区至关重要。对于任何给定的时刻,日期在全球范围内因区域而异。例如,法国巴黎午夜过后几分钟是新的一天,而魁北克蒙特利尔则是“昨天”。
应用ZoneId 以获取ZonedDateTime 对象。
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
Local… 类型LocalDate 类表示没有时间和时区的仅日期值。同样,LocalTime 表示没有日期和时区的时间。您可以将它们视为两个组件,它们与ZoneId 一起构成ZonedDateTime。您可以从ZonedDateTime 中提取这些内容。
LocalDate ld = zdt.toLocalDate();
LocalTime lt = zdt.toLocalTime();
如果您的目标只是生成字符串以呈现给用户,则不需要 Local… 类型。相反,使用DateTimeFormatter 生成仅表示日期部分或时间部分的字符串。该类足够聪明,可以在生成字符串时自动localize。
指定Locale 以确定 (a) 用于翻译日期名称、月份名称等的人类语言,以及 (b) 用于决定诸如缩写、大写、标点符号等问题的文化规范.
Locale l = Locale.CANADA_FRENCH ; // Or Locale.US, Locale.ITALY, etc.
DateTimeFormatter fDate = DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM ).withLocale( locale );
String outputDate = zdt.format( fDate );
DateTimeFormatter fTime = DateTimeFormatter.ofLocalizedTime( FormatStyle.MEDIUM ).withLocale( locale );
String outputTime = zdt.format( fTime );
java.time 框架内置于 Java 8 及更高版本中。这些类取代了旧的麻烦的日期时间类,例如 java.util.Date、.Calendar 和 java.text.SimpleDateFormat。
Joda-Time 项目现在位于 maintenance mode,建议迁移到 java.time。
要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。
大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(请参阅How to use…)。
ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。
【讨论】: