从 java.util.TimeZone 转换为 org.joda.DateTimeZone

Posted

技术标签:

【中文标题】从 java.util.TimeZone 转换为 org.joda.DateTimeZone【英文标题】:Converting from java.util.TimeZone to org.joda.DateTimeZone 【发布时间】:2017-09-02 03:15:30 【问题描述】:

如何在 Java 中将 java.util.TimeZone 的实例转换为 org.joda.DateTimeZone 并保持夏令时?

【问题讨论】:

DateTimeZone#forTimeZone(TimeZone) 有什么问题? 它返回一个 FixedDateTimeZone 实例,它不包含夏令时值 不,它没有。发布您的代码。 您只对 Joda-Time 感兴趣吗? Joda-Time 项目现在处于维护模式,其创建者建议迁移到他们的新创建:Java 8 及更高版本中内置的 java.time 类。 TimeZone timeZone = (Clock.buildTimeZone("test", 60, DateUtilTests.createDate(2013, Calendar.MARCH, 27), DateUtilTests.createDate(2013, Calendar.OCTOBER, 31), 180) ); DateTime gmtDateTime = new DateTime(DateUtilTests.createDate(2013, Calendar.APRIL, 20, 02,00,0), DateTimeZone.forID("GMT"));日期时间 localDateTime = gmtDateTime.withZone(DateTimeZone.forTimeZone(timeZone)); System.out.print(localDateTime);这将返回 2013-04-20T03:00:00.000+01:00(不考虑夏令时) 【参考方案1】:

Joda-Time 处于维护模式

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

java.time.ZoneId

java.util.TimeZone 的现代替代品是 java.time.ZoneIdjava.time.ZoneOffset

您应该避免使用旧的旧日期时间类。但如有必要,您可以转换为 java.time 类型/从 java.time 类型转换。查看添加到旧类的新方法。您可以在TimeZoneZoneId 之间移动。

java.util.TimeZone tz = java.util.TimeZone.getTimeZone( myZoneId );

……和……

java.time.ZoneId z = myLegacyTimeZone.toZoneId();

如果您正在查找该区域的与 UTC 的偏移量或夏令时 (DST) 信息,请查看 ZoneRules 类。搜索 Stack Overflow 以获取更多讨论和示例,或编辑您的问题以更多地描述您的目标。

【讨论】:

你说得对,我现在使用新的 Java 8 API。这样代码就更简单了。问题是遗留系统正在生成具有错误 ID 的自定义 TimeZone java 对象,因此 toZoneId 正在生成异常,因为这些 ID 不受支持【参考方案2】:

当您调用 DateTimeZone.forTimeZone 时,它使用时区 ID,而 Joda 使用自己的 DST 规则创建等效对象 - 它不会从 TimeZone 对象导入规则。

另一个细节是您正在使用“GMT”,这是一个没有 DST 规则的区域(只需检查 DateTimeZone.forID("GMT").isFixed() 的值 - 它返回 true 意味着该区域是固定的,AKA 它没有偏移量变化,也就是它没有 DST)。

您似乎想要一个具有伦敦 DST 规则的区域(基于您选择的 DST 开始和结束日期)。如果是这种情况,您可以使用DateTimeZone.forID("Europe/London") 创建一个区域。


但是如果你想创建一个具有特定 DST 规则的自定义区域,你必须通过扩展 DateTimeZone 类来手动完成。具有 DST 的区域的一个示例从 2013 年 3 月 27 日开始,到 2013 年 10 月 31 日结束,都在午夜(不过,您可以根据需要更改值)。

public class CustomTimeZone extends DateTimeZone 

    private DateTime dstStart;

    private DateTime dstEnd;

    protected CustomTimeZone(String id) 
        super(id);
        // DST starts at 27/Mar/2013 and ends at 31/Oct/2013
        this.dstStart = new DateTime(2013, 3, 27, 0, 0, 0, 0, DateTimeZone.UTC);
        this.dstEnd = new DateTime(2013, 10, 30, 23, 0, 0, 0, DateTimeZone.UTC);
    

    @Override
    public String getNameKey(long instant) 
        return this.getID();
    

    @Override
    public int getOffset(long instant) 
        // check if it's in DST
        if (dstStart.getMillis() <= instant && instant < dstEnd.getMillis()) 
            // DST, offset is 1 hour ahead of UTC - value must be in milliseconds
            return 3600000;
        
        return 0;
    

    @Override
    public int getStandardOffset(long instant) 
        // assuming stardard offset is zero (same as UTC)
        return 0;
    

    @Override
    public boolean isFixed() 
        return false;
    

    @Override
    public long nextTransition(long instant) 
        if (instant < dstStart.getMillis()) 
            return dstStart.getMillis();
        
        if (instant < dstEnd.getMillis()) 
            return dstEnd.getMillis();
        
        return instant;
    

    @Override
    public long previousTransition(long instant) 
        if (instant > dstEnd.getMillis()) 
            return dstEnd.getMillis();
        
        if (instant > dstStart.getMillis()) 
            return dstStart.getMillis();
        
        return instant;
    

    @Override
    public boolean equals(Object obj) 
        if (this == obj) 
            return true;
        
        if (obj instanceof CustomTimeZone) 
            return getID().equals(((CustomTimeZone) obj).getID());
        
        return false;
    

测试这个区域:

CustomTimeZone customZone = new CustomTimeZone("Custom");
// date in DST (between March and October)
DateTime d = new DateTime(2013, 4, 20, 0, 0, 0, 0, customZone);
System.out.println(d); // 2013-04-20T00:00:00.000+01:00

// one minute before DST starts - offset is zero ("Z")
d = new DateTime(2013, 3, 26, 23, 59, 0, 0, customZone);
System.out.println(d); // 2013-03-26T23:59:00.000Z
// add 1 minute - DST starts and offset changes to +01:00 (clock moves 1 hour forward to 1 AM)
System.out.println(d.plusMinutes(1)); // 2013-03-27T01:00:00.000+01:00

// one minute before DST ends - offset is +01:00
d = new DateTime(1383173940000L, customZone);
System.out.println(d); // 2013-10-30T23:59:00.000+01:00
// add 1 minute - DST starts and offset changes to zero ("Z") (clock moves 1 hour back to 23 PM)
System.out.println(d.plusMinutes(1)); // 2013-10-30T23:00:00.000Z

我只创建了一个只有一个 DST 转换的简单案例,但是您可以根据需要使类变得复杂,存储您需要的所有 DST 更改并调整开始和结束日期(以及偏移量)相应地。

【讨论】:

以上是关于从 java.util.TimeZone 转换为 org.joda.DateTimeZone的主要内容,如果未能解决你的问题,请参考以下文章

Android日历序列化与Java 6不兼容

将值从字符转换为数字或从数字转换为字符

警告:从/到不同大小的整数转换为/从指针转换

无法从 'char[]' 转换为 'string[]' [关闭]

C++ 从数组转换为结构并转换为 C#

如何将 NSString 从 CamelCase 转换为 TitleCase,将“playerName”转换为“Player Name”?