Java:最小和最大日期范围

6
我正在从一个存储日期值的数据库中获取一些数据,我让用户选择他们想查看数据的日期范围。我所有关于获取这些日期范围的代码都可以工作,除了获取覆盖所有时间的日期范围的方法,这将是从Java可以处理的最早可能数据的开始值到最大可能日期的结束值。
我的代码有什么问题吗?因为我看不出有什么问题。
public static DateRange getAllTime() {
        /**
         * Get earliest possible
         */
        Calendar c = Calendar.getInstance();
        c.set(
                c.getActualMinimum(Calendar.YEAR), 
                c.getActualMinimum(Calendar.MONTH), 
                c.getActualMinimum(Calendar.DAY_OF_MONTH), 
                c.getActualMinimum(Calendar.HOUR), 
                c.getActualMinimum(Calendar.MINUTE), 
                c.getActualMinimum(Calendar.SECOND)
            );

        c.set(Calendar.MILLISECOND, c.getActualMinimum(Calendar.MILLISECOND));
        Date start = c.getTime();

        /**
         * Get latest possible date
         */
        c.set(
                c.getActualMaximum(Calendar.YEAR), 
                c.getActualMaximum(Calendar.MONTH), 
                c.getActualMaximum(Calendar.DAY_OF_MONTH), 
                c.getActualMaximum(Calendar.HOUR), 
                c.getActualMaximum(Calendar.MINUTE), 
                c.getActualMaximum(Calendar.SECOND)
            );

        c.set(Calendar.MILLISECOND, c.getActualMaximum(Calendar.MILLISECOND));
        Date end = c.getTime();

        DateRange range = new DateRange();
        range.Start = start;
        range.End = end;

        return range;
    }

1
你的方法返回什么? - Abhinav Sarkar
5个回答

18

为什么不使用

  1. new Date(Long.MIN_VALUE) (在公元前292269055年)
  2. new Date(Long.MAX_VALUE) (在公元292278994年)?

由于froginvasion对答案提出了质疑,我想再次确认一下。

    long day=1000*60*60*24;
    System.out.println(new Date(Long.MAX_VALUE-day));
    System.out.println(new Date(Long.MAX_VALUE));
    System.out.println(new Date(0));
    System.out.println(new Date(-day));
    System.out.println(new Date(Long.MIN_VALUE));
    System.out.println(new Date(Long.MIN_VALUE+day));

给了我

Sat Aug 16 07:12:55 GMT 292278994
Sun Aug 17 07:12:55 GMT 292278994
Thu Jan 01 00:00:00 GMT 1970
Wed Dec 31 00:00:00 GMT 1969
Sun Dec 02 16:47:04 GMT 292269055
Mon Dec 03 16:47:04 GMT 292269055

我认为这是正确的。我假设AD/BC被省略了。建议使用new Date(0)作为最小值显然是错误的,因为new Date(-day)显然更小。


1
new Date(Long.MIN_VALUE)不起作用,测试一下。它实际上并没有做你期望的事情。如果你想使用它,请使用new Date(0),它是1970年1月1日。 - froginvasion
4
@froginvasion 我认为答案是正确的,并且该字符串不包含BC/AD。我不认为new Date(0)会给出最小的日期值。 - emory

5

为什么要把生活搞得那么复杂呢?如果你没有开始日期,就不要查询开始日期。如果你没有结束日期,就不要查询结束日期。如果你两个都没有,就不要查询日期。


哈哈,是的,那就是我最后做的。这是一个特殊情况,由于其他每个情况都有一些开始/结束,所以我只使用了一个方法。最后编写了一个方法来处理这种情况,并编写了一个不检查日期的查询。话虽如此,不知道为什么这个方法不起作用让我感到困扰,我真的很想知道原因。 - Christopher Perry

0

我怀疑通过设置年份,然后单独设置所有其他字段的最大值可能会导致溢出。这将使您的结束时间在开始时间附近,并导致拒绝所有记录。您可以尝试仅打印日历时间以查看发生了什么。

正如seanizer所指出的那样,您正在使这个问题变得比应该更复杂 - 处理这个问题的正确方法是在查询中完全省略日期子句。有时这可能很困难,因为SQL语句不是动态生成的。但请注意,即使您无法在运行时修改SQL,条件(在Oracle中)

start_date >= nvl(?, start_date)

如果提供的值为 null,且 start_date 已填,则始终会得到满足。


0

那段代码对我来说是有效的,也许你没有预期它返回的值?

开始时间:Sat Jan 01 00:00:00 PST 1 结束时间:Wed Apr 17 21:34:08 PST 292269054

(如果您包含堆栈跟踪,将更容易提供帮助)


0

数据库支持的最小值和最大值是多少?

您可能需要了解数据库支持的最小值和最大值,而不是Java支持的最小值和最大值。一些数据库只支持datetime类型,例如0001年到9999年。我没有尝试过也没有研究过文档,但我可能会怀疑如果您传递超出数据库支持范围的日期,您的JDBC驱动程序或查询可能会失败。

例如,MariaDB文档中说:

MariaDB使用支持DATETIME数据类型的格式存储值,该格式支持1000-01-01 00:00:00.0000009999-12-31 23:59:59.999999之间的值。

但是,编写依赖于特定品牌的数据库引擎(DBMS)的Java代码并不好。如果您仍然需要,请硬编码这些值:

public static final LocalDateTime MIN_DATABASE_DATETIME
        = LocalDateTime.of(1000, Month.JANUARY, 1, 0, 0);
public static final LocalDateTime MAX_DATABASE_DATETIME
        = LocalDateTime.of(9999, Month.DECEMBER, 31, 23, 59, 59, 999_999_000);

我正在使用并推荐java.time,这是现代Java日期和时间API。

Java支持的最小值和最大值?

Java支持的最小值和最大值作为常量内置。java.time支持的范围比老式的Date类更广泛。让我们看看最小值和最大值是什么:

    System.out.println("Min Java LocalDateTime: " + LocalDateTime.MIN);
    System.out.println("Max Java LocalDateTime: " + LocalDateTime.MAX);

输出:

Min Java LocalDateTime: -999999999-01-01T00:00
Max Java LocalDateTime: +999999999-12-31T23:59:59.999999999

你的代码出了什么问题?

我的代码有问题吗?因为我看不出来有什么问题:

你是正确的,虽然你的代码给出了一个你可以用作最小值的最小值,但它给出的最大值却是离谱的远。当我刚才运行它时,我得到了:

Sat Jan 01 00:00:00 CST 1 - Wed Apr 17 21:34:08 CST 292269054

CalendarDate 确实支持公元前的日期,所以将年份1作为最小值是不正确的。这是因为您没有更改您的Calendar的纪元,所以它仍然处于CE(“AD”)中。 YEAR字段号表示纪元年份,因此最小值为1。

我得到的最大值看起来比最大可能的Date早了9940年,但可能仍然远高于您数据中实际存在的任何日期。这不是真的!您得到的值是公元前292269054年(“在基督诞生之前”),距离Date的最小值只有4个半月左右,与您尝试查找的相反。这可能是由于计算中未检测到的算术溢出所致。我想Calendar从来没有意味着防止溢出和下溢。

getActualMinimum()getActualMaximum()会根据Calendar的实际值给出可能的最小和最大值。因此,c.getActualMinimum(Calendar.MONTH)将在非闰年的二月份给出28,在七月份给出31。这不是您想要的。使用Calendar.HOUR也是一个错误,因为HOUR表示从上午或下午的小时数0到11。

DateCalendar的实际最小值和最大值并不是在午夜或新年,但您的代码将尝试在新年之夜的午夜或非常接近午夜的时间找到值,这是您技术上的缺陷。尝试在最大值所在的8月份找到12月31日可能会导致我提到的溢出。您溢出的4个半月大致与我们最终得出的最小值以上4个半月相符。

链接


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