tl; dr
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )
.toEpochSecond()
…
LocalDate.now( ZoneId.of( "Africa/Tunis" ) )
.plusDays( 1 )
.atStartOfDay( ZoneId.of( "Africa/Tunis" ) )
.toEpochSecond()
…
"SELECT * FROM orders WHERE placed >= ? AND placed < ? ; "
…
myPreparedStatement.setObject( 1 , start )
myPreparedStatement.setObject( 2 , stop )
java.time
現代のjava.timeに取って代わった、古いレガシーである厄介な古い日時クラスを使用しています。クラスにます。
どうやら、データベースのある整数型の列にモーメントを格納しているようです。それは残念です。代わりに、SQL-standardなどのタイプの列を使用する必要がありますTIMESTAMP WITH TIME ZONE
。しかし、この回答では、私たちが持っているものを扱います。
レコードがミリ秒の分解能で瞬間を表し、1日全体のすべてのレコードが必要な場合は、時間範囲が必要です。私たちはスタートの瞬間とストップの瞬間を持っている必要があります。クエリには日付と時刻の条件が1つしかなく、ペアにする必要がありました。
の LocalDate
クラスは、時刻とタイムゾーンなしの日付のみの値を表します。
日付を決定するには、タイムゾーンが重要です。いつでも、日付は世界中でゾーンごとに異なります。たとえば、パリの真夜中から数分後のフランスは新しい日ですが、まだ「昨日」です。モントリオールケベックです。
タイムゾーンが指定されていない場合、JVMは暗黙的に現在のデフォルトのタイムゾーンを適用します。そのデフォルトはいつでも変更される可能性があるため、結果は異なる場合があります。引数として希望/予想タイムゾーンを明示的に指定することをお勧めします。
指定適切なタイムゾーン名をの形式でcontinent/region
、のようなAmerica/Montreal
、Africa/Casablanca
またはPacific/Auckland
。決してなど3-4文字の略称を使用していないEST
か、IST
そのままではない真の時間帯ではなく、標準化、さらには一意ではありません(!)。
ZoneId z = ZoneId.of( "America/Montreal" ) ;
LocalDate today = LocalDate.now( z ) ;
JVMの現在のデフォルトのタイムゾーンを使用する場合は、それを要求し、引数として渡します。省略した場合、JVMの現在のデフォルトが暗黙的に適用されます。デフォルトは、JVM内の任意のアプリの任意のスレッド内の任意のコードによって実行時にいつでも変更される可能性があるため、明示的にすることをお勧めします。
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
または、日付を指定します。月は数字で設定できます。正月は1月から12月まで1〜12です。
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
または、Month
年の各月に1つずつ、事前定義された列挙オブジェクトを使用します。ヒント:Month
単なる整数ではなく、コードベース全体でこれらのオブジェクトを使用して、コードをより自己文書化し、有効な値を確保し、タイプセーフを提供します。
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
LocalDate
手に、私たちは、次の必要性は一瞬、一日の開始と停止のペアにそれを変換します。1日が00:00:00の時刻から始まると想定しないでください。夏時間(DST)などの異常のため、その日は01:00:00などの別の時間に始まる場合があります。したがって、java.timeにその日の最初の瞬間を決定させます。そのような異常を調べるためににZoneId
引数を渡しますLocalDate::atStartOfDay
。結果はZonedDateTime
です。
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
一般に、期間を定義する最良のアプローチは、開始が包括的で、終了が排他的であるハーフオープンアプローチです。つまり、1日は最初の瞬間から始まり、翌日の最初の瞬間までですが、それは含みません。
ZonedDateTime zdtStop = ld.plusDays( 1 ).atStartOfDay( z ) ; // Determine the following date, and ask for the first moment of that day.
1日中のクエリでは、SQLコマンドを使用できませんBETWEEN
。そのコマンドは完全に閉じた([]
)(最初と最後の両方が含まれます)であり、必要に応じて半分開いた([)
)です。私たちは、基準のペアを使用>=
し、<
。
列の名前が不適切です。さまざまなデータベースで予約されている数千語を避けてください。placed
この例で使用してみましょう。
あなたのコードは?
私たちの瞬間を指定するためにプレースホルダーを使用しているはずです。
String sql = "SELECT * FROM orders WHERE placed >= ? AND placed < ? ; " ;
しかしZonedDateTime
、オブジェクトは手元にありますが、データベースは上記のように整数を格納しているようです。あなたがいる場合していたあなたのコラムを定義し、適切に我々は単に渡すことができますZonedDateTime
JDBC 4.2以降をサポートする任意のJDBCドライバでオブジェクトを。
しかし、代わりに、秒単位でエポックからのカウントを取得する必要があります。私はあなたのエポック参照日がUTCで1970年の最初の瞬間であると仮定します。ZonedDateTime
クラスはナノ秒の分解能を備えているため、データ損失の可能性に注意してください。以下の行では、小数秒は切り捨てられます。
long start = zdtStart().toEpochSecond() ; // Transform to a count of whole seconds since 1970-01-01T00:00:00Z.
long stop = zdtStop().toEpochSecond() ;
これで、これらの整数を上記で定義したSQLコードに渡す準備ができました。
PreparedStatement ps = con.prepareStatement( sql );
ps.setObject( 1 , start ) ;
ps.setObject( 2 , stop ) ;
ResultSet rs = ps.executeQuery();
から整数値を取得するとResultSet
、Instant
オブジェクト(常にUTCで)またはZonedDateTime
オブジェクト(タイムゾーンが割り当てられている)に変換できます。
Instant instant = rs.getObject( … , Instant.class ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
java.timeについて
java.timeのフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは面倒古い取って代わるレガシーのような日付時刻クラスをjava.util.Date
、Calendar
、& SimpleDateFormat
。
ジョダタイムプロジェクトは、今でメンテナンスモードへの移行をアドバイスjava.timeのクラス。
詳細については、Oracleチュートリアルを参照してください。また、スタックオーバーフローで多くの例と説明を検索してください。仕様はJSR 310です。
java.timeクラスはどこで入手できますか?
ThreeTen-エクストラプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、java.timeに将来追加される可能性があることを証明する場です。あなたはここにいくつかの有用なクラスのような見つけることがInterval
、YearWeek
、YearQuarter
、および多くを。