この記事は新歓ブログリレー2026 6日目の記事です。
22B (4 月から 26M)の @ikura-hamu です。traP では主に Go でサーバーアプリケーションを書いています。この記事では、最近出会った面白いバグについて説明します。
バグの概要
SysAd 班では部内メッセージングサービス traQ をはじめとしていくつかの部内サービスを開発・運用していますが、僕はゲーム管理・配布アプリである traP Collection というサービスのサーバーを書いています。このバグは traP Collection のサーバーのプログラムで起きました。
traP Collection では多くのユニットテストが記述されています。今年の 3 月 1 日に今までは通っていたテストが急に落ちるようになりました。テスト対象の関数とテストケースを抜き出すと以下のようになります。
テスト対象の関数
保存されているゲームのプレイ時間の統計情報を、期間を決めて取得する関数です。あまりに長い期間を指定するとデータベースに負荷がかかることが想定されるので、指定期間が 10 年より長かったらエラーになるようにしています。
func (g *GamePlayLog) GetEditionPlayStats(
ctx context.Context, editionID values.EditionID, start, end time.Time,
) (*domain.EditionPlayStats, error) {
if end.Before(start) {
return nil, service.ErrInvalidTimeRange
}
const maxYears = 10
if start.AddDate(maxYears, 0, 0).Before(end) {
// start と end の間が10 年より長かったらエラー
return nil, service.ErrTimePeriodTooLong
}
//...省略
return stats, nil
}
テストケース
10 年を超えてる期間を指定した際に ErrTimePeriodTooLong を返すことを確かめるためのテストケースです。開始時刻を現在時刻から 10 年と 1 日引いた時刻、終了時刻を現在時刻として、10 年と 1 日の範囲を指定するようになっています。
{
description: "期間が10年を超えるのでErrTimePeriodTooLong",
editionID: editionID,
start: now.AddDate(-10, 0, -1),
end: now,
executeGetEdition: false,
isErr: true,
err: service.ErrTimePeriodTooLong,
},
テストが落ちた内容
本来は ErrTimePeriodTooLong が返ってくるはずですが、そのエラーが返ってこずに処理が先に進んでしまったことによってテストが落ちていました。つまり、「10 年より長かったらエラー」の処理が正しく処理されていないということになります。
バグの原因
おそらく察しのいい方であれば原因に気づくことができたのではないのでしょうか。このバグは、この日が 3 月 1 日であったことと、10 年前の 2016 年がうるう年であったことが組み合わさって発生しています。
再現のためのプログラムと出力は以下のようになります。
package main
import (
"fmt"
"time"
)
func main() {
now := time.Date(2026, 3, 1, 10, 0, 0, 0, time.UTC)
fmt.Println("now:\t\t\t\t\t", now)
start := now.AddDate(-10, 0, -1) // 10年と1日引く
fmt.Println("start=now.AddDate(-10, 0, -1):\t\t", start)
fmt.Println("start.AddDate(10, 0, 0):\t\t", start.AddDate(10, 0, 0)) // 10年と1日引いたものに10年足す
fmt.Println("start.AddDate(10, 0, 0).Before(now):\t", start.AddDate(10, 0, 0).Before(now))
}
now: 2026-03-01 10:00:00 +0000 UTC
start=now.AddDate(-10, 0, -1): 2016-02-29 10:00:00 +0000 UTC
start.AddDate(10, 0, 0): 2026-03-01 10:00:00 +0000 UTC
start.AddDate(10, 0, 0).Before(now): false
https://go.dev/play/p/Oab5QCEL3XP
2026 年 3 月 1 日の 10 年と 1 日前は、2016 年はうるう年ですから、2016 年 2 月 29 日になります。これに 10 年を足すと、2026 年はうるう年ではないですから、2026 年 3 月 1 日に戻ってきてしまいます。うるう年によって生まれたこの差によって、本来は 10 年と 1 日あるはずの差が 10 年ちょうどになってしまい、テストが落ちてしまっていたのでした。
対策
夜遅かったので、次の日まで待ちました。

機能としては 1 日の差があっても特に問題ないので、いったん放置しています。
ただ、時間関係で他のテストが落ちるのはよくあるので、テスト中の現在時刻を使わず時刻を固定するなどの処置は将来的にしたいと思っています。
おわり
新入生のみなさんは、ぜひ traP に入っておもしろバグと一緒に楽しく生活しましょう。入部を楽しみに待っています。
明日の新歓ブログリレーの担当者は、現代表の @zoi_dayoです。
