简体   繁体   English

如何获得特定工作日的一个月的所有日子?

[英]How to get all days in a month that are a specific weekday?

How do I get the actual date of the month based on a given a day ? 如何根据给定的一天获得当月的实际日期? For example, I would like to retrieve all the dates in June 2017 which are Saturday. 例如,我想检索2017年6月的所有日期,即星期六。 How can I achieve that ? 我怎样才能做到这一点? Sample code will be very much appreciated as I have struggled for days on this. 示例代码将非常受欢迎,因为我已经在这方面奋斗了好几天。

A DateComponents has a weekday property, representing the day of the week. DateComponents具有weekday属性,表示星期几。 The weekdays are (in Foundation's Gregorian calendar) numbered 1 for Sunday, 2 for Monday, …, and 7 for Saturday. 工作日(在基金会的公历中)星期日为1,星期一为2,星期六为7,星期六为7。

A DateComponents also has a weekdayOrdinal property, representing “ the position of the weekday within the next larger calendar unit, such as the month. DateComponents还具有weekdayOrdinal属性,表示“ 工作日在下一个更大的日历单位中的位置,例如月份。 For example, 2 is the weekday ordinal unit for the second Friday of the month. 例如,2是该月第二个星期五的工作日序数单位。

So let's initialize a DateComponents for some Saturday in June 2017. It's generally a good idea to specify a time of noon if you don't care about the time, because midnight (the default time of day) can cause problems in some time zones on some days . 因此,让我们在2017年6月的某个星期六初始化一个DateComponents 。如果您不关心时间,通常指定一个中午时间是个好主意,因为午夜(默认时间)可能会导致某些时区出现问题有些日子

var components = DateComponents(era: 1, year: 2017, month: 06, hour: 12, weekday: 7)

And let's make a calendar. 让我们制作一个日历。

var calendar = Calendar.autoupdatingCurrent

Now we can loop over all the possible weekday ordinals. 现在我们可以循环所有可能的工作日序数。 For each, we'll ask the calendar to generate a date. 对于每个,我们会要求日历生成日期。 Then we ask the calendar to convert the date back to year, month, and day components. 然后我们要求日历将日期转换回年,月和日组件。

In the Gregorian calendar, some months have 5 Saturdays, but most have 4. So when we ask for the 5th Saturday, we'll probably get a date in the following month. 在阳历中,有几个月有5个星期六,但大多数都有4个。所以当我们要求第5个星期六时,我们可能会在下个月得到一个日期。 When that happens, we want to suppress that date. 当发生这种情况时,我们想要压制该日期。

for i in 1 ... 5 {
    components.weekdayOrdinal = i
    let date = calendar.date(from: components)!
    let ymd = calendar.dateComponents([.year, .month, .day], from: date)
    guard ymd.month == components.month else { break }
    print("\(ymd.year!)-\(ymd.month!)-\(ymd.day!)")
}

Output: 输出:

2017-6-3
2017-6-10
2017-6-17
2017-6-24

Objective-C version: Objective-C版本:

NSDateComponents *components = [NSDateComponents new];
components.era = 1;
components.year = 2017;
components.month = 6;
components.hour = 12;
components.weekday = 7;
NSCalendar *calendar = NSCalendar.autoupdatingCurrentCalendar;

for (NSInteger i = 1; i <= 5; ++i) {
    components.weekdayOrdinal = i;
    NSDate *date = [calendar dateFromComponents:components];
    NSDateComponents *ymd = [calendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:date];
    if (ymd.month != components.month) { break; }
    NSLog(@"%ld-%ld-%ld", (long)ymd.year, (long)ymd.month, (long)ymd.day);
}

This is another solution for your problem using calendar method called enumerateDates and using a Date extension 这是使用名为enumerateDates calendar方法和使用Date扩展名解决问题的另一种方法

    //month in MM format, year in yyyy format and dayNumber as Int 1 for sunday, 7 for saturday
    func datesWith(dayNumber:Int,month:String,year:String) -> [Date]
    {
        assert(dayNumber >= 1 && dayNumber <= 7, "Day number is wrong")

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        let date = dateFormatter.date(from: year + "-" + month + "-" + "01")

        guard date != nil else {
            return []
        }
        var resultDates : [Date] = []

        //check if firstDay of month is desired weekday
        if(Calendar.current.component(.weekday, from: date!) == dayNumber)
        {
            resultDates.append(date!)
        }

        Calendar.current.enumerateDates(startingAfter: date!, matching: DateComponents(weekday: dayNumber), matchingPolicy: Calendar.MatchingPolicy.nextTimePreservingSmallerComponents) { (currentDate, result, stop) in
            if(currentDate! > date!.endOfMonth())
            {
                stop = true
                return
            }
            resultDates.append(currentDate!)
        }

        return resultDates
    }

Extension 延期

extension Date {
    func startOfMonth() -> Date {
        return Calendar.current.date(from: Calendar.current.dateComponents([.year, .month], from: Calendar.current.startOfDay(for: self)))!
    }

    func endOfMonth() -> Date {
        return Calendar.current.date(byAdding: DateComponents(month: 1, day: -1), to: self.startOfMonth())!
    }
}

Using it 使用它

override func viewDidLoad() {
    super.viewDidLoad()

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd"
    // Do any additional setup after loading the view, typically from a nib.
   let datesArray = self.datesWith(dayNumber: 5, month: "06", year: "2017")
    for currDate in datesArray {
        debugPrint(dateFormatter.string(from: currDate))
    }
}

Output 产量

"2017-06-01"
"2017-06-08"
"2017-06-15"
"2017-06-22"
"2017-06-29"

Hope this helps 希望这可以帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM