Java 使用BeanUtils.copyProperties时进行时区转换

Java 使用BeanUtils.copyProperties时进行时区转换,java,hibernate,timezone,date-conversion,apache-commons-beanutils,Java,Hibernate,Timezone,Date Conversion,Apache Commons Beanutils,我有一个Hibernate映射的模型类,如下所示 @Entity @Table(name = "USER") public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "User_SEQ") @SequenceGenerator(sequenceName = "User_SEQ", allocationSi

我有一个Hibernate映射的模型类,如下所示

@Entity
@Table(name = "USER")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "User_SEQ")
    @SequenceGenerator(sequenceName = "User_SEQ", allocationSize = 1, name = "User_SEQ")
    private Integer id;

    private Date createdOn;
}
@Test
public void testBeanUtilsDateConverter() throws Exception {
    System.out.println("\ntestBeanUtilsDateConverter - Start");
    Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11, 18, 30, 10).getTime();
    Date newDate = new Date();

    DateConverter converter = new DateConverter();
    converter.setTimeZone(TimeZone.getTimeZone("Europe/Copenhagen"));

    BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
    beanUtilsBean.getConvertUtils().deregister(java.util.Date.class);
    beanUtilsBean.getConvertUtils().register(converter, java.util.Date.class);

    System.out.println(newDate);
    BeanUtils.copyProperties(newDate, date);
    System.out.println(date);
    System.out.println(newDate);

    System.out.println("testBeanUtilsDateConverter - End");
}
我有另一个模型类,如下所示,用于RESTAPI的响应。该类的对象本质上被序列化为JSON

public class UserDTO {
    private Integer id;

    private Date createdOn;
}
由于变量名相同,我使用BeanUtils.copyProperties将所有字段的值从User复制到UserDTO(为了简单起见,目前仅显示上面的2个字段)

数据以GMT格式存储在数据库中,因此createdOn字段包含GMT格式的时间戳。我想返回本地时区的日期,例如“欧洲/哥本哈根”。为此,我使用以下代码(使用apache commons)

代码已执行,但userDTO仍包含GMT格式的日期。时区转换不起作用。我错过了什么

编辑1:

我已尝试通过手动传递日期进行检查,如下所示

@Entity
@Table(name = "USER")
public class User implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "User_SEQ")
    @SequenceGenerator(sequenceName = "User_SEQ", allocationSize = 1, name = "User_SEQ")
    private Integer id;

    private Date createdOn;
}
@Test
public void testBeanUtilsDateConverter() throws Exception {
    System.out.println("\ntestBeanUtilsDateConverter - Start");
    Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11, 18, 30, 10).getTime();
    Date newDate = new Date();

    DateConverter converter = new DateConverter();
    converter.setTimeZone(TimeZone.getTimeZone("Europe/Copenhagen"));

    BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
    beanUtilsBean.getConvertUtils().deregister(java.util.Date.class);
    beanUtilsBean.getConvertUtils().register(converter, java.util.Date.class);

    System.out.println(newDate);
    BeanUtils.copyProperties(newDate, date);
    System.out.println(date);
    System.out.println(newDate);

    System.out.println("testBeanUtilsDateConverter - End");
}
输出:

testBeanUtilsDateConverter - Start
Fri Jun 02 14:04:08 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testBeanUtilsDateConverter - End
testCustomDateConverter - Start
Instantiating MyDateConverter
Fri Jun 02 14:04:09 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testCustomDateConverter - End
因此BeanUtils肯定是在将日期复制到目标,但是转换器要么没有被调用,要么由于某种原因没有执行任何操作

EDIT2-使用自定义转换器

class MyDateConverter implements Converter {

    public MyDateConverter() {
        System.out.println("Instantiating MyDateConverter");
    }

    @Override
    public Object convert(Class Date, Object value) {
        System.out.println("Inside convert()");
        if (value == null) {
            System.out.println("Value is null");
            return (Date) null;
        } else {
            System.out.println("Doing date conversion");
            Date date = new GregorianCalendar(2015, Calendar.JANUARY, 12, 9, 45, 15).getTime();
            return date;
        }
    }
}

@Test
public void testCustomDateConverter() throws Exception {
    System.out.println("\ntestCustomDateConverter - Start");
    Date date = new GregorianCalendar(2014, Calendar.FEBRUARY, 11, 18, 30, 10).getTime();
    Date newDate = new Date();

    BeanUtilsBean beanUtilsBean = BeanUtilsBean.getInstance();
    beanUtilsBean.getConvertUtils().deregister(java.util.Date.class);
    beanUtilsBean.getConvertUtils().register(new MyDateConverter(), java.util.Date.class);

    System.out.println(newDate);
    BeanUtils.copyProperties(newDate, date);
    System.out.println(date);
    System.out.println(newDate);

    System.out.println("testCustomDateConverter - End");
}
输出:

testBeanUtilsDateConverter - Start
Fri Jun 02 14:04:08 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testBeanUtilsDateConverter - End
testCustomDateConverter - Start
Instantiating MyDateConverter
Fri Jun 02 14:04:09 IST 2017
Tue Feb 11 18:30:10 IST 2014
Tue Feb 11 18:30:10 IST 2014
testCustomDateConverter - End

同样的结果。自定义转换器正在实例化,但未调用convert方法。我甚至尝试了一个定制的长转换器来检查它是否与使用Date类有关,但即使这样也没有被调用。注册部分缺少BeanUtils无法调用重写的转换函数的内容。

因此,如果我理解,您希望在数据库中以GMT格式存储日期。。。但是当用户访问数据时,它应该显示在他们自己的时区中?日期存储在数据库中的GMT中。用户向服务器发出RESTAPI调用,并在请求头中发送其时区和日期格式信息。服务器从数据库检索数据,并需要将日期转换为用户的时区,然后再将其作为JSON响应发送回用户。这是一种非常常见的情况。我本可以一个字段一个字段地复制,并使用SimpleDataFormat进行转换,但我想使用BeanUtils.copyProperties进行转换,以便由默认值完成。您是否手动测试了日期转换器?日期不包含时区(但这是一个常见的误解,因此请不要感到羞愧:-)虽然一个
GregorianCalendar
可以,但我要做的是切换到现代日期和时间类,并使用一个
ZonedDateTime
。也许您甚至可以说服Hibernate将日期时间存储为另一个现代类
Instant
。然后转换将非常简单(也可以进行日期转换)。其他选项,只需在
User.createdOn
中存储为
Instant
,并在向用户显示时仅格式化为哥本哈根时区。我想我会考虑一下这个清洁工。