获取一个月内的工作日
Get weekdays within a month
我正在尝试获取给定月份内的日期。
我的计划是
- 获取给定月份的开始日期和结束日期。
- 获取该范围内的所有日期。
- 遍历它们并使用
isDateInWeekend
方法消除周末内的日期。
其余日期为工作日。
所以我创建了两个 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))!
}
}
现在我卡在了第 2 步。在给定开始日期和结束日期的情况下,我找不到获取日期范围的方法。
有办法吗?
在这个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([=10=]) }
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
获取当前日历
let calendar = NSCalendar.currentCalendar()
从当前日期
获取month
和year
日期组件
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: [=14=], toDate: startOfMonth, options: [])!}
过滤周末中的天数
let workDays = allDays.filter{ !calendar.isDateInWeekend([=15=]) }
Swift 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: [=16=], to: startOfMonth)!}
let workDays = allDays.filter{ !calendar.isDateInWeekend([=16=]) }
要获得比上面给出的答案更一般的答案,您可以实现自己的 SequenceType
运行 over/generating NSDate
元素。
从this blog post by Adam Preble(Swift < 2.0)修改SequenceType
DateRange
实现,我们可以构造如下:
/* 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 的范围,就像你可以遍历一个整数范围一样, 而无需明确需要 [=16] 的数组=] 对象.
示例用法(利用 startOfMonth()
和 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 */
数组中一个月的日期 ([NSDate]
) 可能不是问题,但使用序列代替对于更大的日期跨度很有价值,而且当您需要多功能性时,w.r.t .重新分配数组的大小和成员;特别是一个数组,其中您实际上一次只按顺序使用一个成员。
例如在下面的示例中使用 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))
}
}
}
输出:
/* 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
...
Fri, Dec. 23, 2016
Mon, Dec. 26, 2016
Tue, Dec. 27, 2016
Wed, Dec. 28, 2016
Thu, Dec. 29, 2016
Fri, Dec. 30, 2016
// 2nd range print
Fri, Jul. 1, 2016
Mon, Jul. 4, 2016
Tue, Jul. 5, 2016
Wed, Jul. 6, 2016
Thu, Jul. 7, 2016
...
Fri, Jun. 23, 2017
Mon, Jun. 26, 2017
Tue, Jun. 27, 2017
Wed, Jun. 28, 2017
Thu, Jun. 29, 2017
Fri, Jun. 30, 2017 */
我正在尝试获取给定月份内的日期。
我的计划是
- 获取给定月份的开始日期和结束日期。
- 获取该范围内的所有日期。
- 遍历它们并使用
isDateInWeekend
方法消除周末内的日期。
其余日期为工作日。
所以我创建了两个 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))!
}
}
现在我卡在了第 2 步。在给定开始日期和结束日期的情况下,我找不到获取日期范围的方法。
有办法吗?
在这个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([=10=]) }
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
获取当前日历
let calendar = NSCalendar.currentCalendar()
从当前日期
获取month
和year
日期组件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: [=14=], toDate: startOfMonth, options: [])!}
过滤周末中的天数
let workDays = allDays.filter{ !calendar.isDateInWeekend([=15=]) }
Swift 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: [=16=], to: startOfMonth)!}
let workDays = allDays.filter{ !calendar.isDateInWeekend([=16=]) }
要获得比上面给出的答案更一般的答案,您可以实现自己的 SequenceType
运行 over/generating NSDate
元素。
从this blog post by Adam Preble(Swift < 2.0)修改SequenceType
DateRange
实现,我们可以构造如下:
/* 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 的范围,就像你可以遍历一个整数范围一样, 而无需明确需要 [=16] 的数组=] 对象.
示例用法(利用 startOfMonth()
和 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 */
数组中一个月的日期 ([NSDate]
) 可能不是问题,但使用序列代替对于更大的日期跨度很有价值,而且当您需要多功能性时,w.r.t .重新分配数组的大小和成员;特别是一个数组,其中您实际上一次只按顺序使用一个成员。
例如在下面的示例中使用 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))
}
}
}
输出:
/* 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
...
Fri, Dec. 23, 2016
Mon, Dec. 26, 2016
Tue, Dec. 27, 2016
Wed, Dec. 28, 2016
Thu, Dec. 29, 2016
Fri, Dec. 30, 2016
// 2nd range print
Fri, Jul. 1, 2016
Mon, Jul. 4, 2016
Tue, Jul. 5, 2016
Wed, Jul. 6, 2016
Thu, Jul. 7, 2016
...
Fri, Jun. 23, 2017
Mon, Jun. 26, 2017
Tue, Jun. 27, 2017
Wed, Jun. 28, 2017
Thu, Jun. 29, 2017
Fri, Jun. 30, 2017 */