عمود الطابع الزمني خريطة قاعدة البيانات إلى UTC التقويم (JPA) وتمريرها كما UTC التاريخ عبر خدمة ويب (JAX-WS)

StackOverflow https://stackoverflow.com/questions/1821104

  •  10-07-2019
  •  | 
  •  

سؤال

وهذا يبدو وكأنه مهمة بسيطة.
الحصول UTC قيمة الطابع الزمني من DB وتمريرها كما UTC التاريخ عبر خدمة ويب.

لدينا عمود الطابع الزمني DATE_COLUMN وتخزينها هناك وقت في المنطقة الزمنية UTC.

ومع النقابة نحصل هذه المرة مع

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

وكما لدينا لتمرير هذه المرة عبر خدمة ويب في UTC (جاكس-WS 2.0) لدينا getDate وطرق setDate.
ونحن مهتمون في getDate.

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

   return calendar;
}

وهذا لا يعمل كما قد يتصور البعض أنه ينبغي.
وذلك لأن المنطقة الزمنية الافتراضية تطبيق ليست 'بالتوقيت العالمي'.

وهنا مثال للتوضيح.
القيمة في 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;
}

الثانية . تمرير DATEVALUE كما Long عبر خدمة ويب. وهي ليست سيئة إلا أن نفقد نوع حقيقي من الميدان في اختصار.

وبلدي حل وهمي هو

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

ولكن أنا أميل إلى الاعتقاد بأن هناك واحد حقيقي في مكان ما. وأرجو أن نشير بها.

هل كانت مفيدة؟

المحلول

وقررنا استخدام التالية الحل.
استخدام Date لاسترجاع التاريخ من قاعدة البيانات. فذلك لأن Date هو نوع timezoneless.

@Column(name = "DATE_COLUMN")
@Temporal(TemporalType.TIMESTAMP)
private Date dateValue;

public Date getDate()
{
   return dateValue;
}

ولإرساله عبر خدمة ويب في UTC (JAX-WS) أنشأنا 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();
   }
}

وبعد ذلك لتمكين هذه القاعدة على جميع المجالات Datas في وحدة أضفنا إعداد حزمة محددة مثل ذلك.

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

وهذا كل شيء. الآن لدينا حل عام التي تغلف كل منطق في مكان واحد. وإذا أردنا أن ترسل مواعيد timezoneless كما UTC عبر خدمة الإنترنت في بعض وحدة أخرى فلن نحصل سوى تعليم مجموعة معينة.

نصائح أخرى

إذا كنت في حاجة إلى عملية جافا لتشغيل في التوقيت UTC، وأسهل طريقة للقيام بذلك هي من خلال إضافة المعلمة JVM التالية:

-Duser.timezone=UTC

وTimeZone.setDefault(TimeZone.getTimeZone("UTC")); يبدو أن تؤثر على JVM بأكمله.

وهذا سوف يسبب تفشل التطبيقات الأخرى إذا كانوا يتوقعون بالتوقيت المحلي

وهناك حل آخر هو لضبط التوقيت الافتراضي للتطبيق إلا في @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.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top