Swift - 从一组工作日中获取下一个日期

Swift - Get next date from a array of weekdays

上下文

我正在制作一个应用程序,我的任务有截止日期,完成后我想根据用户选择的星期几重复模式设置新的截止日期.

我将截止日期保存为日期。我将重复模式保存为 Int32(星期日 1 个,星期一 2 个,星期二 4 个...),但我可以轻松地将它保存为代表每一天的字符串或数字数组

问题

如何获取下一个截止日期作为日期(以便我可以重复任务)?

例子

如果我有一项任务在星期六完成并且具有每周一和周三的重复模式,我希望将其设置为下周一。如果是星期一或星期二完成的我想定下星期三。

选择重复图案的照片

选择其他日期时从不选择月份。我知道如何处理这个月。问题在于星期几

希望这段代码对您有所帮助

let SecondsPerDay: Int = (24 * 60 * 60)

enum DayOfWeek: Int
{
    case sunday = 1
    case monday = 2
    case tuesday = 3
    case wendnesday = 4
    case thrusday = 5
    case friday = 6
    case saturday = 7

    /**
        Convert a date to a enumeration member
    */
    static func day(from date: Date) -> DayOfWeek
    {
        let formatter: DateFormatter = DateFormatter()
        formatter.dateFormat = "e"


        let day_number: Int = Int(formatter.string(from: date))!

        return DayOfWeek(rawValue: day_number)
    }
}


/**
    Calculate the `TimeInterval` between days contained
    in user preferences.

    - Parameter days: Period selected by user
    - Returns: Interval between dates days
*/
func calculatePattern(withDays days: [DayOfWeek]) -> [TimeInterval]
{
    var pattern: [TimeInterval] = [TimeInterval]()

    for (index, day) in days.enumerated()
    {
        let distance: Int = (index == (days.count - 1)) ?  (7 - (day.rawValue - days[0].rawValue)) : days[index + 1].rawValue - day.rawValue

        let interval: TimeInterval = TimeInterval(SecondsPerDay * distance)

        pattern.append(interval)
    }

    return pattern
}

func nextDay(from days: [DayOfWeek]) -> DayOfWeek
{
    let today: DayOfWeek = DayOfWeek.day(from: Date())

    guard let days = days.filter({ [=10=].rawValue > today.rawValue }) else
    {
        return days.first!
    }

    return days.first!
}



let selectedDays: [DayOfWeek] = [ .monday, .wendnesday, .sunday, .saturday ]

// Pass the array sorted by day in week
let intervals: [TimeInterval] = calculatePattern(withDays: selectedDays.sorted(by: { [=10=].rawValue < .rawValue}))

for interval in intervals
{
    print(interval)
}

TimeInterval 可以使用 Date class 初始值设定项之一在 Date 中转换。

切勿将 86400 用于日期数学计算,CalendarIndexSet 有强大的方法来做到这一点:

// Put your weekday indexes in an `IndexSet`
let weekdaySet = IndexSet([1, 2, 4, 7]) // Sun, Mon, Wed and Sat

// Get the current calendar and the weekday from today
let calendar = Calendar.current
var weekday =  calendar.component(.weekday, from: Date())

// Calculate the next index
if let nextWeekday = weekdaySet.integerGreaterThan(weekday) {
    weekday = nextWeekday
} else {
    weekday = weekdaySet.first!
}

// Get the next day matching this weekday
let components = DateComponents(weekday: weekday)
calendar.nextDate(after: Date(), matching: components, matchingPolicy: .nextTime)
func getdateArryFromWeekdays(_ date: Date, onWeekdaysForNotify weekdays:[Int]) -> [Date]{
    var correctedDate: [Date] = [Date]()
    let now = Date()
    let calendar = Calendar(identifier: Calendar.Identifier.gregorian)
    let flags: NSCalendar.Unit = [NSCalendar.Unit.weekday, NSCalendar.Unit.weekdayOrdinal, NSCalendar.Unit.day]
    let dateComponents = (calendar as NSCalendar).components(flags, from: date)
    let weekday:Int = dateComponents.weekday!

    //no repeat
    if weekdays.isEmpty{
        //scheduling date is eariler than current date
        if date < now {
            //plus one day, otherwise the notification will be fired righton
            correctedDate.append((calendar as NSCalendar).date(byAdding: NSCalendar.Unit.day, value: 1, to: date, options:.matchNextTime)!)
        }
        else { //later
            correctedDate.append(date)
        }
        return correctedDate
    }
        //repeat
    else {
        let daysInWeek = 7
        correctedDate.removeAll(keepingCapacity: true)
        for wd in weekdays {

            var wdDate: Date!
            //schedule on next week
            if compare(weekday: wd, with: weekday) == .before {
                wdDate =  (calendar as NSCalendar).date(byAdding: NSCalendar.Unit.day, value: wd+daysInWeek-weekday, to: date, options:.matchStrictly)!
            }
            else { //after
                wdDate =  (calendar as NSCalendar).date(byAdding: NSCalendar.Unit.day, value: wd-weekday, to: date, options:.matchStrictly)!
            }

            //fix second component to 0
            wdDate = correctSecondComponent(date: wdDate, calendar: calendar)
            correctedDate.append(wdDate)
        }
        return correctedDate
     }

}
func correctSecondComponent(date: Date, calendar: Calendar = Calendar(identifier: Calendar.Identifier.gregorian))->Date {
    let second = calendar.component(.second, from: date)
    let d = (calendar as NSCalendar).date(byAdding: NSCalendar.Unit.second, value: -second, to: date, options:.matchStrictly)!
    return d
}
enum weekdaysComparisonResult {
    case before
    case same
    case after
}