这听起来像一个简单的任务 从DB获取UTC时间戳值,并通过Web服务将其作为UTC日期传递。
我们有时间戳列DATE_COLUMN并以UTC时区存储时间。
使用JPA,我们得到的时间是
@Column(name = "DATE_COLUMN")
private java.sql.Timestamp dateValue;
由于我们必须通过UTC服务(Jax-ws 2.0)通过Web服务,我们有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;
但我倾向于认为某处有真实的。我希望你能指出来。
答案 0 :(得分:4)
我们决定使用以下解决方案
使用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,我们将只注释某个包。
答案 1 :(得分:3)
如果您需要在UTC时区运行java进程,最简单的方法是添加以下JVM参数:
-Duser.timezone=UTC
答案 2 :(得分:3)
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
似乎正在影响整个JVM。
如果他们期望当地时间,这将导致其他应用程序失败
答案 3 :(得分:0)
另一种解决方案是仅在@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"));
}
}
从那时起,Date对象的所有解释都将基于UTC。这包括XML编组。