背景
Springboot プロジェクトの国際化中に、ユーザーが選択した時刻と最終的にデータベースに保存された時刻の間に不一致が発生します。プロジェクトの開発および展開中にタイムゾーンが適切に処理されず、時刻変換の問題が発生した可能性があります。 。
まずタイムゾーンとは何かを理解してください。
1.GMT:グリニッジ標準時
グリニッジ標準時:イギリスのロンドンのグリニッジを経度0度の起点として地球を経度15度ごとにタイムゾーンに分け、24のタイムゾーンに分けられ、隣り合うタイムゾーンの差は1時間です; 例: 中国の北京は東 8 区に位置しており、GMT 時間は北京時間より 8 時間遅れています。
協定世界時とは、厳密な計算によって得られる時刻で、秒単位の精度、誤差は0.9秒以内で、GMTよりも正確な世界時刻です。
サマーセービングタイム、すなわちサマータイムは、夏の豊かな光を利用するために時刻を1時間早める制度で、北米やヨーロッパの多くの国がサマータイムを実施しています。
4.CST: 4 つの異なるタイムゾーンの略称:
中部標準時 (米国) UT-6:00
中部標準時 (オーストラリア) UT+9:30 オーストラリア標準時
中国標準時 UT+8:00 中国標準時
キューバ標準時UT-4:00 キューバ標準時
分析する
ユーザー時間データの流れを図のように描く
タイムゾーンには、クライアント、サーバー、JVM など、いくつかの保存場所があります。MySQL
処理: ユーザーのブラウザは、クライアントのタイムゾーンに基づいて現在時刻を取得します ---「時刻パラメーターをサーバーに渡します --」 JVM は、設定に従ってサーバーの現在のタイムゾーン、または独自に設定されたタイムゾーンを選択します - -- " mysql に時刻を保存します。mysql はインストール時に独自のタイムゾーンを持ちます。
要件: 搬入出時の一貫性を確保するのに時間がかかる
解決策:次に、異なるタイム ゾーンを前後に変換できること、またはタイム ゾーンが一貫していて変換が実行されないことを確認する必要があります。
解決プロセス
1.クライアント
これはユーザーのコンピュータです。どのタイム ゾーンを使用するかをユーザーに尋ねることはできないため、これを変更することはできません。ユーザーはさまざまなタイム ゾーンを使用することができます。これが時代の変化の理由であり、不一致を引き起こす根本的な要因でもあります。
2. サーバーとJVM
サーバーには2つの方法があります
(1) JVM はサーバー上にあります。JVM がタイムゾーンを設定しない場合、デフォルトで現在のサーバーのタイムゾーンが選択されます。
(2) JVM タイム ゾーンを設定します。これにより、サーバーのタイム ゾーンがブロックされます。サーバーのタイム ゾーンは、JVM のタイム ゾーンに影響せず、ユーザーのタイム パラメーターのフローにも影響しません。これを選択します。
[オリジナル]Java プロジェクトが UTC タイムスキームを統一
3.MySQL
タイムゾーンを確認してください:show variables
like
'%time_zone%'
;
mysql のタイムゾーンを設定します: MySQL のデフォルトのタイムゾーンは UTC タイムゾーンです
(1) 永続的な変更: mysql 設定ファイル my-default.ini を変更し、default-time-zone='+08:00' を追加し、mysql を再起動します。有効になります。必ず [mysqld] の下に追加してください。追加しないと、不明な変数 'default-time-zone=+8:00' が表示されます。
my-default.ini文件内:
[mysqld]
default-time-zone='+08:00'
(2) 一時的な変更: mysql コマンド set global time_zone='+08:00' を実行します。これはすぐに有効になり、mysql を再起動すると無効になります。
set time_zone = '+8:00';
set global time_zone='+08:00';
タイムゾーン設定の概要: クライアントがタイムゾーンを設定しない場合、ユーザーはタイムゾーンを自由に変更できます--「JVM のタイムゾーンを UTC に設定します---」mysql の永続的なタイムゾーンを UTC に設定します
コード解決プロセス
1. クライアントはローカルタイムゾーンの時間を選択します
2. フロントエンド コンポーネントが UTC タイム ゾーンに変換する時間を決定します。
3. フロントエンドがバックエンドに渡すとき、バックエンドは @DateTimeFormat アノテーションを使用して形式を変換しますが、これはタイムゾーンを処理できません。
@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
private Date date;
4. バックエンド JVM は次のように設定されます。
@SpringBootApplication
public class Application {
@PostConstruct
void started() {
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
5. コードはデータベースの URL に接続します。useLegacyDatetimeCode
パラメータのデフォルトは ですtrue
。手動で設定する必要がありますfalse
。そうしないと無効になります。
spring.datasource.url=jdbc:mysql://localhost:3306/db?useUnicode=true&characterEncoding=utf-8&useLegacyDatetimeCode=false&serverTimezone=UTC
6.mysql はストレージのタイムゾーンを UTC に設定します
7. データベースからサーバーまで、サーバー バックエンド (前のプロセスはランダムに変更されることはなく、必要な場合のみ) は @JsonFormat を使用し、フロントエンドに戻るときにタイム ゾーンを修正します。
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss",
timezone = "GMT+8"
)
private Date date;