双周发薪频率的开始 date/end 日期 - Swift

Start date/end date for biweekly payroll frequency - Swift

我必须提供特定薪资频率周期的时间跟踪摘要:每月、每周、每两周。我确实找到了一种方法来获取当前周或当前月份的开始日期和结束日期,例如

var startOfMonth: Date? {
    let components = Calendar.current.dateComponents([.year, .month], from: startOfDay)
    return Calendar.current.date(from: components)
}

var endOfMonth: Date? {
    guard let startOfTheMonth = startOfMonth else { return nil }
    var components = DateComponents()
    components.month = 1
    components.second = -1
    return Calendar.current.date(byAdding: components, to: startOfTheMonth)
}

但是我怎样才能得到当前双周周期的那些日期呢?

我假设双周周期(一年 26 次薪水)是从今年年初开始每两周一次:例如。第一个双周是 2020 年的第 1-2 周是 1.01.20-12.01.20;第 24 个双周是 47-48 周是 16.11.20-29.11.20,最后 26 个双周是 51-53 周是 14.12.20-31.12.20。

编辑:

根据@Leo Dabus 的回答,我设法获得了 startOfBiweek 和 endOfBiweek。谢谢!

var startOfBiweek: Date? {
    let biweekIntervals = biweekIntervalsInSameYear(using: .iso8601)
    return biweekIntervals.first(where: { [=13=].contains(self)})?.start
}

var endOfBiweek: Date? {
    let biweekIntervals = biweekIntervalsInSameYear(using: .iso8601)
    return biweekIntervals.first(where: { [=13=].contains(self)})?.end
}

我不知道是否有更简单的方法来完成您想要的,但这就是我想到的。首先,我得到了同一年的所有日子。然后我创建一个包含 26 个子数组的数组,每 2 周对日期进行一次分组。然后我使用每个子数组的第一个和最后一个日期创建一个日期间隔数组。

extension Calendar {
    static let iso8601 = Calendar(identifier: .iso8601)
}
extension Date {
    func dayAfter(using calendar: Calendar = .current) -> Date {
        calendar.date(byAdding: .day, value: 1, to: noon(using: calendar))!
    }
    func noon(using calendar: Calendar = .current) -> Date  {
        calendar.date(bySettingHour: 12, minute: 0, second: 0, of: self)!
    }
    func startOfNextDay(using calendar: Calendar = .current) -> Date {
        calendar.startOfDay(for: dayAfter(using: calendar))
    }
    func lastSecondOfDay(using calendar: Calendar = .current) -> Date {
        calendar.date(byAdding: DateComponents(second: -1), to: calendar.startOfDay(for: dayAfter(using: calendar)))!
    }
    func weekOfYear(using calendar: Calendar = .current) -> Int { calendar.component(.weekOfYear, from: self) }
    func year(using calendar: Calendar = .current) -> Int { calendar.component(.year, from: self) }
    func month(using calendar: Calendar = .current) -> Int { calendar.component(.month, from: self) }
    func allDaysInSameYear(using calendar: Calendar = .current) -> [Date] {
        calendar.range(of: .day, in: .year, for: self)!.map {
            DateComponents(calendar: calendar,year: year(using: calendar), day: [=10=]).date!
        }
    }
    func biweeksInSameYear(using calendar: Calendar = .current) -> [[Date]] {
        allDaysInSameYear(using: calendar).reduce(into: .init(repeating: [], count: 26)) {
            let weekOfYear = .weekOfYear(using: calendar)-1
            let index = weekOfYear > 51 ? 25 : weekOfYear / 2
            [=10=][index].append()
        }
    }
    func biweekIntervalsInSameYear(using calendar: Calendar = .current) -> [DateInterval] {
        biweeksInSameYear(using: calendar).map {
            DateInterval(start: [=10=].first!, end: [=10=].last!.lastSecondOfDay(using: calendar))
        }
    }
}

let biweekIntervals = Date().biweekIntervalsInSameYear(using: .iso8601)
for interval in biweekIntervals {
    print(interval.start.description(with: .current), interval.end.description(with: .current), terminator: "\n")
} 

这将打印:

Wednesday, 1 January 2020 00:00:00 Sunday, 12 January 2020 23:59:59
Monday, 13 January 2020 00:00:00 Sunday, 26 January 2020 23:59:59
Monday, 27 January 2020 00:00:00 Sunday, 9 February 2020 23:59:59
Monday, 10 February 2020 00:00:00 Sunday, 23 February 2020 23:59:59
Monday, 24 February 2020 00:00:00 Sunday, 8 March 2020 23:59:59
Monday, 9 March 2020 00:00:00 Sunday, 22 March 2020 23:59:59
Monday, 23 March 2020 00:00:00 Sunday, 5 April 2020 23:59:59
Monday, 6 April 2020 00:00:00 Sunday, 19 April 2020 23:59:59
Monday, 20 April 2020 00:00:00 Sunday, 3 May 2020 23:59:59
Monday, 4 May 2020 00:00:00 Sunday, 17 May 2020 23:59:59
Monday, 18 May 2020 00:00:00 Sunday, 31 May 2020 23:59:59
Monday, 1 June 2020 00:00:00 Sunday, 14 June 2020 23:59:59
Monday, 15 June 2020 00:00:00 Sunday, 28 June 2020 23:59:59
Monday, 29 June 2020 00:00:00 Sunday, 12 July 2020 23:59:59
Monday, 13 July 2020 00:00:00 Sunday, 26 July 2020 23:59:59
Monday, 27 July 2020 00:00:00 Sunday, 9 August 2020 23:59:59
Monday, 10 August 2020 00:00:00 Sunday, 23 August 2020 23:59:59
Monday, 24 August 2020 00:00:00 Sunday, 6 September 2020 23:59:59
Monday, 7 September 2020 00:00:00 Sunday, 20 September 2020 23:59:59
Monday, 21 September 2020 00:00:00 Sunday, 4 October 2020 23:59:59
Monday, 5 October 2020 00:00:00 Sunday, 18 October 2020 23:59:59
Monday, 19 October 2020 00:00:00 Sunday, 1 November 2020 23:59:59
Monday, 2 November 2020 00:00:00 Sunday, 15 November 2020 23:59:59
Monday, 16 November 2020 00:00:00 Sunday, 29 November 2020 23:59:59
Monday, 30 November 2020 00:00:00 Sunday, 13 December 2020 23:59:59
Monday, 14 December 2020 00:00:00 Thursday, 31 December 2020 23:59:59



另一种方法,这种方法似乎更短,但我建议进一步测试它:

extension Calendar {
    static let iso8601 = Calendar(identifier: .iso8601)
}
extension Date {
    func startOfYear(using calendar: Calendar = .current) -> Date {
        calendar.dateComponents([.calendar,.year], from: self).date!
    }
    func endOfYear(using calendar: Calendar = .current) -> Date {
        startOfYear(using: calendar).adding(.init(year: 1, second: -1))!
    }
    func adding(_ components: DateComponents, wrappingComponents: Bool = false, using calendar: Calendar = .current) -> Date? {
        calendar.date(byAdding: components, to: self)
    }
    func yearForWeekOfYear(using calendar: Calendar = .current) -> Int { 
        calendar.component(.yearForWeekOfYear, from: self)
    }
    func biweekIntervalsInSameYear(using calendar: Calendar = .current) -> [DateInterval] {
        let date = DateComponents(calendar: .iso8601, weekOfYear: 1, yearForWeekOfYear: yearForWeekOfYear(using: .iso8601)).date!
        var intervals: [DateInterval] = [.init(start: startOfYear(using: .iso8601), end: date.adding( .init(second: -1, weekOfYear: 2), using: calendar)!)]
        var weekOfYear = 3
        while let start = Calendar.iso8601.nextDate(after: date, matching: DateComponents(weekOfYear: weekOfYear), matchingPolicy: .strict) {
            if intervals.count < 25 {
                intervals.append(.init(start: start, end: start.adding( .init(second: -1, weekOfYear: 2), using: calendar)!)) } else if intervals.count == 25 {
                    intervals.append(.init(start: start, end: start.endOfYear(using: .iso8601)))
            }
            weekOfYear += 2
        }
        return  intervals
    }
}