java zoneid,Java中的自定义ZoneId /时区

I'm attempting to model an iCalendar VTIMEZONE object using Java's ZoneId and ZoneOffsetTransitionRule.

My VTIMEZONE object looks like

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

I need to create my own ZoneId to model this because, as far as I know, there isn't a ZoneId available with these offsets and in which DST starts on the first Monday of January (as opposed to some Sunday of March).

I have the following for creating a 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));

But I'm not sure if it's correct or how to create a ZoneId from this.

Is that transition rule accurate to model the DAYLIGHT component of my VTIMEZONE?

How can I create a ZoneId from this so I can eventually create a ZonedDateTime?

解决方案

The only way to get a ZoneId (at least if we’re not very hacky) is through the factory methods of ZoneId and its subclass ZoneOffset. It might seem at first that this leaves of with the built-in ZoneIds. However, there’s a backdoor for specifying additional ZoneIds that ZoneId.of can then produce. It’s called ZoneRulesProvider. We need to specify an new and unique ID and we need to specify the zone rules (hence the name ZoneRulesProvider).

So with your ZoneOffsetTransitionRule you are already on the way. We need two of them, though, yours for transitioning to DST (which would normally have happened in the spring) and one for going the other way in the fall.

The following listing isn’t production code, of course, but is just to demonstrate that it is doable to develop and register your own 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 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 provideZoneIds() {

return Set.of(customZoneId);

}

@Override

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

The code prints:

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]

We see that we get the expected DST offset of +02:00 exactly before the transition to standard time and again after the transition to summer time.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值