为什么SimpleDateFormat.format()和SimpleDateFormat.parse()虽然只设置一个TimeZone,但给出了不同的时间?

时间:2013-01-18 05:43:35

标签: java date timezone simpledateformat

我正在尝试借助 SimpleDateFormat 将时区设置为不同国家/地区的时区。 SimpleDateFormat.format()返回给定时区的正确当前时间,但 SimpleDateFormat.parse()返回本地当前时间,我不知道为什么会发生这种情况。这是我的代码 -

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:MM:ss");
dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
System.out.println("Time1 : " + dateFormat.format(new Date()));
System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));

输出是 -

Time1 : 2013-01-17 21:01:55
Time2 : Fri Jan 18 10:30:55 IST 2013

Time1是" America / Los_Angeles"的输出。和时间2是当地的输出(即"亚洲/加尔各答")

我只想要给定时区的当前时间格式为UTC秒(即1970年1月1日以来的秒数)。

为什么SimpleDateFormat.format()和SimpleDateFormat.parse()通过只设置一个时区给出不同的时间?

请帮帮我。

5 个答案:

答案 0 :(得分:4)

使用 Parse ,您可以命令编译器以特定格式了解给定日期。它理解并保持其自己的格式,并准备提供您想要的任何格式!

您正在获取输出,这是您输入日期已成功解析的信号。你无法控制变量存储日期的格式。

使用格式,您可以将日期转换为任何所需的格式。

简单地 解析 - >阅读(我可以用任何方式阅读它并以我想要的任何方式存储) 格式 - >写(我会以你想要的格式给你)

答案 1 :(得分:2)

dateFormat.format()将为您提供给定格式的输出,并将时区更改为格式化程序中设置的时区。 (例如dateFormat.setTimeZone(TimeZone.getTimeZone(“ America / Los_Angeles”))))

dateFormat.parse()假定日期已经在提到的时区中,它将日期转换为您的本地时区。

答案 2 :(得分:0)

第二个println中的

dateFormat.parse()

System.out.println("Time2 : " + dateFormat.parse(dateFormat.format(new Date())));

返回Date和Date.toString()以EEE MMM dd HH:mm:ss zzz yyyy格式返回日期的字符串表示形式。请参见Date.toString()API

答案 3 :(得分:0)

使用第一行,您将本地日期格式化为特定时区。它将返回一个字符串,表示在特定时区传递的参数日期。但是解析函数不同。它将返回一个日期对象表示的数字自1970年1月1日上午12:00,UTC以来的毫秒数。它不包含任何时区信息。

答案 4 :(得分:0)

tl; dr

可怕的旧日期时间类非常令人困惑,尤其是在处理隐式默认时区时。但是,您的谜尚无足轻重,因为这些可怕的旧类早在几年前就被现代的 java.time 类所取代。

Instant.now()                // Capture current moment in UTC. This class replaces `java.util.Date`. 
.atZone(                     // Adjust from UTC to the wall-clock time used by the people of a particular region, a time zone.
    ZoneId.of( "America/Montreal" ) 
)                            // Returns a `ZonedDateTime`
.format(
    DateTimeFormatter.ISO_LOCAL_DATE_TIME
)                            // Returns a String like: `2013-01-17T21:01:55`.
.replace( "T" , " " )        // Replace the `T` in the middle (from the standard ISO 8601 format) with a SPACE.
  

2013-01-17 21:01:55

java.time

问题已经解决,因为 java.time 取代了可怕的旧日期时间类,例如SimpleDateFormat

当前时刻

java.util.Date类被java.time.Instant取代。两者都代表UTC时刻,始终代表UTC。 (尽管Date::toString在应用JVM当前的默认时区时对您说谎)。

Instant instant = Instant.now() ;  // Capture current moment in UTC.

调整为时区。

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

调整到另一个时区。

ZoneId zKolkata = ZoneId.of( "Asia/Kolkata" ) ;  // Contemporary time in India. 
ZonedDateTime zdtKolkata = instant.atZone( zKolkata ) ;

所有三个对象(instantzdtzdtKolkata)表示同一时刻,即时间轴上的同一点。只有挂钟时间不同。

字符串

在生成表示日期时间值的字符串时,除非上下文绝对清晰,否则我建议始终包括偏移量/区域信息。在时间范围不明确的报告中,我在商业世界中看到了很多困惑。

但是,如果您坚持要使用DateTimeFormatter类定义自己的格式化模式,或者使用给定的格式化程序ISO_LOCAL_DATE_TIME并将中间的T替换为SPACE。

DateTimeFormatter f = DateTimeFormatter.ISO_LOCAL_DATE_TIME ;
String output = zdt.format( f ) ;
  

2013-01-17 21:01:55

未分区的日期时间

部分问题是您的字符串2013-01-17 21:01:55含糊不清。该字符串缺少任何时区或UTC偏移量的指示。这样的值是 not 片刻,是 not 在时间线上的一点。例如,印度的晚上9点比魁北克的晚上9点早几个小时。没有区域或偏移量,该字符串仅代表大约26-27小时范围内的潜在时刻,即全球时区范围。

传统类没有此类代表这种价值的类。在现代班级中,为此目的,我们有LocalDateTime,这是一个无时区,日期和时间的无区域/偏移量。

java.time 类在解析/生成字符串时默认使用ISO 8601标准格式。您的输入几乎符合要求。我们只需要在中间用T替换SPACE。

LocalDateTime ldt = LocalDateTime.parse( "2013-01-17 21:01:55".replace( "" , "T" ) ) ;

如果您知道该字符串后面的意图是表示特定时区中的某个时刻,请应用ZoneId来获得ZonedDateTime。例如,如果确定它代表了北美大部分西海岸的一瞬间,请使用America/Los_Angeles

ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; 

要从该区域适应UTC,请提取一个Instant对象。 Instant类表示UTC中时间轴上的时刻,分辨率为nanoseconds(十进制小数的九(9)位)。

Instant instant = zdt.toInstant() ;  // Adjust from some zone to UTC. Same moment, same point on the timeline, different wall-clock time.

关于 java.time

java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendarSimpleDateFormat

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

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

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

在哪里获取java.time类?

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