jjzjj

面向不同地域用户的日期操作/存储的 Java 最佳实践

coder 2024-03-14 原文

我已经阅读了关于日期操作的所有其他问答,但似乎没有一个对我的担忧提供令人满意的答案。

我有一个具有不同地域用户的项目,它使用 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.Datejava.util.Calendar )和 Joda-Time 项目都被 java.time 类(搜索“java.time”的 1,890 个结果)所取代。
  • 您将学会不要将日期时间值作为从纪元开始的计数来跟踪。由于人类无法破译长整数作为日期时间的含义,因此调试和日志记录变得非常困难,因为错误未被发现。并且因为计数的许多粒度(整秒、毫秒、微秒、纳秒、整日等等)和至少 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 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 类?
  • Java SE 8SE 9然后
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6SE 7
  • ThreeTen-Backport 中,大部分 java.time 功能被反向移植到 Java 6 和 7。 .
  • Android
  • ThreeTenABP项目适应 ThreeTen-Backport (如上所述)专门针对Android。
  • How to use… .

  • ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter , 和 more .

    关于面向不同地域用户的日期操作/存储的 Java 最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40075780/

    有关面向不同地域用户的日期操作/存储的 Java 最佳实践的更多相关文章

    1. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

      我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

    3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

      我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

    4. java - 等价于 Java 中的 Ruby Hash - 2

      我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

    5. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

      我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

    6. ruby-on-rails - Ruby 检查日期时间是否为 iso8601 并保存 - 2

      我需要检查DateTime是否采用有效的ISO8601格式。喜欢:#iso8601?我检查了ruby​​是否有特定方法,但没有找到。目前我正在使用date.iso8601==date来检查这个。有什么好的方法吗?编辑解释我的环境,并改变问题的范围。因此,我的项目将使用jsapiFullCalendar,这就是我需要iso8601字符串格式的原因。我想知道更好或正确的方法是什么,以正确的格式将日期保存在数据库中,或者让ActiveRecord完成它们的工作并在我需要时间信息时对其进行操作。 最佳答案 我不太明白你的问题。我假设您想检查

    7. ruby - 检查日期是否在过去 7 天内 - 2

      我的日期格式如下:"%d-%m-%Y"(例如,今天的日期为07-09-2015),我想看看是不是在过去的七天内。谁能推荐一种方法? 最佳答案 你可以这样做:require"date"Date.today-7 关于ruby-检查日期是否在过去7天内,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/32438063/

    8. ruby-on-rails - 将 Ruby 中的日期/时间格式化为 YYYY-MM-DD HH :MM:SS - 2

      这个问题在这里已经有了答案:Railsformattingdate(4个答案)关闭4年前。我想格式化Time.Now函数以显示YYYY-MM-DDHH:MM:SS而不是:“2018-03-0909:47:19+0000”该函数需要放在时间中.现在功能。require‘roo’require‘roo-xls’require‘byebug’file_name=ARGV.first||“Template.xlsx”excel_file=Roo::Spreadsheet.open(“./#{file_name}“,extension::xlsx)xml=Nokogiri::XML::Build

    9. ruby - 查找字符串中的内容类型(数字、日期、时间、字符串等) - 2

      我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s

    10. java - 从 JRuby 调用 Java 类的问题 - 2

      我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

    随机推荐