Java 11,获取用户本地计算机的时区

huangapple go评论75阅读模式
英文:

Java 11 , get timezone of users local machine

问题

我们正在开发应用程序,其中日期以GMT存储,需要根据用户本地时钟时区显示日期和时间。

Java 11,当我更改时区时,需要重新启动JVM,因此在服务器启动时使用旧的时区。

有没有办法在不重新启动JVM的情况下确定机器(操作系统)的时区?

代码:

Calendar cal = Calendar.getInstance();
System.out.println(" -- " + TimeZone.getDefault());
long milliDiff = cal.get(Calendar.ZONE_OFFSET);
// 获得本地偏移,现在循环遍历可用的时区ID。
String[] ids = TimeZone.getAvailableIDs();
String name = null;
for (String id : ids) {
    System.out.println("ID  : " + id);
    TimeZone tz = TimeZone.getTimeZone(id);
    System.out.println("TZ : " + tz.getRawOffset());
    if (tz.getRawOffset() == milliDiff) {
        // 找到匹配项。
        name = id;
        break;
    }
}
System.out.println("Name " + name);

上面的代码在独立运行时正常工作,但在Web应用程序(JVM)中集成时出现问题。

英文:

We are developing applications where dates are stored in GMT , and need is to display date and time according to users local clock timezone

Java 11 , when i change timezone , its requires JVM restart so its taking old timezone of during start of server.

Is there any ways to determine timezone of machine ( OS) without restarting JVM?

Code

Calendar cal = Calendar.getInstance();
        System.out.println(" -- " + TimeZone.getDefault());
        long milliDiff = cal.get(Calendar.ZONE_OFFSET);
        // Got local offset, now loop through available timezone id(s).
        String[] ids = TimeZone.getAvailableIDs();
        String name = null;
        for (String id : ids) {
            System.out.println("ID  : " + id);
            TimeZone tz = TimeZone.getTimeZone(id);
            System.out.println("TZ : " + tz.getRawOffset());
            if (tz.getRawOffset() == milliDiff) {
                // Found a match.
                name = id;
                break;
            }
        }
        System.out.println("Name " + name);

Above code works OK as standalone, but when intregrated in web application ( JVM ) its KO.

答案1

得分: 2

java.time

您正在使用过时的日期时间类,这些类在多年前被现代的 java.time 类替代,这些类在JSR 310中定义。

避免设置默认时区

无需设置JVM的当前默认时区。这样做是有风险的,因为它会立即影响JVM中所有应用程序中所有线程中运行的所有其他代码。而且这样做是不可靠的,因为JVM中的任何线程中的任何应用程序中的任何代码都可以在您不知情的情况下随时更改时区。

Instant

使用 Instant 类捕获当前时刻,该时刻以UTC(与UTC的偏移为零小时-分钟-秒)为基准。

Instant now = Instant.now();
System.out.println("now = " + now);

>now.toString() = 2023-02-16T06:24:54.944850Z

ZoneId

时区由 ZoneId 类表示。

使用大陆/地区格式的真实时区名称,例如Africa/CasablancaEurope/BerlinPacific/Auckland。永远不要使用2-4个字符的伪时区,如CSTIST等。

Set<String> zoneNames = ZoneId.getAvailableZoneIds();
for (String zoneName : zoneNames)
{
    ZoneId z = ZoneId.of(zoneName);
    ZonedDateTime zdt = now.atZone(z);
    System.out.println("Now in zone " + z + " is " + zdt.toString());
}
Now in zone Asia/Aden is 2023-02-16T09:24:54.944850+03:00[Asia/Aden]
Now in zone America/Cuiaba is 2023-02-16T02:24:54.944850-04:00[America/Cuiaba]
…
Now in zone Pacific/Guadalcanal is 2023-02-16T17:24:54.944850+11:00[Pacific/Guadalcanal]
Now in zone Europe/Athens is 2023-02-16T08:24:54.944850+02:00[Europe/Athens]
Now in zone US/Pacific is 2023-02-15T22:24:54.944850-08:00[US/Pacific]
Now in zone Europe/Monaco is 2023-02-16T07:24:54.944850+01:00[Europe/Monaco]

用户所见的当前时刻

您问道:

>需要根据用户本地时钟时区显示日期和时间

在运行时获取JVM的当前默认时区

ZoneId z = ZoneId.systemDefault();

但是,如果关键,您的应用程序应该确认用户的预期时区。

将我们的 Instant 对象调整为该时区。相同的时刻,不同的挂钟时间。

ZonedDateTime zdt = instant.atZone(z);

或者跳过 Instant 对象直接获取 ZonedDateTime

ZonedDateTime zdt = ZonedDateTime.now(z);

英文:

java.time

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310.

Avoid setting default time zone

No need to set the current default time zone of your JVM. Doing so is risky as you immediately affect all other code in all threads running in all apps in that JVM. And doing so is unreliable in that any code in any thread of any app in that JVM can change the zone at any moment behind your back.

Instant

Capture the current moment as seen in UTC (an offset from UTC of zero hours-minutes-seconds) using Instant class.

Instant now = Instant.now();
System.out.println( &quot;now = &quot; + now );

>now.toString() = 2023-02-16T06:24:54.944850Z

ZoneId

Time zones are represented by the ZoneId class.

Use real time zone names in the format of Continent/Region, such as Africa/Casablanca, Europe/Berlin, Pacific/Auckland. Never use 2-4 character pseudo-zones such as CST, IST, etc.

Set &lt; String &gt; zoneNames = ZoneId.getAvailableZoneIds();
for ( String zoneName : zoneNames )
{
    ZoneId z = ZoneId.of( zoneName );
    ZonedDateTime zdt = now.atZone( z );
    System.out.println( &quot;Now in zone &quot; + z + &quot; is &quot; + zdt.toString() );
}
Now in zone Asia/Aden is 2023-02-16T09:24:54.944850+03:00[Asia/Aden]
Now in zone America/Cuiaba is 2023-02-16T02:24:54.944850-04:00[America/Cuiaba]
…
Now in zone Pacific/Guadalcanal is 2023-02-16T17:24:54.944850+11:00[Pacific/Guadalcanal]
Now in zone Europe/Athens is 2023-02-16T08:24:54.944850+02:00[Europe/Athens]
Now in zone US/Pacific is 2023-02-15T22:24:54.944850-08:00[US/Pacific]
Now in zone Europe/Monaco is 2023-02-16T07:24:54.944850+01:00[Europe/Monaco]

Current moment as seen by user

You asked:

>need is to display date and time according to users local clock timezone

Capture the current default time zone of the JVM at runtime.

ZoneId z = ZoneId.systemDefault() ;

However, if critical, your app should confirm the user's intended time zone.

Adjust our Instant object to that zone. Same moment, different wall-clock time.

ZonedDateTime zdt = instant.atZone( z ) ;

Or skip over the Instant object to get ZonedDateTime directly.

ZonedDateTime zdt = ZonedDateTime.now( z ) ;

huangapple
  • 本文由 发表于 2023年2月16日 13:36:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75468224.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定