Java中的自定义ZoneId/时区 [英] Custom ZoneIds / Time Zones in Java

查看:1280
本文介绍了Java中的自定义ZoneId/时区的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

我的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对此进行建模,因为据我所知,没有具有这些偏移量的ZoneId,并且DST在1月的第一个星期一开始(相对于3月的某个星期日).

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

我具有以下创建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.

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

  • 该转换规则对我的VTIMEZONEDAYLIGHT组件建模是否准确?
  • 如何从中创建ZoneId,以便最终创建ZonedDateTime?
  • 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?

推荐答案

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

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

因此,使用您的ZoneOffsetTransitionRule,您已经在路上.不过,我们需要其中两个,而过渡到DST(通常会在春季发生)的则是您的,秋天则需要另一种.

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.

下面的列表当然不是生产代码,而只是为了证明可以开发和注册自己的ZoneRulesProvider.

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

代码显示:

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]

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

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.

这篇关于Java中的自定义ZoneId/时区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆