我们在sqlserver db表中将日期存储为varchar。 当在Java代码中将其作为字符串读取然后解析为Date时,它将被读取为UTC(Java代码位于UT中的服务器中)。将日期重新转换为ET时要晚4小时。如何处理将日期存储在ET的此db列中,以便在Java代码中将其读取为ET。
我们正在研究偏移量,但不完全了解该怎么做。
表03/29/2019 23:23:03中的Varchar日期//我们希望此日期位于ET
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
Date beginDate = sdf.parse("03/29/2019 23:23:03");
//问题是执行此代码时,服务器处于UTC状态。因此beginDate //读取为UTC时间03/29/2019 23:23:03而不是美国东部时间03/29/2019 23:23:03
预计将于03/29/2019 23:23:03美国东部时间 实际的03/29/2019 23:23:03 UTC
答案 0 :(得分:4)
首先,您需要了解Date
对象根本没有时区 。这只是时间的瞬间。因此,即使您正确解析了该值,它也将表示正确的时间点,但是稍后您可能需要将其转换回东部时间。
第二,您需要意识到存储这样的值会引起歧义-如果存储的值是(例如)11/03/2019 01:30,则本地时间会发生两次-一次发生在夏令时之前,一次发生然后。如果您始终存储过去的时间,则应至少考虑存储UTC-尽管that's not always the right answer, particularly not if you're storing future date/time values。
对于解析部分,您只需要在Calendar
使用的SimpleDateFormat
中设置时区。例如:
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York");
Date beginDate = sdf.parse("03/29/2019 23:23:03");
最后,我强烈建议 尽可能开始迁移代码以使用java.time
。与java.util.Date
等API相比,它是一个更好的API。
答案 1 :(得分:2)
Answer by Jon Skeet是正确的。正如他提到的那样,您应该使用JSR 310定义的 java.time 类。几年前,这些现代类取代了可怕的日期时间类,例如Date
和SimpleDateFormat
。这是该方向的一些示例代码。
表03/29/2019 23:23:03中的Varchar日期//我们希望此日期位于ET
将字符串解析为LocalDateTime
,因为我们的输入缺少指示UTC偏移量或时区的指示符。
定义一个格式化模式以匹配输入。
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MM/dd/uuuu HH:mm:ss" ) ;
解析。
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
如果您确实确定该日期和时间是针对特定时区的,请应用ZoneId
以获得ZonedDateTime
。
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;
通过提取Instant
来适应UTC。
Instant instant = zdt.toInstant() ;
您的JDBC驱动程序可能不接受Instant
。因此,将其转换为OffsetDateTime
,其中偏移量设置为零小时-分钟-秒(换句话说,UTC本身)。
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
写入数据库中类型为TIMESTAMP WITH TIME ZONE
的列。从JDBC 4.2及更高版本开始,我们可以直接与数据库交换 java.time 对象。
myPreparedStatement.setObject( … , odt ) ;
和检索。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
调整到所需的时区。
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
现在,您已经拥有完成某些database-refactoring所需的工作,用适当的TIMESTAMP WITH TIME ZONE
列替换了varchar列。
答案 2 :(得分:2)
varchar
作为日期和/或时间。对于许多DBMS,SQL标准中定义的timestamp with timezone
类型是要使用的正确类型。我对SQL Server的了解不够深,无法确切说明您应该在其中使用什么。确保将日期和时间存储在UTC中。varchar
存储的要求,请以UTC以ISO 8601格式存储。例如2019-03-30T03:23:03Z
。2019-03-29T23:23:03-04:00
。03/29/2019 23:23:03
格式(无偏移)进行存储的要求,请注意,在夏令时(DST)结束并且时钟向后移的秋天,您存储的模棱两可时间。在所有情况下,都倾向于使用java.time(现代Java日期和时间API)。罗勒·布尔克(Basil Bourque)的答案向您展示了如何,我无需重复。