PostgreSQLに日付と時刻のデータを保存するための戦略は、IMOが次の2つの点に依存する必要があります。
- ソリューションは絶対にすべきではありません サーバーまたはクライアントのタイムゾーン設定によって異なります。
- 現在、PostgreSQL(ほとんどのデータベースと同様)には、フルを格納するためのデータ型がありません。 タイムゾーン付きの日時。したがって、
Instant
のどちらかを決定する必要があります またはLocalDateTime
データ型。
私のレシピは次のとおりです。
物理的なインスタントを記録する場合 特定のイベントが発生したとき(真の「タイムスタンプ "、通常は作成/変更/削除イベント)、次に使用します:
- Java:
Instant
(Java 8、またはJodatime)。 - JDBC:
java.sql.Timestamp
- PostgreSQL:
TIMESTAMP WITH TIMEZONE
(TIMESTAMPTZ
)
(PostgreSQL固有のデータ型をWITH TIMEZONE
にしないでください /WITHOUT TIMEZONE
混乱させてください:実際にタイムゾーンを保存しているものはありません)
いくつかの定型コード:以下はps
を想定しています PreparedStatement
です 、rs
ResultSet
およびtzUTC
静的なCalendar
UTC
に対応するオブジェクト タイムゾーン。
public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Instant
を書く データベースへTIMESTAMPTZ
:
Instant instant = ...;
Timestamp ts = instant != null ? Timestamp.from(instant) : null;
ps.setTimestamp(col, ts, tzUTC); // column is TIMESTAMPTZ!
Instant
を読む データベースからTIMESTAMPTZ
:
Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? ts.toInstant() : null;
PGタイプがTIMESTAMPTZ
の場合、これは安全に機能します (その場合、calendarUTC
そのコードには効果がありません;ただし、デフォルトのタイムゾーンに依存しないことを常にお勧めします。「安全に」とは、結果がサーバーまたはデータベースのタイムゾーンに依存しないことを意味します。 、またはタイムゾーン情報:操作は完全に元に戻すことができ、タイムゾーン設定に何が起こっても、Java側で最初に持っていたのと同じ「瞬時」を常に取得できます。
タイムスタンプ(物理的なタイムライン上の瞬間)の代わりに、「市民」の現地日時を扱っている場合 (つまり、一連のフィールド{year-month-day hour:min:sec(:msecs)}
)、使用します:
- Java:
LocalDateTime
(Java 8、またはJodatime)。 - JDBC:
java.sql.Timestamp
- PostgreSQL:
TIMESTAMP WITHOUT TIMEZONE
(TIMESTAMP
)
LocalDateTime
を読む データベースからTIMESTAMP
:
Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null )
localDt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);
LocalDateTime
を記述します データベースへTIMESTAMP
:
Timestamp ts = null;
if( localDt != null)
ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
ps.setTimestamp(colNum,ts, tzUTC);
繰り返しになりますが、この戦略は安全であり、安らかに眠ることができます。2011-10-30 23:59:30
を保存した場合 、これらの正確なフィールド(hour =23、minute =59 ...など)は、いつでも取得できます。たとえ明日、Postgresqlサーバー(またはクライアント)のタイムゾーンが変更されたり、JVMまたはOSのタイムゾーンが変更されたりしても、または、お住まいの国がDSTルールなどを変更した場合。
追加:完全な日時指定(ZonedDatetime
)を保存したい場合(当然の要件のようです) :タイムスタンプとタイムゾーン(完全な市民日時情報とタイムゾーンも暗黙的に含まれています)...それでは悪いニュースがあります:PostgreSQLにはこのデータ型がありません(私の知る限り、他のデータベースでもありません) 。おそらくフィールドのペアで、独自のストレージを考案する必要があります。上記の2つのタイプ(非常に冗長ですが、取得と計算には効率的です)、またはそれらの1つにタイムオフセットを加えたもの(タイムゾーン情報が失われ、一部の計算は次のようになります)になります。困難で、一部は不可能です)、またはそれらの1つとタイムゾーン(文字列として。一部の計算は非常にコストがかかる可能性があります)。