システムを扱ったことがある方であれば「1611273600」といった数値を見て「これがUnixtimeの日時データである」ということは理解できるかと思います。
ただし、なんとなく「Unixtimeを使えば計算するのが楽だから」という理由で使っていて、Unixtimeとは何なのかをきちんと整理して理解されている方は少ないのではないでしょうか。
今回の記事では、Unixtimeの基礎知識をおさらいし、PHPで扱う方法を紹介していきたいと思います。
目次
PHPで日付を取得する方法 前提知識
PHPでUnixtimeを扱う方法を紹介する前に、世界の標準時がどういう経緯で制定され、何を基準にしたものなのかについて解説していきたいと思います。
原子時計・国際原子時
「世界の標準時」である「グリニッジ標準時(GMT)」ですが、これは「イギリスのグリニッジ(経度0度)で太陽が南中する時を正午する」という意味合いで制定されいます。
そして、そのグリニッジ標準時が時間を正確に刻むために採用した時計が、セシウム原子の振動数と精密な天体観測を基準に時間を刻む「原子時計」となります。
「原子時計」を基準にした時間は「国際原子時」と呼ばれ、GMT1958年1月1日0時0分0秒を原点としてスタートしましたが、地球の自転速度にふらつきがあることが分かり、実際の太陽の運行と比較すると、秒の単位が常に変動してしまうという問題が発生してしまいました。
そこで登場したのが「協定世界時(UTC)」です。
協定世界時:UTC
協定世界時は、国際原子時の問題で発生する誤差が0.9秒以上とならないよう「うるう秒」を設けて調整した時間です。
これにより、原子時計の制度を保ちながら太陽の運行との誤差を最小限に抑えることができるようになったため、協定世界時が世界の基準となっています。
Unixtime
Unixtimeは各々のPCが端末内で保有している時間で、協定世界時における1970年1月1日0時0分0秒を0として1秒ごとに積算されたものです。
定期的にUTC時刻を取得することでUnixtimeの時間がずれないように調整しています。
冒頭に記載した「1611273600」という数値もUnixtimeにおける日付情報で、2021年1月22日9時0分0秒を表しています。
PHPで日付を取得する方法 関数の解説
それでは早速、PHPで日付を取得する方法を見ていきましょう。
time():UNIX TIMESTAMPを取得
PHPで「現在の日付」を取得する場合によく使われているのが「time()」です。
以下のような記述で使います。
1 |
$now = time(); |
echo $nowで出力してみて、1611から始まる10桁の数字が表示されることを確認しておきましょう。
strtotime():指定した日時のUNIX TIMESTAMPを取得
「指定した日付」からUNIX TIMESTAMPを取得する場合は「strtotime()」を使います。
以下のような記述の場合、「1611532800」が取得されます。
1 |
$someday = strtotime(‘2021/1/25 9:00:00’); |
date():日時の出力
「date()」は「2021/1/25」のような日付フォーマットで日時を表示する関数です。
以下のように記述した場合、現在日時が「2021/1/25 」のフォーマットで表示されます。
1 |
$today = date(‘Y/m/d’); |
なお、第2引数が用意されており、UNIXTIMEで指定した日時を日付フォーマットで出力させることが可能です。
以下の例では、「2021/1/27」が表示されます。
1 |
$thatday = date(‘Y/m/d,1611705600); |
フォーマットに指定できる種類のうち、代表的なものは以下の通りです。
- Y:年(4桁表記)
- y:年(2桁表記)
- M:月(2桁表記)
- n:月(先頭にゼロつけない)
- J:日(1桁はゼロなし)
- d:日(2桁表記)
- H:時間(24時間単位)
- h:時間(12時間単位)
- i:分
- s:秒
- t:指定した月の日数
- w:曜日番号(0[日曜]から6[土曜]の値)
UNIXTIMEを用いるメリット
PHPで日付を取得する方法は以上のとおりですが、大きくわけてUNIXTIMEで取得する場合と日付フォーマットで取得する場合の2種類存在します。
それぞれメリット、デメリットがありますので、まずはUNIXTIMEを用いるメリットを見ていきましょう。
タイムゾーンの考慮が不要
UNIXTIMEを利用するメリットとして、タイムゾーンを考慮する必要がない、という点があります。
「date()」の第1引数のみで日付を取得する場合、以下のように記述してタイムゾーンを設定する必要があります。
1 2 |
date_default_timezone_set('Asia/Tokyo'); echo date(‘Y/m/d H:i:s’); |
たとえば「ユーザーがシステムを利用した日」をサーバーに登録させたい場合「date()」で日付を取得する前に、ユーザーがどこにいるのかを調べ、その地点のタイムゾーンを設定して日付を登録させなければなりません。
特定のタイムゾーンだけを使っているユーザーであれば大きな問題は発生しませんが、タイムゾーンをまたぐ場合、非常に扱いにくいものになってしまいます。
それに対し、UNIXTIMEはUTCの1970年1月1日0時0分0秒からの経過時間で時間を表現しますので、「ユーザーがシステムを利用した時間」を世界共通の時間軸で登録することができます。
フォーマットの考慮が不要
「date()」で日付を表現する場合、「2021/1/25」や「2021-01-25」など、第1引数に指定した内容に応じてフォーマットが変わってしまいます。
そうなると、例えば「2021年1月25日にシステムを利用したユーザー」をデータベースから検索したい場合、「2021/1/25」で検索するパターンと「2021-01-25」で検索するパターンを考慮しなければなりません。
もちろん、それ以外のパターンで登録されている可能性も考慮しなければならないため、事前にきちんとルール付されていなければ検索できないデータが発生することにもなりかねません。
それに対してUNIXTIMEでは10桁の数値を条件に検索すればよいだけなので日付フォーマットを考慮する必要がありません。
計算が楽
UNIXTIMEでは経過秒数で日付情報を表現するので「何秒経過したか」を計算することが容易です。
例えば、勤務時間の計算を行う場合に2つの日付フォーマットの情報から経過時間を計算しようとすると、時間と分を別々に計算しなければなりませんが、UNIXTIMEであれば、経過した秒数を計算した後、60で割るなどの計算を行うだけですみます。
計算のしやすさについては冒頭でも触れたとおり、圧倒的と言えるでしょう。
UNIXTIMEを用いるデメリット
つづいてUNIXTIMEを用いる場合のデメリットを見ていきましょう。
視認しにくい
UNIXTIMEを用いる時のデメリットとして「視認のしにくさ」が挙げられるかと思います。
正直なところ「1611273282」という数値をみて、これが何時何分を表しているのかを瞬時に判断することは不可能でしょう。
つまり、日付情報をユーザーに提示するには必ず日付フォーマットに変換してから表示させる必要がある、ということになりますので、time()で取得したUNIXTIMEをdate()で日付フォーマットに変換する方法やstrtotime()を使って日付フォーマットをUNIXTIMEに変換する方法をしっかりと把握しておくことが重要となります。
2038年問題
time()で取得したUNIXTIMEをdate()で日付フォーマットに変換する方法については問題ないかと思いますが、strtotime()を使ってUNIXTIMEに変換する場合、2038年問題というものに注意しなければなりません。
2038年問題とは、2038年のある時点を過ぎた日時をUNIXTIMEに変換しようとすると誤ったものが出力されてしまう、という問題です。
UNIXTIMEはUTCの1970年1月1日0時0分0秒を起点とする経過秒数であることは前述のとおりですが、UNIXTIMEを定めた当時に、型を「符号付32ビット整数型」と決めてしまったため、扱える範囲が2,147,483,647秒(約68年)までとなっています。
つまり、1970年1月1日0時0分0秒から2,147,483,647秒後である2038年1月19日3時14分7秒を過ぎると値がオーバーフローを起こし、マイナスのデータとして扱われてしまいます。
2038年問題の事例
2038年問題については、2つの日付の真ん中の日時を求めたい、といった場合に発生した事例があります。
例えば、2021年1月26日開始で2021年7月10日納期というスケジュールがあるとして、その中間の日時を求めたい、といった場合です。
計算式としては、それぞれのUnixtimeを足し合わせて2で割ればよいので(1611619200 + 1625875200)/2 = 1618747200(2021年4月18日)となりますが、最初に行う足し算の結果が「3,237,494,400」という数値となり、32ビットの範囲を超えてしまうため誤った計算結果となってしまいます。
2038年問題の対策としては「型を符号付64ビット整数型にする」という方法がとられており、最新のOSではほとんど解決しているといってもよい状況です。
ただし、古いバージョンのアプリケーションの場合は2038年問題を回避することができない可能性がありますので、注意しておくとよいでしょう。
10桁と13桁
UNIXTIMEについては秒単位で計算している10桁のものと、ミリ秒単位で計算している13桁のものの2種類があり、これに気づかず不具合に陥ってしまうことが多々見受けられます。
とくにPHPではミリ秒単位で取得できる関数が実装されてないため、MySQLの13桁のUNIXTIMEであるDATETIME型をdate()の第2引数とした場合、PHP側で正しく取得することができません。
13桁の数位を1000で割ってミリ秒以下を切り捨てて取得するなどの工夫が必要となってきます。
1 2 3 4 5 6 7 8 9 |
$datetime = 1611586800000; echo date("Y-m-d H:i:s",$datetime); //出力結果:53039-02-26 00:00:00 $datetime = 1611586800000 echo date("Y-m-d H:i:s",$datetime/1000); //出力結果:2021-01-26 00:00:00 |
まとめ
いかがでしたか。
PHPでUNIXTIMEを取得する方法が分かりましたでしょうか。
Unixtimeのメリットとデメリットを比較してみましたが、システムの内部で扱う場合にUnixtime、インターフェース側で扱う場合に日付型、というように使い分けるのが重要ではないかと思います。
今回はunixtimeを説明させていただきましたが、今後、PHPでunixtimeを場合に、こちらの記事を思い出していただければ幸いです。