在Java中获取最大日期值的最佳方法是什么?

65

我正在编写一些逻辑,需要将空日期视为未来的永久(相关的日期是过期日期,可能存在也可能不存在)。我不想在代码中到处使用特殊情况以处理空日期,我只想将null转换为最大可能的日期。没有明显的方法可以获取这样的值而不硬编码。如何获取正在使用的任何Date实现的最大值?


2
关于Joda-Time,请参考这个类似的问题 - Basil Bourque
1
这个问题没有一个好的答案,因为(a)最大值和(b)日期时间值的粒度在编程语言、库、数据库等方面有所不同。我建议任意选择一个硬编码值,使其远远超出您的应用程序寿命,但不要超出任何组件的限制。例如 2666-01-01T00:00:00.0Z - Basil Bourque
9个回答

121

尝试一下

new Date(Long.MAX_VALUE)

这应该给你在Java中可能的最长日期值。


9
只是举个反例...这个解决方案仍然对Date对象的实现做了一些假设。如果我的代码在遥远的未来某个时候被编译成Java版本9,而Date已经升级以能够表示quattuordecillion年,但是只有接受long类型参数的构造函数受限于原来的64位日期范围... - jthg
38
笑...好吧,在这种情况下,至少日期值远在未来,因此无论如何都应该被视为不可达。根据当前的Java 6实现,“Sun Aug 17 00:12:55 MST 292278994”。如果您的代码在292278994年仍然存在,我会感到惊讶。 :-) - cjstehno
1
我同意其他答案中的一个观点,即这段代码应该被包装在另一个辅助类中,而不是直接使用。 - cjstehno
3
仅当时区设置为UTC时。 - user177800
1
它不会的,Sun 乐于保持 JDK API 向后兼容,并且他们正在开发基于 joda-time 的新日期/时间 API(JSR-310)。 - Esko
补充@jhg的观点,这个解决方案还有另一个假设,那就是如果进行日期比较时。当然,这只会在JVM进程外持久化了最大日期时才会发生。话虽如此,JVM规范必须改变Long.MAX_VALUE才能改变,我真的不认为这会发生。 - three-cups

21

封装你想要的功能到你自己的类中,使用Long.MAX_VALUE很可能会导致问题。

class ExpirationDate {
    Date expires;

    boolean hasExpiration() {
        return expires == null;
    }

    Date getExpirationDate() {
        return expires;
    } 

    boolean hasExpired(Date date) {
        if (expires == null) {
            return true;
        } else {
            return date.before(expires);
        }
    }

    ...
}

+1;这将在未来使检查过期日期更易读。 - Rob
我需要的逻辑仅适用于单个方法内的代码,因此我认为这是不必要的。 - jthg
1
我会用另一种方式来做。在我看来,expires==null意味着没有过期时间,因此任何日期都是合法的。 - DGoiko

8

对于 Long.MAX_VALUE 的建议加 1。如果您按照日期字段排序,这似乎会对您有所帮助。

但是,不要在需要日期时从某些大常量值构造日期,而是使用全局可见的单例来保存表示您特殊值的 Date 实例:

class DateUtil
{
  public static final Date NO_EXPIRE = new Date( Long.MAX_VALUE );
}

那么您可以使用简单的身份比较 (mydate == DateUtils.NO_EXPIRE) 来测试特定日期是否属于您的特殊情况,而不是使用obj.equals();(即,mydate.equals(DateUtils.NO_EXPIRE);)


1
除非您包括UTC时区,否则此操作仍无法提供最大日期值! - user177800
4
不正确,时区无关紧要。java.util.Date始终在UTC中。这个答案正确地确定了一个java.util.Date对象可以表示的最后时间点。您的评论是否有其他方面我没有理解? - Basil Bourque

4

以下是我的工作内容:

public static final TimeZone UTC;

// 0001.01.01 12:00:00 AM +0000
public static final Date BEGINNING_OF_TIME;

// new Date(Long.MAX_VALUE) in UTC time zone
public static final Date END_OF_TIME;

static
{
    UTC = TimeZone.getTimeZone("UTC");
    final Calendar c = new GregorianCalendar(UTC);
    c.set(1, 0, 1, 0, 0, 0);
    c.set(Calendar.MILLISECOND, 0);
    BEGINNING_OF_TIME = c.getTime();
    c.setTime(new Date(Long.MAX_VALUE));
    END_OF_TIME = c.getTime();
}

请注意,如果时区不是UTC,则会从“时间结束”处获得偏移量,这些偏移量将不是最大值。这对于插入到数据库字段中而不必具有NULL日期特别有用。

如果我处理的所有日期都在同一个时区,这真的很重要吗?'new Date(Long.MAX_VALUE)'将获取当前时区的最大日期。 - jthg
除非您的时区是UTC,否则您将无法真正获得最大的日期对象。 - user177800

3

From Java SE 8 you could use:

LocalDate.MAX

2

您是否考虑过采用Joda Time?它被定为Java 7的基础,作为JSR-310

可能会引起您兴趣的功能是ZeroIsMaxDateTimeField,它基本上将日期时间中的零字段替换为该字段内的最大值。


1

我喜欢Instant.MAX,因为它比Long.MAX_VALUE更有可能在未来得到支持。

但需要注意的是,目前Instant.MAX.toEpochMilli()会抛出溢出错误。


1

我看到的一个问题是,在按到期日期排序时,使用null不容易进行排序。因此,可能需要用实际值(即使它是一个任意的哨兵值,远在未来)来替换。

我想,另一种处理“没有过期”方式就是简单地说某些东西将在100年后过期...除非你的数据库正在处理长期合同!


-1

也许一个选项是使用最大系统日期。您可以通过使用以下方式获取它:

System.out.println(new Date(Long.MAX_VALUE).toString())
//Output:
//Sun Aug 17 12:42:55 IST 292278994

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