我有一个时区值列表,就像我们在Windows OS时区下拉列表中看到的那样。
如果我们在下拉列表中选择任何时区,我们会知道是否存在日光。
如何实现类似的功能?目前,我有一个类似的值列表,就像我们在Windows下拉列表中看到的值一样。
我知道TimeZone
对象将解决此问题,因为它具有boolean
属性,可以说明日光是否保存。但是我对如何使用可用值列表创建TimeZone
对象感到非常困惑。
我的下拉值如下:
- (UTC-12:00(国际日期线西部
- (UTC-11:00(协调的通用时间11
- (UTC-10:00(阿留申群岛
- (UTC-10:00(夏威夷
- (UTC-09:30(Marquesas群岛
使用上面的那些示例值,我如何创建TimeZone
对象?
这是一项艰巨的任务。在此链接上,在"时区数据库" e节中,您会看到Windows时区名称与IANA/OLSON数据库中的名称非常不同(这是Java使用的一个(。
在Java中,您可以使用TimeZone.getAvailableIDs()
或ZoneId.getAvailableZoneIds()
(如果有Java 8(来查看所有可用名称 - 并查看它们如何与Windows timezones列表匹配。
我认为,您能做的最好的方法是将每个Windows名称映射到有效的IANA名称中,因为知道所有情况都没有完美的匹配:IANA数据库更完整,更准确,特别适用于保存日光的数据,包括历史数据和包括历史数据 - 和也比Windows更新更新。
和名称也有很大的不同,IANA更全面并且具有更多名称 - 一个Windows时区名称可以指IANA的一个以上。我不确定是否有一种简单的方法可以将所有名称从一个地映射到另一个名称。
但是,一旦有了这些名称,就很容易检查:
TimeZone zone = TimeZone.getTimeZone("America/New_York");
// check if it has DST now or in the future (doesn't check the past)
boolean hasDST = zone.observesDaylightTime();
// check if a specific date is in DST
Date someDate = // some java.util.Date
boolean dateInDST = zone.inDaylightTime(someDate);
Java 8:
ZoneRules rules = ZoneId.of("America/New_York").getRules();
// if it has DST, isFixed is false
boolean isFixed = rules.isFixedOffset();
// if lists are empty, offset never varies, so there's no DST
List<ZoneOffsetTransitionRule> transitionRules = rules.getTransitionRules();
List<ZoneOffsetTransition> transitions = rules.getTransitions();
// check a specific date (using java.time.Instant)
rules.isDaylightSavings(Instant.now());
// check a specific date (using java.util.Date)
Date date = new Date();
rules.isDaylightSavings(date.toInstant());
请注意,偏移更改并不一定意味着DST。这可能只是一个简单的变化:政府决定改变国家的偏见"永久性" - 这意味着"直到其他一些政治家决定再次改变它"。
日光节省只是一个特定的偏移变化案例,没有办法知道这种更改是否与DST相关 - 例如,一个国家决定更改为某种偏移而不使用DST时;该区域仍未固定(isFixedOffset
返回true
(,因为偏移更改。
在这种情况下,您可以使用过渡列表知道这些更改发生时:
rules.getTransitions().forEach(t -> {
// UTC instant that the change happens
Instant instant = t.getInstant();
// local date and time before the change
LocalDateTime before = t.getDateTimeBefore();
// local date and time after the change
LocalDateTime after = t.getDateTimeAfter();
});
这样,您可以知道具有抵消更改的确切日期。有些时区没有过渡,而是它们有过渡规则(例如" DST始于11月的第一个星期日"(。在这种情况下,您使用过渡规则列表:
rules.getTransitionRules().forEach(r -> {
// check the rule for a specific year
ZoneOffsetTransition t = r.createTransition(2018);
// UTC instant that the change happens
Instant instant = t.getInstant();
// local date and time before the change
LocalDateTime before = t.getDateTimeBefore();
// local date and time after the change
LocalDateTime after = t.getDateTimeAfter();
});
您可以尝试使用您的问题评论中建议的时区。
String zone = "(UTC-12:00) International Date Line West";
String zoneID = "GMT";
zoneID = zoneID + zone.substring(zone.indexOf("-"), zone.indexOf(")"));
System.out.println(zoneID);
TimeZone timeZone = TimeZone.getTimeZone(zoneID);
boolean answer = timeZone.observesDaylightTime();
System.out.print(answer);
您可以尝试使用数组列表在所有值上迭代。TimeZone接受格式的区域ID,如https://docs.oracle.com/javase/7/docs/api/java/java/timezone/timezone.html
update
UTC不使用dst(来源:https://en.wikipedia.org/wiki/coordined_universal_time(,因此您必须将UTC转换为目标时区或使用诸如diensid =" simerica/纽约"。更新的代码:
ZoneId zd = ZoneId.of(zoneID);
System.out.println(zd.getId());
ZonedDateTime zdt = ZonedDateTime.of(
LocalDateTime.of(LocalDate.of(2018, 4, 12), LocalTime.of(11, 30)), zd);
Instant instant = zdt.toInstant();
ZoneRules zr = zd.getRules();
System.out.println(zr.isDaylightSavings(instant));
上面的代码使用Java 8时间类。我也在4月使用了LocalDate
,因为在大多数观察到DST的国家/地区,它在3月的某个地方被应用。