如何将时间戳转换为日期

时间:2019-04-03 10:53:00

标签: java date timestamp

其他系统会在他们所在的时区为我们发送时间戳。如果在其他系统中的云中运行,则需要+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')

2 个答案:

答案 0 :(得分:1)

tl; dr

  

如何确定时间永远正确?

  • 在日期时间输入字符串中包含time zoneoffset-from-UTC指示符。
  • 交换日期时间值时,请使用标准的ISO 8601格式。
  • 在Java中仅使用 java.time 类。切勿使用DateTimestampCalendar等。
  • 提示:在发送之前(通常来说),将其他区域的值调整为UTC。

如果不可能,那么这里是一种解决方法。假设您知道此不良数据的发送者所预期的时区。

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.Timestampjava.util.Date。根据JSR 310的使用,与最早的Java版本捆绑在一起的所有日期时间类现在都是旧的。仅使用现代的 java.time 类。

数据类型错误

您使用了错误的数据类型。要跟踪时刻,即时间轴上的特定点,您必须具有时区或UTC偏移量。 LocalDateTime类与此处使用的类完全错误。该类故意缺少区域或偏移的任何概念。因此,这与您想要的相反。

要跟踪时刻,请使用InstantOffsetDateTimeZonedDateTime

Table of date-time types in Java, both modern and legacy.

如果 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/MontrealAfrica/CasablancaPacific/Auckland。切勿使用2-4个字母的缩写,例如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ISO 8601

您的问题尚不清楚,但似乎您收到的是自定义格式的日期时间输入字符串。我建议您教育人们发布有关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.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

要了解更多信息,请参见Oracle Tutorial。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310

目前位于Joda-Timemaintenance mode项目建议迁移到java.time类。

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

在哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

答案 1 :(得分:1)

只是Basil Bourque’s clever and very informative answer的一小部分补充。

  
      
  1. 我知道日期是CET时区。
  2.   

对不起,这还不够。中欧时间(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