测试正确的时区处理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了测试正确的时区处理相关的知识,希望对你有一定的参考价值。
我们正在处理大量数据,所有数据都以UTC(在Java中)标记。在读取此数据,将其存储在数据库中以及再次将其取出之间,在夏时制期间发生了一些数据关闭一小时的情况。由于UTC没有夏令时的概念,因此这显然是软件中的错误。一旦知道,就很容易修复。
但是,无论当前时差如何,都可以进行一些单元/集成测试,这很好,例如我想更改本地时区,并在这些不同时区中反复运行一些方法,以确保正确处理UTC。
由于测试应该自动运行,并且-最好-在一个Testsuite中运行,我想知道如何最好地测试正确的行为。在重新启动JVM时更改本地设置(例如时区)很容易,但是在测试套件中运行它并不是那么容易。
有人知道支持这种情况的测试环境,库或模式吗?我们通常与JUnit合作,但愿意添加其他环境/技术,以帮助消除此类问题。我想这是一个集成而不是单元测试。
Edit:已经有两个非常有用的答案,但是我想这里肯定还有更多的技术。是否有人有关于何时/多久调用一次TimeZone.getDefault的权威信息(请参阅有关Jon Skeets答案的评论)?
注:即使该问题的答案已被接受,我也不确定要接受哪个答案。即使获得了这种认可,我仍然希望看到更多的想法和技术。
感谢您的输入!
我建议您签出JodaTime,它提供了一些糖来帮助您在代码中更清晰地管理Date / Time / TimeZone类型问题。
我们在测试和生产过程中都使用了这些,因为它如何增强本机Java API来解决日期/时间问题是无与伦比的。在测试中使用它们可以在JUnit中正常运行
Java允许您设置默认时区(java.util.TimeZone.setDefault)。我之前已经编写过测试,以将时区设置为各种不同的选项,并检查一切是否仍然有效。不过要小心-如果要并行化大多数单元测试,则需要使这些测试顺序进行。
我建议您在某些时区进行夏令时测试,而某些时区则不这样做。使用澳大利亚时区也很好,因为夏令时适用于每年的相反时间到北半球。
关于连接到时间服务器并获取更新有什么看法?
您的一小时休假问题确实可能是由于应用了时区调整。我猜您正在(a)与数据库交换字符串而不是对象,(b)使用可怕的旧式日期时间类,或(c)使用的工具或中间件对您说谎,它们是从数据库中检索到的值由于混淆了在从数据库中检索之后并向您显示/报告给您之前应用默认时区的反特性的良好意图。
java.time
解决方案是始终使用现代的[[java.time类,并使用与JDBC 4.2或更高版本兼容的JDBC驱动程序。
在UTC中捕获当前时刻。Instant instant = Instant.now() ;
您的JDBC驱动程序可能支持也可能不支持Instant
。 JDBC 4.2规范莫名其妙地需要对Instant
的支持,但不需要两个更常用的类型OffsetDateTime
和OffsetDateTime
。没问题,因为我们可以轻松转换。
Instant
由于我们指定了ZonedDateTime
常量,所以此ZonedDateTime
仍采用UTC(零小时-分钟-秒的偏移量。)>保存到数据库。
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
检索。
OffsetDateTime
调整到显示给用户的时区。为用户界面生成输出,ZoneOffset.UTC
。
myPreparedStatement.setObject( … , odt ) ;
[注意,在所有代码中均未使用OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
作为日期时间值。如果与数据库交换这些智能对象而不是哑字符串,则不会注入任何时区调整。
关于java.time
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
框架内置于Java 8及更高版本中。这些类取代了麻烦的旧automatically localized日期时间类,例如Locale locale = Locale.JAPAN ; // Specify a `Locale` to determine
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( f ) ;
,String
和java.time。要了解更多信息,请参见legacy。并在Stack Overflow中搜索许多示例和说明。规格为java.util.Date
。
java.util.Date
项目现在位于Calendar
中,建议迁移到Calendar
类。
您可以直接与数据库交换
java.time
对象。使用兼容SimpleDateFormat
或更高版本的SimpleDateFormat
。不需要字符串,不需要Oracle Tutorial类。 Hibernate 5和JPA 2.2支持java.time。 从哪里获取java.time类? - JSR 310,Joda-Time,maintenance mode,java.time和更高版本-具有捆绑实施的标准Java API的一部分。
- Java 9添加了一些次要功能和修复。
- << java.time的大多数功能>在
java.sql.*
中被反向移植到Java 6和7。- java.time
以上是关于测试正确的时区处理的主要内容,如果未能解决你的问题,请参考以下文章