
Go言語で文字列が日付形式か判定!time パッケージを使いこなす
Go言語でユーザー入力やファイルから読み込んだ文字列が、特定の日付形式であるかどうかを判定したい場面は少なくありません。例えば、API から受け取った日付文字列のバリデーションや、ログファイルの日付情報の解析などが挙げられます。
この記事では、Go言語の標準パッケージである time パッケージを利用して、文字列が日付形式かどうかを判定する基本的な方法と、様々な日付フォーマットに対応するためのテクニックを解説します。
1. time.Parse() 関数を使った基本的な判定
time パッケージの Parse() 関数は、指定されたレイアウト(日付フォーマット)に基づいて文字列を time.Time 型の値に変換しようと試みます。変換に成功すれば time.Time オブジェクトと nil のエラーが返り、失敗すればエラーが返ります。このエラーの有無を利用して、文字列が指定された日付形式であるかどうかを判定できます。
package main import ( "fmt" "time" ) func isDate(layout, value string) bool { _, err := time.Parse(layout, value) return err == nil } func main() { dateString1 := "2025-04-18" layout1 := "2006-01-02" // Go のリファレンスレイアウト dateString2 := "18/04/2025" layout2 := "02/01/2006" dateString3 := "2025/04/18 17:54:00" layout3 := "2006/01/02 15:04:05" notDateString := "not a date" fmt.Printf("%q は %q 形式の日付ですか?: %t\n", dateString1, layout1, isDate(layout1, dateString1)) fmt.Printf("%q は %q 形式の日付ですか?: %t\n", dateString2, layout2, isDate(layout2, dateString2)) fmt.Printf("%q は %q 形式の日付ですか?: %t\n", dateString3, layout3, isDate(layout3, dateString3)) fmt.Printf("%q は %q 形式の日付ですか?: %t\n", notDateString, layout1, isDate(layout1, notDateString)) }
ポイント:
time.Parse(layout, value)は、指定されたlayoutにvalueが合致するかどうかを厳密にチェックします。layoutは、Go 言語特有の リファレンスレイアウト を使用します。これは、特定の日付(2006年1月2日 午後3時4分5秒 MST)の各要素を特定の数値で表現したものです。- 年:
2006 - 月:
01(または1for non-padded),Jan,January - 日:
02(または2for non-padded) - 時:
15(24時間形式),03(12時間形式) - 分:
04 - 秒:
05 - タイムゾーン:
MST,-0700,Z0700
- 年:
isDate関数は、time.Parseのエラーがnilであればtrue(日付形式である)、そうでなければfalseを返します。
2. 複数の日付フォーマットに対応する
現実のシステムでは、様々な形式の日付文字列を受け取る可能性があります。複数のフォーマットに対応するためには、それぞれのフォーマットで time.Parse を試行し、最初に成功したものを採用するなどの方法が考えられます。
package main import ( "fmt" "time" ) func parseDateMultiFormat(value string, layouts ...string) (time.Time, error) { for _, layout := range layouts { t, err := time.Parse(layout, value) if err == nil { return t, nil } } return time.Time{}, fmt.Errorf("日付形式が一致しません: %q", value) } func main() { dateString := "18/04/2025" formats := []string{"2006-01-02", "02/01/2006", "2006/01/02"} parsedTime, err := parseDateMultiFormat(dateString, formats...) if err != nil { fmt.Println("エラー:", err) } else { fmt.Println("解析された日時:", parsedTime) } invalidDateString := "2025年4月18日" parsedTimeInvalid, errInvalid := parseDateMultiFormat(invalidDateString, formats...) if errInvalid != nil { fmt.Println("エラー:", errInvalid) } else { fmt.Println("解析された日時:", parsedTimeInvalid) } }
ポイント:
parseDateMultiFormat関数は、可変長引数layoutsで複数の日付フォーマットを受け取ります。- 各フォーマットで
time.Parseを試し、エラーがnilであれば解析成功としてtime.Timeオブジェクトを返します。 - すべてのフォーマットでの解析に失敗した場合、エラーを返します。
3. より厳密な判定のために:ParseStrictLayout()
Go 1.18 以降では、time パッケージに ParseStrictLayout() 関数が導入されました。これは Parse() と似ていますが、より厳密なレイアウトマッチングを行います。例えば、レイアウトにない余分な文字が含まれている場合や、数値がレイアウトの範囲を超えている場合にエラーを返します。
package main import ( "fmt" "time" ) func main() { layout := "2006-01-02" validDate := "2025-04-18" invalidDateExtraChars := "2025-04-18 extra" invalidDateWrongDay := "2025-04-32" _, errValid := time.ParseStrictLayout(layout, validDate) fmt.Printf("%q は厳密な %q 形式ですか?: %t (エラー: %v)\n", validDate, layout, errValid == nil, errValid) _, errExtra := time.ParseStrictLayout(layout, invalidDateExtraChars) fmt.Printf("%q は厳密な %q 形式ですか?: %t (エラー: %v)\n", invalidDateExtraChars, layout, errExtra == nil, errExtra) _, errWrongDay := time.ParseStrictLayout(layout, invalidDateWrongDay) fmt.Printf("%q は厳密な %q 形式ですか?: %t (エラー: %v)\n", invalidDateWrongDay, layout, errWrongDay == nil, errWrongDay) }
ポイント:
time.ParseStrictLayout()は、フォーマットだけでなく、値の妥当性もより厳しくチェックしたい場合に有効です。
4. タイムゾーンを考慮した判定
日付文字列にタイムゾーン情報が含まれている場合、time.Parse() や time.ParseStrictLayout() はそれを解析して time.Time オブジェクトに格納します。タイムゾーンの指定がない場合は、UTC として扱われることに注意が必要です。
特定のタイムゾーンを前提とした判定を行いたい場合は、レイアウトにタイムゾーン情報 (MST, -0700, Z0700) を含める必要があります。
package main import ( "fmt" "time" ) func main() { layoutWithZone := "2006-01-02 15:04:05 MST" dateStringWithZone := "2025-04-18 17:54:00 JST" // JST は Parse では認識されない parsedTimeWithZone, err := time.Parse(layoutWithZone, dateStringWithZone) fmt.Printf("%q を %q で解析 (タイムゾーン考慮): %v (エラー: %v)\n", dateStringWithZone, layoutWithZone, parsedTimeWithZone, err) layoutUTC := "2006-01-02T15:04:05Z" dateStringUTC := "2025-04-18T08:54:00Z" parsedTimeUTC, errUTC := time.Parse(layoutUTC, dateStringUTC) fmt.Printf("%q を %q で解析 (UTC): %v (エラー: %v)\n", dateStringUTC, layoutUTC, parsedTimeUTC, errUTC) }
ポイント:
まとめ
Go言語で文字列が日付形式であるかを判定するには、time パッケージの Parse() 関数(Go 1.18 以降では ParseStrictLayout()) を利用するのが基本です。