使用Calendar对象将时区从EEST更改为HST会意外更改时间 [英] Changing time zone with Calendar object from EEST to HST changes the time-of-day unexpectedly
问题描述
我有一些 TimeStamp
,并且日期格式为"EEEE,MMM dd,yyyy hh:mm a zzz"
.但是我不知道如何显示带有时区的时间戳.当我尝试显示它时,我得到了错误的DateTime或错误的时区
I have some TimeStamp
and I have date format "EEEE, MMM dd, yyyy hh:mm a zzz"
. But I don't know how I can show this timestamp with timezone. When I trying to show it I get wrong DateTime or wrong timezone
example1:
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(device.getUpdatedDate().getTime())); // here is 2018-07-09 20:02:26.506000
SimpleDateFormat sdf = new SimpleDateFormat(EMAIL_DATE_FORMAT);
sdf.format(calendar.getTime()); // i have wrong timezone
我得到美国东部时间2018年7月9日星期一晚上08:02
但是当我添加 sdf.setTimeZone(TimeZone.getTimeZone("HST"));
时,我有正确的时区和错误的时间 HST星期一,2018年7月9日上午7:02
but when i add sdf.setTimeZone(TimeZone.getTimeZone("HST"));
i have right timezone and wrong time
Monday, Jul 09, 2018 07:02 AM HST
预期结果 HST星期一,2018年7月9日晚上08:02
实际结果:美国东部时间2018年7月9日星期一晚上08:02
或 HST,2018年7月9日,星期一,07:02
推荐答案
tl; dr
- 您看到的是功能,而不是错误,它会将同一时刻调整为另一个时区.
- 东欧的晚上8点和夏威夷的早上7点.
- You are seeing a feature, not a bug, adjusting same moment to another time zone.
- 8 PM in eastern Europe is also 7 AM in Hawaii.
您从UTC提前3小时的一个时区调整为UTC落后10小时的另一个时区,总共相差13小时.知道一个地方的8 PM同时在另一个地方的7 AM.
You adjusted from one time zone 3 hours ahead of UTC to another zone 10 hours behind UTC, for a total difference of 13 hours. Understand that 8 PM in one place is simultaneously 7 AM in the other.
请注意我们在以下代码中对
withZoneSameInstant
("Instant")的调用.Note our call to
withZoneSameInstant
(‘Instant’) in the following code.ZonedDateTime.of( 2018 , 7 , 9 , 20 , 2 , 0 , 0 , ZoneId.of( "Europe/Athens" ) // 8 PM in Greece. ) .withZoneSameInstant( // Adjust into another time zone to view the same moment with another wall-clock time. ZoneId.of( "Pacific/Honolulu" ) // 7 AM in Hawaii. ) .toString()
2018-07-09T07:02-10:00 [太平洋/火奴鲁鲁]
2018-07-09T07:02-10:00[Pacific/Honolulu]
不同时刻:使用
调用
="nofollow noreferrer">显然,您想要一个不同的时刻,时间轴上的一个不同的点,它具有相同的日期和一天中的时间,但是具有不同的时区.
Different moment: Call
withZoneSameLocal
Apparently you wanted a different moment, a different point on the timeline, that has the same date and same time-of-day but a different time zone.
请注意以下代码中对
withZoneSameLocal
("Local",而不是"Instant")的调用.Note our call to
withZoneSameLocal
(‘Local’, not ‘Instant’) in the following code.ZonedDateTime.of( 2018 , 7 , 9 , 20 , 2 , 0 , 0 , ZoneId.of( "Europe/Athens" ) // 8 PM in Greece. ) .withZoneSameLocal( // Different moment, coincidentally having the same date and same time-of-day. But different time zone means this is a different point on the timeline. ZoneId.of( "Pacific/Honolulu" ) // Also 8 PM in Hawaii, which happens many hours later than 8 PM in Greece. Different moment, same wall-clock time. ) .toString()
2018-07-09T20:02-10:00 [太平洋/火奴鲁鲁]
2018-07-09T20:02-10:00[Pacific/Honolulu]
详细信息
实时时区
HST
&EEST
是伪区域,不是实时区域.避免使用这3-4个字母代码,因为它们不是标准化的,甚至也不是唯一的(!).
Details
Real time zone
HST
&EEST
are pseudo-zones, not real time zones. Avoid these 3-4 letter codes as they are not standardized and are not even unique(!).使用 tzdata 中定义的实时区域名称 IANA .请参阅Wikipedia中的列表(可能已过时).这些名称采用
Continent/Region
(洲/地区)格式,例如America/Montreal
(美国/蒙特利尔)或Europe/Tallinn
(欧洲/塔林).Use real time zone names as defined in tzdata by the IANA. See a list in Wikipedia (possibly outdated). These names are in
Continent/Region
format such asAmerica/Montreal
orEurope/Tallinn
.ZoneId z = ZoneId.of( "Europe/Vilnius" ) ;
避免使用旧的日期时间类
避免麻烦的类
Calendar
&SimpleDateFormat
.这些在几年前被 java.time 类所取代.使用 java.time 更加清晰和容易.Avoid legacy date-time classes
Avoid the terribly troublesome classes
Calendar
&SimpleDateFormat
. These were supplanted years ago by the java.time classes. Working with java.time is much clearer and easier.让我们开始吧.我想通过
EEST
可以想到一个东欧时区.我可以随意选择一个.Let's get your starting point. I am guessing that by
EEST
you had in mind one of the eastern European time zones. I am choosing one arbitrarily.ZoneId zAthens = ZoneId.of( "Europe/Athens" ) ; LocalDate ld = LocalDate.of( 2018 , Month.JULY , 9 ) ; // 2018-07-09. LocalTime lt = LocalTime.of( 20 , 2 ) ; // 8:02 PM. ZonedDateTime zdtAthens = ZonedDateTime.of( ld , lt , zAthens ) ;
生成表示该String
ZonedDateTime
对象.默认情况下,明智地使用标准的 ISO 8601 格式,以将时区的名称添加为正方形括号.Generate a
String
representing the value of thatZonedDateTime
object. By default, use standard ISO 8601 format wisely extended to append the name of the time zone in square brackets.String outputAthens = zdtAthens.toString() ; // Generate `String` in a format extending standard ISO 8601 format.
2018-07-09T20:02 + 03:00 [欧洲/雅典]
2018-07-09T20:02+03:00[Europe/Athens]
通过
HST
,我想你是说夏威夷时间.该区域的专有名称是Pacific/Honolulu
.By
HST
I guess you mean Hawaii time. The proper name for that zone isPacific/Honolulu
.ZoneId zHonolulu = ZoneId.of( "Pacific/Honolulu" ) ;
让我们将雅典的时刻调整到夏威夷的另一个区域.时间轴上的相同时刻,相同点,但挂钟时间不同.想象一下,每个地方都有一对朋友打电话给他们,同时抬头看着他们墙上的时钟.每个人看到的是不同的时间,可能还有不同的日期,尽管如此,他们在时间轴上遇到的是同一时刻,同一时间点.
Let's adjust our Athens moment into this other zone for Hawaii. Same moment, same point on the timeline, but a different wall-clock time. Imagine a pair of friends in each place calling each and simultaneously looking up at a clock on their wall. Each sees a different time-of-day and possibly a different date, nevertheless they experience the same simultaneous moment, same point on the timeline.
ZonedDateTime zdtHonolulu = zdtAthens.withZoneSameInstant( zHonolulu ) ; // Same moment (same `Instant` inside the `ZonedDateTime`) but a different time zone.
那一天,檀香山比世界标准时间晚10个小时,而雅典比世界标准时间早3个小时.那是总共十三个小时的增量.因此,晚上8点(20:00)减去13是早上7点.我们希望在夏威夷看到早上7点.让我们通过生成另一个ISO 8601格式的字符串来进行验证.
On that date, Honolulu is ten hours behind UTC while Athens is three hours ahead. That is a total delta of thirteen hours. So, 8 PM (20:00) minus 13 is 7 AM. We expect to see 7 AM in Hawaii. Let's verify, by generating another string in ISO 8601 format.
String outputHonolulu = zdtHonolulu.toString() ; // Generate `String` representing the value of the `ZonedDateTime` object.
2018-07-09T07:02-10:00 [太平洋/火奴鲁鲁]
2018-07-09T07:02-10:00[Pacific/Honolulu]
果然,早上7点.
也许您想要的是位于夏威夷的相同日期和同一时间.这意味着您不代表同一时刻.您将在时间轴上代表另一个时间点,相差几个小时.
Perhaps what you wanted was the same date and same time-of-day located in Hawaii. This would mean you are not representing the same simultaneous moment. You would be representing a different point on the timeline, off by several hours.
ZonedDateTime
确实提供了此功能.在概念上调用ZonedDateTime :: withZoneSameLocal
含义:使用相同的内部LocalDate
和相同的内部LocalTime
,但使用不同的分配的ZoneId
.The
ZonedDateTime
does provide for this function. CallZonedDateTime::withZoneSameLocal
meaning conceptually: Use the same internalLocalDate
and the same internalLocalTime
, but use a different assignedZoneId
.ZonedDateTime eightPmOnJuly9InPacificHonolulu = zdtAthens.withZoneSameLocal( zHonolulu) ; String outputDifferentMoment= eightPmOnJuly9InPacificHonolulu.toString() ;
2018-07-09T20:02-10:00 [太平洋/火奴鲁鲁]
2018-07-09T20:02-10:00[Pacific/Honolulu]
UTC
所有在时区之间翻转的现象都会使人变得生气.通过专注于UTC来扎根.将UTC视为一个真实的时间,所有其他区域仅是变化而已.
UTC
All this flipping around between time zones can drive a person batty. Get grounded by focusing on UTC. Think of UTC as The One True Time, and all other zones are but mere variations.
要从时区调整为UTC,请从我们的
ZonedDateTime
对象中提取一个Instant
对象.根据定义,Instant
始终使用UTC.To adjust from a time zone to UTC, extract a
Instant
object from ourZonedDateTime
objects. AnInstant
is always in UTC by definition.Instant instantAthens = zdtAthens.toInstant() ; Instant instantHonolulu = zdtHonolulu.toInstant() ; Instant instantDifferentMoment = eightPmOnJuly9InPacificHonolulu.toInstant() ;
2018-07-09T17:02:00Z
2018-07-09T17:02:00Z
2018-07-09T17:02:00Z
2018-07-09T17:02:00Z
2018-07-10T06:02:00Z
2018-07-10T06:02:00Z
最后的
Z
表示UTC,发音为 Zulu ,并由ISO 8601和其他标准定义.The
Z
on the end means UTC, is pronounced Zulu, and is defined by ISO 8601 and other standards.java.time 框架内置于Java 8及更高版本中.这些类取代了麻烦的旧版日期时间类,例如
Calendar
,&SimpleDateFormat
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as
java.util.Date
,Calendar
, &SimpleDateFormat
.Joda-Time 项目,现在位于<一个href ="https://en.wikipedia.org/wiki/Maintenance_mode" rel ="nofollow noreferrer">维护模式,建议迁移到要了解更多信息,请参见 Oracle教程.并在Stack Overflow中搜索许多示例和说明.规范为 JSR 310 .
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
您可以直接与数据库交换 java.time 对象.使用符合
JDBC驱动程序/jeps/170"rel =" nofollow noreferrer> JDBC 4.2 或更高版本.不需要字符串,不需要 java.sql.*
类.You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for
java.sql.*
classes.在哪里获取java.time类?
Where to obtain the java.time classes?
- java.time 类的Android捆绑包实现的最新版本.
- 对于较早的Android(< 26), ThreeTenABP 项目适应> ThreeTen-Backport (如上所述).请参阅 如何使用ThreeTenABP… .
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
> ThreeTen-Extra 项目扩展了java.time与其他班级.该项目为将来可能在java.time中添加内容提供了一个试验场.您可能会在这里找到一些有用的类,例如
间隔
,年周"
,YearQuarter
和更多这篇关于使用Calendar对象将时区从EEST更改为HST会意外更改时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
tl;dr