【问题标题】:How to replace sun.util.caldender.ZoneInfo with new API in java如何用 java 中的新 API 替换 sun.util.caldender.ZoneInfo
【发布时间】:2019-08-04 13:23:37
【问题描述】:

我在我的一个测试用例中发现了这个 Api Sun.util.calendar.zoneInfo,当我编译它时,我收到警告消息,它说 sun.util.calender.ZoneInfo 是内部专有 API,可能会在未来的版本中删除

@Test @Ignore("This test case was previously ignore, appears incomplete")
    public void test_getTimeZoneFromTimeZoneDifferential() throws Exception {
        TimeZone customCali = DMessageFactory.getTimeZoneFromTimeZoneDifferential("110");
        System.out.println("\ncustomCali: "+customCali+"\n");
        String[] ids = TimeZone.getAvailableIDs();
        for(int i = 0; i < ids.length; i++) {
            TimeZone tz = TimeZone.getTimeZone(ids[i]);

            if(tz instanceof sun.util.calendar.ZoneInfo) {
                TimeZone realZone = ((sun.util.calendar.ZoneInfo) tz).getLastRuleInstance();
                if(realZone == null) {
                    if(tz.useDaylightTime() == customCali.useDaylightTime() &&
                       tz.getOffset(0) == customCali.getOffset(0)) {
                        System.out.println("match2: "+tz+"   "+tz.getDisplayName(true, TimeZone.SHORT));
                    }
                    //System.out.println("no real zone: "+tz);
                    continue;
                }

                if(customCali.hasSameRules(realZone)) {
                    System.out.println("match: "+realZone.getDisplayName(true, TimeZone.SHORT));
                }
                else if(realZone.getOffset(0) == customCali.getOffset(0)) {
                    //System.out.println("semi-match: "+tz);
                }
                else {
                    //System.out.println("NO-match: "+tz);
                }
            } else {
                //System.out.println("no-match: "+tz);
            }
        }

我真的需要替换这个 sun.util.calendar.ZoneInfo 并添加另一个 API 而不会破坏它的功能,请帮我解决这个问题。

【问题讨论】:

    标签: java api junit timezone internals


    【解决方案1】:

    tl;博士

    改用现代的 java.time 类。

    循环所有已知区域,询问该区域的规则集,指定时刻,然后询问您需要的信息。

    Instant instant = Instant.now() ;
    for( ZoneId z : ZoneId.getAvailableZoneIds() )
    {
        String zoneName = z.getDisplayName( TextStyle.SHORT , Locale.US ) ;
    
        ZoneRules rules = z.getRules() ;
    
        ZoneOffset offset = rules.getOffset​( instant ) ;
        int secondsOfOffset = offset.getTotalSeconds() ;
    
        boolean currentlyInDST = rules.isDaylightSavings( instant ) ;
        Duration amountOfCurrentDstAdjustment = rules.getDaylightSavings( instant ) ;
    
        …
    }
    

    sun.util.calender.ZoneInfo 是实现支持 TimeZone(均已过时)

    根据this class JavaDoc,这只是Sun 为JVM 提供的TimeZone 类的具体实现。

    ZoneInfo 是 TimeZone 的实现子类,表示时区的 GMT 偏移和夏令时转换。

    TimeZoneZoneInfo 都已过时。您应该改用现代的 java.time 类。

    在构建Java Platform Module System 时,Oracle 开始逐步取消对已过时或从未打算供公众使用的部分 Java 实现的访问。这是一个持续的过程。从各种com.sun.* 包中调用类的任何代码都应该重写以使用其他类。

    java.time

    TimeZone 是与最早的 Java 版本捆绑在一起的糟糕的日期时间类之一。这些现在是遗留的,几年前被 JSR 310 中定义的现代行业领先的 java.time 类所取代。

    ZoneId = 时区

    时区现在用 ZoneId 类表示,取代了 TimeZoneZoneRules 类跟踪区域中每个区域使用的 offset-from-UTC 的过去、现在和未来更改的历史记录。

    tzdata

    请注意,世界各地的政客经常更改时区。这种情况发生的频率比您想象的要频繁。这些更改由tzdata data file 跟踪。每当您关心的时区发生变化时,您都应该在您的 Java、操作系统、Postgres 等数据库以及管理自己的时区列表的其他库中更新此时区定义列表。

    区域规则

    Continent/Region 的格式指定proper time zone name,例如America/MontrealAfrica/CasablancaPacific/Auckland。切勿使用 2-4 个字母的缩写,例如 ESTIST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

    ZoneId z = ZoneId.of( "America/Montreal" ) ;  
    

    获取该区域的规则。

    ZoneRules rules = z.getRules() ;
    

    Instant 的区域规则

    Instant 代表UTC 中的时刻,即offset-from-UTC 为零时分秒的时刻。通过指定时刻,您可以就当时有效的规则提出问题。

    Instant instant = Instant.now() ;
    boolean currentlyInDST = rules.isDaylightSavings( instant ) ;
    Duration amountOfCurrentDstAdjustment = rules.getDaylightSavings( instant ) ;
    

    循环区域

    您可以通过调用ZoneId.getAvailableZoneIds 方法获取嵌入式tzdata 已知的所有时区,从而重新实现您的代码。您可以循环返回的Set

    Set< String > zones = ZoneId.getAvailableZoneIds() ;
    for( String z : zones )
    {
        ZoneRules rules = ZoneId.of( z ).getRules() ;
        …
    }
    

    你没有解释你的代码,比如这意味着什么:

    DMessageFactory.getTimeZoneFromTimeZoneDifferential("110")
    

    ……所以我能为你做的不多了。

    您的代码似乎正在寻找与其offset-from-UTC(小时-分钟-秒)匹配的时区,无论是否在Daylight Saving Time (DST)。如上所述,您可以向ZoneRules 询问此信息。


    关于java.time

    java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.DateCalendarSimpleDateFormat

    要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

    Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

    您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

    从哪里获得 java.time 类?

    ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

    【讨论】:

      猜你喜欢
      • 2022-07-20
      • 2016-04-23
      • 1970-01-01
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      • 2022-10-13
      • 1970-01-01
      相关资源
      最近更新 更多