2016-10-16 1 views
2

日付操作に関する他のすべてのQ/Aを読んだことがありますが、私の懸念に満足できる回答はありません。地理的に多様なユーザのための日付操作/保管のためのJavaベストプラクティス

私は地理的に多様なユーザーを対象に、そのクラスとデータの一部でDateを使用するプロジェクトを持っています。問題は、それぞれのタイムゾーンで異なるユーザーの日付を操作する効率的な方法を探していることです。回答のほとんどは Dateのライブラリのライブラリを使用することをお勧めします。まだ理解できません。あなたは従来のJavaではできない操作なので、伝統的なJavaではできないJodaで何ができるか説明できる人は、私はそれを使うことを検討するかもしれません。

最後に、System.currentTimeMillis()を使用してデータベース(任意のデータベース)に日付を保存するというアプローチになりました。これにより、タイムゾーンが日付を格納するためにデータベースを使用しているかどうか心配する必要がなくなります。

SELECT * FROM table1 WHERE date1>=1476653369000 

そして、私はその後、フォーマットうResultSetを取得:私は日付の特定の日付または範囲のためのデータベースを照会したい場合、私は照会するDatelong値を使用してクエリを実行しますlong値は、データを要求するユーザーのタイムゾーンを使用して、読み取れるDateにデータベースから取得されます。

Calendar cal = Calendar.getInstance(); 
cal.setTimeInMillis(resultSet.getLong(1)); 
cal.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta")); 
Date myDate = cal.getTime(); 

は、私が読んだことがあるいくつかの意見によると、一部の人々はは、それが推奨されていない理由を、彼らはすべてのミスを言うためにいくつかの理由でSystem.currentTimeMillis()を格納すると、それにもかかわらず、間違いなくベストプラクティスではないことを強調言います。何か不足していますか?これにより、コンバージョンのパフォーマンス上の問題が発生しますかLong->Date/Date->Long?データベースにDateの代わりにLongを使用すると達成できないユースケースはありますか?誰かがこれについての論理的な説明を投稿できますか?

一方、Dateの値をデータベースに保存すると仮定すると、データベースDateを処理している時間帯について心配することはありませんか?

ありがとうございます。

答えて

2

それはあなたがまたは一般的なケースでは、従来のJavaで行うことができないことができるものについては本当にありません従来のJava

で行うことができない私はジョダで行うことができます。これは、ライブラリAPIが、従来のJavaよりも優れた(より強固で正確な)コードを簡単に作成できるようにする方法についてのものです。

Java 8では、Joda APIは多かれ少なかれ、Java 8 SE標準ライブラリに変更され、組み込まれたパッケージ名でそのままコピー/採用されました。

したがって、Java 8を使用している場合は、新しいAPIを選択する必要があります。そうでなければ、Jodaを使用すると、できるだけアップグレードする/ Java 8に移植するための円滑な道を購入することを検討する必要があります。

いくつかの例:日付と時刻タイプのため

  • 一貫したAPI。
  • 日付/時刻オブジェクトは不変です。操作は、変更された値を表す型の新しいインスタンスを返します。 (Java文字列のように)。これにより、日付/時刻オブジェクトの再利用について簡単に判断することができます。
  • DST &タイムゾーンに依存する値/操作とDST &タイムゾーンには依存しないものを混在させないように設計されています。これにより、一貫して正しく動作するコードを記述するのがずっと簡単になり、コーナーケースはタイムゾーン/ロケール/日付/時刻に依存しません。
  • toString()などのデフォルトの設定では、シリアライズ/デシリアライズは最小限の労力で正しく動作することが期待できます。
  • ロケール/カレンダーシステム間で日時を変換する際に、文化/ロケールに依存するコーナーケースや、まだ気づいていなかったこと(たとえば、伝統的な韓国語カレンダーについて知っていましたか? 。また、豊富な書式設定オプション。
  • 地理的に分散したシステム(システムのデフォルトクロック/タイムゾーン& DSTルールが異なる場合がある)で作業する場合やUTCを使用するためinteropの場合に便利な「絶対」タイムスタンプを表す概念。

EDIT追加する:

は、私が読んだことがあるいくつかの意見によると、一部の人々はSystem.currentTimeMillis()を格納すると、彼らはすべてのミスがなぜそれを言うためにいくつかの理由で、それにもかかわらず、間違いなくベストプラクティスではないことを強調言いますお勧めできません。何か不足していますか?

System.currentTimeMillis()にはいくつかの欠点があります。大きな欠点は、クロックのタイプが悪いと定義されていることです。それは単調時計かもしれない、それはDSTとタイムゾーンの対象となる時計かもしれないし、それはUTC時間かもしれない。必ずしも正確なクロックであるとは限らず、実際にミリ秒まで正確であることは保証されていません。ちょうど現時点の現実のように動作する何かを手にすることが起こっても、にはが基本的に現れます。

これは、複数のサーバーを使用して着信要求を処理する場合、サーバーAの出力が別のサーバー上で実行されている状況でSystem.currentTimeMillis()の出力を処理することを検討する必要がある場合には、 B、次の日、言う。

14

私は日付操作

ませに関する他のQ/Aのすべてを読んでいる、あなたは確かにないはそれらすべてを読みました。

  • あなたは(そのようjava.util.Date & java.util.Calendarなど)レガシー日時クラスとジョダタイムプロジェクトの両方が「java.time」に関するjava.timeクラス(検索のための1890件の結果に取って代わられていることを学んでいるだろう)。
  • 日時の値を時代からのカウントとして追跡しないことを学んだとします。人間は長い整数の意味を日時として解読できないため、デバッグとロギングは非常に困難になります。さまざまなソフトウェアプロジェクトで多くの細かいカウント(全秒、ミリ秒、マイクロ秒、ナノ秒、一日以上など)と少なくともcouple dozen of epochsが使用されているため、エラー、誤解、混乱の原因となる前提でデータが曖昧になります。
  • データベースで日付/時刻型を使用して、日付/時刻値を追跡する方法を学んだとします。
  • 日時の値をUTCで作業して保存することを学んだとします。ロジックによって必要な場合、またはプレゼンテーションのためにユーザーが期待する場合にのみ、タイムゾーンに調整します。 "グローバルに考える、現地で考える"
  • 業界初の努力の中で、レガシーの日時クラスは設計が難しく、混乱し、面倒です。詳細はWhat's wrong with Java Date & Time API?を参照してください。 Joda-Timeは業界初の優れた日時ライブラリであり、Java 8以降に組み込まれたjava.timeクラスの代わりにインスピレーションを受けました。

このすべてがスタックオーバーフローに多く回既にカバーされているように私はやや簡単になるでしょう。

UTCで作業します。 Javaでは、Instantクラスが一般的に使用されることを意味します。 Instantクラスは、タイムライン上のUTCの瞬間を表し、nanoseconds(小数点以下9桁まで)の解像度を表します。

Instant instant = Instant.now(); 

Postgresなどの深刻なデータベースは、日付時刻の値をUTCで追跡します。 JDBCドライバーは、データベース内部で保管されたデータからJavaタイプへの変換の詳細を処理します。 JDBC 4.2以降に準拠するJDBCドライバは、PreparedStatement::setObject &の方法で直接java.time型を処理できます。

非準拠のドライバについては
myPreparedStatement.setObject(… , instant); 

、データベースと通信するためにそのようなjava.sql.Timestampとしてのjava.sqlタイプを使用するようにフォールバックして、古いクラスに追加された新しいメソッドを経由してjava.timeタイプへ/から変換します。データベースが日時の値をどのように扱うかの内部的な詳細は、java.timeとはかなり異なる場合があります。ほとんどの場合、JDBCドライバは、あなたからのすべてのきめ細かな詳細を隠します。しかし、一つの重大な問題は解決策であり、データベースで勉強する必要があります。 java.timeクラスは日付時刻を最大でnanosecondsの解像度で処理しますが、データベースはそうではありません。たとえば、Postgresは解像度はmicrosecondsです。だから、前後に行くということはデータの損失を意味します。データベースと一致するように、java.timeクラスの切り捨てメソッドを使用したいとします。

myPreparedStatement.setTimestamp(… , java.sql.Timestamp.from(instant)); 

したがって、タイムゾーンは関係ありません。だから、 "データベースの日付を扱う際にタイムゾーンを心配する必要はありません"。

同じ瞬間を地域のwall-clock timeのレンズで見たい場合はZoneIdを入力してZonedDateTimeを取得してください。

ZoneId z = ZoneId.of("Asia/Kolkata"); 
ZonedDateTime zdt = instant.atZone(z); 

データベースにバックゾーン日時をとる場合、Instantを抽出します。

任意の瞬間について、日付と時刻は地球儀によってタイムゾーンによって異なります。したがって、契約が切れるなど正確な時期が重要な場合は、日付のみの値を使用することに注意してください。正確な瞬間の日時値を使用するか、または日付のみの横に目的のタイムゾーンを格納して、正確な瞬間を後で計算することができます。

LocalDate ld = LocalDate.of(2016, 1 , 1); 
// Determine the first moment of 2016-01-01 as it happens in Kolkata. 
ZonedDateTime zdt = ld.atStartOfDay(ZoneId.of("Asia/Kolkata")); 
Instant instant = zdt.toInstant(); // Adjust to UTC and store. 

java.timeについて

java.timeフレームワークは、Java 8に組み込まれており、後にされています。これらのクラスは、java.util.Date,.Calendar,java.text.SimpleDateFormatなどの面倒な古いlegacy日時クラスに取って代わります。

Joda-Timeプロジェクト(現在はmaintenance mode)は、java.timeへの移行を推奨しています。

詳しくはOracle Tutorialをご覧ください。そして、多くの例と説明のためにStack Overflowを検索してください。仕様はJSR 310です。

ここで、java.timeクラスを取得するには?

  • Java SE 8SE 9以降
    • 内蔵しています。
    • バンドルされた実装の標準Java APIの一部です。
    • Java 9には、いくつかのマイナーな機能と修正が加えられています。
  • Java SE 6SE 7
    • java.time機能の多くは、ThreeTen-BackportのJava 6 & 7に戻って、移植されます。
  • Android
    • ThreeTenABPプロジェクトはThreeTen-バックポート具体的にAndroidのため(上記)を適応させます。
    • How to use…を参照してください。

ThreeTen-Extraプロジェクトでは、追加のクラスでjava.timeを拡張します。このプロジェクトは、将来のjava.timeへの追加の可能性を証明する土台です。ここで便利なクラスはInterval,YearWeek,YearQuartermoreなどがあります。

関連する問題