Custom ZoneIds / Time Zones in Java

浪子不回头ぞ 提交于 2019-11-29 17:20:02

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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!