はじめに
こんにちは、StackdriverあらためGoogle Cloud Operations担当者です。Google Cloud Operationsもさることながら、Go Conferenceの運営など、長らくGoコミュニティに関わってきましたが、まだまだ知らないことがあったということを昨日今日で知ったので共有します。
time.minWall
time.minWall
という値があります。
const ( hasMonotonic = 1 << 63 maxWall = wallToInternal + (1<<33 - 1) // year 2157 minWall = wallToInternal // year 1885 nsecMask = 1<<30 - 1 nsecShift = 30 )
これは time
パッケージ内で時刻の起源を設定するための定数値なのですが、これが1885年に設定されているわけです。1900年とかならまだしも、なぜ1885年なのかという疑問が湧いてきます。実際これは自分が気付いたわけではなく、友人の @la_luna_azul がふとしたときに疑問に思っていたのを見て調べてみたら、自分もよくわからなかったわけです。
1885年といえば、思いつくのはBack To The Future 3で過去に戻ったときの年です。偶然の一致とはいえ、この年をわざわざ指定するということは少なからずその影響があったのでは?という期待が湧いてきます。実際、この定数値を決めるにあたっての理由になりそうな記録を探してみると以下の2つが見つかりました。
ここでRuss Coxは次のように回答しています。
OK, this is checked in for Go 1.9. I moved the internal epoch to 1885 (max year 2157) to avoid any possible problem with NTP-epoch-derived times. I also adjusted the design doc to reflect this change and some minor encoding changes.
Thanks for the constructive conversation everyone.
しかし、ここでは1885年に設定したという事実は書いていても、その根拠は書かれていません。Go 1.9でepochのデフォルトを1885年にしたと書いてあるので、そのproposalがあるはずです。探してみると次のproposalが見つかります。
ここでは次のようにコメントされています。
Unix-based systems often use 1970, and Windows-based systems often use 1980. We are unaware of any systems using earlier default wall times, but since the NTP protocol epoch uses 1900, it seemed more future-proof to choose a year before 1900.
なるほどepochがいろいろあるけれど、とりあえず1900年より前にしておけば良さそうだからそうしたと。しかし、そこでわざわざ1885年に設定する理由はありません。もう自分の中では「もうBack To The Futureの年というイースターエッグなんでしょ!」と思ってはいたんですが、やはり確証は欲しいものです。こういうものは聞いてしまうのは無粋かもしれないし、知ったところでなんになるわけではないけど、もう知りたくてたまらない!!
そこでRuss Coxにメールしてみました。するとすぐに返事が返ってきました。
Yes, people talked me into moving it back before 1900, and 1885 was the obvious choice due to its historical significance to Hill Valley, California. :-)
やっぱりBack To The Futureだったのか!!なんかスッキリした!!
http.aLongTimeAgo
こんな質問に答えてくれるRuss Coxは優しいなあと思っていたら、話はこれで終わりではありませんでした。先の返信に続けて、次のような返事があったのです。
See also http.aLongTimeAgo, which is now sadly set to time.Unix(1, 0) but used to be time.Unix(233431200, 0).
// aLongTimeAgo is a non-zero time, far in the past, used for // immediate cancellation of network operations. var aLongTimeAgo = time.Unix(1, 0)
たしかにこれはいま time.Unix(1, 0)
になっています。昔はどうだったんでしょうか。Go 1.8でこの定数が導入されたので見てみると
// aLongTimeAgo is a non-zero time, far in the past, used for // immediate cancelation of network operations. var aLongTimeAgo = time.Unix(233431200, 0)
このepoch秒が表す日付はいつなのでしょうか。見てみましょう。
1977年5月25日です。"A long time ago"とこの年が紐づくものといえば....
Star Warsしかありませんね!!!これの第1作目、Episode IVの公開日を見てみましょう。
ドンピシャでした。実際にこれはどのように使われているかというと、コメントにあるようにネットワークの操作を即座にキャンセルするためにわざとありえない過去の時間を指定することで接続をキャンセルさせるというときに使われます。Go本体のコードだと次のように出てきます。
cr.conn.rwc.SetReadDeadline(aLongTimeAgo)
デッドラインを過去に設定することで強制的にキャンセルさせるわけです。
おわりに
こういうようなちょっとした遊び心は自分でプログラムを書いているときにも入れたくなるわけですが、そういう仲間内のおふざけみたいなものを垣間見れるとより親近感が湧いてくる気がします。これからもこういう発見ができることを楽しみにしています。
おまけ
この記事を書くにあたって、一応Russ Coxに「公開してもいいですか?」と聞いたら
Feel free. No secrets here.
という返事をくれました。隠してはないけど表には書かない、遊び心を感じる回答でした。
おまけ2
mattnさんが、http.aLongTimeAgo
に関してついた line comment を見つけてくれました。
「この変な数字は何?。誕生日?」「スターウォーズの上映が開始された日だよ。」 / “net, net/http: adjust time-in-past constant even earlier · golang/go@698…” https://t.co/kexk9XGqX1
— mattn (@mattn_jp) 2017年4月9日