今さら聞けないNSDateとタイムゾーンの関係について。国際対応を考えた時、タイムゾーンについてきちんと理解する必要があります。ウェブプログラマからアプリプログラマにコンバートした方の多くは問題ないでしょうが、アプリの開発から始める人もたくさんいるでしょうし、タイムゾーンでハマることも多いと思います。タイムゾーンそのものについて説明している記事はたくさんありますが、NSDateと絡めて説明している記事はあまりないと思うので書くことにしました。

タイムゾーンとは

世界には時差というものがあり、同じ時間でも国が違えば表示上の日時は異なります。たとえば東京が日曜の朝の9時の時、ブラジル・リオデジャネイロは土曜の22時です。逆に東京が朝9時の時、北海道や沖縄など距離が離れたところも朝9時です。このように同じ日時を使う領域をタイムゾーンと言います。タイムゾーンが異なる国や地域どうしでは時差があると言えます。

GMTとは

タイムゾーンごとに日時が異なるのは、あくまで人間の認識上、生活上の都合と言っていいでしょう。現実には東京の朝9時とリオデジャネイロの22時は同じ日時です。そこで本当は同じ日時であることを示す基準となる時間が存在します。それがGMT(グリニッジ標準時)です。

GMTで日曜の0時(AM)であるとき、東京は朝の9時です。つまりGMTから+9時間の時差があります。リオデジャネイロはGMTから-2時間の時差があります。これにちなんで以下の様に表記することがあります。

東京 GMT+09:00
リオデジャネイロ GMT-02:00

NSDateはタイムゾーンを意識しない

初心者が不思議に思うのは、なぜNSDateにgetYear、getDay、getMinutesといった日時を取得するメソッドがないのかということかもしれません。でも、これは国際対応を考えると理にかなっています。

例えばTwitterのようなアプリで、何かを投稿し、その日時を記録するとします。

  • ユーザーAさんが東京にいて日曜の朝の9時に投稿した
  • ユーザーBさんがリオデジャネイロの土曜日の22時に投稿した
  • 両者はタイムゾーンが異なるが、同じ時刻に投稿している

ここで、北京にいるユーザーCさんが、AさんBさんの投稿日時を見た時、同じ日時が表示されるべきで、さらにそれは北京のタイムゾーンでの日時であるべきです。では、AさんBさんの投稿日時はプログラムでどのような形式で管理するのが望ましいでしょうか?

前回Aした時から、現在までの経過時間が5時間以上経過していたら、Bを実行する。このようなプログラムを書くことはよくあります。仮に飛行機に乗っている間にAをした場合、5時間も経てばタイムゾーンが異なる地域に入るでしょう。その場合、どう経過時間を計算するのが望ましいでしょうか?

こういったケースを考えると、プログラム上は基本的にGMTで日時を管理した方が良いでしょう。そして画面表示など人間が日時を認識する必要がある時のみ、GMTからタイムゾーンを適用した日時に変換する方が理にかなっています。

NSDateはGMTの1970年1月1日 00:00:00からの経過秒数で日時を管理しています。タイムゾーンは管理しません。それゆえタイムゾーンによって変わりうるgetYear、getMinutesといったメソッドは存在しません。もっというとNSDateはGMTに特化した日時クラスと言えます。

タイムゾーンを考慮した日時を得る

NSDateからタイムゾーンを適用した日時を得たいならNSCalendarを使うとよいでしょう。この件に関しては以下の記事を参考にして下さい。

NSDateから年月日時分秒を得る

タイムゾーンを考慮した日時を文字列で得る

NSDateからタイムゾーンを適用した日時を、その国の言語も含めた文字列(日本なら2014年10月など)として得たいならNSDateFormatterを使うと良いでしょう。この件に関しては以下の記事を参考にして下さい。

日時表示を多言語対応する

まとめ

  • NSDateはGMTで日時を管理し、タイムゾーンは管理しない
  • NSCalendarを使うとNSDateからタイムゾーンを考慮した日時を取得できる
  • NSDateFormatterを使うとNSDateからタイムゾーンを考慮した日時を文字列で取得できる