デイトとデイト・コンポーネント
次に、デイトについて見直します。やはりObjective-CではNSDateというクラスでしたが、SwiftではDateという構造体です。そのままデフォルトのオブジェクトを作成すると、現在の日時を表すオブジェクトが得られます。
let now = Date()
このオブジェクトがどんなものなのか、例によってSwift Playgroundsのデバッグ機能で確認してみましょう。
この表示は誤解を招くのですが、日付と時刻がグレゴリア暦で、タイムゾーンは日本で簡略に表示されます。このような表示を可能にするためには、どのカレンダー(暦法、言語、タイムゾーン)を使うのかを決めなければなりませんが、デイトオブジェクト自体にはカレンダーの情報は含んでいません。
これは、あくまでデバッグ機能として、currentのカレンダーを使って便宜的に表示しているものと考えられます。実際にデイトの情報を人間が読めるようなものにするためには、まずカレンダーを決め、一般的な日時を構成する要素に変換する必要があります。
この日時を構成する要素のことをデイト・コンポーネントと呼び、SwiftではDateComponentsという構造体の要素として表現されています。実際には、DateComponentsはカレンダーオブジェクトのプロパティとして含まれています。それを使って、カレンダーと、その中の要素を同時に指定して、デイトから変換することで、目的の要素の値を得ることができます。
例えば、現在のデイトからcurrentのカレンダーを使って年の数字を取り出してみましょう。
デバッガーで確認すると、期待どおり2018と数字が得られました。
カレンダーが異なれば、年の数字も違ってくるという例を見て見ましょう。上で作ったjapaneseのカレンダーの年を取り出してみます。
結果は30となりました。これは言うまでもなく平成の年号の数字です。この場合のjapaneseのカレンダーは、年が平成で表されたものだったのです。なお、来年には皇位継承によって年号が変わるので対応が必要です。その際には、一部のiOSのアプリにはちょっとした混乱が発生するのかもしれません。
複数のコンポーネントを同時に取り出すこともできます。カレンダーオブジェクトのdateComponentsメソッドを使って、取り出したいコンポーネントの集合と、元の日時オブジェクトを与えればいいのです。
この例では、年(平成)、月、日、時、分、秒、曜日の順に結果が表示されています。曜日は、この場合、日曜日始まりで、数字は1からなので、金曜日を表しています。最後のfalseは、今月がうるう月(Leap Month)かどうかで、そうではないことを表しています。
秒数計算機を作る
ここまでで、カレンダーやデイトについて、だいたいの基本はカバーできたので、実際にプログラムを作って動かしてみましょう。まずは、日時の入力に便利なデイトピッカーを使って、現在の日時から、デイトピッカーで指定した日時(月日、時、分)までの秒数を計算するものです。
今回、すでに説明が長くなっているので、今後の説明は最小限にとどめます。これまでのUIViewControllerを使ったプログラムの経験と、今回のカレンダー、デイトについての知識があれば、ほとんど説明は不要なほどでしょう。
まずは、DateViewControllerのクラスを作って、デイトピッカー(UIDatePicker)とラベルを配置します。
デイトピッカーをユーザーが操作して値が変化した際には、同じクラス内のdateChangedというメソッドが呼ばれるようにターゲットを設定しています。そのメソッドの中では、デイトピッカーで指定したデイトを、dpオブジェクトのdateというプロパティで読み取ります。
そこで得られたデイトオブジェクトのtimeIntervalSinceNowプロパティで、現在の日時との差を秒で取得し、それを四捨五入し、さらに整数に変換して「秒」を付けてラベルに表示しています。
プログラムを起動するとデイトピッカーには現在日時が表示され、当然ながらその下に「0秒」と表示されます。
ここから、例えば分を適当に進めると、現在との差が秒で表示されます。
もちろん時間を進めれば、より大きな秒差が表示されます。
日を戻して過去にすると、秒差はマイナスで表示されます。もちろんこれはバグではなく仕様です。マイナス表示は、〜秒前を表すものと思ってください。
日数計算機を作る
秒表示では、言うまでもなく年単位の差を計るのには適当ではありません。ほかの単位でも同時に表示するようにしてもいいのですが、ここではあえて日数の差だけを計算するプログラムに改造してみます。
まずは、デイトピッカーのモードを変更します。デフォルトでは、月日、時、分を表示して設定可能になっていましたが、モードを.dateに変更することで、年、月、日の表示になるので、日数計算にはうってつけです。
ユーザーがデイトピッカーを動かして、止まった時に呼ばれるdateChangedメソッドは、秒数計算の場合よりもちょっとだけ複雑になっています。
まずうるう年なども含めて、正確な日数を計算するためにカレンダーを導入しています。また、時刻によらず日の差だけがわかるように、現在もデイトピッカーで指定した日も、その日の初めの時刻を比較の対象にしています。
比較は、日数だけでいいのですが、2つのデイトを指定して差分を取るメソッドの場合、複数のコンポーネントを指定できるものしかありません。そこで集合の要素として.dayだけを指定して日数を求めています。答えはコンポーネントとして得られるので、そこから日数を表す整数を取り出してラベルに表示します。
念のために動きを確認しましょう。デイトピッカーには、ねらいどおり年、月、日だけが表示され、動かすと今日との日数差が表示されます。
過去を指定すると、やはりマイナスの日数が表示されます。
ちなみに、これは、iPadが最初に発表された日からの日数を表示しています。早いものでもうじき3000日になるのです。
次回の予定
今回は、iOSで日付をデータとして扱うためのデイト、カレンダーの基礎を説明しました。それだけでは物足りないので、秒数や日数の差分を計算するプログラムまで作ったため、かなり分量が多くなってしまいました。それでも、日時を指定したフォーマットで文字列に変換するDateFormatterなど、まだ取り上げていない内容も残っています。そのあたりは、さらに地味な話になりそうなので、別の機会に譲るとして、次回はまたiOSの基本的なユーザーインターフェースの話に戻る予定です。