Gop*_*opi 9 java oracle timezone datetime date
在我们的网络应用程序中,我们需要显示和输入不同时区的不同国家/地区的日期时间信息.现在,我们正在为每个国家/地区维护单独的Web服务器和单独的数据库(oracle 11g).
我们计划将所有门户网站合并为一个数据库(oracle 11g).此门户应捕获/显示用户本地时区的日期和时间.
到目前为止,我已经搜索了这个,我得到了以下建议.
1)将Web服务器和数据库服务器的时区设置为UTC,同时将获取数据(数据和时间)转换为用户本地时区.
如果您建议采用这种方法,请澄清以下具体问题.
大多数时候我们只捕捉日期,是否需要始终捕捉日期和时间以及时区?
在javascript/java/oracle中存储我们需要将用户本地时区转换为UTC的日期和时间?
在获取我们需要将UTC转换为用户
本地时区查询本身/ java/java脚本的日期和时间时?
很多地方我们有报告显示基于日期列,如
今天/当前月/日期范围.我们可以处理这个(输入 - 用户本地时区 - 数据库在UTC)?
2)以用户本地时区和UTC捕获日期和时间.存储为单独的列,用户本地时区将用于显示目的,UTC将用于业务逻辑.
如果您建议采用这种方法,请澄清以下具体问题.
存储用户本地时区和UTC是否常见?
哪个列我必须检查条件,同时根据日期列显示报告,如今天/当前月/日期范围?
我们必须将哪种数据类型用于日期列
(日期/时间戳/时间戳与时区/时间戳与本地时
区)?
提前致谢
Bas*_*que 18
阅读问题夏令时和时区最佳做法.你的基本上是重复的.
是的,通常服务器应将其操作系统设置为UTC作为时区,或者如果未提供使用GMT或雷克雅未克冰岛时区.您的Java实现可能会将此设置作为其自己的当前默认时区.
但是不要依赖于设置为UTC的时区.系统管理员可以改变它.JVM中任何应用程序的任何线程中的任何Java代码都可以通过调用在运行时更改JVM的当前默认时区TimeZone.setDefault.因此,养成一个习惯,即始终通过在Java代码中传递可选参数来指定所需/预期的时区.
我认为这是一个设计缺陷,任何日期时间框架都会使时区成为可选的.由于程序员像其他人一样,无意识地根据自己的个人时区进行思考,除非提示,否则可选择会产生无穷无尽的混乱.因此,在日期工作中经常不关注这个问题.添加JVM默认值变化的问题.顺便说一句,Locale同样的问题应该始终明确指定.
您的业务逻辑,数据存储和数据交换几乎总是以UTC完成.几乎每个数据库都有一个功能,可以将任何输入调整为UTC并以UTC格式存储.
向用户显示日期时间时,请调整到预期时区.序列化日期时间值时,请使用ISO 8601字符串格式.请参阅VickyArora针对Oracle 的答案(我是Postgres的人).请务必仔细阅读文档,并通过试验来完全理解数据库的行为.在这方面,SQL规范并未详细说明,并且行为差别很大.
请记住,在使用Java和JDBC时,您将使用java.sql.Timestamp相关的数据类型.它们始终是UTC,自动.将来期望更新JDBC驱动程序以直接使用Java 8及更高版本中内置的java.time框架中定义的新数据类型.
旧类已经过时了java.time.学习使用java.time,同时避免使用旧的java.util.Date/.Calendar,让您的编程生活更加愉快.
在更新JDBC驱动程序之前,您可以使用java.time中内置的转换便捷方法.请参阅下面的示例,其中Instant是UTC时刻,ZonedDateTime是一个调整为时区的瞬间.
Instant instant = myJavaSqlTimestamp.toInstant();
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Run Code Online (Sandbox Code Playgroud)
走向另一个方向.
java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( zdt.toInstant() );
Run Code Online (Sandbox Code Playgroud)
如果您的业务需求认为原始输入数据的时区很重要,需要记住,那么将其显式存储为数据库表中的单独列.您可以使用UTC的偏移量,但不提供完整信息.时区是偏移量加上一组规则,用于过去,现在和将来处理异常情况,例如夏令时.所以适当的时区名称是最合适的,例如America/Montreal.
您说您收集了许多仅限日期的值,没有时间和没有时区.java.time中的类是LocalDate.与LocalTime和一样LocalDateTime,"Local ..."部分意味着没有特定的地点,因此没有时区,因此没有时间轴上的一点 - 没有实际意义.
请记住,根据定义,仅限日期的值不明确.在任何特定时刻,日期都在世界各地不同.例如,在巴黎午夜之后,法国是新的一天,但在蒙特利尔魁北克,日期仍然是"昨天".
通常在商业中,某些时区是隐含的,甚至是无意识的直觉.对数据点的无意识直觉往往不能长期有效,特别是在软件方面.最好明确说明时区是什么意思.您可以在日期旁边存储预期的区域,例如数据库表中的另一列,或者您可以在编程代码中进行注释.我相信存储日期时间值会更好更安全.那么我们如何将仅限日期转换为日期时间?
通常新的一天是午夜之后,即一天的第一时刻.您可能认为这意味着时间,00:00:00.0但并非总是如此.夏令时(DST)和可能的其他异常可能会将第一时刻推到不同的挂钟时间.让java.time确定第一次通过LocalDate类及其atStartOfDay方法的正确时间.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
ZonedDateTime todayStart = today.atStartOfDay( zoneId );
Run Code Online (Sandbox Code Playgroud)
在某些业务环境中,可以将新的一天定义(或假设)为营业时间.例如,假设纽约的出版商在当地时间上午9点表示"书籍草稿将于1月2日到期".让我们在该时区获得该日期的时间.
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.of( 2016 , 1 , 2 , 9 , 0 , 0 , 0 , zoneId );
Run Code Online (Sandbox Code Playgroud)
这对在新西兰工作的作者意味着什么?调整到她特定的时区,通过电话向她展示withZoneSameInstant.
ZoneId zoneId_Pacific_Auckland = ZoneId.of( "Pacific/Auckland" );
ZonedDateTime zdt_Pacific_Auckland = zdt.withZoneSameInstant( zoneId_Pacific_Auckland );
Run Code Online (Sandbox Code Playgroud)
对于数据库存储,我们转换为Instant(在UTC时间轴上的一个时刻)并传递java.sql.Timestamp如上所述.
java.sql.Timestamp ts = java.sql.Timestamp.from( zdt.toInstant() );
Run Code Online (Sandbox Code Playgroud)
从数据库中检索时,转换回纽约日期时间.转换java.sql.Timestamp为a Instant,然后应用时区ZoneId来获取a ZonedDateTime.
Instant instant = ts.toInstant();
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
Run Code Online (Sandbox Code Playgroud)
如果数据库驱动程序符合JDBC 4.2或更高版本,则可以直接传递/获取java.time类型,而不是转换为java.sql类型.尝试PreparedStatement::setObject和ResultSet::getObject方法.