簡體   English   中英

如果不是這樣,如何使 Swift 的 DateComponents 的小時和分鍾具有可比性?

[英]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
}

分機 function

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 ,所以我的BoundDateComponents ,必須符合Comparable 我拿了一張紙,在上面跑了一些例子,這個實現看起來很合理。

在我的代碼中,我確保DateComponents.hourDateComponents.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 天?)

如何在 swift 4

[英]How to skip the rounding of the time when it is coming exact hours and minutes in swift 4

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM