如何从 java 中的时区偏移量获取时区?

How to get timezone from timezone offset in java?

我知道如何得到相反的结果。给定一个时区我可以通过以下代码片段获得时区偏移量:

TimeZone tz = TimeZone.getDefault();
System.out.println(tz.getOffset(System.currentTimeMillis()));

我想知道如何从时区偏移中获取时区名称。

给定,

timezone offset = 21600000(以毫秒为单位;+6.00 偏移量)

我想获得以下任何可能的时区名称的结果:

(GMT+6:00) Antarctica/Vostok
(GMT+6:00) Asia/Almaty
(GMT+6:00) Asia/Bishkek
(GMT+6:00) Asia/Dacca
(GMT+6:00) Asia/Dhaka
(GMT+6:00) Asia/Qyzylorda
(GMT+6:00) Asia/Thimbu
(GMT+6:00) Asia/Thimphu
(GMT+6:00) Asia/Yekaterinburg
(GMT+6:00) BST
(GMT+6:00) Etc/GMT-6
(GMT+6:00) Indian/Chagos

使用TimeZone#getAvailableIDs(int)

import java.util.*;
class Hello
{
   public static void main (String[] args) throws java.lang.Exception
   {
     TimeZone tz = TimeZone.getDefault();
     int offset = 21600000;
     String[] availableIDs = tz.getAvailableIDs(offset);
     for(int i = 0; i < availableIDs.length; i++) {
       System.out.println(availableIDs[i]);
     }
   }
}

tl;博士

Instant instant = Instant.now();
List < String > names =
        ZoneId
                .getAvailableZoneIds()
                .stream()
                .filter(
                        ( String name ) ->
                                ZoneId
                                        .of( name )
                                        .getRules()
                                        .getOffset( instant )
                                        .equals(
                                                ZoneOffset.ofHours( 6 )
                                        )
                )
                .collect( Collectors.toList() )
;

在 Java 14.0.1:

names = [Asia/Kashgar, Etc/GMT-6, Asia/Almaty, Asia/Dacca, Asia/Omsk, Asia/Dhaka, Indian/Chagos, Asia/Qostanay, Asia/Bishkek, Antarctica/Vostok, Asia/Urumqi, Asia/Thimbu, Asia/Thimphu]

java.time

现代解决方案使用 java.time 类 多年前取代了糟糕的遗留日期时间 类。具体来说,TimeZone 被替换为:

与 UTC 的偏移量仅仅是本初子午线之前或之后的小时-分钟-秒数。时区要多得多。时区是特定地区的人们使用的偏移量的过去、现在和未来变化的历史。时区的名称采用 Continent/Region 格式。参见 list of zones

获取JVM的当前时区。

ZoneId z = ZoneId.systemDefault() ;

获取当前定义的所有 ZoneId 个对象的列表。请注意,时区经常被政客更改。因此,此列表及其包含的规则将会更改。让你的 tzdata 保持最新。

Set< String > zones = ZoneId.getAvailableZoneIds() ;

你问过:

I want to know how to get the timezone name from timezone offset.

许多时区可能在任何给定时刻巧合地共享相同的偏移量。在下面的代码中,我们循环所有已知时区,询问每个时区的偏移量。

由于时区规则会随着时间而改变(由政治家决定),您必须提供一个时刻,您希望每个时区使用的偏移量。这里我们使用运行时间的当前时刻。

// Convert your milliseconds to an offset-from-UTC.
int milliseconds = 21_600_000;
int seconds = Math.toIntExact( TimeUnit.MILLISECONDS.toSeconds( milliseconds ) );
ZoneOffset targetOffset = ZoneOffset.ofTotalSeconds( seconds );

// Capture the current moment as seen in UTC (an offset of zero hours-minutes-seconds).
Instant now = Instant.now();

// Loop through all know time zones, comparing each one’s zone to the target zone.
List < ZoneId > hits = new ArrayList <>();
Set < String > zoneNames = ZoneId.getAvailableZoneIds();
for ( String zoneName : zoneNames )
{
    ZoneId zoneId = ZoneId.of( zoneName );

    ZoneRules rules = zoneId.getRules();
    // ZoneRules rules = zoneId.getRules() ;
    ZoneOffset offset = rules.getOffset( now );
    if ( offset.equals( targetOffset ) )
    {
        hits.add( zoneId );
    }
}

转储到控制台。看到这个 code run live at IdeOne.com.

// Report results.
System.out.println( "java.version " + System.getProperty("java.version") ) ;
System.out.println( "java.vendor " + System.getProperty("java.vendor") ) ;
System.out.println() ;
System.out.println( "targetOffset = " + targetOffset );
System.out.println( "hits: " + hits );

在 IdeOne.com 查看此代码 运行。

java.version 12.0.1

java.vendor Oracle Corporation

targetOffset = +06:00

hits: [Asia/Kashgar, Etc/GMT-6, Asia/Almaty, Asia/Dacca, Asia/Omsk, Asia/Dhaka, Indian/Chagos, Asia/Qyzylorda, Asia/Bishkek, Antarctica/Vostok, Asia/Urumqi, Asia/Thimbu, Asia/Thimphu]


关于java.time

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.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time 类.

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* 类。 Hibernate 5 和 JPA 2.2 支持 java.time

在哪里获取java.time类?