日付、時刻関連の基礎知識整理

クイズ

  • GMTUTCは同じですか? 違いを説明できますか?
  • 時間を計測するときの最も基本となる単位は何ですか? 1年? 1日?
  • java.util.Dateクラスのようなコンピューター上の日時値はどのような値を保持していますか?

前置き

来年元旦(2017年、平成29年)の8時59分から9時にかけて、うるう秒が1秒追加されるそうな。

とあるニュースによると、「なぜわざわざ元旦にやるんだ! SEが大変じゃないか!」という言い分があるそうだが、それはおかしい。システム屋の都合が全人類の都合に優先される道理はない。まあ、前回のように7月とかにやればええやろって話もわからんでもないが。日本の場合、時差の関係で朝に仕事ができるんだから幾分マシなのでは? とか思ったりもする。ともあれ、PGである私にはあまり関係のない話であるとしておこう。

私くらいの老人PGになると、2000年問題の時のことを思い出す。

とはいえ、あの頃は私はまだ1年目のひよっこで、先輩方が忙しそうにしていたなぁくらいの記憶しかないが。
今にして思えば、年を2桁で勘定するなんて、そんな馬鹿げた設計があるわけないとは思うのだが、実際には自分たちの書いたプログラムだけの問題ではなく、関連するOSやミドルウェア等に問題がないとも言い切れず、非常に緊迫した大晦日であったことだろう。

今回のうるう秒の件は、システム時刻上、8:59:60(JST) という時刻が発生することに問題がないかどうか、あるいはOSレベルでそれが発生しないように対策が必要なのかどうかということになるのではないだろうか。

2012年(前々回)のうるう秒挿入時には、Linuxカーネルの不具合によって、JavaMySQLプロセスがハングしてしまったということもあるそうなので、注意が必要だ。

自分自身に関していえば、幸い(?)今はミッションクリティカルなシステムを抱えていないので、最悪、

「2017年1月1日 8:30 - 9:30 システムメンテナンス」

という最強の対策を取ることができる。ただしこの場合、元旦の出社は覚悟せねばなるまい。

まあ、前回2015年の時も、自分の周囲では何も障害は発生しなかったし、来年も大丈夫だろうと、楽観的に考えているところだ。


さて今回、この雑記帳では、うるう秒の挿入に対してシステムレベルでどう対策するか、という話は置いておいて、日付と時刻に関する一般常識レベルのおさらいと整理をしておこうと思う。

一応、ずいぶんと昔に勉強したことはあったような気がするが、今他の人にきちんと説明できるかどうかと考えるとかなり怪しい。

というわけで、自分のためのメモとして最低限必要な分だけまとめておく。


まずは面倒臭さの認識が必要

そもそもなぜこんなふうに勉強し直さなければならないのかといえば、日時というのはすべての人間に関わることでありながら、普通の人がごく当たり前に理解できるような簡単なことでもないからである。

理由の1つは天文学が関わっていること、もう1つは歴史的に時刻の計測方法が色々あること、さらには言葉の定義がややこしいこと等が挙げられる。

私は大人になるまで時間というものを本気で理解しようとしてこなかったし、そもそも理解していないなんて思ってもいなかった。

まずは、「時間の定義をきちんと理解するのは意外と難しいことなんだよ」というのをきちんと認識する必要がある。


時間の基本単位は「秒」である

歴史的に、すべての人にとって、12:00は昼でなければならない。

昼は太陽が昇っており、明るくなければ昼とは言えないのである。

日が昇って沈んでまた昇るまでの間が1日とされている。

そしてそれがだいたい365回繰り返されると、地球が太陽の周りを1周するので、それが1年である。

こうして書いてみると、その定義が恐ろしく曖昧であることがわかる。

なぜそうなってしまったのかということに関しても歴史的興味はあるが、これはもう変えることができないし、生きていく中で、皆自然とそう受け入れているはずである。

私はその手の専門家ではないので断言はできないが、おそらく「1年がどれだけの時間的長さなのか」というものについて厳密な定義はないものと思われる。
一般的には、「地球が太陽の周りを1周した」ら1年であるが、そもそもその時間が一定ではないのだから決めようがない。

現代では、時間の基本単位は「秒」であると決められている。
ところが、1年を正確に「n秒」と表わすことはできない。
1年を何秒と決めてしまうと、地球の公転周期自体が完全に安定したものではないがゆえ、そのうち12:00が朝になったり夜になってしまうからだ。
そこで、本記事の前置きとなった「うるう秒」なるものが出てくるのだが・・・。

では、1秒とはなんなのか。

これはきちんと定義されている。

wikiより

秒は、セシウム 133 の原子の基底状態の二つの超微細構造準位の間の遷移に対応する放射の周期の9192631770倍の継続時間である.

なるほど、分からん。

自身の理解のためにものすごく大雑把にまとめてしまうと、以下のようになる。

  • 人は大昔からずっと、1日を24で割って、60で割って、さらに60で割った値を1秒としていた(この時代は1秒よりも1日という概念の方が重要だった)
  • 19世紀頃、天文学的な観測から、そもそも1日の長さが一定ではないことに気づいてしまった
  • これまでのやり方では、「1日」も「1秒」も時間を表す単位としては不都合なので、もっと普遍的なモノがないかと探すようになる
  • 普遍的に時間を計測できる「何か」があれば、そいつを地球の自転や公転周期などの天文学的な観測とバランスを取れるような値として「1秒」を定義すれば良い
  • 1960年頃、セシウムという原子から時間計測に対して都合の良い性質が見つかり、その結果、「セシウム原子時計」というものが発明される
  • 今は原子時計をたくさん使って、統計的になるべく正確な「1秒」というものを計測しており、これをすべての時間の基本単位とすることにしている(それでも、どうしても不確かさはあるようだ)


ということ…だと思う…。

私はこのように理解しているが、厳密には正しくないかもしれないので注意。


GMTという用語はなるべく使わない方が良い

私がいつまで経っても日時というものを正しく理解できないでいた1つの原因がこのGMTという言葉である。

今では(というよりずっと昔から)世界で共通の時刻はUTCなのである。ところが、未だに、至る所で、GMTという言葉が出てくる。それもそのはず、ある分野においては、GMTUTCの「同義語」として使って良いということが世界的に認められているからである。

実際にGMT, UTCでググってみると、GMTUTCは同じ」という解説が出てきたり、GMTUTCは時間差がある」という解説が出てきたりする。これをすぐにきちんと調べれば良いが、よく調べずにどちらかの解説を鵜呑みにしてしまうと、それが混乱の素となってしまうだろう。

そもそもGMTとは、イギリスのグリニッジ天文台における「平均太陽」時である。
これを日本語にすると、なぜか、グリニッジ「標準」時になってしまうのである。歴史的背景もあるので、誤訳とまでは言えないが、これが多くの人がGMTを勘違いしてしまう大きな原因になっているような気がする。もしも今後、GMTという言葉を使うとしたら、心の中でグリニッジ平均太陽時」と日本語訳するようにすれば、GMTを誤認識しなくて済むだろう。

理解のポイントは、「人は太陽を基準として時間を計測することをやめた」という点にある。

ではなぜ、「ある分野」において、GMTUTCの同義語としても良いことになっているのか。

それは何も難しいことではなく、その差を細かく意識する必要がない状況においては、単に「世界で共通の日時」という意味の言葉として使っても良いとされているだけである。

だが、我々プログラマーは、その「ある分野」の外に居ると思った方が良い。

GMTというのは、今では「UT」(世界時)なるものに継承されている。
UTをきちんと認識しなければいけない分野の人々(我々を含む)にとっては、GMTというものは、学術的に消滅したと考えるべきである。

  • UT0 ... 地球の回転に基づいた時刻(昔のやり方、観測場所によって微妙に時間がずれる)
  • UT1 ... UT0に対して地球の地軸のブレを補正(季節によって1日 +/- 3秒くらいずれる)
  • UT2 ... UT1に対して地球の自転の変動補正(最近では使われない)

UT0からUT2までのそれぞれの計測方法を理解することはそこまで重要ではないと思われる。
これらはすべて、正確に時を刻むという役割から外されて、我々人類が認識している時刻と天体位置の関係性を表すものになったのである。

重要なのは以下4点。

  1. GMTはUTとして継承されており、UT0〜UT2として、以前よりも細かく定義されている。
  2. UT1になるべく合わせるような形としてUTCが決められている。(この両者にはわずかな時間差がある)
  3. JSTUTCを9時間進めた値である。
  4. プログラムで使うデータとしての日時は、ほとんどの場合UTCである。

4に関してプログラマーレベルの話でいうと、データとして扱っている日時はほとんどの場合UTCであって、それを日本のユーザー向けに表示するときに「JSTに変換して見せている」だけのことである。

業務システムの開発に携わったことのある人なら当然のことであろうが、お客さんや新人は知らない人の方が多数なので、きちんと教えてあげないといけない。中には、日時データをJST(日本の時間)として保存していると考えている人も居るかもしれないし、居ても不思議ではない。理解してしまえば単純なことで、ただ単に見えている文字列とコンピューター上のデータとの間で時差調整をしているだけの話であって、その時差の値がいくつかというのは、UTCJSTの間では+9と定義されているということである。

ということで、GMTという言葉は、実際のところ使う必要がないのである。


TAI(国際原子時

英語ではInternational Atomic Timeであるが、フランス語の略語なのでTAIというらしい。

先述の通り、人は地球と太陽を基準として正確に時を測ろうとすることを止めたのである。しかし、UT0〜UT2は、いずれも天体観測によるものであって、こないだのび太ん家で発明した原子時計とやらはUT側では使われていない。

原子時計によって、今の世の中で一番正確に時を刻んでいるのが、このTAIである。

こいつの弾き出す1秒が、厳密な意味(SI単位系)の秒である。

さて、物理的には、TAIによって人類すべての共通の時を刻めれば良いのだが、そうもいかない。西暦やカレンダーをすべてこのTAIに合わせてしまうと、長い時が経った時にいずれ昼夜が逆転してしまうからである。

やはり、人類にとっては、太陽が昇っている時間が昼でなければならず、9時は朝だし、12時は昼だし、18時は夕方(夜の浅い時間)でなければならないのである。
(いっその事その概念を捨てされれば、時差もなくなって良いのだが)

そういったわけで、TAIとは別に、UTCというものが定義されているのである。


UTC協定世界時

協定世界時というのは、昔は例のグリニッジ天文台の時刻に合わせられていたが、原子時計が発明された後からは、TAIをベースとして、なるべくUT1に合わせるように方針が変更された。

これが具体的にどういうことかというと、

UTC = TAI - うるう秒(累計 = 2017年時点で37.0)

ということである。

うるう秒は、以下の2つの要件を満たすように決定する。

  1. UTCとUT1の差を 0.9 SI秒以内に収めること
  2. UTCとTAIの差を 1 SI秒の整数倍になるようにすること

ここで重要なのは、我々の文明において今最も信頼できるTAIの値を決して崩さないということである。
正確な時に対して昼夜が逆転しないようにUTC側をいじる。
その時、調整に使う値がうるう秒なのである。

そのうるう秒の加算(状況によっては減算されることもあるのかもしれないが)をいつ実施するかは、とある世界的な団体が決めており、前々回が2012年、前回が2015年、次回が2017年ということになる。

当然、JSTUTCとの+9時間の関係性を維持するために、即刻合わせなければならない。
ということで、日本も世界と同時にうるう秒を挿入することになる。


今回のうるう秒挿入に関する正式な公示が↓こちら

https://datacenter.iers.org/web/guest/eop/-/somos/5Rgv/latest/16

ご覧のように、

2016 December 31, 23h 59m 59s
2016 December 31, 23h 59m 60s
2017 January 1, 0h 0m 0s

となるので、元旦になる直前の一瞬だけ、23時59分60秒という時刻が発生することになる。

JSTでいうとそれは、8時59分60秒である。


最初のクイズに対する自分なりの答え

GMTUTCは同じですか? 違いを説明できますか?

GMTというものは今は存在しない。世界で共通の日時はUTCである。
GMTはUT0, UT1, UT2として再定義されており、これらは地球と太陽の位置関係と同期した時刻である。
一方、UTC原子時計を基準として、UT1に対して0.9秒以内の差を維持するように調整された値であり、調整のために、数年に1度、うるう秒が挿入される。

時間を計測するときの最も基本となる単位は何ですか? 1年? 1日?

秒である。現在では、原子時計の1秒がSI単位とされている。
1 日 = 24 × 60 × 60 = 86400 秒のように1日に基づいて秒が算出されるわけではない。

java.util.Dateクラスのようなコンピューター上の日時値はどのような値を保持していますか?

ほとんどのコンピューターの日時値はUTCを表現するようなデータ構造を持っている。
java.util.Dateで言えば、値としてはUTC日時を保持しており、それがtoStringなりDateFormat#formatされる際に、ロケールに応じた日時表現文字列に変換される。
うるう秒を考慮するため、秒の値は、0〜61までと定義されている。(ごく稀にうるう秒が2回挿入される可能性があるらしい)
ただし、UTCとの時刻同期は行っても、うるう秒の反映まではしないこともあるらしい。
JavaのDateクラスについてはAPIリファレンスにかなり詳しく書かれている)


まとめ

地球や太陽の位置とは無関係に、ひたすらに正しい時刻を刻み続けるのはTAIであって、UTCは人間の生活リズム=UT1に近くなるようにちょいちょい修正されている値、そして人類で共通の日時はそのUTCである。

少々長くはなったが、私はひとまずこれで理解したということにしている。
私の場合は、これを教えてくれた先輩というのは居ないので、長いこと、頭の中で世界標準時=GMTという言葉を使っており、それをずっとUTCとは別物だという合っているような合っていないような曖昧な認識でいた。

そして、今回のようにうるう秒の話が出た時に、GMTUTCの差分を埋めるもんだと勝手に思い込んでしまって、恥ずかしい思いをしそうになったところ、

「ちょっと待て、それはなんか違う気がするぞ」

と思い立ってきちんと調べたのであった。

ということを何年か前にやって、その時にきちんと理解したつもりでいたのだが、そのまま放置しておくとやっぱりまた忘れてしまうもので、今回はこうやってはてなダイアリーとかいうサービスを使って、電子的に記録しておくことにしたのであった。

結局のところ、上記の私の誤認識というのは、GMTという言葉をUT1とすれば、ほぼ合っている話になるのであって、やはりGMTという曖昧な言葉は使わない方が良いと思う。

そんなわけで、次に忘れた時には、この自分のメモを読み返せば済みそうなものだが、問題はここにこれを書いたこと自体を忘れてしまわないかどうか、そこが問題。




おしまい