其他系统会在他们所在的时区为我们发送时间戳。如果在其他系统中的云中运行,则需要+2小时。本地是好的,因为服务器是相同的时区。我如何确定时间永远是正确的?
String TIME_STAMP_FORMAT = "yyyy-MM-dd-HH.mm.ss.SSSSSS";
DateTimeFormatter TIME_STAMP_FORMATTER = DateTimeFormatter.ofPattern(TIME_STAMP_FORMAT, Locale.getDefault());
private static Timestamp parseTimestamp(String dateString) {
try {
return Timestamp.valueOf(LocalDateTime.parse(dateString, TIME_STAMP_FORMATTER));
} catch (DateTimeParseException e) {
log.error("Not able to parse timestamp", e);
}
return null;
}
Date afterParse = parseTimestamp('2018-12-31-12.30.50.000200')
答案 0 :(得分:1)
如何确定时间永远正确?
Date
,Timestamp
,Calendar
等。如果不可能,那么这里是一种解决方法。假设您知道此不良数据的发送者所预期的时区。
LocalDateTime // Represent a date and time-of-day without the context of a time zone or offset-from-UTC. NOT a moment, NOT a point on the timeline. A meaningless value until you assign a zone/offset.
.parse(
"2018-12-31-12.30.50.000200" , // Avoid such custom formats. Use only ISO 8601 when exchanging date-time values textually.
DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) // Define formatting pattern to match youre input.
) // Returns a `LocalDateTime` object.
.atZone( // Give meaning to the `LocalDateTime` object by applying a time zone.
ZoneId.of( "Africa/Tunis" ) // Always specify a time zone with `Continent/Region` name, never the 2-4 character pseudo-zones popularly seen in the media.
) // Returns a `ZonedDateTime` object.
.toInstant() // Adjust from a time zone to UTC by extracting an `Instant` object. Same moment, same point on the timeline, different wall-clock time.
请参阅此code run live at IdeOne.com。
最好避免使用java.util.Date
类。但是,如果必须与尚未更新为 java.time 的旧代码进行互操作,则可以进行转换。调用添加到旧类中的新方法,例如Date.from( Instant )
。
请勿使用java.sql.Timestamp
或java.util.Date
。根据JSR 310的使用,与最早的Java版本捆绑在一起的所有日期时间类现在都是旧的。仅使用现代的 java.time 类。
您使用了错误的数据类型。要跟踪时刻,即时间轴上的特定点,您必须具有时区或UTC偏移量。 LocalDateTime
类与此处使用的类完全错误。该类故意缺少区域或偏移的任何概念。因此,这与您想要的相反。
要跟踪时刻,请使用Instant
,OffsetDateTime
或ZonedDateTime
。
如果 java.time 类具有带有可选时区(ZoneId
)或自UTC偏移量(ZoneOffset
)自变量的方法,请考虑所需的自变量。 始终传递区域/偏移量。然后,您无需担心系统管理员如何在运行时设置JVM当前的默认时区。
ZonedDateTime.now( // Capture the current moment as seen through the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Pacific/Auckland" )
)
或者,根据定义,使用始终为UTC的Instant
。
Instant.now() // Capture the current moment in UTC.
以Continent/Region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用2-4个字母的缩写,例如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
您的问题尚不清楚,但似乎您收到的是自定义格式的日期时间输入字符串。我建议您教育人们发布有关ISO 8601标准的数据。该标准定义了文本之间在系统之间交换的日期时间值的实用格式。
java.time 类在解析/生成字符串时默认使用ISO 8601格式。
如果数据发布者正在向您发送诸如2018-12-31-12.30.50.000200
之类的值以便进行交流,则它们失败了。没有区域或偏移量的日期和时间是无用的,就像在不指示货币的情况下传达一定数量的钱一样。
您是否可以确定此错误数据输入的发送方隐式假定的时区?如果是这样,请应用它,作为对他们的不良实践的笨拙的权宜之计。
如果没有任何区域/偏移量指示,请首先将您的输入解析为LocalDateTime
。
String input = "2018-12-31-12.30.50.000200" ;
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd-HH.mm.ss.SSSSSS" ) ;
LocalDateTime ldt = LocalDateTime.parse( input , f ) ;
应用ZoneId
以获得ZonedDateTime
对象,从而进行调整以查看该特定地区的人们所使用的挂钟时间。
ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = ldt.atZone( ldt ) ;
通常最好使用UTC中的时刻,除非您有特定的理由使用时区(例如向用户演示)。因此,请从您的ZonedDateTime
中提取一个Instant
。
Instant instant = zdt.toInstant() ;
符合ISO 8601的字符串末尾的Z
表示UTC,并发音为“ Zulu”。
请参阅此code run live at IdeOne.com。
输入:2018-12-31-12.30.50.000200
ldt:2018-12-31T12:30:50.000200
zdt:2018-12-31T12:30:50.000200 + 09:00 [亚洲/东京]
即时:2018-12-31T03:30:50.000200Z
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
目前位于Joda-Time的maintenance mode项目建议迁移到java.time类。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
在哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 1 :(得分:1)
只是Basil Bourque’s clever and very informative answer的一小部分补充。
- 我知道日期是CET时区。
对不起,这还不够。中欧时间(CET)是许多欧洲和非洲(!)时区的通用术语,其时区有所不同。欧洲标准时间通常在标准时间为+01:00,夏季为+02:00(称为中欧夏季时间或CEST)。非洲人全年都在+01:00。对于过去的日期,仅几十年前,一些区域使用夏令时(DST),其他区域则没有使用夏令时,一些区域则在+00:00,+ 01:00或+02:00,并且在历史上还有许多其他偏移通常不使用整个小时。
未来更糟!有人建议欧洲联盟放弃夏令时,将其留给每个成员国使用永久标准时间还是永久夏令时,避免在春季和秋季进行时间调整。这方面正在进行一场权力斗争,所以我们不知道它是否会发生,也不知道每个成员国会选择什么。因此,即使您可以从其他系统(例如,欧洲/萨拉热窝)告诉我字符串的确切时区,也没人知道2019-11-01-00.30.50.000200
(距离现在不到7个月)是否会偏移+ 01:00或+02:00。
BBC新闻上的链接:European MPs vote to end summer time clock changes。