我创建了以下示例代码来演示这种行为,并展示我提出的解决方案。
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);
小心点。带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和长名称,使列表看起来如下所示?