OP 的真正问题(在他对自己的 OP 的评论中澄清)大约是 1/1/1。正如您在我的 TL;DR; 中的 Playground 中所见,如果您未指定,Apple 会打印“31 Dec 0001”而不是“31 Dec 0001 BC”带有 Era 的 DateFormatter,因此如果 OP 的本地时区不是 UTC,那么公元 1/1/1 很容易是 31/1/1 BC(前一天)。
NSDate / Date 可以有效地使用到过去约 3000 万年,但 NSDateComponents / DateComponents 操作在公元前 4500 年之前会失败。请继续阅读以了解详细信息...
TL;DR;
正如一些评论员和受访者所指出的,[NSDate distantPast](或 Swift 中的 Date.distantPast)由 API 提供,然而,这不是最低要求NSDate / Date - 这只是为了方便业务逻辑,因为很少有应用程序需要对 BCE 进行计算(请注意,.distantFuture 也是任意的 - 它是公元 4001 年 1 月 1 日)。
其他受访者 (@peko) 处理过真正的“distantFuture”最大值,但没有人完全探索过最小值。
那么,当您实际给它提供.distantPast 之前的日期时,Date 会做什么?这是一个小游乐场:
// Swift 5 Playground
import Foundation
var d = Date.distantPast // "31 Dec 1 at 23:58"
// However, that's the default print, which *does not* include Era
let df = DateFormatter()
df.dateFormat = "EEEE dd MMMM yyyy G" // "G" is Era
print(df.string(from: d)) // "Friday 31 December 0001 BC\n"
// What happens when we go lower?
d = d.addingTimeInterval(-1e12) // "29 Nov 31689 at 22:12"
print(df.string(from: d)) // Thursday 29 November 31689 BC\n"
// Lower still?
d = d.addingTimeInterval(-1e14) // "18 Feb 3200497 at 12:25"
print(df.string(from: d)) // "Tuesday 18 February 3200497 BC\n"
// But it breaks here...
d = d.addingTimeInterval(-1e15) // ""
print(df.string(from: d)) // "\n"
所以NSDate / Date 的有效时间最短为 3000 万年。
然而,我在计算时遇到了很多困难,而NSDate / Date 无法处理。
具体来说,Calendar 的.dateComponents(unitFlags, from: date) 失败(并打印如下错误消息),早于公元前 4713 年左右。
2021-12-03 19:15:48.885955+0000 Tempus II[61381:6027263] [一般]
CFAbsoluteTime -268229356861.914001 超出日历计算
范围。
... "-268229356861.914001" 是公元前 6500 年,但任何尝试对公元前 4713 年之前的任何事物进行 DateComponent 计算都会给出类似的信息,计算会出错!
这是另一个小游乐场,您可以自己尝试一下:
let df = DateFormatter()
df.dateFormat = "EEEE dd MMMM yyyy G" // "G" is Era
// 500BC -> by 1000 years, which works
let dc500 = DateComponents(calendar: .autoupdatingCurrent,
era: 0,
year: 500)
var d = Calendar.autoupdatingCurrent.date(from: dc500)!
print(df.string(from: d)) // Thursday 01 January 0500 BC\n"
d = Calendar.autoupdatingCurrent.date(byAdding: delta, to: d)!
print(df.string(from: d)) // "Monday 01 January 0501 AD\n"
// *** NB 501AD is the RIGHT answer for 500BC + 1000, as there
// *** was no year 0
d = Calendar.autoupdatingCurrent.date(byAdding: delta, to: d)!
print(df.string(from: d)) // "Friday 01 January 1501 AD\n"
// 5000BC -> by 2000 years, which doesn't work
delta = DateComponents(calendar: .autoupdatingCurrent,
year: 2000)
let dc5000 = DateComponents(calendar: .autoupdatingCurrent,
era: 0,
year: 5000)
d = Calendar.autoupdatingCurrent.date(from: dc5000)!
print(df.string(from: d)) // "Sunday 01 January 5000 BC\n"
d = Calendar.autoupdatingCurrent.date(byAdding: delta, to: d)!
print(df.string(from: d)) // "Tuesday 01 January 2713 BC\n"
// *** WRONG!
d = Calendar.autoupdatingCurrent.date(byAdding: delta, to: d)!
print(df.string(from: d)) // "Wednesday 01 January 0713 BC\n"
// *** Back on track again
d = Calendar.autoupdatingCurrent.date(byAdding: delta, to: d)!
print(df.string(from: d)) // "Thursday 01 January 1288 AD\n"
// *** Again, correct
// 713 -> 1BC + 1 AD -> 1288 = 1288 + 713 - 1 = 2000
附言
在不了解TimeZone、Calendar、DateComponents和DateFormatter的情况下,不要在业务逻辑中使用Date!