代码之家  ›  专栏  ›  技术社区  ›  Mykola Golubyev

将数据库时间戳列映射到UTC日历(JPA),并通过WebService(JAX WS)将其作为UTC日期传递。

  •  2
  • Mykola Golubyev  · 技术社区  · 15 年前

    这听起来很简单。
    从数据库中获取UTC时间戳值,并通过Web服务将其作为UTC日期传递。

    我们有时间戳列日期列,并将时间存储在UTC时区。

    这次我们和JPA一起

    @Column(name = "DATE_COLUMN")
    private java.sql.Timestamp dateValue;
    

    由于这次我们必须通过UTC(JAXWS2.0)中的Web服务,所以我们有getDate和setDate方法。
    我们对GetDate感兴趣。

    public Calendar getDate()
    {
       Calendar calendar = Calendar.getInstance(utcTimeZone);
       calendar.setTimeInMillis(dateValue.getTime());
    
       return calendar;
    }
    

    这并不像你认为的那样管用。
    这是因为应用程序的默认时区不是“UTC”。

    下面是一个澄清的例子。
    “日期”列中的值等于“30.11.09 16:34:48833045000”,当我将其转换为UTC时,我得到“2009-11-30T14:34:48.833Z”。
    相差2小时。这是因为我的默认时区是“欧洲/赫尔辛基”。

    如果只想将“日期栏”映射到 Calendar

    @Column(name = "DATE_COLUMN")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar dateValue;
    
    public Calendar getDate()
    {
       calendar.setTimeZone(utcTimeZone);
       return calendar;
    }
    

    我不想更改应用程序的时区,因为它看起来不像解决方案。

    到目前为止,我们只有两个选择。

    弗斯特 .计算应用程序时区和UTC之间的偏移量,并在calendar.setTimeZone中自动减法后手动添加。

    public Calendar getDate()
    {
       Calendar calendar = Calendar.getInstance(utcTimeZone);
       calendar.setTimeInMillis(dateValue.getTime());
    
       int offset = TimeZone.getDefault().getOffset(dateValue.getTime());
    
       calendar.add(Calendar.MILLISECOND, offset);
    
       return calendar;
    }
    

    第二 . 将日期值传递为 Long 通过Web服务。这并不坏,只是我们在WSDL中丢失了字段的实际类型。

    我的想象解是

    @Column(name = "DATE_COLUMN")
    @Temporal(type = TemporalType.TIMESTAMP, timezone = 'UTC')
    private Calendar dateValue;
    

    但我倾向于认为在某个地方真的存在。我希望你能指出。

    4 回复  |  直到 13 年前
        1
  •  4
  •   Mykola Golubyev    15 年前

    我们决定使用以下解决方案。
    使用 Date 用于从数据库中检索日期。这是因为 日期 是无时区类型。

    @Column(name = "DATE_COLUMN")
    @Temporal(TemporalType.TIMESTAMP)
    private Date dateValue;
    
    public Date getDate()
    {
       return dateValue;
    }
    

    并通过我们创建的UTC(JAX WS)中的WebService发送它 UtcTimestampAdapter 在封送阶段将区域从应用程序的默认值更改为UTC。

    public class UtcTimestampAdapter extends XmlAdapter<XMLGregorianCalendar, Date>
    {
       @Override
       public XMLGregorianCalendar marshal(Date date) throws Exception
       {
          GregorianCalendar calendar = new GregorianCalendar();
          calendar.setTime(date);
    
          DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
          XMLGregorianCalendar xmlCalendar = 
             dataTypeFactory.newXMLGregorianCalendar(calendar);
    
          //Reset time zone to UTC
          xmlCalendar.setTimezone(0);
    
          return xmlCalendar;
       }
    
       @Override
       public Date unmarshal(XMLGregorianCalendar calendar) throws Exception
       {
          return calendar.toGregorianCalendar().getTime();
       }
    }
    

    然后启用此规则 Data 在模块中的s字段中,我们像这样添加了特定于包的设置。

    @XmlJavaTypeAdapter(value = UtcTimestampAdapter.class, type = Date.class)
    @XmlSchemaType(name = "dateTime", type = XMLGregorianCalendar.class)
    package com.companyname.modulename;
    

    就是这样。现在我们有了将所有逻辑封装在一个地方的通用解决方案。如果我们想通过其他模块中的Web服务以UTC的形式发送无时区的日期,我们只需注释特定的包。

        2
  •  3
  •   David Rabinowitz    15 年前

    如果您需要Java进程在UTC时区运行,最简单的方法是添加以下JVM参数:

    -Duser.timezone=UTC
    
        3
  •  3
  •   freewill    13 年前

    TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 似乎正在影响整个JVM。

    这将导致其他应用程序在预期本地时间时失败。

        4
  •  0
  •   Hank Jesus M C    13 年前

    另一种解决方案是只在 @StartupBean :

    import java.util.TimeZone;
    import javax.annotation.PostConstruct;
    import javax.ejb.Singleton;
    import javax.ejb.Startup;
    
    @Startup
    @Singleton
    public class StartupBean {
    
        @PostConstruct
        public void initializeTheServer() {
            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        }
    }
    

    从那时起,日期对象的所有解释都将基于UTC。这包括XML编组。