Map-Datenbank Timestamp-Spalte zu UTC Kalender (JPA) und geben sie als UTC-Datum via WebService (JAX-WS)

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

  •  10-07-2019
  •  | 
  •  

Frage

Das klingt wie eine einfache Aufgabe.
Erhalten Sie UTC-Zeitstempel-Wert von DB und geben sie als UTC-Datum via Web Service.

Wir haben Zeitstempel Spalte DATE_COLUMN und speichern es Zeit in UTC-Zeitzone.

Mit JPA bekommen wir diesmal mit

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

Und wie wir dieses Mal über Web-Service in UTC passieren müssen (JAX-WS 2.0) haben wir getDate und setDate Methoden.
Wir interessieren uns für getDate.

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

   return calendar;
}

Das funktioniert nicht, wie Sie vielleicht denken, es sollte.
Und das ist, weil die Standardzeitzone der Anwendung ist nicht ‚UTC‘.

Hier ist ein Beispiel für die Klarstellung.
Wert im DATE_COLUMN gleich zu "30.11.09 16: 34: 48,833045000", wenn ich es zu UTC übersetze ich "2009-11-30T14: 34: 48.833Z".
Der Unterschied beträgt 2 Stunden. Und das liegt daran, dass meine Standard-Zeitzone „Europa / Helsinki“ ist.

Das gleiche Problem, wenn Sie nur abbilden wollen 'DATE_COLUMN' Calendar

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

public Calendar getDate()
{
   calendar.setTimeZone(utcTimeZone);
   return calendar;
}

Ich will nicht Anwendung der Zeitzone ändern, weil es wie die Lösung aussieht nicht.

Mit dem jetzt haben wir nur zwei Möglichkeiten.

Erste . Offset berechnet zwischen Zeitzone der Anwendung und UTC und fügen Sie es manuell nach dem automatischen Subtraktion in der 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;
}

Zweite . Pass DATWERT als Long via Web Service. Was nicht schlecht ist, außer, dass wir wirklichen Typen des Feldes in Wsdl verlieren.

Meine imaginäre Lösung

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

Aber ich neige dazu zu denken, dass es irgendwo die echte ist. Und ich hoffe, dass Sie es heraus zeigen können.

War es hilfreich?

Lösung

Wir entschieden uns folgende Lösung zu verwenden.
Verwenden Sie Date für Datum aus der Datenbank abgerufen werden. Es ist, weil Date timezoneless Typ ist.

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

public Date getDate()
{
   return dateValue;
}

Und es via WebService in UTC zu senden (JAX-WS) wir UtcTimestampAdapter erstellt Zone aus der Anwendung standardmäßig in der Serialisieren Phase UTC zu ändern.

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();
   }
}

Dann diese Regel auf alle Datas Felder zu ermöglichen, in dem Modul wir Paket spezifische Einstellung wie so hinzugefügt.

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

Das ist es. Jetzt haben wir generische Lösung, die alle Logik in einem Ort zu kapseln. Und wenn wir timezoneless Daten als UTC via Web-Service in einem anderen Modul senden möchten wir nur bestimmtes Paket mit Anmerkungen versehen.

Andere Tipps

Wenn Sie den Java-Prozess müssen im UTC-Zeitzone zu laufen, ist der einfachste Weg, dies zu tun ist, indem Sie die folgenden JVM-Parameter:

-Duser.timezone=UTC

TimeZone.setDefault(TimeZone.getTimeZone("UTC")); scheint die gesamte JVM zu beeinflussen.

Dies führt dazu, andere Anwendungen fehlschlagen, wenn sie lokale Zeit erwarten

Eine andere Lösung ist es, die Standard-Zeitzone für die Anwendung nur in einem @StartupBean zu setzen:

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"));
    }
}

Von nun an alle Interpretation von Date-Objekten wird auf UTC basieren. Dazu gehören XML-Rangierung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top