JDBC URL 時區設置問題

這篇主要是想要紀錄一下,最近發現的時區設置問題。
我在使用 Java 中的 new Date() 時,寫入 DB 的時間中發現少了時區,也就是少了 8 小時。

Quick Start

我的處理方式:

  • 先檢查 Java 程式是否有處理時區,發現是用系統的時區。
  • 再來檢查 DB Server 的時區,發現不正確後調整。
  • DB 時區調整後,還是有一樣的問題,最後才發現是 JDBC URL 語法問題。

1. Docker 中的時區

我是使用 Docker 來啟動我的 mysql 的。

1
$ docker run -p 3306:3306 -d -e MYSQL_ROOT_PASSWORD=root --name=mysql mysql:5.7

由於一開始沒有設定時區,因此我是進入到 container 調整我的時區的。

  • 進入 container

    1
    $ docker exec -it mysql sh
  • 我們可先使用 date 指令確認一下目前系統時間

    1
    date
  • 使用 tzselect 指令調整時區,執行過程請參考下方:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    # tzselect
    Please identify a location so that time zone rules can be set correctly.
    Please select a continent, ocean, "coord", or "TZ".
    1) Africa
    2) Americas
    3) Antarctica
    4) Asia
    5) Atlantic Ocean
    6) Australia
    7) Europe
    8) Indian Ocean
    9) Pacific Ocean
    10) coord - I want to use geographical coordinates.
    11) TZ - I want to specify the time zone using the Posix TZ format.
    #? 4
    Please select a country whose clocks agree with yours.
    1) Afghanistan 18) Israel 35) Palestine
    2) Armenia 19) Japan 36) Philippines
    3) Azerbaijan 20) Jordan 37) Qatar
    4) Bahrain 21) Kazakhstan 38) Russia
    5) Bangladesh 22) Korea (North) 39) Saudi Arabia
    6) Bhutan 23) Korea (South) 40) Singapore
    7) Brunei 24) Kuwait 41) Sri Lanka
    8) Cambodia 25) Kyrgyzstan 42) Syria
    9) China 26) Laos 43) Taiwan
    10) Cyprus 27) Lebanon 44) Tajikistan
    11) East Timor 28) Macau 45) Thailand
    12) Georgia 29) Malaysia 46) Turkmenistan
    13) Hong Kong 30) Mongolia 47) United Arab Emirates
    14) India 31) Myanmar (Burma) 48) Uzbekistan
    15) Indonesia 32) Nepal 49) Vietnam
    16) Iran 33) Oman 50) Yemen
    17) Iraq 34) Pakistan
    #? 43

    The following information has been given:

    Taiwan

    Therefore TZ='Asia/Taipei' will be used.
    Local time is now: Thu Aug 15 17:14:10 CST 2019.
    Universal Time is now: Thu Aug 15 09:14:10 UTC 2019.
    Is the above information OK?
    1) Yes
    2) No
    #? Yes
    Please enter a number in range.
    #? 1

    You can make this change permanent for yourself by appending the line
    TZ='Asia/Taipei'; export TZ
    to the file '.profile' in your home directory; then log out and log in again.

    Here is that TZ value again, this time on standard output so that you
    can use the /usr/bin/tzselect command in shell scripts:
    Asia/Taipei
  • 複製時區至 /etc/localtime

    1
    cp /usr/share/zoneinfo/Asia/Taipei  /etc/localtime
  • 更新時間

    1
    ntpdate time.windows.com
  • 離開 containerrestart

    1
    docker restart mysql

JDBC 連線 URL 設定

  • 透過 DB Client 驗證時間是否正確,可使用 select now(); 語法。
  • 確認正確後,但是使用 Java 寫法中的 new Date() 時,寫入 DB 的時間還是不正確,少了時區。

後來上網找資料才發現,我使用到了新版本的 mysql driver : mysql-connector-java:8.0.16
新版本的 JDBC URL 需要增加 serverTimezone,調整如下:

1
jdbc:mysql://localhost:3306/gp_lotcenter?serverTimezone=Asia/Taipei

補充說明

在使用 Docker 啟動 mysql 時,可以一開始就帶入本地端的時間配置給 container,如:

1
2
3
4
5
$ docker run -p 3306:3306 -d \
-e MYSQL_ROOT_PASSWORD=root \
-v /etc/localtime:/etc/localtime:ro \
-v /etc/timezone:/etc/timezone:ro \
--name=mysql mysql:5.7

這樣就不用特地進入 container 裡面調整時區了。

今天先到這邊了,如果有其他問題,歡迎寄信討論!謝謝!

謝謝您的支持與鼓勵

Ads