5
2

相対的な日時の一覧(Swift)

Last updated at Posted at 2023-12-02

はじめに

本記事は SwiftWednesday Advent Calendar 2023 の3日目の記事です。
昨日は @ojun_9 さんで Xcode 15のPreview Macroにおける依存注入について でした。

date.formatted(.relative(presentation: .named)) を使うと、「32 秒前」や「4 週間前」のように日時を相対的に表せます。
具体的な日時の範囲と文言が気になり、調べて一覧にしたので紹介します。

環境

  • OS:macOS Sonoma 14.0(23A344)
  • Swift:5.9

相対的な日時の一覧

相対的な日時の一覧です。

  • 「0 秒前」を「2023/12/01(金) 17:11:52」とする
  • 未来の日時は使用頻度が低いため「1 秒後」のみ確認している
  • 3 年より前は確認していない
日時の範囲 / ロケール ja_JP
日本
en_US
アメリカ
1 秒後 1 秒後 in 1 second
0 秒前 now
1 秒前 1 秒前 1 second ago
2 秒前 2 秒前 2 seconds ago
59 秒前 59 秒前 59 seconds ago
1 分 〜 1 分 29 秒前 1 分前 1 minute ago
1 分 30 秒 〜 2 分 29 秒前 2 分前 2 minutes ago
59 分 30 秒 〜 59 分 59 秒前 60 分前 60 minutes ago
1 時間前 〜 1 時間 29 分 59 秒前 1 時間前 1 hour ago
1 時間 30 分 〜 2 時間 29 分 59 秒前 2 時間前 2 hours ago
23 時間 30 分 〜 23 時間 59 分 59 秒前 24 時間前 24 hours ago
1 日前 〜 2023/11/30(木) 00:00:00 昨日 yesterday
2023/11/29(水) 23:59:59 〜 2023/11/29(水) 00:00:00 一昨日 2 days ago
2023/11/28(火) 23:59:59 〜 2023/11/28(火) 00:00:00 3 日前 3 days ago
2023/11/25(土) 23:59:59 〜 2023/11/25(土) 00:00:00 6 日前 6 days ago
2023/11/24(金) 23:59:59 〜 2023/11/20(月) 00:00:00 先週 last week
2023/11/19(日) 23:59:59 〜 2023/11/13(月) 00:00:00 2 週間前 2 weeks ago
2023/11/12(日) 23:59:59 〜 2023/11/06(月) 00:00:00 3 週間前 3 weeks ago
2023/11/05(日) 23:59:59 〜 2023/11/04(土) 00:00:00 4 週間前 4 weeks ago
2023/11/03(金) 23:59:59 〜 2023/11/01(水) 00:00:00 先月 last month
2023/10/31(火) 23:59:59 〜 2023/10/01(日) 00:00:00 2 ヶ月前 2 months ago
2023/01/31(火) 23:59:59 〜 2023/01/01(日) 00:00:00 11 ヶ月前 11 months ago
2022/12/31(土) 23:59:59 〜 2022/01/01(土) 00:00:00 昨年 last year
2021/12/31(金) 23:59:59 〜 2021/01/01(金) 00:00:00 2 年前 2 years ago
2020/12/31(木) 23:59:59 〜 2020/01/01(水) 00:00:00 3 年前 3 years ago

思ったより複雑で面白い結果になりました。

おそらく以下のルールとなっています。

  • 1 秒前 〜 59 秒前 → 「○○ 秒前」
  • 1 分前 〜 59 分 59 秒前 → 「○○ 分前」(30 秒が境界値)
  • 1 時間前 〜 23 時間 59 分 59 秒前 → 「○○ 時間前」(30 分が境界値)
  • 1 日前 〜 6 日前 → 「○○ 日前」(「昨日」や「一昨日」などの例外あり)
  • 1 週間前 〜 4 週間前 → 「○○ 週間前」(月曜始まり、「先週」などの例外あり)
  • 5 週間前 〜 先月 → 「先月」
  • 先々月 〜 今年1月1日 → 「○○ ヶ月前」
  • 昨年 → 「昨年」
  • 2 年前 〜 → 「○○ 年前」

ソースコード

検証に使ったソースコードを紹介します。
1秒単位で確認するために実際はもっと汚いコードでしたが、それ以外は変えていません。

様々なロケールで確認したかったので Date.RelativeFormatStyle を使っていますが、 date.formatted(.relative(presentation: .named)) でも結果は同様だと思います。

import Foundation

printRelativeDate(timeIntervalSinceNow: 1) // 1 秒後
printRelativeDate(timeIntervalSinceNow: 0) // 0 秒前
printRelativeDate(timeIntervalSinceNow: -1) // 1 秒前
printRelativeDate(timeIntervalSinceNow: -2) // 2 秒前
printRelativeDate(timeIntervalSinceNow: -(60 - 1)) // 59 秒前
printRelativeDate(timeIntervalSinceNow: -60) // 1 分前
printRelativeDate(timeIntervalSinceNow: -(60 + 1)) // 1 分 1 秒前
printRelativeDate(timeIntervalSinceNow: -((60 + 30) - 1)) // 1 分 29 秒前
printRelativeDate(timeIntervalSinceNow: -(60 + 30)) // 1 分 30 秒前
printRelativeDate(timeIntervalSinceNow: -(((2 * 60) + 30) - 1)) // 2 分 29 秒前
printRelativeDate(timeIntervalSinceNow: -((2 * 60) + 30)) // 2 分 30 秒前
printRelativeDate(timeIntervalSinceNow: -(((59 * 60) + 30) - 1)) // 59 分 29 秒前
printRelativeDate(timeIntervalSinceNow: -((59 * 60) + 30)) // 59 分 30 秒前
printRelativeDate(timeIntervalSinceNow: -((60 * 60) - 1)) // 59 分 59 秒前
printRelativeDate(timeIntervalSinceNow: -(60 * 60)) // 1 時間前
printRelativeDate(timeIntervalSinceNow: -(((60 + 30) * 60) - 1)) // 1 時間 29 分 59 秒前
printRelativeDate(timeIntervalSinceNow: -((60 + 30) * 60)) // 1 時間 30 分前
printRelativeDate(timeIntervalSinceNow: -((((2 * 60) + 30) * 60) - 1)) // 2 時間 29 分 59 秒前
printRelativeDate(timeIntervalSinceNow: -(((2 * 60) + 30) * 60)) // 2 時間 30 分前
printRelativeDate(timeIntervalSinceNow: -((((23 * 60) + 30) * 60) - 1)) // 23 時間 29 分 59 秒前
printRelativeDate(timeIntervalSinceNow: -(((23 * 60) + 30) * 60)) // 23 時間 30 分前
printRelativeDate(timeIntervalSinceNow: -((24 * 60 * 60) - 1)) // 23 時間 59 分 59 秒前
printRelativeDate(timeIntervalSinceNow: -(24 * 60 * 60)) // 1 日前
printRelativeDate(timeIntervalSinceNow: -(2 * 24 * 60 * 60)) // 2 日前
printRelativeDate(timeIntervalSinceNow: -(3 * 24 * 60 * 60)) // 3 日前
printRelativeDate(timeIntervalSinceNow: -(6 * 24 * 60 * 60)) // 4 日前
printRelativeDate(timeIntervalSinceNow: -(7 * 24 * 60 * 60)) // 7 日前
printRelativeDate(timeIntervalSinceNow: -(11 * 24 * 60 * 60)) // 11 日前
printRelativeDate(timeIntervalSinceNow: -(12 * 24 * 60 * 60)) // 12 日前
printRelativeDate(timeIntervalSinceNow: -(18 * 24 * 60 * 60)) // 18 日前
printRelativeDate(timeIntervalSinceNow: -(19 * 24 * 60 * 60)) // 19 日前
printRelativeDate(timeIntervalSinceNow: -(25 * 24 * 60 * 60)) // 25 日前
printRelativeDate(timeIntervalSinceNow: -(26 * 24 * 60 * 60)) // 26 日前
printRelativeDate(timeIntervalSinceNow: -(27 * 24 * 60 * 60)) // 27 日前
printRelativeDate(timeIntervalSinceNow: -(28 * 24 * 60 * 60)) // 28 日前
printRelativeDate(timeIntervalSinceNow: -(30 * 24 * 60 * 60)) // 30 日前
printRelativeDate(timeIntervalSinceNow: -(31 * 24 * 60 * 60)) // 31 日前
printRelativeDate(timeIntervalSinceNow: -(61 * 24 * 60 * 60)) // 61 日前
printRelativeDate(timeIntervalSinceNow: -(62 * 24 * 60 * 60)) // 62 日前
printRelativeDate(timeIntervalSinceNow: -(303 * 24 * 60 * 60)) // 303 日前
printRelativeDate(timeIntervalSinceNow: -(304 * 24 * 60 * 60)) // 304 日前
printRelativeDate(timeIntervalSinceNow: -(334 * 24 * 60 * 60)) // 334 日前
printRelativeDate(timeIntervalSinceNow: -(335 * 24 * 60 * 60)) // 335 日前
printRelativeDate(timeIntervalSinceNow: -((335 + (365 - 1)) * 24 * 60 * 60)) // 699 日前
printRelativeDate(timeIntervalSinceNow: -((335 + 365) * 24 * 60 * 60)) // 700 日前
printRelativeDate(timeIntervalSinceNow: -((335 + (365 * 2) - 1) * 24 * 60 * 60)) // 1064 日前
printRelativeDate(timeIntervalSinceNow: -((335 + (365 * 2)) * 24 * 60 * 60)) // 1065 日前
printRelativeDate(timeIntervalSinceNow: -((335 + (365 * 3)) * 24 * 60 * 60)) // 1430 日前
printRelativeDate(timeIntervalSinceNow: -((335 + (365 * 3) + 1) * 24 * 60 * 60)) // 1431 日前

// MARK: - Privates

private func printRelativeDate(timeIntervalSinceNow: Int) {
    let calendar = Calendar.current
    let date = calendar.date(byAdding: .second, value: timeIntervalSinceNow, to: .now)!
    let formatStyle = Date.RelativeFormatStyle(
        presentation: .named,
        locale: Locale(identifier: "ja_JP"),
        calendar: calendar
    )
    print("\(date.formatted(date: .complete, time: .standard)): \(formatStyle.format(date))")
}

おわりに

相対的な日時についての理解が深まりました。
使用を検討している場合、本記事が参考になれば幸いです :relaxed:

以上 SwiftWednesday Advent Calendar 2023 の3日目の記事でした。
明日も @ojun_9 さんで @Observable Macro を構造体へ適用させる難しさについて です。

5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2