如何知道一个国家是否存在夏令时?

时间:2018-02-16 05:01:22

标签: java timezone dst

我有一个时区值列表,就像我们在Windows操作系统时区下拉列表中看到的那样。

如果我们在下拉列表中选择任何时区,我们就会知道是否存在夏令时。

我怎样才能实现这种类似功能?目前,我有一个类似的值列表,就像我们在Windows下拉列表中看到的那样。

我了解TimeZone对象将解决此问题,因为它具有boolean属性,用于说明是否存在夏令时。但我对如何使用可用的值列表创建TimeZone对象感到困惑。

我有下面的下拉值:

  • (UTC-12:00)International Date Line West
  • (UTC-11:00)世界协调时间-11
  • (UTC-10:00)阿留申群岛
  • (UTC-10:00)夏威夷
  • (UTC-09:30)马克萨斯群岛

使用上面的示例值,我如何创建TimeZone对象?

2 个答案:

答案 0 :(得分:2)

这是一项艰巨的任务。在this link,在"时区数据库" 部分,您会看到Windows时区名称与Iana / Olson数据库中的名称非常不同(是Java使用的那个。

在Java中,您可以使用TimeZone.getAvailableIDs()ZoneId.getAvailableZoneIds()(如果您有Java 8)查看所有可用名称 - 并查看它们与Windows时区列表的匹配程度。

我认为你能做的最好的事情就是将每个Windows名称映射到一个有效的Iana名称,知道所有情况都不匹配:Iana数据库更加完整和准确,特别适用于Daylight保存数据,包括历史数据 - 并且比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。这可能只是一个简单的改变:政府决定永久地改变国家的抵消和#34; - 这意味着&#34;直到其他政治家决定再次改变它为止#34;。

夏令时只是抵消变更的一个特例,并且无法知道这种变化是否与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();
});

通过此,您可以知道具有偏移更改的确切日期。 有些时区没有转换,但是它们有转换规则(例如&#34; DST从11月的第一个星期日开始,#34;)。在这种情况下,您使用转换规则列表:

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();
});

答案 1 :(得分:1)

您可以按照问题的评论中的建议尝试使用TimeZone。

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);

您可以尝试使用数组列表来迭代所有值,而不是像我一样使用字符串。时区按照https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html

中所示的格式接受区域ID

<强>更新

UTC不使用DST(来源:https://en.wikipedia.org/wiki/Coordinated_Universal_Time),因此您必须将UTC转换为目标时区或使用城市名称,例如zoneID =&#34; America / New_York&#34 ;。 更新的代码:

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,因为在大多数观察到夏令时的国家,它会在3月的某个地方应用。