加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

适用于地理位置不同的用户的日期操作/存储的Java最佳实践

发布时间:2020-12-15 07:38:28 所属栏目:Java 来源:网络整理
导读:我已经阅读了关于日期操作的所有其他Q / A,但它们似乎都没有给我满意的答案. 我有一个地理位置不同的用户项目,它在一些类和数据中使用Date.问题是我正在寻找一种有效的方法来操纵各自时区中不同用户的日期,大多数答案建议使用Joda库进行日期操作,这还不太明
我已经阅读了关于日期操作的所有其他Q / A,但它们似乎都没有给我满意的答案.

我有一个地理位置不同的用户项目,它在一些类和数据中使用Date.问题是我正在寻找一种有效的方法来操纵各自时区中不同用户的日期,大多数答案建议使用Joda库进行日期操作,这还不太明白因为我还没有找到任何您无法使用传统Java进行操作,因此,如果有人可以解释我使用传统Java无法完成的Joda操作,那么我可以考虑使用它.

我终于开始使用System.currentTimeMillis()将我的日期保存到数据库(任何数据库).这样可以避免让我担心使用数据库存储日期的时区.如果我想查询数据库中的特定日期或日期范围,我会使用我想要查询的日期的长值来执行查询:

SELECT * FROM table1 WHERE date1>=1476653369000

在检索ResultSet时,我会使用请求数据的用户的时区将从数据库检索到的long值格式化为可读日期.

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类取代(1,890个结果用于搜索’ java.time’).
>您将学会不将日期时间值作为从纪元开始的数量来跟踪.由于人类无法将长整数的含义解读为日期时间,因此调试和日志记录变得非常困难,因为未发现错误.并且因为在各种软件项目中使用了许多粒度的计数(整秒,毫秒,微秒,纳秒,整天等)以及至少一个couple dozen of epochs,所以在假设导致错误,误解和混淆的情况下,会对数据产生歧义.
>您将学会在数据库中使用日期时间类型来跟踪日期时间值.
>您将学会以UTC格式工作和存储日期时间值.仅在逻辑需要或用户期望的情况下调整到时区进行演示. “全球化思考,本地化.”
>您可能已经了解到,虽然是勇敢的行业第一次努力,但遗留日期时间类设计不当,令人困惑且麻烦.有关讨论,请参阅What’s wrong with Java Date & Time API?. Joda-Time是业界第一个很好的日期时间库,它启发了它的替代,即Java 8及更高版本中内置的java.time类.

我会稍微简短一点,因为所有这些已经在Stack Overflow上已经多次介绍过了.

以UTC工作.在Java中,这意味着通常使用Instant类. Instant类代表UTC时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位).

Instant instant = Instant.now();

任何严肃的数据库(如Postgres)都会以UTC格式跟踪日期时间值. JDBC驱动程序处理从数据库内部存储数据转换为Java类型的详细信息.符合JDBC 4.2及更高版本的JDBC驱动程序可以通过PreparedStatement :: setObject& amp;来直接处理java.time类型. ResultSet :: getObject方法.

myPreparedStatement.setObject( …,instant );

对于不兼容的驱动程序,回退到使用java.sql.Timestamp等java.sql类型与数据库通信,并通过添加到旧类的新方法转换为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();

请注意,在任何特定时刻,日期和时间在全球各个时区都有所不同.因此,如果确切的时刻很重要,例如合同到期时,请注意使用仅限日期的值.要么使用确切时刻的日期时间值,要么将预期时区与日期一起存储,以便稍后计算确切时刻.

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类?

> Java SE 8SE 9及更高版本

>内置.
>部分标准Java API,带有捆绑实现.
> Java 9增加了一些小功能和修复.

> Java SE 6SE 7

>大部分java.time功能都被反向移植到Java 6& 07年7月7日.

> Android

> ThreeTenABP项目专门针对Android调整了ThreeTen-Backport(如上所述).
>见How to use….

ThreeTen-Extra项目使用其他类扩展了java.time.该项目是未来可能添加到java.time的试验场.您可以在这里找到一些有用的类,例如Interval,YearWeek,YearQuarter和more.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读