在Swift中迭代日期范围的最有效方法是什么?

sha*_*dev 5 ios swift

我正在构建一个Swift习惯构建应用程序.在某一时刻,用户选择他们想要创建的习惯的持续时间(以天为单位).用户还可以选择他们想要练习的星期几(星期日,星期一,星期二等).开始日期是他们养成习惯的日子.

我目前有开始日期和结束日期(基于用户选择的天数).但是,在该日期范围内,我需要提取用户选择的特定日期的日期.

我的想法是,对于时间间隔内的每个工作日值'x'(startDate,endDate),返回日历日期.但是,我尝试创建一个DateInterval,我无法迭代它,因为它不符合协议'序列'.

有没有一种有效的方法来迭代这个日期范围并提取这些其他日期?有没有更好的方式,我还没有想到?

这是我目前的日期入门代码如下:

var date = Date()
var duration = 10
let calendar = Calendar.current

let dateEnding = Calendar.current.date(byAdding: .day, value: duration, to: date as Date)!

//Returns a number representing day of the week.  i.e. 1 = Sunday
let weekDay = calendar.component(.weekday, from: date)


//Initializing a time interval, based on user selected duration and start date
let timeInterval = DateInterval.init(start: date, end: dateEnding)
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助...

And*_*eev 15

我们可以采取Strideable协议的力量:

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)

然后在你的功能中:

// Iterate by 1 day
// Feel free to change this variable to iterate by week, month etc.
let dayDurationInSeconds: TimeInterval = 60*60*24
for date in stride(from: startDate, to: endDate, by: dayDurationInSeconds) {
    print(date)
}
Run Code Online (Sandbox Code Playgroud)

输出:

2018-07-19 12:18:07 +0000
2018-07-20 12:18:07 +0000
2018-07-21 12:18:07 +0000
2018-07-22 12:18:07 +0000
2018-07-23 12:18:07 +0000
....
Run Code Online (Sandbox Code Playgroud)

代码取自此提案

  • 这是否适用于夏令时?例如,日期间隔何时包含小时变化的那一天? (3认同)
  • 日子并不总是持续那么多秒。我强烈建议使用内置日历函数 (3认同)
  • 不幸的是,当当前日期是 **1 月 29 日、30 日或 31 日** 时,我遇到了一个无限循环问题,而您尝试迭代超过 40 天。不清楚为什么这种边缘情况存在,但 **for 循环永远不会终止**。 (2认同)

rma*_*ddy 8

如果我正确理解您的问题,用户将在某些工作日核对并提供一段时间的持续时间.

假设您在数组中选择了工作日和持续时间,您可以获得匹配日期列表,如下所示:

// User selected weekdays (1 = Sunday, 7 = Saturday)
var selectedWeekdays = [2, 4, 6] // Example - Mon, Wed, Fri
var duration = 10 // Example - 10 days

let calendar = Calendar.current
var today = Date()
let dateEnding = calendar.date(byAdding: .day, value: duration, to: today)!

var matchingDates = [Date]()
// Finding matching dates at midnight - adjust as needed
let components = DateComponents(hour: 0, minute: 0, second: 0) // midnight
calendar.enumerateDates(startingAfter: today, matching: components, matchingPolicy: .nextTime) { (date, strict, stop) in
    if let date = date {
        if date <= dateEnding {
            let weekDay = calendar.component(.weekday, from: date)
            print(date, weekDay)
            if selectedWeekdays.contains(weekDay) {
                matchingDates.append(date)
            }
        } else {
            stop = true
        }
    }
}

print("Matching dates = \(matchingDates)")
Run Code Online (Sandbox Code Playgroud)

  • @OwenGodfrey这个被弃用的方式是什么?所有这些API仍在使用中. (5认同)

Ale*_*nov 5

尝试这个

let calendar = NSCalendar.currentCalendar()
let startDate = ...
let endDate = ...
let dateRange = calendar.dateRange(startDate: startDate,
                                     endDate: endDate,
                                   stepUnits: .Day,
                                   stepValue: 1)

for date in dateRange {
    print("It's \(date)!")
}
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是 dateRange 已被弃用并且不再适用于 Swift 4。 (7认同)
  • 这是 Swift 2 代码。为什么?Swift 2 早已不复存在。Swift 4 是当前版本。 (3认同)