Swift - 给定一个固定的字符串数组(时间),找到下一个最接近的时间

Swift - Given a fixed array of Strings (times), find the next closest time

我正在使用 UIKit 开发一个简单的 iOS 应用程序,它可以显示下一班公交车的发车时间。

我有一个字符串数组,代表出发时间。我已将这些字符串转换为 DateComponents 对象并尝试使用 .nextDate 方法访问下一个最接近的时间。不幸的是,在搜索并尝试了各种选项之后,我似乎无法弄清楚。我尝试了一个具有固定值的日期组件对象。这有效,但没用。我需要从数组中获取值(除非有另一个我不知道的选项)。

到目前为止我的代码看起来是什么:

let currentTime = Date()
    let calendar = Calendar.current
    
var busTimes = ["15:02", "15:27", "15:52", "16:12", "16:37", "17:02", "17:27", "17:52", "18:12", "18:32", "18:52", "19:17"]

 @IBAction func calculateRoute(_ sender: Any) {
    
        
        let myDate = busTimes[0].getMyDate() 

let nextBusTime = calendar.nextDate(after: currentTime, matching: myDate, matchingPolicy: .nextTime, repeatedTimePolicy: .first, direction: .forward )!

print(nextBusTime) //prints only the first value ofc

}

extension String {
    func getMyDate() -> DateComponents {
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "HH:mm"
        dateFormatter.timeZone = TimeZone.current
        let date = dateFormatter.date(from: self)
        let dateComp = Calendar.current.dateComponents([.hour, .minute], from: date!)
        
        return dateComp
    }
}

我希望 return 下一个最接近的值。假设当前时间是 15:15,那么输出应该是下一个最接近的时间,即 15:27.

提前致谢!

首先让我们定义一个允许我们表达时间的类型。

struct Time {
    let hour: Int
    let minute: Int

    static let zero = Time(hour: 0, minute: 0)
}

让我们也实现一个初始化器,这样我们就可以方便地传入字符串化的时间值

extension Time {
    init(_ string: String) {
        let ints = string
            .components(separatedBy: ":")
            .compactMap(Int.init)
        hour = ints.first ?? 0
        minute = ints.last ?? 0
    }
}

let timeFromString = Time("2:30")

让我们也符合 Comparable 以便我们可以比较 Time 个值并对 Time 个值Array 进行排序

extension Time: Comparable {
    static func < (lhs: Time, rhs: Time) -> Bool {
        return lhs.hour * 60 + lhs.minute < rhs.hour * 60 + rhs.minute
    }
}

print(Time("02:00") < Time("03:44"))
print([Time("03:44"), Time("02:00"), Time("1:30")].sorted())

true

[01:30, 02:00, 03:44]

这只是为了好玩。我们可以用 String 文字

初始化 Time
extension Time: ExpressibleByStringLiteral {
    init(stringLiteral: String) {
        self.init(stringLiteral)
    }
}

let timeFromStringLiteraL: Time = "3:30"

这将使我们能够将 Time 值转换为友好的 String 值,主要用于调试。

extension Time: CustomStringConvertible {
    var description: String {
        return String(format: "%02d:%02d", hour, minute)
    }
}

print(Time("4:30"))

04:30

现在让我们扩展 Calendar 以便我们可以将 Date 值转换为 Time

extension Calendar {
    func time(from date: Date) -> Time? {
        let timeComponents = dateComponents([.hour, .minute], from: date)
        guard let hour = timeComponents.hour,
                let minute = timeComponents.minute else { return nil }
        return Time(hour: hour, minute: minute)
    }
}

let timeFromDate = Calendar.current.time(from: Date())

现在让我们创建一个类型来为我们管理 Time 值。请注意当您传入时间值时它是如何排序的。这会设置 next(after:) 方法,因此它可以轻松找到指定时间后的下一个时间。

struct Schedule {
    let times: [Time]

    init(times: [Time]) {
        self.times = times.sorted()
    }

    func next(after time: Time) -> Time? {
        times.first(where: { [=16=] > time })
    }
}

综合起来

let times: [Time] = ["01:22", "15:02", "15:27", "15:52", "16:12", "16:37", "20:00", "17:02", "17:27", "17:52", "18:12", "18:32", "18:52", "19:46", "18:37", "19:17", "19:32", "19:33"]

let schedule = Schedule(times: times)

let now = Calendar.current.time(from: Date())!
let next = schedule.next(after: now)
print("Next time: \(next ?? .zero)")

或:

["01:22", "15:02", "15:27", "20:22", "20:23"]
    .map { Time([=18=]) }
    .filter { [=18=] > now }
    .sorted()
    .prefix(1)
    .forEach { print([=18=]) }