繁体   English   中英

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

[英]Why SimpleDateFormat.format() and SimpleDateFormat.parse() are giving different time though setting only one TimeZone?

我正在尝试通过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”的输出,而Time2是local(即“ Asia / Calcutta”)的输出

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

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

请帮我。

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

您将得到一个输出,这表示您输入日期已成功解析。 您无法控制变量存储的date的格式。

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

只需解析->阅读(我可以以任何方式阅读并以我想要的任何方式存储)格式->写(我会以您想要的格式给您)

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

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

第二个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

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

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

由于可怕的旧日期时间类(例如SimpleDateFormat已被java.time取代,因此该问题不存在

当前时刻

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

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偏移量的指示。 这样的值不是时刻, 也不是时间轴上的一点。 例如,印度的晚上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表示时间轴上的时刻,分辨率为纳秒 (最多十进制的九(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及更高版本中。 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

现在处于维护模式Joda-Time项目建议迁移到java.time类。

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

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

在哪里获取java.time类?

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM