2015-09-15 4 views
2

В частности, на SQL-сервере (и я принимаю другие), существует тип datetimeoffset, который может хранить временную метку со смещением other, чем GMT. (Выглядит так: «1998-01-01 15: 00: 00.0000000 +06: 00»)Как сохранить существующий часовой пояс в JPA

Но попытка сохранить календарь в базе данных автоматически преобразует его в GMT (хотя я не могу сказать, кто это делает JPA , Hibernate или sqljdbc), поэтому он выглядит так: «1998-01-01 9: 00: 00.0000000 +00: 00»

Есть ли способ предотвратить это для определенных атрибутов?

+0

есть ли причина, почему вы хотите использовать другое смещение, чем UTC (GMT) =? – AlexWien

+0

Да, я хочу запомнить смещение, которое было дано мне. Так что, когда я отправляю его по электронной почте, он находится в том же самом смещении. (Я хочу, чтобы клиент видел его в своем часовом поясе, а не в GMT, а не в моем.) Я все же хочу сохранить смещение, потому что мне приходится запускать вычисления против других значений в этой таблице, которые находятся в разных часовых поясах. – mike

+0

Я правильно понял, вы не хотите использовать UTC в качестве ссылки ?, так что GMT + 6.0 не желателен? Вам нужна другая ссылка, например EST + 03:00? – AlexWien

ответ

1

Altough могут быть и другие решения с использованием баз данных SQL, я всегда следовать этому подходу:

В базе данных или файла, который я всегда хранить раз в UTC, без исключения. Если часовой пояс необходимо сохранить, например, для пользовательского интерфейса, я сохраняю смещение UTC в дополнительном поле.

Таким образом, у меня есть правильное время, и если необходимо, часовой пояс сохраняется.

+0

Алекс Я не могу просто сказать компании о выделении SQL-таблица «на принципе». Поэтому я спросил, как правильно использовать datetimeoffset, предоставляемый в SQL через интерфейс JPA. Если бы я спросил о правильном дизайне для таблицы, тогда ваш ответ был бы совершенно контекстуальным. Но, поскольку это стоит, вы не предлагаете решение моей нынешней проблемы, просто заявляя, что это не должно быть сделано. Как оказалось, я смог придумать довольно простое решение. – mike

+0

@mike Я предлагаю решение для всех остальных, которые могут определять/изменять свою структуру данных. – AlexWien

1

Найден способ сделать это

package testers.jpa.beans; 

import java.io.Serializable; 
import java.text.ParseException; 
import java.text.SimpleDateFormat; 
import java.util.Calendar; 

import javax.persistence.Basic; 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.NamedQuery; 
import javax.persistence.Table; 
import javax.persistence.Transient; 

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 

@Entity 
@Table(name = "dbo.tester") 
//Ignore the actual calendar object here because the jsonner strips the timezone info from it 
@JsonIgnoreProperties(value = { "date" }) 
@NamedQuery(name = "NameAndOffset.purge", query = "DELETE FROM NameAndOffset") 
public class NameAndOffset implements Serializable { 
    private static final long serialVersionUID = 1L; 
    private String name; 
    private Calendar date; 

    public NameAndOffset() { 

    } 

    public NameAndOffset(String name, Calendar date) { 
     this.name = name; 
     this.date = date; 
    } 

    @Id 
    @Basic 
    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    /** 
    * Return a string representation of the {@link NameAndOffset#date} object.<br/> 
    * This will be used by JPA and the Jsonner to prevent losing the timezone 
    * information<br/> 
    * <br/> 
    * For this to work properly you must tell both the Json mapper and JPA to 
    * ignore anything else that relates to the {@link NameAndOffset#date} field 
    * 
    * @return A String representation of the {@link NameAndOffset#date} field, 
    *   formatted for SQL Server's datetimeoffset data type 
    */ 
    @Basic 
    @Column(name = "date") 
    public String getDateTimeOffset() { 
     return new OffsetDateFormat().formatCalendar(date); 
    } 

    public void setDateTimeOffset(String date) throws ParseException { 
     this.date = new OffsetDateFormat().parseCalendar(date); 
    } 

    //Ignore the actual calendar object here because JPA strips the timezone info from it 
    @Transient 
    public Calendar getDate() { 
     return date; 
    } 

    public void setDate(Calendar date) throws ParseException { 
     this.date = date; 
    } 

    class OffsetDateFormat extends SimpleDateFormat { 

     private static final long serialVersionUID = 1L; 
     private static final String OFFSET_FORMAT = "yyyy-MM-dd HH:mm:ss.S Z"; 

     public OffsetDateFormat() { 
      super(OFFSET_FORMAT); 
     } 

     public Calendar parseCalendar(String source) throws ParseException { 
      //pull out the colon in the offset 
      int timeZoneColon = source.lastIndexOf(":"); 
      String nocolon = source.substring(0, timeZoneColon) + source.substring(timeZoneColon + 1); 

      Calendar cal = Calendar.getInstance(); 

      cal.setTime(parse(nocolon)); 
      //after parsing, the timezone of this DateFormatter changes to whatever was represented in the string 
      //make sure the new calendar reflects this 
      cal.setTimeZone(getTimeZone()); 
      return cal; 
     } 

     public String formatCalendar(Calendar calendar) { 
      setTimeZone(calendar.getTimeZone()); 
      String nocolon = format(calendar.getTime()); 

      //add the colon 
      StringBuffer sb = new StringBuffer(nocolon.substring(0, nocolon.length() - 2)).append(":").append(nocolon.substring(nocolon.length() - 2)); 

      return sb.toString(); 
     } 

    } 

} 
+0

проблема этого решения заключается в том, что вам нужно использовать между или любым другим запросом для фильтрации даты, поскольку он хранится как String в вашей базе данных. – leonardoborges

Смежные вопросы