通过DateTimeFormatter将时间区域传递给DateTimeFormatterBuilder时会丢失时区吗?

时间:2016-01-15 21:19:57

标签: jodatime

我需要使用几种日期格式解析日期,假设某个时区,然后在另一个时区(即UTC)输出。我希望DateTimeFormatterBuilder可以提供帮助,但是看起来附加到解析器和打印机的时区信息会丢失/忽略?

参见测试和输出:

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
import org.joda.time.format.DateTimeParser;
import org.junit.Test;

public class JodaBuilderTest {


@Test
public void aTestOfTimeZoneRetentionOfFormattersPassedToBuilder() throws    Exception {     

    String [] parsePatterns = new String [] { "MM/dd/yyyy HH:mm:ss", "MM/dd/yyyy" };
     String printPattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
     String inputString = "08/03/2015 01:01:01";

    DateTimeZone tz = DateTimeZone.forOffsetHours(-3);
    DateTimeParser[] parsers = new DateTimeParser[parsePatterns.length];
    for (int index = 0; index < parsePatterns.length; index++) {

        parsers[index] = DateTimeFormat.forPattern(parsePatterns[index]).withZone(tz).getParser();
    }
    DateTimeFormatterBuilder builder = new DateTimeFormatterBuilder()
      .append(DateTimeFormat.forPattern(printPattern).withZoneUTC().getPrinter(), parsers);
    DateTimeFormatter parser = builder.toFormatter();

    DateTimeZone parserdtz = parser.getZone();
    System.out.println("parserdtz: " + parserdtz);
    DateTime dt = parser.parseDateTime(inputString);
    System.out.println("parser zone is " + dt.getZone());
    String dtout = dt.toString();
    System.out.println("expecting UTC-3: 2015-08-03T01:01:01.000-03:00");
    System.out.println("got:\t\t" + dtout);
    String dtoutFmt = dt.toString(parser);
    System.out.println("expecting UTC: 2015-08-03T04:01:01.000-00:00");
    System.out.println("got:\t\t" + dtoutFmt);
    org.junit.Assert.assertEquals("2015-08-03T04:01:01.000-00:00", dtoutFmt);

}
}

输出如下

parserdtz: null
parser zone is America/New_York
expecting UTC-3: 2015-08-03T01:01:01.000-03:00
got:        2015-08-03T01:01:01.000-04:00
expecting UTC: 2015-08-03T04:01:01.000-00:00
got:        2015-08-03T01:01:01.000-04:00

所以它似乎忽略了解析器上的UTC-3设置和打印机上的UTC设置以及默认为系统区域(EDT)。 我错过了什么或这是预期的行为吗?我唯一不能使用建筑商的办法吗?我也无法在parser上设置区域,即     DateTimeFormatter parser = builder.toFormatter().withZone(DateTimeZone.forOffsetHours(-3)); 因为这会覆盖打印机。我想我可以为打印机创建一个单独的格式化程序,但那么构建器的打印机参数的目的是什么?我应该将其设置为null吗?感觉不对。

1 个答案:

答案 0 :(得分:0)

以下是一些澄清:

DateTimeParser DateTimePrinter 实例根据特定格式模式解析/打印DateTime。但是,时区和区域设置不是打印机/解析器实例的一部分。它们在运行时期间根据具体情况提供。请参阅DateTimePrinter.printTo的签名:

void printTo(StringBuffer buf,
             long instant,
             Chronology chrono,
             int displayOffset,
             DateTimeZone displayZone, // zone provided at runtime
             Locale locale)

至于打印机 - 它可以读取任何时区,因此与其配置无关。

请记住DateTimePrinter/Parser javadocs中的片段:

  

用于创建/解析日期时间的文本表示的内部接口。

因此,打印机/解析器本身没有内部设置的时区。您可以删除打印机/解析器上的withZone(tz) / withZoneUTC()配置,因为它们不会改变任何内容。

然而,DateTimeFormatter有。这是您在时区时应该使用的顶级API。如果在格式化程序上设置时区X,则它将能够读取任何时区字符串,但创建的DateTime实例将转换为该时区X。同样,在打印任何DateTime实例(在任何时区)时,它将被打印为转换为时区X。如果您确实试图将字符串专门解析为-03:00时区,则需要一个DateTimeFormatter实例,当您想以UTC格式打印时,需要一个不同的格式化程序实例。

因此,拥有原始formatter(从parser重命名),您可以

DateTime dt = formatter.withZone(DateTimeZone.forID("-03:00")).parseDateTime(inputString);

并打印:

String dtoutFmt = dt.toString(formatter.withZoneUTC());

我确信如果您为变量使用相关名称会更清楚一点 - 对formatter实例使用DateTimeFormatter以避免与实际DateTimeParser混淆