问题
I hava serval time zone strings in utc format, such as "UTC+08:00", "UTC-05:00", the question is how can i convert these utc format strings to the TimeZone Object(java.util.TimeZone) in java?
i have tried to convert by zoneId as follows, but did not work:
ZoneId zoneId = ZoneId.of("UTC+08:00");
TimeZone timeZone = TimeZone.getTimeZone(zoneId);
i know TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
would work, but i do not know the mapping between "UTC+08:00" and "Asia/Shanghai"
回答1:
tl;dr
- Do not use
TimeZone
class (now legacy). - Use
ZoneOffset
andZoneId
instead.
Example:
ZoneOffset.of( "+08:00" )
Use java.time.ZoneId
, not TimeZone
The troublesome old date-time classes bundled with the earliest versions of Java are now legacy, supplanted by the java.time classes. Among these old legacy classes is TimeZone
, now supplanted by ZoneId and ZoneOffset.
An offset-from-UTC is a number of hours and minutes adjustment ahead of, or behind, UTC. This is represented by the ZoneOffset
class.
A time zone is a collection of offsets, the history of changes in the offset used by a particular region in determining their wall-clock time. This is represented by the ZoneId
class.
Using a time zone is always preferable to an offset as a zone has the offset plus so much more information. But your examples are only mere offsets. So use the ZoneOffset
to parse the strings after deleting the characters UTC
.
String input = "UTC+08:00".replace( "UTC" , "" ) ;
ZoneOffset offset = ZoneOffset.of( input ) ;
Do not guess the time zone
You cannot assume that a particular offset implies a particular time zone. Many zones may have used a particular offset in the past, present, or future. So you should not guess the zone.
Take, for example, the offset of +08:00
. That offset is currently used by several different time zones including Asia/Shangai
, Asia/Macao
, and Australia/Perth
.
If you are certain a particular zone was intended for a date-time value, apply it to get a ZonedDateTime. But do not guess.
The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.now() ;
ZoneId z = ZoneId.of( "Asia/Shanghai" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
If you do not know for certain the intended time zone and have only an offset, use the offset to get an OffsetDateTime.
Instant instant = Instant.now() ;
ZoneOffset offset = ZoneOffset.of( "+08:00" ) ;
OffsetDateTime odt = instant.atOffset( offset ) ;
Convert
Best to avoid the old legacy class TimeZone
. But if you must use that class to work with old code not yet updated for the java.time classes, you can convert to/from a ZoneId
. Use the new conversion methods added to the old classes.
TimeZone myLegacyTimeZone = TimeZone.getTimeZone( myModernZoneId );
…and…
ZoneId z = myLegacyTimeZone.toZoneId() ;
Note that ZoneOffset
is a subclass of ZoneId
. Normally, we ignore that inheritance relationship. If you have only a mere offset such as +08:00
, use ZoneOffset
. If you have a full time zone such as Asia/Shanghai
, use ZoneId
. One exception to this rule is for this conversion to/from TimeZone
where only the superclass ZoneId
is recognized.
回答2:
If you strip the UTC, you can parse it as a ZoneOffset, which extends ZoneId
ZoneId zoneId = ZoneOffset.of("+08:00")
回答3:
Since you can use the modern classes in the java.time
package, I recommend you stick with them and avoid the outdated classes like TimeZone
, SimpleDateFormat
and Date
. I am mostly repeating what @Basil Bourque already said in his answer, but also wanted to demonstrate how nicely his suggestion fits into your context:
DateTimeFormatter format = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");
ZonedDateTime dateTime = LocalDateTime.parse(dateTimeString, format).atZone(zoneId);
Instant i = dateTime.toInstant();
System.out.println(dateTime + " -> " + i);
I have also demonstrated that you may convert the ZonedDateTime
to an Instant
in case you need that. The snippet prints
2017-05-05T05:05+08:00[UTC+08:00] -> 2017-05-04T21:05:00Z
If you are sure your date-time string and your zone string belong together, there is no need to go through String.replace()
for removing UTC
from the beginning of the zone string.
I am parsing the string independently of the time zone and then combining it with the zone offset information afterward. I think it’s more natural than having to know the zone for parsing.
In case you need an oldfashioned Date
, for example for a call to some legacy code, that’s easy enough:
Date d = Date.from(i);
The old classes are troublesome
Even though I know the old classes have a tendency to show unwanted behaviour without telling you that anyting is wrong, I was still negatively surprised to learn that the code in your question didn’t work. It gives a time zone of GMT! It’s documented that this is a possibility, though, in the documentation of TimeZone.getTimeZone(ZoneId):
Returns:
the specified TimeZone, or the GMT zone if the given ID cannot be understood.
One may stil wonder how a simple time zone like UTC+08:00
can be “not understood”.
来源:https://stackoverflow.com/questions/43820248/how-can-i-convert-time-zone-string-to-the-timezone-object-in-java