我已经阅读了关于日期操作的所有其他问答,但似乎没有一个对我的担忧提供令人满意的答案。
我有一个具有不同地域用户的项目,它使用 Date
在它的一些类和数据中。问题是我正在寻找一种有效的方法来操作各自时区中不同用户的日期,大多数答案建议使用 Joda图书馆 Date
操作,目前还不太明白,因为我还没有发现任何传统Java无法完成的操作,所以如果有人可以解释我可以用Joda做什么用传统的Java做不到的,那我可以考虑使用它。
我终于来到了使用System.currentTimeMillis()
的方法将我的日期保存到数据库(任何数据库)中。这将避免我担心哪个时区正在使用数据库来存储日期。如果我想查询数据库的特定日期或日期范围,我将使用 long
执行查询。 Date
的值我想查询:
SELECT * FROM table1 WHERE date1>=1476653369000
当检索
ResultSet
时然后我会格式化 long
从数据库中检索到可读的值 Date
使用请求数据的用户的时区。Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(resultSet.getLong(1));
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
Date myDate = cal.getTime();
根据我看到的一些意见,有人强调存储
System.currentTimeMillis()
绝对不是最好的做法,然而,出于某种原因,他们都错过了说为什么不值得推荐。我错过了什么吗?这是否会导致转换的性能问题 Long->Date
/Date->Long
?是否有使用 Long
时无法完成的用例?相反 Date
在数据库中?有人可以对此发表合理的解释吗?另一方面,假设我继续使用
Date
在数据库中存储日期的值,有没有办法避免在处理数据库时担心时区 Date
?提前致谢。
最佳答案
I have read all of the other Q/A about Date Manipulation
不,您当然没有全部阅读。
java.util.Date
和 java.util.Calendar
)和 Joda-Time 项目都被 java.time 类(搜索“java.time”的 1,890 个结果)所取代。 我会稍微简短一些,因为所有这些都已经在 Stack Overflow 上讲过很多次了。
在 UTC 工作。在 Java 中,这意味着
Instant
类是常用的。 Instant
class 代表时间线上的一个时刻 UTC分辨率为 nanoseconds (最多九 (9) 位小数)。Instant instant = Instant.now();
任何严肃的数据库(例如 Postgres)都以 UTC 跟踪日期时间值。您的 JDBC 驱动程序处理从数据库内部存储的数据转换为 Java 类型的细节。符合 JDBC 4.2 的 JDBC 驱动程序以后可以通过
PreparedStatement::setObject
直接处理 java.time 类型& ResultSet::getObject
方法。myPreparedStatement.setObject( … , instant );
对于不兼容的驱动程序,回退到使用 java.sql 类型,例如
java.sql.Timestamp
与数据库通信,并通过添加到旧类中的新方法在 java.time 类型之间进行转换。数据库如何处理日期时间值的内部细节可能与 java.time 的处理方式大不相同。在大多数情况下,JDBC 驱动程序对您隐藏了所有细节。但一个关键问题是分辨率,您应该在数据库中研究它。 java.time 类处理分辨率高达 nanoseconds 的日期时间。但您的数据库可能没有。例如,Postgres 使用的分辨率为 microseconds .所以来回意味着数据丢失。您想使用 java.time 类上的截断方法来匹配您的数据库。myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) );
因此,不涉及时区。所以不用“在处理数据库日期时担心时区”。
当您想通过一个地区的镜头 wall-clock time 看到同一时刻时, 申请
ZoneId
获得 ZonedDateTime
.ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
将分区日期时间带回数据库时,提取
Instant
.Instant instant = zdt.toInstant();
请注意,对于任何给定时刻,全局各地的日期和时间都会因时区而异。因此,如果某个确切时刻很重要,例如契约(Contract)到期时,请注意使用仅限日期的值。要么使用确切时刻的日期时间值,要么将预期时区与仅日期一起存储,以便稍后可以计算确切时刻。
LocalDate ld = LocalDate.of( 2016, 1 , 1 );
// Determine the first moment of 2016-01-01 as it happens in Kolkata.
ZonedDateTime zdt = ld.atStartOfDay( ZoneId.of( "Asia/Kolkata" ) );
Instant instant = zdt.toInstant(); // Adjust to UTC and store.
关于 java.time
java.time框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy日期时间类,例如
java.util.Date
, .Calendar
, & java.text.SimpleDateFormat
.Joda-Time项目,现在在 maintenance mode , 建议迁移到 java.time。
要了解更多信息,请参阅 Oracle Tutorial .并在 Stack Overflow 上搜索许多示例和解释。规范为 JSR 310 .
从哪里获得 java.time 类?
ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如
Interval
, YearWeek
, YearQuarter
, 和 more .
关于面向不同地域用户的日期操作/存储的 Java 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40075780/