Java 中的时区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1694885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TimeZones in Java
提问by Vish
I am allowing users on my web app to schedule events based on time zones of their choice.
我允许我的网络应用程序上的用户根据他们选择的时区安排事件。
I want to present a good list of time zones to the end user and then convert it easily to java.util.TimeZone
object at the server end.
我想向最终用户提供一个很好的时区列表,然后java.util.TimeZone
在服务器端轻松将其转换为对象。
String[] TimeZone.getAvailableIds()
is something I could use, but the issue is that it prints about 585 time zone ids.
String[] TimeZone.getAvailableIds()
是我可以使用的东西,但问题是它打印了大约 585 个时区 ID。
What is the best way to present to the user a brief list of time zones (like a Windows box would for time zone settings) and easily convert to TimeZone object at server end using its id?
向用户呈现时区简要列表(就像 Windows 框用于时区设置)并在服务器端使用其 id 轻松转换为 TimeZone 对象的最佳方式是什么?
采纳答案by ZZ Coder
The list of timezones is very application and locale specific. Only you know what zones are most applicable to your users. We actually have different lists for different regions.
时区列表非常适合应用程序和区域设置。只有您知道哪些区域最适合您的用户。我们实际上有不同地区的不同列表。
Here is our list for US users for your reference,
这是我们的美国用户列表供您参考,
"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",
回答by Pascal Thivent
Couldn't you use a list of custom time zone IDs using "GMT +/- Hours" notation (skipping minutes)?
您不能使用使用“GMT +/- 小时”表示法(跳过分钟)的自定义时区 ID 列表吗?
(EDIT: With my first suggestion, daylight saving time transition is not automatic. To address this issue, you could first ask the user to select a GMT offset and then show a (linked) list of time zone IDs for the given offset using:
(编辑:根据我的第一个建议,夏令时转换不是自动的。要解决此问题,您可以首先要求用户选择 GMT 偏移量,然后使用以下方法显示给定偏移量的时区 ID(链接)列表:
public static String[] getAvailableIDs(int rawOffset)
This way, the user would be able choose his time zone in a shorterlist (better for user experience) and benefit from daylight savings behavior.)
这样,用户将能够在较短的列表中选择他的时区(更好的用户体验)并受益于夏令时行为。)
回答by Yuval Adam
If you need the granularity of choosing exactly how the list would look, I would use the best hard-coded list I could find (this is a good example) and ensure it is displayed and converted as precisely as possible.
如果您需要精确地选择列表的外观,我将使用我能找到的最好的硬编码列表(这是一个很好的例子)并确保它尽可能精确地显示和转换。
Just keep in mind that each one of those 585 time zones does have a semantic meaning (such as DST for example) and users might want to choose the best time zone for them. Although I do agree that list can be much shorter.
请记住,这 585 个时区中的每一个都具有语义(例如 DST),用户可能希望为他们选择最佳时区。尽管我确实同意该列表可以更短。
回答by Andrew Duffy
I did this for a company I don't own any of anymore, so can't provide code. The JVM on Windows comes with a file called tzmappings
(look in C:\Program Files\Java\jre6\lib
or similar) which maps Windows timezones to Java's zoneinfo-based Continent/City form.
我为一家我不再拥有任何公司的公司这样做了,因此无法提供代码。Windows 上的 JVM 带有一个名为tzmappings
(look inC:\Program Files\Java\jre6\lib
或类似)的文件,它将 Windows 时区映射到 Java 的基于 zoneinfo 的 Continent/City 表单。
Unfortunately, the textual names in tzmappings
are terrible, so you need to do a few minutes of tabulation. Open regedit and navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
. Under this is a key for each timezone on the machine; Windows 7 has about 90. Each key has a value called Display
which is the textual name you want; look for the key itself in tzmappings
to find the Java time zone identifier for each one.
不幸的是,里面的文字名称tzmappings
很糟糕,所以你需要做几分钟的制表。打开 regedit 并导航到HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
. 下面是机器上每个时区的键;Windows 7 大约有 90 个。每个键都有一个称为Display
您想要的文本名称的值;查找键本身tzmappings
以找到每个键的 Java 时区标识符。
回答by Spike Williams
With that many, I wouldn't try to shoehorn them into a select box list.... I'd put them on a list in a separate modal dialog (or popup, if you must), let the user scroll through and click the name they want. They would click on a link in the modal dialog, and it would populate a text field with the correct code, and you could then submit that to your server.
有这么多,我不会尝试将它们硬塞到选择框列表中......我会将它们放在单独的模式对话框(或弹出窗口,如果必须)中的列表中,让用户滚动并单击他们想要的名字。他们会点击模态对话框中的链接,它会用正确的代码填充文本字段,然后您可以将其提交给您的服务器。
Better yet, have them click their location on a map of the world, and use an image map to translate that location to the appropriate time zone.
更好的是,让他们在世界地图上单击他们的位置,然后使用图像地图将该位置转换为适当的时区。
回答by tbruyelle
You can reduce the list with TZ IDs which match only the following regexp
您可以使用仅匹配以下正则表达式的 TZ ID 来减少列表
^(Africa|America|Asia|Atlantic|Australia|Europe|Indian|Pacific)/.*
回答by Neil
I've just written a small Java utility that provides a list of Windows time zones (the zones in the time zone selection dialog in Windows), and their associated Java TimeZone objects. See https://github.com/nfergu/Java-Time-Zone-List
我刚刚编写了一个小型 Java 实用程序,它提供了 Windows 时区列表(Windows 中时区选择对话框中的区域)及其关联的 Java TimeZone 对象。见https://github.com/nfergu/Java-Time-Zone-List
This is based on the CLDR mappings at http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml
这是基于http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml上的 CLDR 映射
回答by Bryan
Just to complement the answer by tbruyelle I added a few more countries (e.g. Canada), removed the "/" portion of the filter and provided a means to sort the list.
只是为了补充 tbruyelle 的答案,我添加了更多国家/地区(例如加拿大),删除了过滤器的“/”部分并提供了对列表进行排序的方法。
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;
}
回答by Basil Bourque
ZoneId
ZoneId
The TimeZone
class is now legacy, supplanted years ago by the modern java.timeclasses defined in JSR 310. Specifically replaced by java.time.ZoneId
.
在TimeZone
类现在是传统的,取代年前由现代java.time在JSR 310中定义的类的具体取代java.time.ZoneId
。
Most of the currently used time zones are in the name format of Continent/Region
. See a sortable list at Wikipedia.
当前使用的大多数时区的名称格式为Continent/Region
. 请参阅Wikipedia 上的可排序列表。
Get a list of all the time zone names.
获取所有时区名称的列表。
Set<String> zoneIds = ZoneId.getAvailableZoneIds() ;
System.out.println( "zoneIds = " + zoneIds );
See a distinct list of those prefixes.
查看这些前缀的不同列表。
zoneIds.stream().map( s -> s.split( "/" )[0] ).collect( Collectors.toSet()).stream().forEach( System.out::println );
As mentioned in the Answer by tbruyelle, one way to narrow the list for presentation to the user is to filter on that Continent
portion. Of those, I would guess it best to focus on:
正如tbruyelle的回答中所述,缩小向用户展示的列表的一种方法是过滤该Continent
部分。其中,我想最好专注于:
- Europe
- Africa
- Antarctica
- Atlantic
- America
- Pacific
- Indian
- Australia
- 欧洲
- 非洲
- 南极洲
- 大西洋
- 美国
- 太平洋
- 印度人
- 澳大利亚
…plus add Etc/UTC
.
...加上添加Etc/UTC
。
In Java code, sorted alphabetically.
在 Java 代码中,按字母顺序排序。
List < String > zoneGroupNames = List.of(
"Africa" ,
"Antarctica" ,
"Atlantic" ,
"America" ,
"Australia" ,
"Europe" ,
"Indian" ,
"Pacific" ,
"UTC"
);
Multimap of zone group name to zone names
区域组名称到区域名称的多重映射
Build a Map
of each zone group name to collection of zone id names. We need a map of the group name such as Europe
to a list of the zone names such as Europe/Berlin
, Europe/London
, and Europe/Malta
.
Map
将每个区域组名称构建为区域 ID 名称的集合。我们需要地图的组名,如Europe
到区名称,比如列表Europe/Berlin
,Europe/London
和Europe/Malta
。
Map < String, List < String > > mapGroupNameToZoneNames = new TreeMap <>();
Mapping a key to a collection of values is known as a "multimap". We now have built-in multimap functionality with the Map
implementations bundled with Java. Call Map::computeIfAbsent
(see this Answer).
将键映射到值集合称为“多重映射”。我们现在有内置的 multimap 功能Map
和 Java 捆绑的实现。打电话Map::computeIfAbsent
(见这个答案)。
Set < String > zoneIdStrings = ZoneId.getAvailableZoneIds();
for ( String zoneIdString : zoneIdStrings )
{
String groupName = zoneIdString.split( "/" )[ 0 ];
if ( zoneGroupNames.contains( groupName ) )
{
mapGroupNameToZoneNames.computeIfAbsent( groupName , ( x -> new ArrayList <>() ) ).add( zoneIdString );
} // Else skip it.
}
System.out.println( "mapGroupNameToZoneNames = " + mapGroupNameToZoneNames );
Present to user
呈现给用户
Present that list of groups to the user. Say the user selects item # 6 (index 5), which is currently Europe
.
向用户展示该组列表。假设用户选择了当前为 的项目 #6(索引 5)Europe
。
String groupNameChosenByUser = zoneGroupNames.get( 5 ); // Europe
List < String > zoneNamesOfGroup = mapGroupNameToZoneNames.get( groupNameChosenByUser );
Present that list of zone names for that one group. Say the user selects item # 12 (index 11), which is currently Europe/Malta
.
显示该一组的区域名称列表。假设用户选择项目 #12(索引 11),它当前是Europe/Malta
。
String zoneNameChosenByUser = zoneNamesOfGroup.get( 11 ); // Malta
Make a ZoneId
object from the string of that zone name.
ZoneId
从该区域名称的字符串中创建一个对象。
ZoneId zoneIdChosenByUser = ZoneId.of( zoneNameChosenByUser );
zoneIdChosenByUser.toString() = Europe/Malta
zoneIdChosenByUser.toString() = 欧洲/马耳他