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
用于日期数学计算,Calendar
和 IndexSet
有强大的方法来做到这一点:
// 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
}
上下文
我正在制作一个应用程序,我的任务有截止日期,完成后我想根据用户选择的星期几重复模式设置新的截止日期.
我将截止日期保存为日期。我将重复模式保存为 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
用于日期数学计算,Calendar
和 IndexSet
有强大的方法来做到这一点:
// 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
}