Java如何获取时区ID列表’;s表示给定的时区缩写
是否可以找到给定时区缩写的时区ID列表?例如,对于缩写词Java如何获取时区ID列表’;s表示给定的时区缩写,java,timezone,simpledateformat,java-time,Java,Timezone,Simpledateformat,Java Time,是否可以找到给定时区缩写的时区ID列表?例如,对于缩写词IST,时区ID是亚洲/耶路撒冷,亚洲/加尔各答和欧洲/都柏林有趣的问题。由于缩略语没有标准化,因此不可能有权威的答案,也不可能有可靠的方法来获得这样的答案。我突然想到了两种方法: 从JVM中获取它们 在网上找到他们 从JVM获取区域: String givenAbbr = "IST"; LocalDateTime summerSouthernHemisphere = LocalDate.of(2018, Month.JAN
IST
,时区ID是亚洲/耶路撒冷
,亚洲/加尔各答
和欧洲/都柏林
有趣的问题。由于缩略语没有标准化,因此不可能有权威的答案,也不可能有可靠的方法来获得这样的答案。我突然想到了两种方法:
String givenAbbr = "IST";
LocalDateTime summerSouthernHemisphere = LocalDate.of(2018, Month.JANUARY, 31).atStartOfDay();
LocalDateTime summerNorthernHemisphere = LocalDate.of(2018, Month.JULY, 31).atStartOfDay();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("z");
Set<ZoneId> zones = new HashSet<>();
for (String id : ZoneId.getAvailableZoneIds()) {
ZoneId zone = ZoneId.of(id);
String abbr = summerSouthernHemisphere.atZone(zone).format(dtf);
if (abbr.equals(givenAbbr)) {
zones.add(zone);
}
abbr = summerNorthernHemisphere.atZone(zone).format(dtf);
if (abbr.equals(givenAbbr)) {
zones.add(zone);
}
}
System.out.println(zones);
不过,其中一些只是同一时区的名称。例如,Eire与欧洲/都柏林的规则相同。因此,如果需要,可以进行进一步的过滤。您可以使用oneZoneId.getRules().equals(anotherZoneId.getRules())
来确定两个ZoneId
对象是否具有相同的分区规则
缩写CST的列表更长,同义词更多:
[PRC, America/Matamoros, Asia/Taipei, America/Regina, America/El_Salvador,
America/North_Dakota/New_Salem, Asia/Harbin, America/Costa_Rica,
America/North_Dakota/Center, America/Guatemala, America/Winnipeg,
Asia/Chongqing, America/Rankin_Inlet, America/Indiana/Knox,
America/Belize, SystemV/CST6CDT, Mexico/General,
America/North_Dakota/Beulah, CST6CDT, America/Swift_Current,
America/Knox_IN, Asia/Chungking, Asia/Macao, Asia/Shanghai,
America/Indiana/Tell_City, America/Menominee, America/Bahia_Banderas,
America/Managua, Canada/East-Saskatchewan, Asia/Macau, America/Havana,
America/Resolute, US/Central, US/Indiana-Starke, Cuba, America/Monterrey,
America/Chicago, America/Merida, America/Mexico_City, Canada/Central,
America/Tegucigalpa, America/Rainy_River, Canada/Saskatchewan, SystemV/CST6]
我的方法的一个局限性是,一些时区有不止一个名称,因此有不止一个三个或四个字母的缩写。我上面的代码只捕获其中一个
另一个限制是,像我这样选择两个日期永远不会给你所有可能的过去和未来,甚至可能错过一些我只是没有找到正确的日期。我试着选择一个日期,北半球是冬天,南半球是夏天,而另一个日期正好相反。这将涵盖目前的大多数情况,但你永远不知道是否有一个或三个时区的过渡不遵循夏季和冬季,因为我们知道它。如果你想获得更好的覆盖率,这里有一些很好的建议
从互联网上获取它们
当然,另一个答案是你的搜索毫无疑问已经提出的:这些名单在互联网上是公开的。例如和。正如所料,上述两份清单并不一致。例如,后者知道ADT的两种解释,前者只有一种。后一个列表给出了许多同义词缩写,从而说明了我上面的观点,即每个区域可以有多个缩写。有关oracle文档的,请参阅Java 8文档 github上实现此方法的示例maven项目 在实现方面,您可以使用下面的代码
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
ZoneId berlin = ZoneId.of("Europe/Berlin");
// 2014-02-20 12:00
LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);
// 2014-02-20 12:00, Europe/Berlin (+01:00)
ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);
// 2014-02-20 03:00, America/Los_Angeles (-08:00)
ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);
int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800
// a collection of all available zones
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
ZoneId losAngeles=ZoneId.of(“美国/洛杉矶”);
柏林地区=欧洲/柏林地区;
// 2014-02-20 12:00
LocalDateTime dateTime=LocalDateTime.of(2014,02,20,12,0);
//2014-02-20 12:00,欧洲/柏林(+01:00)
ZonedDateTime berlinDateTime=ZonedDateTime.of(日期时间,柏林);
//2014-02-20 03:00,美国/洛杉矶(-08:00)
ZonedDateTime losAngelesDateTime=柏林时间。带ZonesMaiInstant(洛杉矶);
int offsetInSeconds=losAngelesDateTime.getOffset().getTotalSeconds();//-28800
//所有可用区域的集合
设置allZoneIds=ZoneId.getAvailableZoneIds();
已经提供了大量详细的信息,比如三个字母的缩写(如IST
或PST
)是,你应该更喜欢长的(格式总是大陆/城市
,如亚洲/加尔各答
或欧洲/柏林
)
但这个答案中有一个棘手的细节:它将2018年1月和7月作为冬季和夏季的基准日期(因此可以对照标准和夏令时检查缩写)。但并不能保证所有情况下都需要冬季和夏季时间,因为时区规则可能会改变——仅仅因为时区今天有DST,并不意味着它将永远有DST(反之亦然)
因此,与其选择一些日期/时间并希望所有时区之间都有DST更改,最好的方法是从ZoneRules
对象获取所有更改-它包含所有转换日期(由于DST开始/结束或某些政府决定其国家现在将位于另一时区,该时区的偏移量发生变化的时刻)
它还涵盖了一个时区在过去使用缩写,但后来改为另一个,因为我正在检查所有时区的更改历史
代码非常相似。唯一的区别是,我没有使用固定日期(2018年1月/7月),而是查看区域的所有转换(如果时区没有转换-这意味着它从未有过DST或任何其他更改-我得到当前日期)。我还创建了一个集的字符串(因为您只需要名称,但也可以存储ZoneId
对象):
您可以看到,IST
用于Europe/Dublin
。这不是最简单的方法,但每次IANA更新其数据库时,都需要一些时间才能将更改包含在JDK中(尽管您可以,如果您愿意的话)
因此,如果您想要最新的信息,您可以定期检查IANA网站的更新。我编辑了您的答案的格式,但我仍然不知道这是如何解决问题的。答案很好!但不幸的是,我发现了一个无法获得所有时区的情况(不是IST-检查我的答案).但我还是保留我的投票权。你是绝对正确的,@Hugo,我已经知道这个限制,我应该从一开始就把它解释清楚。我已经编辑了。回答得很好。谢谢。我在考虑IANA时区数据库,但没有花时间去调查它是如何或是否包含缩写的。看来对于Java可能会出现缩写,包括除您自己的Java版本之外的其他Java版本,这可能是您能得到的最好的报道
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");
ZoneId berlin = ZoneId.of("Europe/Berlin");
// 2014-02-20 12:00
LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);
// 2014-02-20 12:00, Europe/Berlin (+01:00)
ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);
// 2014-02-20 03:00, America/Los_Angeles (-08:00)
ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);
int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800
// a collection of all available zones
Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
String ist = "IST";
Set<String> zones = new HashSet<>();
// formatter to get the abbreviation
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("z");
for (String id : ZoneId.getAvailableZoneIds()) {
ZoneId zone = ZoneId.of(id);
ZoneRules rules = zone.getRules();
List<ZoneOffsetTransition> transitions = rules.getTransitions();
if (transitions.isEmpty()) {
// no transitions found, just pick any date
String abbrev = fmt.format(ZonedDateTime.now(zone));
if (ist.equals(abbrev)) {
zones.add(id);
}
} else {
for (ZoneOffsetTransition transition : transitions) {
// get the instant that the transition occurred and convert to this zone
String abbrev = fmt.format(transition.getInstant().atZone(zone));
if (ist.equals(abbrev)) {
zones.add(id);
}
}
}
}
System.out.println(zones);
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Dublin -0:25:00 - LMT 1880 Aug 2
-0:25:21 - DMT 1916 May 21 2:00 # Dublin MT
-0:25:21 1:00 IST 1916 Oct 1 2:00s
0:00 GB-Eire %s 1921 Dec 6 # independence
0:00 GB-Eire GMT/IST 1940 Feb 25 2:00
0:00 1:00 IST 1946 Oct 6 2:00
... etc