具有夏令时的Spring @DateTimeFormat转换错误

时间:2011-11-04 19:23:43

标签: java spring-mvc jodatime dst

我在配置了夏令时的机器上使用Spring MVC(America / Sao_Paulo Time Zone)。在我的表单类中,我使用注释DateTimeFormat来配置我的Date的输出:

public class JustificativaOcorForm {
  ...
  @NotNull
  @DateTimeFormat(pattern="yyyy-MM-dd")
  private Date dataMarcacao;
  ...
}

调试时我得到的日期是16/10/2011(日/月/日),这是白天时间的开始,但春天将其转换为2011-10-15。为什么呢?

2011-11-04 16:35:31,965 [http-8080-Processor25] DEBUG org.springframework.core.convert.support.GenericConversionService - Converting value Sun Oct 16 00:00:00 BRST 2011 of [TypeDescriptor @javax.validation.constraints.NotNull @org.springframework.format.annotation.DateTimeFormat java.util.Date] to [TypeDescriptor java.lang.Long]
2011-11-04 16:35:31,965 [http-8080-Processor25] DEBUG org.springframework.core.convert.support.GenericConversionService - Converted to 1318730400000
2011-11-04 16:35:32,010 [http-8080-Processor25] DEBUG org.springframework.core.convert.support.GenericConversionService - Converted to '2011-10-15'

我看到了这个问题:@DateTimeFormat in Spring produces off-by-one day error

但是Spring 3使用了Joda-Time,我的类路径中有joda-time-2.0.jar,所以我不知道为什么会这样,以及如何解决它。

[编辑]

我已经测试过创建LocalData objets,并找到了一些东西:

LocalDate ld = new LocalDate( new SimpleDateFormat("dd/MM/yyyy").parse("16/10/2011").getTime() );
System.out.println( new SimpleDateFormat("dd/MM/yyyy HH:mm:ss Z z").format( ld.toDate() )  );
//prints 15/10/2011 00:00:00 -0200 BRST

LocalDate ld2 = new LocalDate( 2011,10,16 );
System.out.println( new SimpleDateFormat("dd/MM/yyyy HH:mm:ss Z z").format( ld2.toDate() )  );
//prints 16/10/2011 00:00:00 -0200 BRST

似乎第一种方法是认为时间是UTC,因为调试我可以看到Joda使用DateTimeZone类的convertUTCToLocal方法。

也许这也是Spring的默认值,他预计UTC也会有一个日期,我正在通过BRT日期。

所以我认为我的解决方案是将对象更改为LocalDate,并使用第二种方法创建此对象的实例。

1 个答案:

答案 0 :(得分:5)

这可能会回答您问题的部分内容。

当你有一个java.util.Data对象时,它将在你的系统时区内打印到toString中。因此,如果您将日期设置为UTC 2011-10-16 00:00:00,该日期将在日期内部转换为UTC时间戳。 toString将在您当地时区打印该时间戳,并且 UTC之后将会是几个小时(因为圣保罗位于伦敦西部),所以大致在2011-10-15 22:00:00。这就是你在断点和调试打印上看到的。尽管如此,数据在内部可能仍然是正确的。

如果发现打印日期的唯一真正方法是通过SimpleDateFormat这样:

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
    try {
        Date dateInUTC = dateFormat.parse("2011-10-16 00:00:00");
        Date currentDate = new Date();
        String stringInUTC = dateFormat.format(currentDate);
        System.out.println(dateInUTC);
        System.out.println(currentDate);
        System.out.println(stringInUTC);
    }
    catch (ParseException e) {
        // not too worry, I wrote a nice date
    }

现在打印件看起来很混乱

Sun Oct 16 01:00:00 CET 2011
Thu Nov 10 15:47:46 CET 2011
2011-11-10 14:47:46

但是让我们来看看。

  1. 首先,我的SimpleDateFormat获取一种格式,我将其设置为假设所有文本输入和输出都是UTC时区。
  2. 当我解析将被解释为UTC的日期2011-10-16 00:00:00但是当我打印它时,java使用我的区域设置(CET)将其打印为2011-10-16 01:00:00 ,这也是我在断点上看到的内容
  3. 当我创建一个新的Date()时,Date将在我的语言环境中,当我打印它时它将显示15:47(我当前的时间)但是当我用我的时区识别SimpleDateFormat格式化时它会显示时间UTC。
  4. 那就是说,java和日期会让你迷惑,直到你拔掉头发:)

    希望这会有所帮助。