当前位置: 首页 > 知识库问答 >
问题:

使用Joda处理时区偏移转换和夏时制

翟淇
2023-03-14

我创建了以下示例代码来演示这种行为,并展示我提出的解决方案。

public class FooBar {
public static final DateTimeZone EST = DateTimeZone.forID("EST");
public static final DateTimeZone EASTERN = DateTimeZone.forID("US/Eastern");

public static final DateTimeFormatter EST_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(EST);
public static final DateTimeFormatter EASTERN_FORMATTER = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(EASTERN);


public static void main(String[] args) {
    final String[] listOfDateTimeStrings = {"2014-03-09 02:00:00.000", "2014-03-08 02:00:00.000"}; 

    System.out.println(" *********** 1st attempt  *********** ");
    for (String dateTimeString: listOfDateTimeStrings){
        try{
            final DateTime dateTime = DateTime.parse(dateTimeString, EASTERN_FORMATTER);
            System.out.println(dateTime);       
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }
    }

    System.out.println(" *********** 2nd attempt  *********** ");
    for (String dateTimeString: listOfDateTimeStrings){
        try{
            final DateTime dateTime = DateTime.parse(dateTimeString, EST_FORMATTER);
            System.out.println(dateTime);       
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }
    }

    System.out.println(" *********** 3rd attempt  *********** ");
    for (String dateTimeString: listOfDateTimeStrings){
        try{
            DateTime dateTime = DateTime.parse(dateTimeString, EST_FORMATTER);
            dateTime = dateTime.withZone(EASTERN);
            System.out.println(dateTime);       
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }
    }       

}

}

产出:

 *********** 1st attempt  *********** 
Cannot parse "2014-03-09 02:00:00.000": Illegal instant due to time zone offset transition (America/New_York)
2014-03-08T02:00:00.000-05:00
 *********** 2nd attempt  *********** 
2014-03-09T02:00:00.000-05:00
2014-03-08T02:00:00.000-05:00
 *********** 3rd attempt  *********** 
2014-03-09T03:00:00.000-04:00
2014-03-08T02:00:00.000-05:00
DateTime dateTime = DateTime.parse(dateTimeString, A_FORMATTER_WITH_TIME_ZONE_A);
dateTime = dateTime.withZone(TIME_ZONE_B);

共有1个答案

东门清夷
2023-03-14

小心点。带zone(...)的方法的行为记录如下:

返回具有不同时区的此datetime的副本,保留毫秒的瞬间。

记住这一点,您必须理解EST和“America/New_York”(比过时的id“US/EAST”更好)是不一样的。第一个(EST)具有固定的偏移(没有DST),但第二个具有包括可能的间隙的DST。只有当您确定以下情况时,您才应使用EST替换EAST

阅读原始规范要求后进行更新(过时-请参见下文):

如果遗留系统的规范规定所有时间都存储在EST中,那么您应该以这种方式解析它,而根本不使用“america/new_york”进行解析。相反,您可以在第二阶段将解析的EST-instants转换为New-York-time(使用With Zone(Easter)。这样您将不会有任何异常逻辑,因为(解析的)Instants总是可以以明确的方式转换为本地时间表示形式(解析的instantDateTime类型的Instants转换为本地时间,转换结果包含本地时间)。代码示例:

public static final DateTimeZone EST = DateTimeZone.forID("EST");
public static final DateTimeZone EASTERN = DateTimeZone.forID("US/Eastern");
public static final DateTimeFormatter EST_FORMATTER = 
  DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(EST);

// in your parsing method...
String input = "2014-03-09 02:00:00.000";
DateTime dt = EST_FORMATTER.parseDateTime(input);
System.out.println(dt); // 2014-03-09T02:00:00.000-05:00
System.out.println(dt.withZone(EASTERN)); // 2014-03-09T03:00:00.000-04:00

在评论和澄清OP后更新:

// Joda-Time cannot parse "EDT" so we use hard-coded offsets
public static final DateTimeZone EST = DateTimeZone.forOffsetHours(-5);
public static final DateTimeZone EDT = DateTimeZone.forOffsetHours(-4);

public static final DateTimeZone EASTERN = DateTimeZone.forID("America/New_York");
public static final org.joda.time.format.DateTimeFormatter FORMATTER = 
    org.joda.time.format.DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
String input = "2014-03-09 02:00:00.000";
LocalDateTime ldt = FORMATTER.parseLocalDateTime(input); // always working
System.out.println(ldt); // 2014-03-09T02:00:00.000
DateTime result;

try {
    result = ldt.toDateTime(EASTERN);
} catch (IllegalInstantException ex) {
    result = ldt.plusHours(1).toDateTime(EDT); // simulates a PUSH-FORWARD-strategy at gap
    // result = ldt.toDateTime(EST); // the same instant but finally display with EST offset
}
System.out.println(result); // 2014-03-09T03:00:00.000-04:00
// if you had chosen <<<ldt.toDateTime(EST)>>> then: 2014-03-09T02:00:00.000-05:00

生成datetime的方法toDateTime(DateTimeZone)的文档如下:

在夏时制重叠中,当相同的本地时间出现两次时,此方法返回第一次出现的本地时间。

换句话说,它在重叠的情况下选择较早的偏移(在秋季)。所以不需要打电话

result = ldt.toDateTime(EASTERN).withEarlierOffsetAtOverlap();
result = ldt.toDateTime(EDT).withEarlierOffsetAtOverlap();
 类似资料:
  • 在我的网站中,用户A创建了一个从上午9:00开始的事件。我将该时间转换为GMT,这样,如果用户B在两小时前的不同时区看到该事件,它可以转换为用户B的时区,并显示该事件在11:00AM开始。 我唯一的想法是,当我得到如下所示的时区偏移量时,我是否应该总是将日期设置为一月,以便无论实际月份如何,我总是得到相同的时区偏移量?或者有没有更好的方法来处理这件事?

  • 在我的一个项目中,我必须将UTC DateTime转换为用户特定的日期和时间。我正在使用xml获取时间偏移量和夏令时参数。 例如offset=“GMT+2”dst=“true” 谢谢,

  • 问题内容: 只是为了验证这一点:我有这种la脚和脑死法,可以计算当前位置的时区偏移量。我想知道是否在需要调整“夏令时”时需要进行调整(目前,我所在的位置为CET时区,所以是“冬季时间”,因此很难验证)。 感谢您的任何提示。 问题答案: 通常,Joda时间会自己照顾DST,因此您不必担心。但是,我注意到您正在传递给getOffset()。鉴于时区偏移量取决于日期,因此您确实应该传递计算偏移量的日期/

  • 我有一个格式为“2019-04-25T16:34:28-05:00”的字符串。我已经通过模式“yyyy-mm-dd't'hh:mm:ssz”通过joda-time解析了字符串。 它在DateTime中给出的输出是“2019-04-25t15:34:28.000-06:00”。

  • 所以基本上我需要做的就是想办法从2013-07-30T00:00:000000+11:00中提取出+11:00。请救命!

  • Joda Time的时区ID可以简单地用以下代码段显示。 但是,如何显示相应的时区偏移量、时区ID和长名称,使列表看起来如下所示?