如何从java.util.Date中获取日期部分(忽略时间部分)?

5
我希望比较两个 java.util.Date 对象的日期部分。我该如何实现?我不想单独比较日期、月份和年份。
谢谢!

感谢 Charles 的编辑 :) - MozenRath
我在以下链接中回答了类似的问题:https://dev59.com/r3M_5IYBdhLWcg3wdzDz - Richard Gomes
5个回答

4
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。

我有点犹豫是否要使用 API 方法,因为这需要在我的类中导入新的内容。 - MozenRath

3
一个Date只是时间的一个瞬间,只有在应用日历和时区后才真正具有日期的含义。因此,如果您想遵循标准Java API,您应该查看Calendar - 您可以创建一个带有正确Date和时区的Calendar对象,然后将时间组件设置为0。
然而,最好使用Joda Time来开始,并使用其LocalDate类型,这更准确地反映了您感兴趣的内容。

我将日历组件设置为0,并且它有效了!实际上,我一直在处理日历对象,但是使用setTime()方法设置日期。这是问题不可避免的来源。此外,我正在使用具有Date参数而不是Calendar的比较功能。所以,需要处理日期。不管怎样,非常感谢! - MozenRath
我不能使用Joda Time,因为我正在开发一个产品,为了一些微不足道的事情添加API将是浪费。 - MozenRath
1
@Piyush:你现在这么说…但是在你维护应用程序几年并不断被内置API的缺陷所困扰后再来说这句话吧…认真地,如果有任何方法可以在这里开始使用Joda Time,你将在代码可读性和可维护性方面获得重大胜利。 - Jon Skeet
@Jon,我知道长期问题,但问题是我目前只面临一个问题,我可以使用Java API来解决它。此外,IBM添加新API到产品的流程非常复杂,而我在这里不是决策者。我只是编写代码的人:P - MozenRath
1
@Piyush:好的,那你可别说我没警告过你... :) - Jon Skeet

2

是的,这就是我做的 :). 不过问题不同。他正在使用 java.sql.* 包。 - MozenRath

1
以下是一种利用Joda Time并支持时区的解决方案。 因此,您将在JVM中当前配置的时区中获取日期和时间(分别为currentDatecurrentTime)。
请注意,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;
    }
}

1

tl;dr

LocalDate ld = 
    myUtilDate.toInstant()
              .atZone( ZoneId.of( "America/Montreal" ) )
              .toLocalDate() ;

避免使用旧的日期时间类

您正在使用麻烦的旧的日期时间类,请避免使用它们。

相反,使用java.time类。这些类替代了旧类以及Joda-Time库。

转换

将您的java.util.Date转换为Instant

Instant类表示具有UTC时间线上的一个时刻,精度为纳秒

Instant instant = myUtilDate.toInstant();

时区

应用时区非常重要。由于时区的存在,同一时刻在全球各地的日期是不同的。例如,在法国巴黎午夜过后几分钟就是新的一天,而在魁北克蒙特利尔仍然是“昨天”。

使用ZoneId来获取ZonedDateTime对象。

ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );

本地类型

LocalDate类表示仅包含日期值的对象,没有时间和时区。同样,LocalTime表示不带日期和时区的时间。您可以将这两个组件与ZoneId一起组成ZonedDateTime。您可以从ZonedDateTime中提取这些组件。

LocalDate ld = zdt.toLocalDate();
LocalTime lt = zdt.toLocalTime();

字符串

如果您的目标仅是为了生成展示给用户的字符串,不需要使用Local…类型。相反,使用DateTimeFormatter来生成仅表示日期部分或时间部分的字符串。该类足够智能,在生成字符串时自动本地化

指定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.time 框架是内置于 Java 8 及以后版本的。这些类取代了旧的麻烦日期时间类,如 java.util.Date.Calendarjava.text.SimpleDateFormat

Joda-Time 项目现在处于维护模式,建议迁移到 java.time。

要了解更多信息,请参见 Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。

许多java.time的功能在ThreeTen-Backport中向Java 6和7进行了回溯,并在ThreeTenABP中进一步适应Android(请参见如何使用...)。 ThreeTen-Extra项目通过附加类来扩展java.time。该项目是可能未来添加到java.time的试验场。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接