这听起来像是一项简单的任务。
从数据库获取 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/