如何获取特定月份的每个星期四或一周中的其他日期的日期?
Posted
技术标签:
【中文标题】如何获取特定月份的每个星期四或一周中的其他日期的日期?【英文标题】:How to get dates for every thursday or other day of week in specific month? 【发布时间】:2017-05-03 12:51:34 【问题描述】:我想获取每周特定日期的日期。
假设我有一个约会:2017-04-13
。这是四月,4 月 13 日是Thursday
。我需要得到四月份的每个日期,即Thursday
。
我该怎么做?
输出应该是:2017-04-06
、2017-04-13
、2017-04-20
、2017-04-27
【问题讨论】:
【参考方案1】:短解:
// 获取当前日历和当前日期 让日历 = Calendar.current 现在让 = 日期() // 获取年、月、工作日和工作日序号的当前日期组件 var components = calendar.dateComponents([.year, .month, .weekdayOrdinal, .weekday], from: now) // 获取该月特定工作日的范围(出现次数) 让 range = calendar.range(of: .weekdayOrdinal, in: .month, for: now)! // 遍历范围,将组件设置为适当的工作日序号并获取日期 对于 range.lowerBound 中的序数..
请注意,print
始终以 UTC 格式打印日期。
编辑:
range(of: .weekdayOrdinal, in: .month
不起作用,无论日期如何,它都会返回1..<6
。
这是一个可行的选择。它检查日期是否超出月份范围
// Get current calendar and date for 2017/4/13
let calendar = Calendar.current
let april13Components = DateComponents(year:2017, month:4, day:13)
let april13Date = calendar.date(from: april13Components)!
// Get the current date components for year, month, weekday and weekday ordinal
var components = calendar.dateComponents([.year, .month, .weekdayOrdinal, .weekday], from: april13Date)
// Loop thru the range, set the components to the appropriate weekday ordinal and get the date
for ordinal in 1..<6 // maximum 5 occurrences
components.weekdayOrdinal = ordinal
let date = calendar.date(from: components)!
if calendar.component(.month, from: date) != components.month! break
print(calendar.date(from: components)!)
【讨论】:
【参考方案2】:试试这个游乐场:
import UIKit
let dateString = "2017-04-13"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
let referenceDate = dateFormatter.date(from: dateString)!
let calendar = Calendar.current
let firstDayComponents = calendar.dateComponents([.year, .month], from: referenceDate)
let monthFirst = calendar.date(from: firstDayComponents)!
let weekDay = calendar.component(.weekday, from: referenceDate)
var oneDay = DateComponents()
oneDay.day = 1
var checkDate = monthFirst
while calendar.component(.month, from: checkDate) == calendar.component(.month, from: referenceDate)
if calendar.component(.weekday, from: checkDate) == weekDay
let thisDay = dateFormatter.string(from: checkDate)
print(thisDay)
checkDate = calendar.date(byAdding: oneDay, to: checkDate)!
【讨论】:
【参考方案3】:这段代码完成了这项工作。我添加了一些日志以了解其背后的一些逻辑。
你可以随意设置dateInit
,剩下的代码会查找同年同月同一个工作日的所有日子。
我打印了两个版本的日期表示(NSDate
对象和 NSString
对象),用于时区问题和“这不是同一天”的呼喊。
它使用enumerateDatesStartingAfterDate:matchingComponents:options:usingBlock:
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSString *dateStr = @"2017-04-13";
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd"];
NSDate *dateInit = [dateFormatter dateFromString:dateStr];
NSLog(@"dateInit: %@", dateInit);
NSDateComponents *componentsToMatch = [calendar components:(NSCalendarUnitMonth|NSCalendarUnitWeekday) fromDate:dateInit];
NSDate *startOfMonth = [calendar dateFromComponents:[calendar components:(NSCalendarUnitYear|NSCalendarUnitMonth) fromDate:dateInit]];
NSLog(@"StartOfTheMonth: %@", startOfMonth);
NSArray *daysToFind = @[@"2017-04-06", @"2017-04-13", @"2017-04-20", @"2017-04-27"]; //According to author
NSLog(@"DaysToFind: %@", daysToFind);
NSMutableArray *allDaysInMonthMatchingWeekDay = [[NSMutableArray alloc] init];
[calendar enumerateDatesStartingAfterDate:startOfMonth
matchingComponents:componentsToMatch
options:NSCalendarMatchStrictly
usingBlock:^(NSDate * _Nullable date, BOOL exactMatch, BOOL * _Nonnull stop)
NSLog(@"DateBlock: %@", date);
[allDaysInMonthMatchingWeekDay addObject:date];
];
NSLog(@"allDaysInMonthMatchingWeekDay: %@",allDaysInMonthMatchingWeekDay);
for (NSDate *aDate in allDaysInMonthMatchingWeekDay)
NSLog(@"Found: %@", [dateFormatter stringFromDate:aDate]);
日志:
$>dateInit: 2017-04-12 22:00:00 +0000
$>StartOfTheMonth: 2017-03-31 22:00:00 +0000
$>DaysToFind: (
"2017-04-06",
"2017-04-13",
"2017-04-20",
"2017-04-27"
)
$>DateBlock: 2017-04-05 22:00:00 +0000
$>DateBlock: 2017-04-12 22:00:00 +0000
$>DateBlock: 2017-04-19 22:00:00 +0000
$>DateBlock: 2017-04-26 22:00:00 +0000
$>allDaysInMonthMatchingWeekDay: (
"2017-04-05 22:00:00 +0000",
"2017-04-12 22:00:00 +0000",
"2017-04-19 22:00:00 +0000",
"2017-04-26 22:00:00 +0000"
)
$>Found: 2017-04-06
$>Found: 2017-04-13
$>Found: 2017-04-20
$>Found: 2017-04-27
注意:对于componentsToMatch
,我尝试设置 Year/Month/WeekDay 标志单元,但枚举在第一次出现时停止,没有搜索很长时间为什么,我想出了只有月份和工作日标志让它工作。也许我错过了一些小问题。
编辑: 在 Swift 3 中(它可以工作,但由于我是一名 Objective-C 开发人员而不是 Swift 开发人员,它可能存在问题,例如包装/展开等)
let calendar = NSCalendar.init(calendarIdentifier: .gregorian)
let dateStr = "2017-04-13"
let dateFormatter = DateFormatter.init()
dateFormatter.dateFormat = "yyyy-MM-dd"
let dateInit = dateFormatter.date(from: dateStr)!
print("dateInit: \(dateInit)")
let componentsToMatch = calendar?.components([.month,.weekday], from: dateInit)
let startOfMonth = calendar?.date(from: (calendar?.components([.year,.month], from: dateInit))!)
print("StartOfTheMonth:\(startOfMonth)")
calendar?.enumerateDates(startingAfter: startOfMonth!, matching: componentsToMatch!, options: .matchStrictly, using: (date, extactMatch, stop) in
print("DateBlock: \(date)")
)
【讨论】:
【参考方案4】:我会为任何给定的时间跨度为Calendar
编写扩展名,并使用枚举来命名工作日
enum WeekDay: Int
case sunday = 1
case monday
case tuesday
case wednesday
case thursday
case friday
case saturday
struct TimeSpan
let startDate: Date
let endDate: Date
extension Calendar
func allOccurrenceOf(day: WeekDay, in timeSpan:TimeSpan) -> [Date]
let startDateWeekDay = Int(self.component(.weekday, from: timeSpan.startDate))
let desiredDay = day.rawValue
let offset = (desiredDay - startDateWeekDay + 7) % 7
let firstOccurrence = self.startOfDay(for:self.date(byAdding: DateComponents(day:offset), to: timeSpan.startDate)!)
guard firstOccurrence.timeIntervalSince1970 < timeSpan.endDate.timeIntervalSince1970 else
return []
var filtered = [firstOccurrence]
while true
let nextDate = self.date(byAdding: DateComponents(day: 7), to: filtered.last!)!
if nextDate < timeSpan.endDate
filtered.append(nextDate)
break
return filtered
请注意,我破解它的速度可能相当快。我相信这可以更迅速地表达出来。在实际生产代码中,我也会尝试从中消除所有 !
。
用法:
let tuesdays = Calendar.autoupdatingCurrent.allOccurrenceOf(day: .tuesday, in: TimeSpan(startDate: Date(), endDate: Calendar.autoupdatingCurrent.date(byAdding: DateComponents(month:1), to: Date())!))
【讨论】:
【参考方案5】:按照评论中的建议。查看更新的代码。随工作日更新
func getNumberOfDaysInMonth (month : Int , Year : Int, weekday: Int) -> [String]
let dateComponents = NSDateComponents()
dateComponents.year = Year
dateComponents.month = month
let calendar = Calendar.current
let date = calendar.date(from: dateComponents as DateComponents)
let range = calendar.range(of: .day, in: .month, for: date!)
let numDays:Int = (range?.upperBound)!
let thuFormatter = DateFormatter()
var dateArray:[String] = [String]()
thuFormatter.dateFormat = "yyyy-MM-dd"
for day in 1...numDays
dateComponents.day = day
let date2 = calendar.date(from: dateComponents as DateComponents)
print(calendar.component(.weekday, from: date2!))
if calendar.component(.weekday, from: date2!) == weekday
let dateThu = thuFormatter.string(from: date2!)
dateArray.append(dateThu)
return dateArray
然后像这样称呼它
let myThu:[String] = getNumberOfDaysInMonth(month: 4, Year: 2017,weekday: 3)
print(myThu)
【讨论】:
我建议let date2 = calendar.date(from: dateComponents as DateComponents); if calendar.component(.weekday, from: date2!) == 5 numberOfSundays += 1; let dateThu = thuFormatter.string(from: date2!); dateArray.append(dateThu)
而不是使用NSDateFormatter
和可能根据语言而改变的字符串比较。如果只是将其转换为DateComponents
,请避免使用NSDateComponents
,并使用Calendar
而不是NSCalendar
,全部用于Swift 3。以上是关于如何获取特定月份的每个星期四或一周中的其他日期的日期?的主要内容,如果未能解决你的问题,请参考以下文章
用 Javascript 获取一周中的天数,一周从星期日开始
如何在 Objective-C 中的特殊日期获得一周中的星期一?
当用户从日期选择器中选择日期时,如何在下拉列表中获取特定的星期几?