7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

「Goのtime.Formatによるミリ秒切り捨て」と「MySQLのINSERTによるミリ秒四捨五入」で1秒の誤差が生まれた話

Last updated at Posted at 2022-12-01

背景

2022年春頃にZOZOTOWNでログイン通知機能ログイン履歴機能をリリースしました。QAのフェーズにおいて、「ログイン通知で表示されるログイン時刻」と「ログイン履歴で表示されるログイン時刻」で最大1秒の誤差が生まれるケースがあることが判明しました。どちらの時刻もミリ秒までは表示しない仕様です。1秒とはいえ、これらの値が不一致なのは問題なので原因調査と対策をしました。

原因

ログイン通知で表示されるログイン時刻

ログイン通知で表示されるログイン時刻は、サーバがログインリクエストを受け付けた時の日時です。つまり、Goのアプリケーション上でのみ処理するデータです。アプリケーションでは、その日時を下のようにFormatし、ミリ秒を切り捨てます。

package main

import (
	"fmt"
	"time"
)

func main() {
	t, _ := time.Parse("2006/01/02 15:04:05", "2022/04/05 10:00:00.500")
	fmt.Println(t.Format("2006/01/02 15:04:05"))
}
2022/04/05 10:00:00

ログイン履歴で表示されるログイン時刻

ログイン履歴で表示されるログイン時刻は、一度MySQLのDBにINSERTされたデータをSELECTで取得したデータです。

カラムの型はDATETIMEで、ミリ秒は扱いません。もし、ミリ秒のデータをINSERTするとミリ秒が四捨五入されます。

mysql> INSERT INTO test VALUES (CAST('2022/04/05 10:00:00.500' as datetime));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM test;
+---------------------+
| t                   |
+---------------------+
| 2022-04-05 10:00:01 |
+---------------------+
1 row in set (0.00 sec)

原因まとめ

上記の通り、「ログイン通知で表示されるログイン時刻」はGoのtimeパッケージのFormatでミリ秒以下が切り捨てられるのに対して、「ログイン履歴で表示されるログイン時刻」はMySQLのINSERTによりミリ秒以下が四捨五入されることが原因でした。

対策

ログイン履歴情報をDBにINSERTする前に、時刻情報のミリ秒を切り捨てるように改修しました。

7
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?