英文:
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/Casablanca
,Europe/Berlin
,Pacific/Auckland
。永远不要使用2-4个字符的伪时区,如CST
,IST
等。
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( "now = " + 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 < 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]
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 ) ;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论