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

喜欢而已 提交于 2020-11-29 08:56:32

问题


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




回答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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!