The Gopher character is based on the Go mascot designed by Renée French.
Gopherのイラストはegonelbre/gophersを利用しました。
はじめに
TIG/EXユニット所属の宮永です。 Go 1.20連載の4本目です。
Go 1.20 Release Notesに記載のMinor changes to the libraryのtimeパッケージのアップデート4点について解説します。
1. layoutにDateTime,DateOnly,TimeOnlyが追加された
Proposalはこちらのissueでされています。
Goの日時表現ですが、他の多くの言語とは勝手が異なります。
今回のアップデートを確認する前に他の言語とGoとの日時表現の違いについて確認します。
例えば、Pythonでyyyy-mm-ddという形式でフォーマットをかける場合は以下の様にします。
from datetime import datetime |
Rustの場合は以下の様にします。
use chrono::Utc; |
いずれの場合も文字列%Y-%m-%dを与えてフォーマットしています。
ではGoの場合はどうでしょうか。
package main |
2006-01-02?
はじめて見たとき2006-01-02って何がなんだかわかりませんでした。
ググってみるとこんな記事がありました。
Goのtimeパッケージのリファレンスタイム(2006年1月2日)は何の日?
答えは単純だ。これはアメリカ式の時刻の順番なのだ。”1月2日午後3時4分5秒2006年”(つまり「自然な順番」で1, 2, 3, 4, 5, 6)を指しているのである。Go開発者のRob Pikeさんがgolang-nutsメーリングリストで、最初からよく考えていればこの順番にはしなかったと言っていたが(英語圏でもイギリスとかだと違う順番だしね)、もうその順番になっているので変えられないし、それにきちんと文章化もされているともコメントしていた。従ってこれは単純にそういうものだと思うしかなさそうだ。
そんな馬鹿な!と思いましたが受け入れるしかありません。正直2006-01-02の文字列、私は覚えられないので毎度コピー&ペーストしてます。
▼おとなりのチームにも同じ悩みを抱えている方がいました
(その気持ちとてもわかります!!!)
今回のアップデートでyyyy-mm-ddは以下の様にできます。
package main |
これなら私でも覚えられます。
些細なアップデートですが、待ち望んでいた方は多かったのではないでしょうか。
今回追加された定数ですが、それぞれの以下のように定義されています。
DateTime = "2006-01-02 15:04:05" |
2. Time.Compareメソッドの追加
Proposalはこちらのissueでされています。
Proposalを立てた方の主張をまとめると
「Time型の比較には
Before()、Equal()、After()の3つがあるが、これはそれぞれ<、==、>に相当する。以前、以後を表す<=、>=のメソッドもほしい!!」
ということです。たしかに以前、以後というメソッドがないため、Go1.20がリリースされる前までは
以前を表すのに!x.After(y)(>の否定)で<=となる)とするしかありませんでした。
x.Equal(y) || x.Before(y)でもいいですね
今回Time.Compareメソッドの追加により以前、以後は以下の様に表現することが可能になりました。
以前(xはyよりも前) ⇒
x.Compare(y)<=0以後(xはyよりも後) ⇒
x.Compare(y)>=0
CompareメソッドはGoの他のライブラリも同じようなルールで実装されているため、使い勝手も良さそうです。今後頻繁に使う機会が出てきそうです。
3. Parseでナノ秒以下の入力の精度は無視する様になった
issueはこちらです。
issueにかかれているコードをそのまま引用します。
package main |
入力として0が10個並んでおり、厳密にいえばRFC3339Nanoが期待している桁数よりも多い状況です。
このコードの出力としては両者とも2021-09-29 16:04:33 +0000 UTC <nil>を期待していますが、実際には以下の様に出力されます。
2021-09-29 16:04:33 +0000 UTC <nil> |
Go 1.20では、2つ目の例でエラーとならないように、ナノ秒以下の精度が入力の場合には無視するようになります。
4. Time.MarshalJSONメソッドのRFC3339への準拠がより厳格になった
あれTime.Marshalだけ?Time.Unmarshalはいいの?
と思ったのですが、こちらのissueに経緯が書かれていました。
こちらのissueの対応でTime.UnmarshalとTime.MarshalのRFC3339への準拠がより厳格になったということですが、Time.Unmarshalの対応でAWS SDKのテストでエラーがでてしまうという事態になったようです。そのためTime.Unmarshalについてはロールバックされ、Go1.20ではTime.MarshalのみGo 1.20 Release Notesに記載されているということみたいです。
こちらのissueによると既存のParseにはいくつか問題があるようで、もともとはこの問題に対応するためにTime.Unmarshalで厳格な対応を入れたかったようです。
例えば、現行のParseでは少数部の.と,を区別していないようで、どちらもエラーなくParseされるようです。
import ( |
0000-01-01 00:00:00 +0000 UTC |
他には時間の桁が1桁を許容するという問題もあるようで、00:00:00.000Zと書くべきところを0:00:00.000ZとしてもParseされるようです。
package main |
0000-01-01 00:00:00 +0000 UTC |
確かにこのままでは定義が明確ではなくなるため対応が必要そうですが、AWS SDKのテストでエラーがでてくるとなると影響は大きそうです。timeはGo1.21でも変更がありそうですね。
まとめ
本記事ではGo 1.20リリースのtimeパッケージのアップデートについて解説しました
- layoutに
DateTime,DateOnly,TimeOnlyが追加された Time.Compareメソッドの追加によって以前、以後が表現できるようになったParseでナノ秒以下の入力の精度は無視する様になったTime.MarshalJSONメソッドのRFC3339への準拠がより厳格になった
個人的にはlayoutに定数が追加されたアップデートが地味に嬉しかったです。😀
次は辻さんの HTTP ResponseControllerです。