11
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

【Swift】DateComponentsFormatterで「時間の量」を出力する

過去3回の投稿では拙作カレンダーアプリで利用しているコードを含め、日付に関する操作や出力を説明してきました。

第一回:Calendarに日付操作のメソッドを追加してみた
第二回:DateFormatterで日付や時刻を出力する
第三回:DateIntervalFormatterで日付や時刻の範囲を出力する

今回はDateComponentsFormatterについて説明します。

DateComponentsFormatterとは

このクラスはいわば「時間の量」を表す文字列を出力できます。例えば「2年5か月12日」、「2時間10分28秒」などです。またそれらを縮めて「約2年5か月」「約2時間10分」のような出力もできます。さらに「残り10日」や「残り12分」のような出力もできるようになっています。

TimeIntervalを出力する

以下のコードで、310秒を「分」と「秒」で出力できます。

let time:TimeInterval = 310
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .brief
formatter.allowedUnits = [.minute, .second]
print(formatter.string(from: time))

// 出力:5min 10sec(英語の場合)
// 出力:5分10秒(日本語の場合)

後述のUnitsStyleを変えることで、例えば英語の場合には「5 minutes, 10 seconds」や「5m 10s」などと表示させることができます。

includesApproximationPhraseを使うと「約」、includesTimeRemainingPhraseを使うと「残り」を出力できます。

let time:TimeInterval = 350
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .brief
formatter.includesApproximationPhrase = true
formatter.allowedUnits = [.minute]
print(formatter.string(from: time))

// 出力:About 5min
// 出力:約 5分

上記のコードでは350秒が「約 5分」と表示されるので、秒の部分は切り捨てられていることが分かります。

let time:TimeInterval = 310
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .brief
formatter.includesTimeRemainingPhrase = true
formatter.allowedUnits = [.minute, .second]
print(formatter.string(from: time))

// 出力:5min 10sec remaining
// 出力:残り5分10秒

上記はタイマーアプリやダウンロードの残り時間などを表示する場合に使えそうです。

DateComponentsを出力する

var components = DateComponents()
components.month = 2
components.day = 10 
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.month, .day]
print(formatter.string(from: components))

// 出力:2 months, 10 days
// 出力:2か月 10日

DateComponentsの一部を出力できます。DateFormatterだと「2月10日」と表示されますが、DateComponentsFormatterだと「2か月 10日」となります。

2つのDateから出力する

let formatter = DateComponentsFormatter()
formatter.unitsStyle = .full
formatter.allowedUnits = [.year, .month, .day]
let date1 = Date()
let date2 = Calendar.current.move(date1, byDays:400)
print(formatter.string(from: date1, to: date2))

// 出力:1 year, 1 month, 3 days
// 出力:1年 1か月 3日

2つのDateの時間差を出力できます。DateIntervalFormatterだと「2018年7月14日~2019年8月18日」のような表示になりますが、DateComponentsFormatterだと「1年 1か月 3日」となります。

UnitsStyleについて

UnitsStyleを変えることによって、日にちや時間の出力を変えることができます。

日にちの場合:

UnitsStyle 英語 日本語
.spellOut one year, one month, three days 一年 一か月 三日
.full 1 year, 1 month, 3 days 1年 1か月 3日
.short 1 yr, 1 mth, 3 days 1年 1か月 3日
.brief 1yr 1mth 3days 1年1か月3日
.abbreviated 1y 1mo 3d 1y1m3d

時間の場合:

UnitsStyle 英語 日本語
.spellOut one hour, twenty-two minutes, thirty seconds 一時間 二十二分 三十秒
.full 1 hour, 22 minutes, 30 seconds 1時間 22分 30秒
.short 1 hr, 22 min, 30 sec 1時間 22分 30秒
.brief 1hr 22min 30sec 1時間22分30秒
.abbreviated 1h 22m 30s 1h22m30s
.positional 1:22:30 1:22:30

ローカライズについて

DateComponentsFormatterクラスはDateFormatterDateIntervalFormatterと違ってlocaleプロパティがなく、出力する言語をコードで自由に変えることができません。

DateComponentsFormatterクラスはアプリ側が対応している言語で出力される仕様になっています。例えばアプリが日本語にローカライズされており、なおかつシステム言語が日本語に設定されている場合は、日本語で出力されます。アプリが日本語にローカライズされていない場合は、システム言語が日本語だとしても出力は英語となります。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
11
Help us understand the problem. What are the problem?