java 为什么 SimpleDateFormat.format() 和 SimpleDateFormat.parse() 虽然只设置了一个 TimeZone 却给出了不同的时间?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14393073/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why SimpleDateFormat.format() and SimpleDateFormat.parse() are giving different time though setting only one TimeZone?
提问by Deepu
I am trying to set the Timezone to the different country's timezone with help of 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. Here is the my code -
我试图在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())));
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(i.e. "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.
请帮我。
回答by madhairsilence
with Parse, you command the compiler to understand the given date in specific format. It understands and keep it in its own format and ready to give whatever format you want!
使用Parse,您可以命令编译器以特定格式理解给定的日期。它理解并保持其自己的格式,并准备好提供您想要的任何格式!
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.
您将获得一个输出,这是您输入的日期已成功解析的信号。您无法控制变量存储的日期格式。
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 )
简单解析 -> 阅读(我可以以任何方式阅读并以我想要的任何方式存储)格式 -> 写(我会给你你想要的格式)
回答by Pooja Garg
dateFormat.format() will give you the output in given format and it will change the timezone to the one set in formatter. (eg dateFormat.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));)
dateFormat.format() 将以给定格式为您提供输出,并将时区更改为格式化程序中设置的时区。(例如 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() 假设日期已经在提到的时区中,它会将日期转换为您的本地时区。
回答by Basil Bourque
tl;dr
tl;博士
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.timeclasses.
可怕的旧日期时间类非常令人困惑,尤其是在处理隐式默认时区时。但是你的谜团没有实际意义,因为这些可怕的旧类在多年前被现代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
时间
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
. Both represent a moment in UTC, always in UTC. (Despite Date::toString
lying to you, in applying the JVM's current default time zone.)
该java.util.Date
班所取代java.time.Instant
。两者都代表 UTC 中的一个时刻,始终为 UTC。(尽管Date::toString
在应用 JVM 的当前默认时区时对您撒谎。)
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. Only the wall-clock time is different.
所有三个对象(instant
、zdt
、 & zdtKolkata
)都代表同一时刻,时间线上的同一点。只有挂钟时间不同。
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
空格替换中间的。
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
. That string lacks any indicator of time zone or offset-from-UTC. Such a value is nota moment, is nota point on the timeline. For example, 9 PM in India comes several hours sooner than 9 PM in Québec. Without a zone or offset, that string represents only potentialmoments along a range of about 26-27 hours, the range of time zones around the globe.
部分问题是您的 string 的歧义2013-01-17 21:01:55
。该字符串缺少时区或UTC 偏移量的任何指示符。这样的价值不是一个时刻,也不是时间线上的一个点。例如,印度的晚上 9 点比魁北克的晚上 9 点早几个小时。如果没有时区或偏移量,该字符串仅表示大约 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.timeclasses use ISO 8601 standard formats by default when parsing/generating strings. Your input nearly complies. We need only replace the SPACE in the middle with a T
.
该java.time类解析/生成字符串时,使用ISO 8601标准格式默认。您的输入几乎符合要求。我们只需要将中间的 SPACE 替换为T
.
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
. For example, if you are certain it represents a moment on most of the west coast of North America, use America/Los_Angeles
.
如果您知道该字符串背后的意图是表示特定时区中的某个时刻,请应用 aZoneId
来获取ZonedDateTime
. 例如,如果您确定它代表北美西海岸大部分地区的某个时刻,请使用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. The Instant
class represents a moment on the timeline in UTCwith a resolution of nanoseconds(up to nine (9) digits of a decimal fraction).
要从该区域调整到 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.
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10、Java SE 11及更高版本 - 标准 Java API 的一部分,具有捆绑实现。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 多的java.time功能后移植到Java 6和7在ThreeTen-反向移植。
- 安卓
- 更高版本的 Android 捆绑实现java.time类。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。
The ThreeTen-Extraproject extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
该ThreeTen-额外项目与其他类扩展java.time。该项目是未来可能添加到 java.time 的试验场。你可能在这里找到一些有用的类,比如Interval
,YearWeek
,YearQuarter
,和更多。
回答by Evgeniy Dorofeev
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. See Date.toString() API
返回日期和 Date.toString() 以EEE MMM dd HH:mm:ss zzz yyyy
格式返回日期的字符串表示形式。请参阅 Date.toString() API
回答by Renjith
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. It does not contain any time zone information.
第一行,您将本地日期格式化为特定时区。它将返回一个字符串,表示在特定时区传递的参数日期。但解析函数不同。它将返回一个日期对象,表示自一月以来的毫秒数1970 年 1 月 1 日凌晨 12:00,UTC。它不包含任何时区信息。