gpt4 book ai didi

java - Java 中的自定义 ZoneIds/时区

转载 作者:行者123 更新时间:2023-11-29 08:27:32 25 4
gpt4 key购买 nike

我正在尝试使用 Java 的 ZoneIdZoneOffsetTransitionRule 为 iCalendar VTIMEZONE 对象建模。

我的 VTIMEZONE 对象看起来像

BEGIN:VTIMEZONE
TZID:Central European Standard Time
BEGIN:STANDARD
DTSTART:16010101T030000
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=10
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:16010101T020000
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
RRULE:FREQ=YEARLY;INTERVAL=1;BYMONTH=1;BYDAY=MO
END:DAYLIGHT
END:VTIMEZONE

我需要创建自己的 ZoneId 来对此进行建模,因为据我所知,没有可用于这些偏移量且 DST 开始的 ZoneId在一月的第一个星期一(而不是三月的某个星期日)。

我有以下用于创建 ZoneOffsetTransitionRule

ZoneOffsetTransitionRule of =
ZoneOffsetTransitionRule.of(Month.JANUARY, 1, DayOfWeek.MONDAY, LocalTime.of(2, 0),
false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofHours(1),
ZoneOffset.ofHours(1), ZoneOffset.ofHours(2));

但我不确定它是否正确或如何从中创建一个 ZoneId

  • 该转换规则对我的 VTIMEZONEDAYLIGHT 组件建模是否准确?
  • 如何从中创建一个 ZoneId,以便最终创建一个 ZonedDateTime

最佳答案

获得 ZoneId 的唯一方法(至少如果我们不是非常 hacky)是通过 ZoneId 的工厂方法和它的子类 ZoneOffset。乍一看,这似乎与内置的 ZoneId 无关。但是,有一个后门用于指定 ZoneId.of 可以生成的其他 ZoneId。它称为 ZoneRulesProvider。我们需要指定一个新的唯一 ID,并且需要指定区域规则(因此得名 ZoneRulesProvider)。

因此,通过您的 ZoneOffsetTransitionRule,您已经在路上了。不过,我们需要其中两个,一个用于过渡到夏令时(通常在 Spring 发生),另一个用于在秋季过渡到夏令时。

当然,以下 list 不是生产代码,只是为了证明开发和注册您自己的 ZoneRulesProvider 是可行的。

    final String customZoneId = "Custom-CEST-1";

final ZoneOffset standardOffset = ZoneOffset.ofHours(1);
final ZoneOffset summerTimeOffset = ZoneOffset.ofHours(2);
// At least one transistion is required
ZoneOffsetTransition initialTransition = ZoneOffsetTransition.of(
LocalDateTime.of(1601, 1, 1, 3, 0), summerTimeOffset, standardOffset);
List<ZoneOffsetTransition> transitionList = List.of(initialTransition);

// Rules for going to and from summer time (DST)
ZoneOffsetTransitionRule springRule =
ZoneOffsetTransitionRule.of(Month.JANUARY, 1, DayOfWeek.MONDAY, LocalTime.of(2, 0),
false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, standardOffset,
standardOffset, summerTimeOffset);
ZoneOffsetTransitionRule fallRule =
ZoneOffsetTransitionRule.of(Month.OCTOBER, -1, DayOfWeek.SUNDAY, LocalTime.of(2, 0),
false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, standardOffset,
summerTimeOffset, standardOffset);
ZoneRules rules = ZoneRules.of(standardOffset, standardOffset,
transitionList, transitionList, List.of(springRule, fallRule));

// The heart of the magic: the ZoneRulesProvider
ZoneRulesProvider customProvider = new ZoneRulesProvider() {

@Override
protected Set<String> provideZoneIds() {
return Set.of(customZoneId);
}

@Override
protected NavigableMap<String, ZoneRules> provideVersions(String zoneId) {
return new TreeMap<>(Map.of(customZoneId, rules));
}

@Override
protected ZoneRules provideRules(String zoneId, boolean forCaching) {
return rules;
}
};

// Registering the ZoneRulesProvider is the key to ZoneId using it
ZoneRulesProvider.registerProvider(customProvider);

// Get an instance of our custom ZoneId
ZoneId customZone = ZoneId.of(customZoneId);
// Transition to standard time was Sunday, October 29, 2017,
// so try the day before and the day after
System.out.println(LocalDate.of(2017, Month.OCTOBER, 28).atStartOfDay(customZone));
System.out.println(LocalDate.of(2017, Month.OCTOBER, 30).atStartOfDay(customZone));
// The special thing about our custom ZoneID is that transition to DST
// happened on Monday, January 1. Try the day before and the day after.
System.out.println(LocalDate.of(2017, Month.DECEMBER, 31).atStartOfDay(customZone));
System.out.println(LocalDate.of(2018, Month.JANUARY, 2).atStartOfDay(customZone));

代码打印:

2017-10-28T00:00+02:00[Custom-CEST-1]
2017-10-30T00:00+01:00[Custom-CEST-1]
2017-12-31T00:00+01:00[Custom-CEST-1]
2018-01-02T00:00+02:00[Custom-CEST-1]

我们看到我们在转换到标准时间之前和转换到夏令时之后再次获得了 +02:00 的预期 DST 偏移。

关于java - Java 中的自定义 ZoneIds/时区,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51406787/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com