java - 将数据库时间戳列映射到 UTC 日历 (JPA) 并通过 WebService (jax-ws) 将其作为 UTC 日期传递

标签 java jpa timezone jax-ws

这听起来像是一项简单的任务。
从数据库获取 UTC 时间戳值并通过 Web 服务将其作为 UTC 日期传递。

我们有时间戳列 DATE_COLUMN 并在其中存储 UTC 时区的时间。

有了 JPA,我们用

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

因为我们必须通过 UTC 网络服务(Jax-ws 2.0)传递这个时间,所以我们有 getDate 和 setDate 方法。
我们对 getDate 感兴趣。

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

   return calendar;
}

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

这里举个例子来说明。
DATE_COLUMN 中的值等于“30.11.09 16:34:48,833045000”,当我将其转换为 UTC 时,我得到“2009-11-30T14:34:48.833Z”。
相差2小时。这是因为我的默认时区是“欧洲/赫尔辛基”。

如果您只想将“DATE_COLUMN”映射到 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;
}

其次。通过 Web 服务将 dateValue 作为 Long 传递。这还不错,只是我们在 wsdl 中丢失了字段的真实类型。

我想象中的解决方案是

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

但我倾向于认为某处是真实的。我希望你能指出这一点。

最佳答案

我们决定使用以下解决方案。
使用 Date 从数据库中检索日期。这是因为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 字段启用此规则,我们像这样添加了特定于包的设置。

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

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

关于java - 将数据库时间戳列映射到 UTC 日历 (JPA) 并通过 WebService (jax-ws) 将其作为 UTC 日期传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1821104/

相关文章:

c++ - 使用 C++ 在 Windows 中获取时区

java - FirebaseError 异常电子邮件/密码身份验证

java - Yocto 构建上的 Oracle JDK 安装

java - 检查 objekt 是否是数组

java - JPA 多对一在引用表中具有常量值

java - QueryDSL 是否可以在生成的类中使用抽象类方法?

SQL Server 作业/时间表 - 美国与英国夏令时调整

java - Android 按钮背景图像更改回 XML 中的状态

java - 实体管理器提交的性能不佳 - 指数

javascript - 如何将日期从一个时区转换为另一个时区