在一个月内获得工作日

时间:2016-02-24 11:59:19

标签: ios swift nsdate weekday weekend

我试图在一个月内获得日期。

我的计划是

  1. 获取给定月份的开始和结束日期,。
  2. 获取该范围内的所有日期。
  3. 使用isDateInWeekend方法迭代它们并消除周末内的日期。
  4. 剩余的日期是工作日。

    所以我创建了两个NSDate扩展方法来获取月份的开始和结束日期。

    extension NSDate {
        var startOfMonth: NSDate {
            let calendar = NSCalendar.currentCalendar()
            let components = calendar.components([.Year, .Month], fromDate: self)
            return calendar.dateFromComponents(components)!
        }
    
        var endOfMonth: NSDate {
            let calendar = NSCalendar.currentCalendar()
            let components = NSDateComponents()
            components.month = 1
            return (calendar.dateByAddingComponents(components, toDate: self.startOfMonth, options: NSCalendarOptions())?.dateByAddingTimeInterval(-1))!
        }
    }
    

    现在我被困在第二步了。在找到开始日期和结束日期时,我无法找到一种方法来获得一系列日期。

    有办法做到这一点吗?

3 个答案:

答案 0 :(得分:4)

  • 获取当前日历

    let calendar = NSCalendar.currentCalendar()
    
  • 从当前日期获取monthyear日期组件

    let components = calendar.components([.Year, .Month], fromDate: NSDate())
    
  • 获取该月第一天的日期

    let startOfMonth = calendar.dateFromComponents(components)!
    
  • 获取当月的天数

    let numberOfDays = calendar.rangeOfUnit(.Day, inUnit: .Month, forDate: startOfMonth).length
    
  • 为当月的每一天创建一个NSDate个实例数组

    let allDays = Array(0..<numberOfDays).map{ calendar.dateByAddingUnit(.Day, value: $0, toDate: startOfMonth, options: [])!}
    
  • 过滤周末内的天数

    let workDays = allDays.filter{ !calendar.isDateInWeekend($0) }
    

斯威夫特3:

let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month], from: Date())
let startOfMonth = calendar.date(from:components)!
let numberOfDays = calendar.range(of: .day, in: .month, for: startOfMonth)!.upperBound
let allDays = Array(0..<numberOfDays).map{ calendar.date(byAdding:.day, value: $0, to: startOfMonth)!}
let workDays = allDays.filter{ !calendar.isDateInWeekend($0) }

答案 1 :(得分:1)

要获得比上面给出的更一般的答案,您可以实施自己的SequenceType运行/生成NSDate元素。

this blog post by Adam Preble修改SequenceType DateRange实施(Swift&lt; 2.0),我们可以构建以下内容:

/* Modified version of Adam Preble:s DateRange: http://adampreble.net/blog/2014/09/iterating-over-range-of-dates-swift/ */
func < (left: NSDate, right: NSDate) -> Bool {
    return left.compare(right) == NSComparisonResult.OrderedAscending
}

struct DateRange : SequenceType {
    var calendar: NSCalendar
    var startDate: NSDate
    var endDate: NSDate
    var stepUnits: NSCalendarUnit
    var stepValue: Int

    func generate() -> Generator {
        return Generator(range: self, firstDate: true)
    }

    struct Generator: GeneratorType {
        var range: DateRange
        var firstDate : Bool = true

        mutating func next() -> NSDate? {
            if firstDate {
                firstDate = false
                return range.startDate
            }

            guard let nextDate = range.calendar.dateByAddingUnit(range.stepUnits,
                value: range.stepValue, toDate: range.startDate,
                options: NSCalendarOptions.MatchFirst) where !(range.endDate < nextDate) else {
                    return nil
            }

            range.startDate = nextDate
            return nextDate
        }
    }
}

有了这个,你可以迭代一系列NSDate:s,就像你可以结束一系列整数而不需要明确需要一个NSDate个对象< / em>的

使用示例(使用startOfMonth()的{​​{1}}和endOfMonth()扩展名:

NSDate

输出:

/* Your NSDate extension */
extension NSDate {
    // ... as in your question above
}

/* Example usage */
let formatter = NSDateFormatter()
formatter.dateFormat = "EEE, MMM. d, yyyy"

// print week days of current month, using DateRange (as well as your extension)
if let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) {

    let dateRange = DateRange(calendar: calendar,
        startDate: NSDate().startOfMonth,
        endDate: NSDate().endOfMonth,
        stepUnits: NSCalendarUnit.Day,
        stepValue: 1)

    for date in dateRange where !calendar.isDateInWeekend(date) {
        print(formatter.stringFromDate(date))
    }
}

数组(/* Mon, Feb. 1, 2016 Tue, Feb. 2, 2016 Wed, Feb. 3, 2016 Thu, Feb. 4, 2016 Fri, Feb. 5, 2016 Mon, Feb. 8, 2016 Tue, Feb. 9, 2016 ... Thu, Feb. 25, 2016 Fri, Feb. 26, 2016 Mon, Feb. 29, 2016 */ )中一个月的日期可能不是问题,但是使用序列代替对于更大的日期跨度,以及当您需要多功能性时,w.r.t。重新分配数组的大小和成员;特别是一个数组,在这个数组中,你一次只能按顺序使用一个成员。

E.g。在下面的示例中使用[NSDate]数组是非常不必要的(并且可能会产生不必要的开销;但是让我们离开,因为我们想避免一些评论者提出早熟优化罪的主题:))

NSDate

输出:

// versatile use of DateRange over somewhat "large" ranges of dates
formatter.dateFormat = "yyyy-MM-dd"
if let calendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian),
    startDate = formatter.dateFromString("2016-01-01"),
    endDate = formatter.dateFromString("2016-12-31") {

    formatter.dateFormat = "EEE, MMM. d, yyyy"

    // initialize dateRange instance
    var dateRange = DateRange(calendar: calendar,
        startDate: startDate,
        endDate: endDate,
        stepUnits: NSCalendarUnit.Day,
        stepValue: 1)

    // print all week days of 2016
    for date in dateRange where !calendar.isDateInWeekend(date) {
        print(formatter.stringFromDate(date))
    }
    print("")

    // re-use same dateRange instance and print
    // all week days of July 2016 -> June 2017
    formatter.dateFormat = "yyyy-MM-dd"
    if let startDate = formatter.dateFromString("2016-07-01"),
        endDate = formatter.dateFromString("2017-06-30") {

        // update dateRange instance
        dateRange.startDate = startDate
        dateRange.endDate = endDate
        formatter.dateFormat = "EEE, MMM. d, yyyy"
        for date in dateRange where calendar.isDateInWeekend(date) {
            print(formatter.stringFromDate(date))
        }
    }
}

答案 2 :(得分:0)

answer的帮助下,我能够做到这一点。

let calendar = NSCalendar.currentCalendar()
let normalizedStartDate = calendar.startOfDayForDate(NSDate().startOfMonth)
let normalizedEndDate = calendar.startOfDayForDate(NSDate().endOfMonth)

var dates = [normalizedStartDate]
var currentDate = normalizedStartDate
repeat {
    currentDate = calendar.dateByAddingUnit(NSCalendarUnit.Day, value: 1, toDate: currentDate, options: .MatchNextTime)!
    dates.append(currentDate)
} while !calendar.isDate(currentDate, inSameDayAsDate: normalizedEndDate)

let weekdays = dates.filter { !calendar.isDateInWeekend($0) }
weekdays.forEach { date in
    print(NSDateFormatter.localizedStringFromDate(date, dateStyle: .FullStyle, timeStyle: .NoStyle))
}

它有效!

Monday, February 1, 2016
Tuesday, February 2, 2016
Wednesday, February 3, 2016
Thursday, February 4, 2016
Friday, February 5, 2016
Monday, February 8, 2016
Tuesday, February 9, 2016
Wednesday, February 10, 2016
Thursday, February 11, 2016
Friday, February 12, 2016
Monday, February 15, 2016
Tuesday, February 16, 2016
Wednesday, February 17, 2016
Thursday, February 18, 2016
Friday, February 19, 2016
Monday, February 22, 2016
Tuesday, February 23, 2016
Wednesday, February 24, 2016
Thursday, February 25, 2016
Friday, February 26, 2016
Monday, February 29, 2016