我从具有存储日期值的数据库中获取一些数据,并且我让用户选择他们想要查看数据的日期范围。获取这些日期范围的所有代码都有效,除了获取所有时间的日期范围的方法,这是最早可能的数据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;
}
答案 0 :(得分:17)
为什么不使用
由于青蛙入侵挑战了答案,我以为我会仔细检查
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正被压制。使用新Date(0)作为最小值的建议显然是错误的,因为新的Date(-day)明显更小。
答案 1 :(得分:4)
为什么让生活如此复杂?如果您没有开始日期,请不要查询开始日期。如果您没有结束日期,请不要查询结束日期。如果您没有,请不要查询日期。
答案 2 :(得分:0)
那段代码对我有用,也许你不期望它返回的值?
开始时间:1月1日00:00:00太平洋标准时间1 结束:4月17日星期三21:34:08太平洋标准时间292269054
(如果包含堆栈跟踪,将更容易提供帮助)
答案 3 :(得分:0)
我怀疑可能通过设置年份然后分别为所有其他字段设置最大值来获得溢出。这会使你的结束时间在你的开始时间附近并导致所有记录被拒绝。您可以尝试打印日历时间以查看正在发生的事情。
正如seanizer指出的那样,你真的让它变得比它应该更复杂 - 处理这个问题的正确方法是在查询中完全保留date子句。这有时可能很困难,因为sql语句不是动态生成的。但请注意,即使你无法在运行时修改sql,条件(在Oracle中)
start_date >= nvl(?, start_date)
如果提供的值为null并且填充了start_date,则始终满足。
答案 4 :(得分:0)
您实际上可能需要数据库支持的最小值和最大值,而不是 Java 支持的最小值和最大值。某些数据库的 datetime
类型仅支持 0001 到 9999 年。我没有尝试或研究过文档,但我可能怀疑如果您在时间间隔之外传递日期,您的 JDBC 驱动程序或查询可能会失败数据库支持。
例如 MariaDB 文档说:
<块引用>MariaDB 以某种格式存储使用 DATETIME
数据类型的值
支持 1000-01-01 00:00:00.000000
和
9999-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.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
我的代码有问题吗,因为我看不到问题:
你是对的,虽然你的代码给出了一个你可以使用的最小值,但它给出的最大值却是尽可能的远。当我刚刚运行它时,我得到:
<块引用>1 月 1 日星期六 00:00:00 CST 1 - 4 月 17 日星期三 21:34:08 CST 292269054
Calendar
和 Date
did 支持共同纪元之前(“基督之前”)的日期,因此将第 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 的小时。
Date
和 Calendar
的实际最小值和最大值不会落在午夜或新年,但您的代码将尝试在新的午夜或非常接近午夜查找值年份,这是你技术的缺陷。试图在 8 月份最大值下降的年份中找到 12 月 31 日可能是我提到的溢出的原因。您溢出的 4 个半月与我们结束时超出最小值的 4 个半月大致相符。
DATETIME
in the MariaDB knowledge base