[英]How to make hours and minutes of Swift's DateComponents comparable if not this way?
我正在開發的應用程序的要求使我在處理時間(特別是小時和分鍾)時將DateComponents
用作橋梁。 另一個要求讓我制作DateComponents: Comparable
並且當我發現一些令人討厭的行為時,我無法解釋。
為了論證,假設有一個組件,用戶可以在其中選擇他喜歡的時間。 他可以選擇一個預定義的時間來調整它。
由於應用程序的界面需要對更改做出反應,因此它應選擇最接近小時設置的枚舉。
enum TimeOfDay: String {
case morning
case evening
}
extension TimeOfDay {
private static let morningHours =
DateComponents(hour: 0, minute: 0)...DateComponents(hour: 15, minute: 00)
static func appropriateTimeOfDay(for time: DateComponents) -> Self {
var timeOfDay: Self?
if morningHours.contains(time) {
timeOfDay = .morning
} else {
timeOfDay = .evening
}
return timeOfDay!
}
}
因為我想使用func contains(_ element: Bound) -> Bool
,所以我的Bound
是DateComponents
,必須符合Comparable
。 我拿了一張紙,在上面跑了一些例子,這個實現看起來很合理。
在我的代碼中,我確保DateComponents.hour
和DateComponents.minute
在應該比較的地方永遠不會為nil
,因此強制解包。
extension DateComponents: Comparable {
public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool {
return lhs.hour! < rhs.hour! || lhs.minute! < rhs.minute!
}
}
但是,我遇到了問題。 測試表明,盡管contains
在范圍內工作了整整幾個小時,但只要幾分鍾發揮作用,時間就不會包含在范圍內。
樣品測試供那些希望自己檢查的人使用。
func testDateComponentsWithMinutesContainedInRange() {
let range = DateComponents(hour: 0, minute: 0)...DateComponents(hour: 15, minute: 0)
let hours = [
DateComponents(hour: 00, minute: 1),
DateComponents(hour: 12, minute: 30),
DateComponents(hour: 14, minute: 59),
]
// conditions for ClosedRange.contains
// all passed
for hour in hours {
XCTAssert(range.lowerBound < hour)
XCTAssert(hour < range.upperBound)
XCTAssertNotEqual(hour, range.lowerBound)
XCTAssertNotEqual(hour, range.upperBound)
}
// ClosedRange.contains
for time in hours {
XCTAssert(range.contains(time), "failed for \(time.hour!):\(time.minute!)")
}
}
經過幾個小時的撓頭,我找到了解決問題的絕妙答案。 代碼,為了方便讀者,貼在下面。
// [post][1]
// [author][2]
extension DateComponents: Comparable {
public static func < (lhs: DateComponents, rhs: DateComponents) -> Bool {
let now = Date()
let calendar = Calendar.current
return calendar.date(byAdding: lhs, to: now)! < calendar.date(byAdding: rhs, to: now)!
}
}
我的問題仍然存在——我的嘗試有什么問題? 我只想檢查DateComponents
的小時和分鍾,而它們都是Int?
.
我的瘋狂猜測是,分鍾有 60(實際上是 59)秒這一事實使得比較器contains
go 瘋子。
你的擴展沒有意義。
考慮這個例子:
let lhs = DateComponents(hour: 13, minute: 2)
let rhs = DateComponents(hour: 12, minute: 12)
print(lhs < rhs)
即使 13:02 明顯在(也就是大於)12:12 之后,打印結果為真。
您將不得不進行數學計算以計算總分鍾數並比較這些分鍾值。 對於數小時和數分鍾,手動計算還算不錯,但當您計算數天、數周和數月時,就會變得一團糟。 (一個月有多少天?哪個月?一年有多少天?是閏年嗎?)
將 dateComponents 添加到某個日期至少有一定的意義。 當您將 2 組不同的日期組件添加到固定日期時,當您添加描述最長時間跨度的 DateComponents object 時,生成的日期(可比較)將是最大的。
請記住,將組件添加到日期也有陷阱,具體取決於您使用的單位以及您用作“基准日期”的日期。 (例如,我在當前日期上加一個月。那是多少天?取決於。是二月,有 29 天,還是一月,有 31 天?)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.