简体   繁体   English

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

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

I am trying to set the Timezone to the different country's timezone with help of SimpleDateFormat . 我正在尝试通过SimpleDateFormat将时区设置为其他国家的时区。 SimpleDateFormat.format() returns correct current time of the given Timezone, but SimpleDateFormat.parse() returns local current time, I dont know why this is happening. SimpleDateFormat.format()返回给定时区的正确当前时间,但是SimpleDateFormat.parse()返回本地当前时间,我不知道为什么会这样。 Here is the my code - 这是我的代码-

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())));

The Output is - 输出是-

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

Time1 is the output of "America/Los_Angeles" and Time2 is the output of local(ie "Asia/Calcutta") . Time1是“ America / Los_Angeles”的输出,而Time2是local(即“ Asia / Calcutta”)的输出

I just want the current time of given Timezone in UTC Seconds format (ie Seconds since Jan 1, 1970). 我只想要UTC秒格式的给定时区的当前时间(即,自1970年1月1日以来的秒)。

Why SimpleDateFormat.format() and SimpleDateFormat.parse() are giving different time though setting only one Timezone? 为什么虽然只设置一个时区,但SimpleDateFormat.format()和SimpleDateFormat.parse()却给出了不同的时间?

Please help me. 请帮我。

with Parse , you command the compiler to understand the given date in specific format. 使用Parse ,您可以命令编译器理解特定格式的给定日期。 It understands and keep it in its own format and ready to give whatever format you want! 它了解并保持其自己的格式,并准备提供您想要的任何格式!

You are getting a output, which is a signal that you input date is parsed successfully. 您将得到一个输出,这表示您输入日期已成功解析。 You dont have a control over the format of the date , that the variable is storing. 您无法控制变量存储的date的格式。

using format, you can convert the date to any desired format. 使用格式,您可以将日期转换为任何所需的格式。

Simply Parse -> Reading ( I may read it in whatever manner and store in whatever manner I want) Format -> Write ( I will give you in the format you wanted ) 只需解析->阅读(我可以以任何方式阅读并以我想要的任何方式存储)格式->写(我会以您想要的格式给您)

dateFormat.format() will give you the output in given format and it will change the timezone to the one set in formatter. dateFormat.format()将为您提供给定格式的输出,并将时区更改为格式化程序中设置的时区。 (eg dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));) (例如dateFormat.setTimeZone(TimeZone.getTimeZone(“ America / Los_Angeles”)));)

Whereas dateFormat.parse() assumes date is already in mentioned timezone and it will convert the date to your local timezone. 而dateFormat.parse()假定日期已在提到的时区中,它将日期转换为您的本地时区。

dateFormat.parse() in the second println 第二个println中的dateFormat.parse()

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

returns Date and Date.toString() returns string representation of the date in EEE MMM dd HH:mm:ss zzz yyyy format. 返回Date和Date.toString()以EEE MMM dd HH:mm:ss zzz yyyy格式返回日期的字符串表示形式。 See Date.toString() API 参见Date.toString()API

With the first line, you are formatting your local date to specific timezone.It will return a string which represents the argument date passed in specific time zone.But parse function is different.It will return a date object represents a number of milliseconds since January 1, 1970, 12:00 AM, UTC. 在第一行中,您正在将本地日期格式化为特定时区,它将返回一个字符串,该字符串表示在特定时区中传递的参数日期,但是解析函数有所不同。它将返回一个日期对象,该对象表示自一月份以来的毫秒数1970年1月1日,UTC。 It does not contain any time zone information. 它不包含任何时区信息。

tl;dr tl; dr

The terrible old date-time classes are quite confusing, especially in their handling of implicit default time zones. 糟糕的旧日期时间类非常令人困惑,尤其是在处理隐式默认时区时。 But your mystery is moot, as these terrible old classes were supplanted years ago by modern java.time classes. 但是,您的谜尚无足轻重 ,因为这些可怕的旧类早在几年前就被现代的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 2013-01-17 21:01:55

java.time java.time

The issue is moot as the terrible old date-time classes such as SimpleDateFormat have been supplanted by the java.time . 由于可怕的旧日期时间类(例如SimpleDateFormat已被java.time取代,因此该问题不存在

Current moment 当前时刻

The java.util.Date class is replaced by java.time.Instant . java.util.Date类由java.time.Instant替换。 Both represent a moment in UTC, always in UTC. 两者都代表UTC时刻,始终代表UTC。 (Despite Date::toString lying to you, in applying the JVM's current default time zone.) (尽管在应用JVM的当前默认时区时对您说谎,尽管Date::toString 。)

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

Adjust into a time zone. 调整到一个时区。

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

Adjust into another time zone. 调整到另一个时区。

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

All three objects ( instant , zdt , & zdtKolkata ) represent the very same simultaneous moment , the same point on the timeline. 这三个对象( instantzdtzdtKolkata )都表示同一时刻 ,时间轴上的同一点。 Only the wall-clock time is different. 只有挂钟时间不同。

Strings 弦乐

When generating strings representing date-time values, I recommend always including the offset/zone information unless the context is absolutely crystal-clear. 当生成表示日期时间值的字符串时,除非上下文绝对清晰,否则我建议始终包括偏移量/区域信息。 I have seen much confusion in the business world caused by reports where the time frame was ambiguous. 在时间范围不明确的报告中,我在商业世界中看到了很多困惑。

But if you insist, either define your own formatting pattern with DateTimeFormatter class, or use the given formatter ISO_LOCAL_DATE_TIME and replace the T in the middle with a SPACE. 但是,如果您坚持要用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

Unzoned date-time 未分区日期时间

Part of the problem is the ambiguity of your string 2013-01-17 21:01:55 . 问题的一部分是您的字符串的歧义2013-01-17 21:01:55 That string lacks any indicator of time zone or offset-from-UTC. 该字符串缺少任何时区或UTC偏移量的指示。 Such a value is not a moment, is not a point on the timeline. 这样的值不是时刻, 也不是时间轴上的一点。 For example, 9 PM in India comes several hours sooner than 9 PM in Québec. 例如,印度的晚上9点比魁北克的晚上9点早几个小时。 Without a zone or offset, that string represents only potential moments along a range of about 26-27 hours, the range of time zones around the globe. 没有区域或偏移量,该字符串仅代表沿全球时区范围约26-27小时的潜在时刻。

The legacy classes had no such class to represent this kind of value. 传统类没有此类代表这种价值的类。 In the modern classes, we have LocalDateTime for this purpose, a non-moment, date and time-of-day without zone/offset. 在现代类中,我们为此设置了LocalDateTime ,这是一个无时区,日期和时间的无区域/偏移量。

The java.time classes use ISO 8601 standard formats by default when parsing/generating strings. 解析/生成字符串时, java.time类默认使用ISO 8601标准格式。 Your input nearly complies. 您的输入几乎符合要求。 We need only replace the SPACE in the middle with a T . 我们只需要在中间用T替换SPACE即可。

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

If you know for a fact that the intent behind that string was to represent a moment in a particular time zone, apply a ZoneId to get a ZonedDateTime . 如果您知道该字符串后面的意图是表示特定时区中的某个时刻,请应用ZoneId来获取ZonedDateTime For example, if you are certain it represents a moment on most of the west coast of North America, use America/Los_Angeles . 例如,如果您确定它代表了北美大部分西海岸的一刻,请使用America/Los_Angeles

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

To adjust from that zone to UTC, extract a Instant object. 要从该区域调整为UTC,请提取一个Instant对象。 The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). Instant类以UTC表示时间轴上的时刻,分辨率为纳秒 (最多十进制的九(9)位数字)。

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

About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧的旧式日期时间类,例如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. 现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参见Oracle教程 And search Stack Overflow for many examples and explanations. 并在Stack Overflow中搜索许多示例和说明。 Specification is JSR 310 . 规格为JSR 310

You may exchange java.time objects directly with your database. 您可以直接与数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later. 使用与JDBC 4.2或更高版本兼容的JDBC驱动程序 No need for strings, no need for java.sql.* classes. 不需要字符串,不需要java.sql.*类。

Where to obtain the java.time classes? 在哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目为将来可能在java.time中添加内容提供了一个试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

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

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