失去了一天的约会

Posted

技术标签:

【中文标题】失去了一天的约会【英文标题】:lost one day for a date 【发布时间】:2015-10-15 19:38:23 【问题描述】:

在客户端,我使用 dd/MM/yyyy 日期格式。该字段使用 twitter bootstrap 3 日期时间选择器 (https://eonasdan.github.io/bootstrap-datetimepicker/)

我通过 twitter bootstrap 3 日期时间选择器输入 24/07/2015 在我发送的 json 中,我看到:生日:“24/07/2015”

在我的 dto 中,我愿意

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
private Date birthdate;

当我在服务器上收到日期时,在我的 d 中看到:23/07/2015 19:00

一天过去了。

有什么解释吗?

【问题讨论】:

您是否检查过系统上的当地时间设置? 客户端/服务器在同一台机器上:两者都是 edt -4 小时(mtl 时间)... 绝对是时区转换问题。一方面将时间视为UTC,另一方面将转换为本地时间。我们在与第 3 方系统的某些客户端/服务器集成中遇到了这个问题。死的赠品是加到其他时间的“19:00”,正好是5个小时的时差(实际上不是一整天)。 浏览器端我得到了一个新日期:2015 年 7 月 24 日星期五 23:49:26 GMT-0400 (EDT)。在我得到的服务器上:Fri Jul 23:49:26 EDT 2015. 我认为东部夏令时 (EDT) = GMT-4 (USA + Canada) 如果您使用 Postman 等工具查询您的服务,日期是否不正确?就我而言,问题出在 restTemplate 客户端,而不是在服务器中。 【参考方案1】:

我在 java 中遇到了同样的问题。您可以使用 ObjectMapper 设置为默认时区

ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
mapper.setTimeZone(TimeZone.getDefault());

这里的解决方案:Jackson @JsonFormat set date with one day less

完整的配置类:

@Configuration
@EnableWebMvc
public class WebMvcConfiguration implements WebMvcConfigurer 
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) 
    for (HttpMessageConverter converter : converters) 
        if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) 
            ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
            mapper.registerModule(new Hibernate5Module());
            mapper.setTimeZone(TimeZone.getDefault());
        
    

【讨论】:

【参考方案2】:

从日期选择器中选择日期时,我在 JavaScript 中遇到了同样的问题。我使用 .toString() 方法格式化了字段,但该函数给了我一个不同的日期(我也搞砸了一天)。像这样:

var mydate = new Date('2020-04-03'); console.log(mydate.toString());

//Thu Apr 02 2020 20:00:00 GMT-0400 (Eastern Daylight Time)

我改用 .toUTCString() 修复它。

var mydate = new Date('2020-04-03');

console.log(mydate.toUTCString());

//Fri, 03 Apr 2020 00:00:00 GMT

【讨论】:

【参考方案3】:

有同样的问题。使用邮递员验证客户端不是罪魁祸首。似乎杰克逊使用的时区与系统的时区存在问题。不得不更改 Jackson 配置以补偿日期

@Configuration

public class JacksonConfig 

    @Bean
    @Primary
    public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() 
        final Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder = new Jackson2ObjectMapperBuilder();
        jackson2ObjectMapperBuilder.timeZone(TimeZone.getDefault());
        jackson2ObjectMapperBuilder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
        jackson2ObjectMapperBuilder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return jackson2ObjectMapperBuilder;
    


【讨论】:

【参考方案4】:

AimZ 的答案是我指出这一点的原因,但我将这三行添加到我的 application.properties 文件中并实现了同样的效果

spring.jackson.date-format=yyyy-MM-dd

spring.jackson.serialization.write-dates-as-timestamps:false

spring.jackson.time-zone:EST

【讨论】:

【参考方案5】:

根据JacksonFAQDateHandling页面:

与 TimeZone (java.util.Calendar) 关联的所有时间对象 等)杰克逊构造使用标准时区(GMT),不是 本地时区(无论是什么)。即:杰克逊默认为 使用 GMT 进行所有处理除非另有明确说明。

在您的情况下,日期似乎已自动转换为 GMT/UTC。尝试明确提供您的本地时区以避免 UTC 转换 [如问题中所述这个时间怎么会相差 9 小时? (5 小时、3 小时等) 在同一页]:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd/MM/yyyy", timezone="EST")

其次,我认为您正在使用Date.toString() 打印日期。 Note java Date 类与时区无关,但其toString() 方法在打印前使用系统的默认时区。

这里看起来24/07/2015 00:00 UTC 正在被toString() 转换为23/07/2015 19:00 EST。这两个都代表相同的时刻时间,但在不同的时区。

【讨论】:

我不使用 toString(),但是当@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy") 时,可能会调用 toString。有没有标准的解决方案来管理这个?只保留 gmt 日期...但需要知道某处用户的时区才能正确显示日期。也许某些东西可以与 java 8 或 joda 的新日期一起使用? 最佳实践是将日期/时间信息以 UTC 格式存储在数据库中,并存储用户的时区。然后在向用户显示日期时使用该时区或在存储前删除时区偏移量。有很多文章列出了这种方法的好处,即应用程序可以支持不同的时区。 Java8 Date API 提供了一组新的类来处理日期/时间。这是一篇关于 Java8 Date API dzone.com/articles/deeper-look-java-8-date-and 的好文章。 Java8 或 Joda 简化了日期/时区处理。

以上是关于失去了一天的约会的主要内容,如果未能解决你的问题,请参考以下文章

泪目了,记录一下改了一天的bug

ubuntu16.04 装了一天的gitlab

VCenter的经验教训-为了偷懒5分钟结果花了一天的时间来查错

一个智障安装了一天的python和graphlab的血泪史

花了一天的时间给粉丝做了一个小米官网(高仿)

花了一天的时间给粉丝做了一个小米官网(高仿)