[英]Java Best Practice for Date Manipulation/Storage for Geographically Diverse Users
我已经阅读了有关日期操作的所有其他问题,但是似乎都没有一个令人满意的答案。
我有一个具有不同地理位置用户的项目,该项目在某些类和数据中使用Date
。 事实是,我正在寻找一种有效的方式来为不同用户在各自的时区中操作日期,大多数答案建议使用Joda库进行Date
操作,由于我仍然没有发现任何东西,所以这还不太了解您无法使用传统Java执行此操作,因此,如果有人可以解释使用传统Java无法完成的Joda功能 ,那么我可以考虑使用它。
我终于找到了使用System.currentTimeMillis()
将日期保存到数据库(任何数据库)中的方法。 这样可以避免我担心使用数据库存储日期的时区。 如果要在数据库中查询特定日期或日期范围,我将使用要查询的Date
的long
值执行查询:
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
时担心时区?
提前致谢。
我已经阅读了有关日期操作的所有其他问答。
不,你肯定没看过他们所有。
java.util.Date
和java.util.Calendar
)和Joda-Time项目都被java.time类所替代(在'java.s中搜索的结果为1,890个)。时间')。 我会有些简短,所有这一切都已经覆盖了很多次了堆栈溢出。
在UTC工作。 在Java中,这意味着通常使用Instant
类。 Instant
类以UTC表示时间轴上的时刻,分辨率为纳秒 (最多十进制的九(9)位数字)。
Instant instant = Instant.now();
任何严肃的数据库,例如Postgres,都会以UTC跟踪日期时间值。 JDBC驱动程序处理从数据库内部存储的数据转换为Java类型的细节。 符合JDBC 4.2及更高版本的JDBC驱动程序可以通过PreparedStatement::setObject
和ResultSet::getObject
方法直接处理java.time类型。
myPreparedStatement.setObject( … , instant );
对于不符合标准的驱动程序,回落到使用的java.sql类型,如java.sql.Timestamp
与数据库进行通信,并通过加入到老班新方法转换到/自java.time类型。 数据库如何处理日期时间值的内部细节可能与java.time的方法完全不同。 在大多数情况下,JDBC驱动程序会向您隐藏所有细节。 但是一个关键问题是分辨率,您应该在数据库中进行研究。 java.time类处理的日期时间的分辨率最高为纳秒,但数据库可能不会。 例如,Postgres使用微秒的分辨率。 因此来回意味着数据丢失。 您想在java.time类上使用截断方法来匹配您的数据库。
myPreparedStatement.setTimestamp( … , java.sql.Timestamp.from( instant ) );
因此,不涉及任何时区。 因此,无需“在处理数据库日期时担心时区”。
当您想通过某个区域的时钟时钟看到同一时刻时 ,请应用ZoneId
来获取ZonedDateTime
。
ZoneId z = ZoneId.of( "Asia/Kolkata" );
ZonedDateTime zdt = instant.atZone( z );
将带区域的日期时间带回到数据库时,请提取Instant
。
Instant instant = zdt.toInstant();
请注意,在任何给定时刻,日期和一天中的时间在全球范围内随时区变化。 因此,如果确切的时刻很重要,例如合同到期时,请注意不要使用仅日期的值。 可以将日期时间值用于确切的时刻,或者将预期的时区与仅日期一起存储,以便稍后可以计算出准确的时刻。
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 8及更高版本中。 这些类取代了麻烦的旧式旧式日期时间类,例如java.util.Date
, .Calendar
和java.text.SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time。
要了解更多信息,请参见Oracle教程 。 并在Stack Overflow中搜索许多示例和说明。 规格为JSR 310 。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。 该项目为将来可能在java.time中添加内容提供了一个试验场。 您可以在这里找到一些有用的类,比如Interval
, YearWeek
, YearQuarter
,和更多 。
我可以用Joda做什么,而传统Java则无法做到
通常情况下,这与使用传统Java可以做什么或不能做什么有关。 与库API的工作方式有关的更多信息是如何使您比传统Java更好地编写更好(更健壮和更正确)的代码。
如此之多以至于从Java 8开始,Joda API几乎被逐字复制/采用,只是更改了程序包名称并将其合并到Java 8 SE标准库中。
因此,如果您使用的是Java 8,则应该选择新的API,否则,您应该考虑使用Joda至少会为您提供一条通向Java 8升级/移植的平稳之路。
一些例子:
toString()
类的东西,因此可以期望序列化/反序列化以最小的努力正确地工作。 Instant
的概念表示“绝对”时间戳,当使用地理分布式系统(系统默认时钟/时区和DST规则可能不同)或互操作时,该概念非常有用,因为它使用UTC。 编辑添加:
根据我已阅读的一些意见,有人强调说,存储
System.currentTimeMillis()
绝对不是最佳实践,但是由于某些原因,他们都错过了为什么不推荐这样做的原因。 我想念什么吗?
System.currentTimeMillis()
有一些缺点。 最大的缺点是时钟的类型定义不正确。 它可以是单调时钟,也可以是受DST和时区限制的时钟,也可以是UTC时间。 它也不一定是准确的时钟,实际上并不能保证精确到毫秒。 基本上,将发生什么事情都可以像当前时间一样进行 。
这意味着,例如,如果您想使用多个服务器来处理传入请求,则当您不得不考虑在另一个服务器上运行的程序的上下文中使用服务器A
的System.currentTimeMillis()
的输出时,这将变得很棘手。 B
第二天说。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.