Java中的时区

TimeZones in Java

我允许我的web应用程序上的用户根据他们选择的时区来安排活动。

我想向最终用户提供一个很好的时区列表,然后在服务器端将其轻松转换为java.util.TimeZone对象。

我可以使用String[] TimeZone.getAvailableIds(),但问题是它打印了大约585个时区ID。

向用户展示时区的简短列表(如时区设置的Windows框)并使用其ID轻松转换为服务器端的时区对象的最佳方法是什么?


时区列表非常特定于应用程序和区域设置。只有您知道哪些区域最适合您的用户。我们针对不同的地区有不同的列表。

这是我们的用户列表,供您参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
   "Pacific/Midway",
   "US/Hawaii",
   "US/Alaska",
   "US/Pacific",
   "America/Tijuana",
   "US/Arizona",
   "America/Chihuahua",
   "US/Mountain",
   "America/Guatemala",
   "US/Central",
   "America/Mexico_City",
   "Canada/Saskatchewan",
   "America/Bogota",
   "US/Eastern",
   "US/East-Indiana",
   "Canada/Eastern",
   "America/Caracas",
   "America/Manaus",
   "America/Santiago",
   "Canada/Newfoundland",
   "Brazil/East",
   "America/Buenos_Aires",
   "America/Godthab",
   "America/Montevideo",
   "Atlantic/South_Georgia",
   "Atlantic/Azores",
   "Atlantic/Cape_Verde",
   "Africa/Casablanca",
   "Europe/London",
   "Europe/Berlin",
   "Europe/Belgrade",
   "Europe/Brussels",
   "Europe/Warsaw",
   "Africa/Algiers",
   "Asia/Amman",
   "Europe/Athens",
   "Asia/Beirut",
   "Africa/Cairo",
   "Africa/Harare",
   "Europe/Helsinki",
   "Asia/Jerusalem",
   "Europe/Minsk",
   "Africa/Windhoek",
   "Asia/Baghdad",
   "Asia/Kuwait",
   "Europe/Moscow",
   "Africa/Nairobi",
   "Asia/Tbilisi",
   "Asia/Tehran",
   "Asia/Muscat",
   "Asia/Baku",
   "Asia/Yerevan",
   "Asia/Kabul",
   "Asia/Yekaterinburg",
   "Asia/Karachi",
   "Asia/Calcutta",
   "Asia/Colombo",
   "Asia/Katmandu",
   "Asia/Novosibirsk",
   "Asia/Dhaka",
   "Asia/Rangoon",
   "Asia/Bangkok",
   "Asia/Krasnoyarsk",
   "Asia/Hong_Kong",
   "Asia/Irkutsk",
   "Asia/Kuala_Lumpur",
   "Australia/Perth",
   "Asia/Taipei",
   "Asia/Tokyo",
   "Asia/Seoul",
   "Asia/Yakutsk",
   "Australia/Adelaide",
   "Australia/Darwin",
   "Australia/Brisbane",
   "Australia/Sydney",
   "Pacific/Guam",
   "Australia/Hobart",
   "Asia/Vladivostok",
   "Asia/Magadan",
   "Pacific/Auckland",
   "Pacific/Fiji",
   "Pacific/Tongatapu",

我刚刚编写了一个小的Java实用工具,它提供了一个Windows时区列表(Windows中的时区选择对话框中的区域),以及它们相关的Java时区对象。请参阅https://github.com/nfergu/java-time-zone-list

这是基于位于http://unicode.org/repos/cldr/trunk/common/supplementary/windowszones.xml的cldr映射的。


您可以使用仅匹配以下regexp的TZ ID减少列表

1
^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*

为了补充tbruyelle的答案,我增加了一些国家(如加拿大),删除了过滤器的"/"部分,并提供了对列表进行排序的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static void main(String[] args)
{
    List<String> simplifiedTimezoneList = getTimezoneIdList();

    for (String tz : simplifiedTimezoneList)
        System.out.println(tz);
}

public static List<String> getTimezoneIdList()
{
    String[] temp = TimeZone.getAvailableIDs();
    List<String> timezoneList = new ArrayList<String>();
    List<String> simplifiedTimezoneList = new ArrayList<String>();
    for (String tz : temp)
    {
        timezoneList.add(tz);
    }
    Collections.sort(timezoneList);
    String filterList ="Canada|Mexico|Chile|Cuba|Brazil|Japan|Turkey|Mideast|Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific";
    Pattern p = Pattern.compile("^(" + filterList +").*");
    for (String tz : timezoneList)
    {
        Matcher m = p.matcher(tz);
        if (m.find())
        {
            simplifiedTimezoneList.add(tz);
        }
    }
    return simplifiedTimezoneList;
}

有了这么多,我就不想把它们塞进选择框列表了。我将它们放在一个单独的模式对话框(或者弹出窗口,如果必须的话)的列表中,让用户滚动并单击他们想要的名称。他们会点击模式对话框中的一个链接,它会用正确的代码填充一个文本字段,然后您可以将其提交给您的服务器。

更好的是,让他们在世界地图上单击他们的位置,并使用图像地图将该位置转换为适当的时区。


我是为一家我不再拥有的公司做的,所以不能提供代码。Windows上的JVM带有一个名为EDCOX1 OR 0的文件(参见EDCOX1,1或类似),它将Windows时区映射到Java的基于ZONEING的大陆/城市窗体。

不幸的是,tzmappings中的文本名很糟糕,所以您需要做几分钟的制表。打开regedit并导航到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones。下面是机器上每个时区的键;Windows7大约有90个。每个键都有一个名为EDCOX1(4)的值,它是您想要的文本名称;在EDCOX1(0)中查找密钥本身,以找到每一个的Java时区标识符。


如果您需要精确选择列表的外观,我将使用我能找到的最佳硬编码列表(这是一个很好的示例),并确保尽可能精确地显示和转换列表。

请记住,585个时区中的每一个都具有语义含义(例如DST),用户可能希望为他们选择最佳时区。尽管我同意这个列表可以短得多。


您不能使用"gmt+/-hours"表示法(跳过分钟)的自定义时区ID列表吗?

(编辑:根据我的第一个建议,夏令时转换不是自动的。要解决此问题,您可以首先要求用户选择一个GMT偏移量,然后使用以下方法显示给定偏移量的时区ID列表(链接):

1
public static String[] getAvailableIDs(int rawOffset)

这样,用户可以在较短的列表中选择自己的时区(更好地满足用户体验),并从夏令时行为中获益。