如何在 Swift 上使用 strideable 逐日从 StartDate 迭代到 EndDate?

Jam*_*mes 3 date ios swift

我试图创建一个接收函数:

- 开始日期 (DATE)。

- 结束日期 (DATE)。

能够以 yyyy-MM-dd 格式逐日迭代打印日期

但我收到以下错误:

"Cannot invoke 'stride' with an argument list of type '(from: Date, to: Date, by: Int)'"
Run Code Online (Sandbox Code Playgroud)

我尝试了什么?

我的约会对象符合跨步协议

extension Date: Strideable {
    public func distance(to other: Date) -> TimeInterval {
        return other.timeIntervalSinceReferenceDate - self.timeIntervalSinceReferenceDate
    }

    public func advanced(by n: TimeInterval) -> Date {
        return self + n
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我可以使用 stride 函数

stride(from: <#T##Strideable#>, to: <#T##Strideable#>, by: <#T##Comparable & SignedNumeric#>)
Run Code Online (Sandbox Code Playgroud)

在我的 ViewDidLoad 上尝试运行它

override func viewDidLoad() {
        super.viewDidLoad()
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy/MM/dd"
        let startDate = formatter.date(from: "2014/01/01")
        let endDate = formatter.date(from: "2019/03/31")
        let dayDurationInSeconds = 60*60*24

        for date in stride(from: startDate!, to: endDate!, by: dayDurationInSeconds) {
            print(date)
        }
}
Run Code Online (Sandbox Code Playgroud)

我希望在我的控制台上看到什么?

2014-01-01
2014-01-02
2014-01-03
.........
2019-03-30
2019-03-31
Run Code Online (Sandbox Code Playgroud)

Rob*_*ier 8

您的代码不编译因为你用整数大步,但是已经定义了你StrideTimeInterval。如果您修复以下类型,它将完成您期望的大部分工作dayDurationInSeconds

let dayDurationInSeconds: TimeInterval = 60*60*24
Run Code Online (Sandbox Code Playgroud)

但这会给你完全错误的结果,因为不是每天都是 86,400 秒。DST 每年两次以位置相关的方式改变白天的长度。

执行日期数学的正确方法是使用Calendar. 如果您不使用Calendar,则不能使用任何未在几秒钟内明确显示的内容。

您可能想要的是更像这样的东西,它枚举相关日期之间的所有午夜 (UTC)。请记住,DateFoundation 中的 a 不是“约会”。这是一个精确的瞬间。如果您真的想使用“日期”,那么您想要的是DateComponents.

let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
let startDate = formatter.date(from: "2014/01/01")!
let endDate = formatter.date(from: "2019/03/31")!

var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(identifier: "UTC")!

calendar.enumerateDates(startingAfter: startDate,
                        matching: DateComponents(hour: 0, minute: 0, second:0),
                        matchingPolicy: .nextTime) { (date, _, stop) in
                            guard let date = date, date < endDate else {
                                stop = true
                                return
                            }

                            print(date)
}
Run Code Online (Sandbox Code Playgroud)