Swift Playgroundsで学ぶiOSプログラミング

Swiftで秒数・日数計算機を作る

文●柴田文彦 編集●吉田ヒロ

2018年01月22日 17時00分

デイトとデイト・コンポーネント

 次に、デイトについて見直します。やはりObjective-CではNSDateというクラスでしたが、SwiftではDateという構造体です。そのままデフォルトのオブジェクトを作成すると、現在の日時を表すオブジェクトが得られます。

let now = Date()

 このオブジェクトがどんなものなのか、例によってSwift Playgroundsのデバッグ機能で確認してみましょう。

日時については、Dateのデフォルトのオブジェクトを作成することで、その時点での日時データを含んだオブジェクトを作成することができます。いったん作成したオブジェクトの日時は固定されるので、勝手に進んだりはしません

 この表示は誤解を招くのですが、日付と時刻がグレゴリア暦で、タイムゾーンは日本で簡略に表示されます。このような表示を可能にするためには、どのカレンダー(暦法、言語、タイムゾーン)を使うのかを決めなければなりませんが、デイトオブジェクト自体にはカレンダーの情報は含んでいません。

 これは、あくまでデバッグ機能として、currentのカレンダーを使って便宜的に表示しているものと考えられます。実際にデイトの情報を人間が読めるようなものにするためには、まずカレンダーを決め、一般的な日時を構成する要素に変換する必要があります。

 この日時を構成する要素のことをデイト・コンポーネントと呼び、SwiftではDateComponentsという構造体の要素として表現されています。実際には、DateComponentsはカレンダーオブジェクトのプロパティとして含まれています。それを使って、カレンダーと、その中の要素を同時に指定して、デイトから変換することで、目的の要素の値を得ることができます。

 例えば、現在のデイトからcurrentのカレンダーを使って年の数字を取り出してみましょう。

日時を構成する要素の値を知るには、カレンダーに含まれるコンポーネントのメソッドを使って日時オブジェクトから指定した要素の値を取り出すようにします。この場合、年の要素の値が2018になっています

 デバッガーで確認すると、期待どおり2018と数字が得られました。

 カレンダーが異なれば、年の数字も違ってくるという例を見て見ましょう。上で作ったjapaneseのカレンダーの年を取り出してみます。

暦のIDとして.japaneseを指定して作成したカレンダーで現在の年の要素を調べると30になっています。これは平成という年号での年の値です

 結果は30となりました。これは言うまでもなく平成の年号の数字です。この場合のjapaneseのカレンダーは、年が平成で表されたものだったのです。なお、来年には皇位継承によって年号が変わるので対応が必要です。その際には、一部のiOSのアプリにはちょっとした混乱が発生するのかもしれません。

 複数のコンポーネントを同時に取り出すこともできます。カレンダーオブジェクトのdateComponentsメソッドを使って、取り出したいコンポーネントの集合と、元の日時オブジェクトを与えればいいのです。

デイトオブジェクトからは、日時を表す要素を複数まとめて取り出すこともできます。そのためには、取り出したい要素の種類を集合として与えます。答えは、DateComponentsタイプ(構造体)として返ってきます

 この例では、年(平成)、月、日、時、分、秒、曜日の順に結果が表示されています。曜日は、この場合、日曜日始まりで、数字は1からなので、金曜日を表しています。最後のfalseは、今月がうるう月(Leap Month)かどうかで、そうではないことを表しています。

秒数計算機を作る

 ここまでで、カレンダーやデイトについて、だいたいの基本はカバーできたので、実際にプログラムを作って動かしてみましょう。まずは、日時の入力に便利なデイトピッカーを使って、現在の日時から、デイトピッカーで指定した日時(月日、時、分)までの秒数を計算するものです。

 今回、すでに説明が長くなっているので、今後の説明は最小限にとどめます。これまでのUIViewControllerを使ったプログラムの経験と、今回のカレンダー、デイトについての知識があれば、ほとんど説明は不要なほどでしょう。

 まずは、DateViewControllerのクラスを作って、デイトピッカー(UIDatePicker)とラベルを配置します。

デイトピッカーで指定した月日、時、分と、現在日時との差を秒で表示するプログラムを作るために、DateViewControllerクラスを定義します。これはその前半です

 デイトピッカーをユーザーが操作して値が変化した際には、同じクラス内のdateChangedというメソッドが呼ばれるようにターゲットを設定しています。そのメソッドの中では、デイトピッカーで指定したデイトを、dpオブジェクトのdateというプロパティで読み取ります。

DateViewControllerクラスの後半です。ユーザーがデイトピッカーを操作して日時を設定した際に呼ばれるdateChangedメソッドと、デイトピッカーとラベルをレイアウトするviewWillLayoutSubviewsメソッドを含んでいます

 そこで得られたデイトオブジェクトのtimeIntervalSinceNowプロパティで、現在の日時との差を秒で取得し、それを四捨五入し、さらに整数に変換して「秒」を付けてラベルに表示しています。

 プログラムを起動するとデイトピッカーには現在日時が表示され、当然ながらその下に「0秒」と表示されます。

このプログラムを動かすと、標準的な月日、時、分を設定可能なデイトピッカーと、その下には「0秒」というラベルも表示されます

 ここから、例えば分を適当に進めると、現在との差が秒で表示されます。

まず分の値だけを進めてみます。現在と、その分との差が秒数で表示されます

 もちろん時間を進めれば、より大きな秒差が表示されます。

時の値を進めると、当然ながらより大きな秒数の差が表示されます

 日を戻して過去にすると、秒差はマイナスで表示されます。もちろんこれはバグではなく仕様です。マイナス表示は、〜秒前を表すものと思ってください。

現在日時よりも過去の日を指定すると、秒数の表示はマイナスになります

日数計算機を作る

 秒表示では、言うまでもなく年単位の差を計るのには適当ではありません。ほかの単位でも同時に表示するようにしてもいいのですが、ここではあえて日数の差だけを計算するプログラムに改造してみます。

 まずは、デイトピッカーのモードを変更します。デフォルトでは、月日、時、分を表示して設定可能になっていましたが、モードを.dateに変更することで、年、月、日の表示になるので、日数計算にはうってつけです。

秒数ではなく、日数で差分を表示するようにプログラムを改造します。デイトピッカーのモードとしては.dateを設定して、年、月、日を設定できるようにします

 ユーザーがデイトピッカーを動かして、止まった時に呼ばれるdateChangedメソッドは、秒数計算の場合よりもちょっとだけ複雑になっています。

日数計算のために大きく変わるのは、dateChangeメソッドの中身だけです。計算時の時刻を無視するために、比較する日の最初の時刻を算出して計算しています

 まずうるう年なども含めて、正確な日数を計算するためにカレンダーを導入しています。また、時刻によらず日の差だけがわかるように、現在もデイトピッカーで指定した日も、その日の初めの時刻を比較の対象にしています。

 比較は、日数だけでいいのですが、2つのデイトを指定して差分を取るメソッドの場合、複数のコンポーネントを指定できるものしかありません。そこで集合の要素として.dayだけを指定して日数を求めています。答えはコンポーネントとして得られるので、そこから日数を表す整数を取り出してラベルに表示します。

 念のために動きを確認しましょう。デイトピッカーには、ねらいどおり年、月、日だけが表示され、動かすと今日との日数差が表示されます。

プログラムを動かしてまず日を進めてみると、今日との差が日数で表示されました

 過去を指定すると、やはりマイナスの日数が表示されます。

誕生日など、過去の記念的な日から今日までの日数を正確に求めることができます

 ちなみに、これは、iPadが最初に発表された日からの日数を表示しています。早いものでもうじき3000日になるのです。

次回の予定

 今回は、iOSで日付をデータとして扱うためのデイト、カレンダーの基礎を説明しました。それだけでは物足りないので、秒数や日数の差分を計算するプログラムまで作ったため、かなり分量が多くなってしまいました。それでも、日時を指定したフォーマットで文字列に変換するDateFormatterなど、まだ取り上げていない内容も残っています。そのあたりは、さらに地味な話になりそうなので、別の機会に譲るとして、次回はまたiOSの基本的なユーザーインターフェースの話に戻る予定です。

mobileASCII.jp TOPページへ

mobile ASCII

Access Rankingアクセスランキング