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

3

7

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"

Palaeozoic answered 6/5, 2017 at 12:5 Comment(5)
Oh, i am so sorry to made a clerical mistake. It should be mapping between "UTC+08:00" and "Asia/Shanghai" rather than "mapping between "UTC+05:00" and "Asia/Shanghai". Your detailed answer and kindly reminder helped me a lot, thank you very much!Palaeozoic
Please provide a little more context. From the question I am thinking that possibly there is a better solution for you than converting the string UTC+08:00 to a TImeZone. From where have you got the string? What do you want to use the TimeZone for?Valona
i got date string such as "2017-05-05 05:05" , and it's tine zone string such as "UTC+08:00", i need timeZone Object to assemble SimpleDateFormat Object, and then parse the date string ` SimpleDateFormat fromFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); fromFormat.setTimeZone(timeZone);Date resultDate = format.parse(date)`Palaeozoic
Thank you for the context. In this case, if there is any way you can use the newer classes in the java.time package, you will most probably want to. They are both generally less errorprone and more convenient to work with, they also suit your particular job better. You can use one of the answers and then LocalDateTime.parse(yourDateString, DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm")).atOffset(zoneOffsetFromAnswer) or ….atZone(zoneIdFromAnswer). You may also convert to Instant (and even to Date, but you will try to see if you can avoid using the outdated Date class).Valona
As I understand what you are really needing to obtain, you have no need to map UTC+08:00 to Asia/Shanghai. You just need to interpret your date-time-string in a time zone or zone offset of UTC+08:00.Valona
I
10

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

Immunogenetics answered 6/5, 2017 at 14:5 Comment(0)
P
2

If you strip the UTC, you can parse it as a ZoneOffset, which extends ZoneId

ZoneId zoneId = ZoneOffset.of("+08:00")
Patience answered 6/5, 2017 at 12:38 Comment(3)
While technically correct, assigning a ZoneOffset to a ZoneId is misleading. The ZoneId class is intended to represent a full time zone, and a time zone is a collection of offsets, the history of changes to the offset used by a particular region. The subclass relationship between ZoneOffset and ZoneId is for convenience in the internals of the java.time framework and should generally not be used in apps as seen in this Answer.Immunogenetics
@BasilBourque The JavaDoc says ZoneId is intended for both purposes. "A ZoneId is used to identify the rules used to convert between an Instant and a LocalDateTime. There are two distinct types of ID [...]" ZoneRegion is the other subclass for time zone regions.Patience
I think you still need to explain how this will help the asker (granted that it will).Valona
V
0

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

Valona answered 7/5, 2017 at 6:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.