Spring @DateTimeFormat 夏令时转换错误

发布于 2024-12-13 12:25:22 字数 1934 浏览 0 评论 0原文

我在配置了夏令时(美国/圣保罗时区)的计算机上使用 Spring MVC。在我的表单类中,我使用注释 DateTimeFormat 来配置日期的输出:

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

在调试时,我得到日期 16/10/2011 (dd/MM/yyyy),这是夏令时的开始,但 Spring 将其转换为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会产生off-by-有一天错误

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

[编辑]

我已经测试了创建 LocalData 对象,并发现了一些东西:

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 使用的方法 ConvertUTCToLocal类 DateTimeZone。

也许这也是 Spring 的默认日期,他也希望有一个 UTC 日期,而我正在传递 BRT 日期。

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

I'm using Spring MVC on a machine that has Daylight Saving Time configured (America/Sao_Paulo Time Zone). In my form class I used the annotation DateTimeFormat to configure the output of my Date:

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

While debugging I'm getting the date 16/10/2011 (dd/MM/yyyy) that's the start of the daylight time, but Spring converts it to 2011-10-15. Why?

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'

I see this question: @DateTimeFormat in Spring produces off-by-one day error

but Spring 3 uses Joda-Time and I have joda-time-2.0.jar in my classpath so I don't know why this occurs and how I can solve it.

[EDIT]

I've tested creating LocalData objets, and found something:

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

It seems that the first approach is thinking that the time is in UTC, because debugging I can see that Joda use the method convertUTCToLocal of the class DateTimeZone.

Maybe this is the default of the Spring too, he expect's one date in UTC too and i am passing the BRT Date.

So I think my solution is change the objects to LocalDate and use the second way to create the instance of this object.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倚栏听风 2024-12-20 12:25:22

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

当您有一个 java.util.Data 对象时,它将在 toString 内以您的系统时区打印。因此,如果您设置的日期为 UTC 2011-10-16 00:00:00,则该日期将在 Date 内部转换为 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. 当我解析日期 2011-10-16 00:00:00 时,该日期将被解释为 UTC 但当我打印它时,java 使用我的语言环境 (CET) 将其打印为 2011-10-16 01:00:00,即也是我在断点上看到的内容
  3. 当我创建一个新的 Date() 时,该日期将位于我的区域设置中,当我打印它时,它将显示 15:47 (我当前的time),但是当我使用时区感知 SimpleDateFormat 对其进行格式化时,它将显示 UTC 时间。

也就是说,java 和日期会让你感到困惑,直到你抓狂:)

希望这对一些人有帮助。

This might answer parts of your question.

When ever you have a java.util.Data object that will be printed in your systems time zone inside toString. So, if you set a date that is in UTC 2011-10-16 00:00:00 that's going to be converted into a UTC timestamp internally in the Date. toString will print that timestamp in your local timezone and that's going to be a couple of hours after UTC (since Sao Paolo is west of London) so roughly 2011-10-15 22:00:00. That is what you'll see on break points and debug prints. The Data might still be correct internally though.

If found that the only real way of printing Dates is through SimpleDateFormat like this:

    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
    }

Now the print will look very confusing

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

But lets walk through it.

  1. First, my SimpleDateFormat gets a format and I set it to assume all text in and out is in UTC timezone.
  2. When I parse the date 2011-10-16 00:00:00 that will be interpretted as UTC but when I print it java uses my locale (CET) to print this as 2011-10-16 01:00:00, that is also what I would see on a break point
  3. When I create a new Date() that Date will be in my locale and when I print it it will show 15:47 (my current time) but when I format it with my timezone aware SimpleDateFormat it will show the time in UTC.

That said, java and dates will confuse you until you pull your hair out :)

Hope this helps some.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文