我没有找到一种方法来获得没有夏令时干扰的时区偏移。
LocalDateTime dt = LocalDateTime.now();
...
ZoneId zone = ZoneId.of(s);
ZonedDateTime zdt = dt.atZone(zone);
ZoneOffset offset = zdt.getOffset();
这似乎有效,但初始DataTime可能会受到DST的影响。
还有:
int rawOffset = tZone.getRawOffset();
但是,这总是一个正数,所以我们永远不会得到-05:00
。
所以我想要的是一种在没有DST干扰的情况下获得偏移的方法。有什么想法吗?
答案 0 :(得分:3)
使用ZoneRules.getStandardOffset(Instant)
。
ZoneId zone = ZoneId.of(s);
ZoneRules rules = zone.getRules();
ZoneOffset standardOffset = rules.getStandardOffset(Instant.now());
答案 1 :(得分:0)
根据Java API文档,TimeZone.getRawOffset()将返回正确的历史偏移量。
public abstract int getRawOffset()
返回添加到UTC以获取此时区的标准时间的时间量(以毫秒为单位)。由于此值不受夏令时影响,因此称为原始偏移。
如果基础TimeZone实现子类支持历史GMT偏移量更改,则该方法返回当前日期的原始偏移值。例如,在檀香山,它的原始偏移从1947年的GMT-10:30变为GMT-10:00,这种方法总是返回-36000000毫秒(即-10小时)。
返回: 添加到UTC的原始偏移时间量(以毫秒为单位)。 也可以看看: Calendar.ZONE_OFFSET
来自:https://docs.oracle.com/javase/7/docs/api/java/util/TimeZone.html#getRawOffset()
答案 2 :(得分:0)
首先,请记住,抵消会随着时间的推移而变化(甚至是标准的),主要是因为政府,法律和其他外部因素。
这就是为什么API需要Instant
作为参考:知道在特定时刻的标准偏移是什么(无论Instant
是过去,现在还是未来)。如果不及时了解,您无法说出偏移量。这就是@Joachim's answer是正确的原因。
但正如您在评论中所说,您不想依赖Instant.now()
,我已经完成了以下代码 - 请记住,解决方案并非100%理想,因为上面的原因。它是我遵循你的标准的最好的。
您可以使用java.time.zone.ZoneRules
课程来完成此操作,您可以直接从ZoneId
实例获取该课程:
// pick a timezone with DST
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get rules
ZoneRules rules = zone.getRules();
// check if offset changes over time (if it returns false, it means is not fixed, so it has DST)
System.out.println(rules.isFixedOffset()); // false
在上面的代码中,rules.isFixedOffset()
会返回false
,这意味着相应的时区偏移会随着时间的推移而变化(因此,它会有DST更改)。
要知道何时发生DST更改,您必须获得所有转换:
// get all transitions (all dates where DST starts or ends)
List<ZoneOffsetTransition> transitions = rules.getTransitions();
transitions.stream().forEach(System.out::println);
这会打印很多行(因为这个时区几乎每年都有DST)。这是最后两行的样本:
转换[重叠于2039-02-20T00:00-02:00至-03:00
过渡[在2039-10-16T00:00-03:00到-02:00之间的差距]
这意味着在午夜的 2039-02-20 中,偏移量将从-02:00
更改为-03:00
(DST结束 - 时钟向后移动1小时),并且在 2039-10-16 午夜,偏移量将从-03:00
变为-02:00
(DST开始 - 时钟向前移动1小时)。
所以,如果你想知道它不是夏令时的偏移量,你只需要进行最后一次转换,检查它是否是间隙或重叠并在之前或之后得到偏移:
// get the last transition
ZoneOffsetTransition last = transitions.get(transitions.size() - 1);
// find the offset without DST interference
ZoneOffset offsetWithoutDST;
// overlap means that clock moves back 1 hour (when DST ends)
if(last.isOverlap()) {
// DST ends, get the offset after it
offsetWithoutDST = last.getOffsetAfter();
} else {
// DST starts, get the offset before it
offsetWithoutDST = last.getOffsetBefore();
}
System.out.println(offsetWithoutDST);
在这种情况下,它会打印-03:00
,这是&#34;正常&#34; America/Sao_Paulo
时区的偏移量(当它不是DST时)。
PS:请注意,DST甚至标准偏移量会随着时间的推移而变化很大。
仅仅因为今天的偏移是一个,它并不意味着它总是一样的:政府可以随时改变偏移,并且在过去的日期 - 比如1900年之前 - 抵消比今天(每个城市都有自己的时间,有-03:06:28
等偏移量。)
上面的代码获取当前时区规则的标准(非DST)偏移量。如果你想知道30年前的非DST偏移是什么,你可以使用@Joachim's answer(通过30年前的Instant
作为参数)。