はじめに
-
ユーザーが指定したコンテンツ表示予約時間の9時間前にコンテンツが表示されてしまう、とユーザーから問合せがありました
-
コンテンツ表示予約時間の抽出SQLが以下の状態となっており、環境構築時にMySQLを日本時間にしておけば今回の問題が起きなかったのでは、と思ったので、とりあえず試してみます
SELECT * FROM contents AS c WHERE c.reservation_time <= NOW();
前提(試した環境)
- ホストOSバージョン: macOS Catalina 10.15.4
- Windows Proであれば、PowerShellでもイケると思います(たぶん)
- dockerバージョン: 19.03.8
- docker for mac(windows)必須
- dockerコンテナのMySQLイメージのバージョン: 5.7系(業務で使用中のものと合わせているので)
※ニワカなので、おかしな実装や考え方をしているかもしれませんが、ご指摘くださると嬉しいです!
実現方法
-
MySQLが載ってるOSのタイムゾーンを日本時間にする
- MySQLはOSのタイムゾーンをデフォルトで見るため
- MySQLのタイムゾーンを日本時間にする
結論
-
「1.MySQLが載ってるOSのタイムゾーンを日本時間にする」がDBコンテナ再起動不要な分オススメ
-
そもそもSQLの
NOW()
関数を使わずに、アプリ側で現在時刻を埋め込むようにすべきなのかも(アプリ側のタイムゾーンを日本時間にしている前提)- 本番環境でDockerを使っていなければ、システムOSを日本時間に変更することを忘れる可能性があるので。。。
アプリ側としてCakePHPを利用しており、`NOW()`を使わない例
# sample.php use Cake\Datasource\ConnectionManager; $now = date('Y-m-d H:i:s'); // アプリ側のタイムゾーンで現在時刻を取得 $sql = "SELECT * FROM contents AS c WHERE c.reservation_time <= '" . $now . "'"; $connection = ConnectionManager::get('default'); $results = $connection->execute($sql)->fetchAll('assoc');
-
execute()
ではなくfind()
メソッドなど使うべきですが…いったんわかりやすさ重視で
(ちなみにはじめにの問合せの修正対応は上記を行いました)
実現手順
MySQLが載ってるOSのタイムゾーンを日本時間にする
-
dockerfileを以下の通り、ホストOSの適当なディレクトリに用意する
(ファイル名: dockerfile)FROM mysql:5.7 RUN apt-get update RUN apt-get install -y tzdata && \ cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime ENV MYSQL_ROOT_PASSWORD root
-
以下のコマンドを実行する
# イメージのビルド(例:`docker build -t mysql57_jst:latest ./`) ホストOS% docker build -t <好きなイメージ名>:<好きなタグ名> <作成したdockerfileがいるパス> # DBコンテナ作成&起動(例:`docker run -d -it --name mysql57 mysql57_jst:latest`) ホストOS% docker run -d -it --name <好きなDBコンテナ名> <作成したイメージ名>:<作成したタグ名>
MySQLのタイムゾーンを日本時間にする
-
以下のコマンドを実行する
# DBコンテナ作成&起動(DBコンテナがなければ) ホストOS% docker run --name <好きなDBコンテナ名> -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7 # DBコンテナに入る ホストOS% docker exec -it <作成したDBコンテナ名> bash # タイムゾーンのテーブルを取得 DBコンテナ% mysql_tzinfo_to_sql /usr/share/zoneinfo/ # タイムゾーンを日本時間にする設定ファイルを新規作成(conf.dディレクトリの配下であればファイル名は何でもOK) DBコンテナ% echo "" >> /etc/mysql/conf.d/etc-mysql.cnf DBコンテナ% sed -i -e "1i [mysqld]\n default-time-zone='Asia/Tokyo'" /etc/mysql/conf.d/etc-mysql.cnf DBコンテナ% exit # DBコンテナの再起動(MySQL単体の再起動ができないので) ホストOS% docker restart <作成したDBコンテナ名>
MySQLのタイムゾーンが日本時間になっているか確認する
-
以下のコマンドを実行する
# DBコンテナに入る ホストOS% docker exec -it <作成したDBコンテナ名> bash # MySQLにログイン DBコンテナ% mysql -u root -p Enter password: root # タイムゾーン確認 mysql> SHOW VARIABLES LIKE '%time_zone%'; # 実際に日本の現在時刻と一致しているか確認 mysql> SELECT NOW();
おわりに
- コロナのせいで、せっかくの連休なのに外出自粛というのはツラいですが、耐えましょう。。。
参考
- 参考というか、本記事はほぼ以下の記事をマネっこしている状況ですが、、、
ありがとうございます!