简体   繁体   中英

How can i convert time zone string to the TimeZone Object in java?

I have several 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 java.util.TimeZone in Java?

I have tried to convert by ZoneId as follows, but it 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"

tl;dr

  • Do not use TimeZone class (now legacy).
  • Use ZoneOffset and ZoneId 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 byZoneId 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.

如果你去掉UTC,你可以把它解析为一个ZoneOffset,它扩展了ZoneId

ZoneId zoneId = ZoneOffset.of("+08:00")

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”.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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