はじめに
本記事は 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))")
}
おわりに
相対的な日時についての理解が深まりました。
使用を検討している場合、本記事が参考になれば幸いです
以上 SwiftWednesday Advent Calendar 2023 の3日目の記事でした。
明日も @ojun_9 さんで @Observable Macro を構造体へ適用させる難しさについて です。