【Swift】秒から何時間何分何秒に変換する

2021.12.15

「秒を何時間何分何秒に変換したいな〜」と思っていたら体が勝手に調べていたので記事にまとめることにしました。

開発環境

  • Xcode 13
  • Swift 5.5

秒から何時間何分何秒に変換する

今回はDateComponentsFormatterというクラスを使用します。

DateComponentsFormatter

このクラスは、時間の量を文字列表現に変換してくれるフォーマッターで、時間の量をユーザーが読み取り可能な文字列にフォーマットしてくれます。 このフォーマッターには多くのオプションがあり、出力文字列を省略したり拡張したりすることが可能です。 また何も設定しなければ、このフォーマッターは文字列を生成する時に現在のローカルと言語を考慮してくれます

ローカライズ対応を自動でやってくれるなんて素敵ですね。

変換してみよう

TimeInterval型で3661秒を何時何分何秒の文字列に変換してみました。

let time:TimeInterval = 3661

let dateFormatter = DateComponentsFormatter()
dateFormatter.unitsStyle = .full
dateFormatter.allowedUnits = [.hour, .minute, .second]
print(dateFormatter.string(from: time)!)

// US出力: 1 hour, 1 minute, 1 seconds
// JP出力: 1時間 1分 1秒

オプションを設定することでいい感じに出力してくれました。

オプションについて少し見ていきましょう。

unitStyle

こちらの値を設定することで時間の量の表現を変更することが出来ます。

すべての日付と時刻の値は、現在のユーザーの言語設定に従ってローカライズおよびフォーマットされます。

UnitsStyle US JP
.spellOut one hour, one minute, one second, thirty seconds 一時間 一分 一秒
.full 1 hour, 1 minute, 1 seconds 1時間 1分 1秒
.short 1 hr, 1 min, 1 sec 1時間 1分 1秒
.brief 1hr 1min 1sec 1時間1分1秒
.abbreviated 1h 1m 1s 1時間1分1秒
.positional 1:01:01 1:01:01

結果としてはこのような違いがありました。

せっかくなのでスタイル名の英語の意味も調べてみました。

  • Spell outは「略さずに書く」
  • Briefは「簡素な」
  • Abbreviateは、「短縮された」
  • Positionalは、「位置の」という意味で時間単位のそれぞれの位置に配置されるという認識で理解しました

allowUnits

今回は何時間何分何秒ということで、[.hour, .minute, .second]を設定しましたが、

dateFormatter.allowedUnits = [.hour, .minute, .second]

下記のように様々な単位を設定することが出来ます。

  • .era: 時代
  • year: 年
  • yearForWeekOfYear: 週カウント年単位
  • quarter: カレンダーの四半期
  • month: 月
  • weekOfYear: 年暦単位の週
  • weekOfMonth: 月暦単位の週
  • weekday: 平日単位
  • weekdayOrdinal: 序数の平日単位
  • day: 日
  • hour: 時間
  • minute: 分
  • second: 秒
  • nanosecond: ナノ秒

includesApproximationPhrase

フレーズを含むかどうかを設定できるBool値で、出力の値にを付けてくれます。優しいですね。

dateFormatter.includesApproximationPhrase = true

出力させてみましょう!

let time:TimeInterval = 3661

let dateFormatter = DateComponentsFormatter()
dateFormatter.unitsStyle = .short
dateFormatter.allowedUnits = [.hour, .minute, .second]
dateFormatter.includesApproximationPhrase = true

print(dateFormatter.string(from: time)!)

// US出力: About 1 hr, 1 min, 1 sec
// JP出力: 約1時間 1分 1秒

サザンオールスターズさんの勝手にシンドバッドさながら、だいたいの時間の文字列を出力してくれました。

includesTimeRemainingPhrase

残りフレーズを含むかどうかを設定できるBool値で、出力の値に残りを付けてくれます。優しいですね。

dateFormatter.includesTimeRemainingPhrase = true

出力させてみましょう!

let time:TimeInterval = 3661

let dateFormatter = DateComponentsFormatter()
dateFormatter.unitsStyle = .short
dateFormatter.allowedUnits = [.hour, .minute, .second]
dateFormatter.includesTimeRemainingPhrase = true

print(dateFormatter.string(from: time)!)

// US出力: 1 hr, 1 min, 1 sec remaining
// JP出力: 残り1時間 1分 1秒

残り1時間 1分 1秒」という形で出力されました。

zeroFormattingBehavior

zeroFormattingBehaviorでは値が0の時に単位がどういう振る舞いをするのか設定することが出来ます。

例えば、.padを設定すると、の単位を保持して表示することが出来ます。

let time:TimeInterval = 3600

let dateFormatter = DateComponentsFormatter()
dateFormatter.unitsStyle = .abbreviated
dateFormatter.allowedUnits = [.hour, .minute, .second]
dateFormatter.zeroFormattingBehavior = .pad

print(dateFormatter.string(from: time)!)
// US出力: 1h 0m 0s
// JP出力: 1時間0分0秒

地域や言語に影響を受ける点

冒頭でも記載したのですが、このDateComponentsFormatterは、何も設定しなければ、このフォーマッターは文字列を生成する時に現在のローカルと言語を考慮してくれます。 これは実はありがたいようで時々ありがたくないことがあるかと思います。笑

ユーザーの地域や言語設定に関わらず、日本語で文字列を返したい時は、Calendarを設定してあげます。

let time:TimeInterval = 3600
let dateFormatter = DateComponentsFormatter()
dateFormatter.unitsStyle = .abbreviated
dateFormatter.allowedUnits = [.hour, .minute, .second]

var calender = Calendar.current
calender.locale = Locale(identifier: "ja_JP")
// 日本のカレンダーを設定する
dateFormatter.calendar = calender

print(dateFormatter.string(from: time)!)
// 出力: 1時間

DateComponentsFormattercalendarに日本のローカルカレンダーを設定してあげると現在地や言語設定に関わらず日本語で表示することが出来ました。

ただし、この方法でincludesApproximationPhraseincludesTimeRemainingPhrasetrueにすると、言語設定が英語の場合には、Aboutremainingだけは英語で表示されてしまうので気をつけましょう。

おわりに

このDateComponentsFormatterクラスを使えば、「今、何時?」と聞かれて、大体の時間を返すアプリが容易に作れそうですね。 気が向いたら作りたいと思います。

参考