java 将数据库时间戳列映射到 UTC 日历 (JPA) 并通过 WebService (jax-ws) 将其作为 UTC 日期传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1821104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Map Database timestamp column to UTC Calendar (JPA) and pass it as UTC date via WebService (jax-ws)
提问by Mykola Golubyev
This sounds like a simple task.
Get UTC timestamp value from DB and pass it as UTC date via Web Service.
这听起来像是一项简单的任务。
从 DB 获取 UTC 时间戳值并通过 Web 服务将其作为 UTC 日期传递。
We have timestamp column DATE_COLUMN and store there time in UTC time zone.
我们有时间戳列 DATE_COLUMN 并将时间存储在 UTC 时区。
With JPA we get this time with
使用 JPA,我们得到了这次
@Column(name = "DATE_COLUMN")
private java.sql.Timestamp dateValue;
And as we have to pass this time via Web Service in UTC (Jax-ws 2.0) we have getDate and setDate methods.
We are interested in getDate.
因为我们必须通过 UTC (Jax-ws 2.0) 中的 Web 服务来传递这个时间,所以我们有 getDate 和 setDate 方法。
我们对 getDate 感兴趣。
public Calendar getDate()
{
Calendar calendar = Calendar.getInstance(utcTimeZone);
calendar.setTimeInMillis(dateValue.getTime());
return calendar;
}
This doesn't work as you may think it should.
And this is because application's default time zone is not 'UTC'.
这并不像您认为的那样工作。
这是因为应用程序的默认时区不是“UTC”。
Here is an example for clarification.
Value in the DATE_COLUMN equals to "30.11.09 16:34:48,833045000", when I translate it to UTC I get "2009-11-30T14:34:48.833Z".
The difference is 2 hours. And this is because my default time zone is "Europe/Helsinki".
这里是一个澄清的例子。
DATE_COLUMN 中的值等于“30.11.09 16:34:48,833045000”,当我将其转换为 UTC 时,我得到“2009-11-30T14:34:48.833Z”。
相差2小时。这是因为我的默认时区是“欧洲/赫尔辛基”。
Same problem if you just want to map 'DATE_COLUMN' to Calendar
如果您只想将“DATE_COLUMN”映射到相同的问题 Calendar
@Column(name = "DATE_COLUMN")
@Temporal(TemporalType.TIMESTAMP)
private Calendar dateValue;
public Calendar getDate()
{
calendar.setTimeZone(utcTimeZone);
return calendar;
}
I don't want to change application's time zone because it doesn't look like the solution.
我不想更改应用程序的时区,因为它看起来不像解决方案。
By now we have only two options.
到目前为止,我们只有两个选择。
First. Calculate offset between application's time zone and UTC and add it manually after automatic subtraction in the calendar.setTimeZone.
首先。计算应用程序的时区和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;
}
Second. Pass dateValue as Longvia Web Service. Which is not bad except that we lose real type of the field in wsdl.
第二。Long通过 Web 服务传递 dateValue 。除了我们在 wsdl 中丢失了字段的真实类型之外,这还不错。
My imaginary solution is
我想象的解决方案是
@Column(name = "DATE_COLUMN")
@Temporal(type = TemporalType.TIMESTAMP, timezone = 'UTC')
private Calendar dateValue;
But I tend to think that there is the real one somewhere. And I hope you can point it out.
但我倾向于认为在某处有真正的。我希望你能指出来。
回答by Mykola Golubyev
We decided to use following solution.
Use Datefor retrieving date from database. It is because Dateis timezoneless type.
我们决定使用以下解决方案。
使用Date从数据库中检索日期。这是因为Date是无时区类型。
@Column(name = "DATE_COLUMN")
@Temporal(TemporalType.TIMESTAMP)
private Date dateValue;
public Date getDate()
{
return dateValue;
}
And to send it via WebService in UTC (jax-ws) we created UtcTimestampAdapterto change zone from application's default to UTC in the marshaling phase.
为了在 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();
}
}
Then to enable this rule to all Datas fields in the module we added package specific setting like so.
然后为了Data在模块中的所有s 字段中启用此规则,我们添加了特定于包的设置,如下所示。
@XmlJavaTypeAdapter(value = UtcTimestampAdapter.class, type = Date.class)
@XmlSchemaType(name = "dateTime", type = XMLGregorianCalendar.class)
package com.companyname.modulename;
That's it. Now we have generic solution which encapsulate all logic in one place. And if we want to send timezoneless dates as UTC via web service in some other module we will just annotate certain package.
而已。现在我们有了将所有逻辑封装在一个地方的通用解决方案。如果我们想通过其他模块中的 Web 服务将无时区日期作为 UTC 发送,我们将只注释某些包。
回答by David Rabinowitz
If you need the java process to run at the UTC timezone, the easiest way to do so is by adding the following JVM parameter:
如果您需要 Java 进程在 UTC 时区运行,最简单的方法是添加以下 JVM 参数:
-Duser.timezone=UTC
回答by freewill
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));seems to be affecting the entire JVM.
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));似乎正在影响整个JVM。
This will cause other applications fail if they were expecting local time
如果他们期望本地时间,这将导致其他应用程序失败
回答by Hank
Another solution is to set the default timezone for the application only in a @StartupBean:
另一种解决方案是仅在以下位置为应用程序设置默认时区@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"));
}
}
From then on, all interpretation of Date objects will be based on UTC. This includes XML marshalling.
从那时起,Date 对象的所有解释都将基于 UTC。这包括 XML 编组。

