【问题标题】:List of all American holidays as NSDates作为 NSDates 的所有美国假期列表
【发布时间】:2011-05-17 18:00:51
【问题描述】:

我正在寻找一种将所有美国假期作为NSDates 数组的方法。有没有办法实现它?

【问题讨论】:

    标签: ios cocoa-touch calendar nsdate


    【解决方案1】:

    斯威夫特 4: 检查此链接以获取复活节和阵亡将士纪念日的美国假期日期。 Using NSDate to get date for Easter

    我编辑了上面的链接代码添加了一些假期:

    extension Date {
    var isUSHoliday: Bool {
        let components = Calendar.current.dateComponents([.year, .month, .day, .weekday, .weekdayOrdinal], from: self)
        guard let year = components.year,
            let month = components.month,
            let day = components.day,
            let weekday = components.weekday,
            let weekdayOrdinal = components.weekdayOrdinal else { return false }
        
        let easterDateComponents = Date.dateComponentsForEaster(year: year)
        let easterMonth: Int = easterDateComponents?.month ?? -1
        let easterDay: Int = easterDateComponents?.day ?? -1
        let memorialDay = Date.dateComponentsForMemorialDay(year: year)?.day ?? -1
        
        // weekday is Sunday==1 ... Saturday==7
        // weekdayOrdinal is nth instance of weekday in month
        
        switch (month, day, weekday, weekdayOrdinal) {
        case (1, 1, _, _): return true                      // Happy New Years
        case (1, _, 2, 3): return true                      // Martin Luther King - 3rd Mon in Jan
        case (2, 14, _, _): return true                     // Valentine day - 14th in Feb
        case (2, _, 2, 3): return true                      // Washington's Birthday - 3rd Mon in Feb
        case (3, 17, _, _): return true                     // Saint Patrick's Day - 17th Mar
        case (easterMonth, easterDay, _, _): return true    // Easter - rocket science calculation
        case (5, _, 1, 2): return true                      // Mothers day - 2nd Sun in May
        case (5, memorialDay, _, _): return true            // Memorial Day
        case (5, _, 1, 3): return true                      // Fathers day - 3rd Sun in May
        case (7, 4, _, _): return true                      // Independence Day - 4th July
        case (9, _, 2, 1): return true                      // Labor Day - 1st Mon in Sept
        case (10, _, 2, 2): return true                     // Columbus Day - 2nd Mon in Oct
        case (10, 31, _, _): return true                    // Halloween Day - 31st Oct
        case (11, 11, _, _): return true                    // Veterans Day  - 11th Nov
        case (11, _, 5, 4): return true                     // Happy Thanksgiving - 4th Thurs in Nov
        case (12, 25, _, _): return true                    // Christmas/Happy Holiday
        case (12, 31, _, _): return true                    // New years Eve
        default: return false
        }
        
    }
    //New Year
    static func newYearDay(year: Int) -> Date? {
        var firstDayJan = DateComponents()
        firstDayJan.month = 1 // 1st Month
        firstDayJan.day  = 1  // 1st Day
        firstDayJan.year = year
        return Calendar.current.date(from: firstDayJan)
    }
    // Martin Luther King Jr Day
    static func martinLKDay(year: Int) -> Date? {
        var thirdMonJan = DateComponents()
        thirdMonJan.month = 1 //1 month
        thirdMonJan.weekday  = 2 // Monday
        thirdMonJan.weekdayOrdinal = 3 //3rd week
        thirdMonJan.year = year
        return Calendar.current.date(from: thirdMonJan)
    }
    //Valentine Day
    static func valentineDay(year: Int) -> Date? {
        var firstDayFeb = DateComponents()
        firstDayFeb.month = 2
        firstDayFeb.day  = 14
        firstDayFeb.year = year
        return Calendar.current.date(from: firstDayFeb)
    }
    //Washington's Birthday
    static func washingtonBDay(year: Int) -> Date? {
        var thirdMonFeb = DateComponents()
        thirdMonFeb.month = 2 //month Feb
        thirdMonFeb.weekday  = 2 // Monday
        thirdMonFeb.weekdayOrdinal = 3 //3rd week
        thirdMonFeb.year = year
        return Calendar.current.date(from: thirdMonFeb)
    }
    //Saint Patrick's Day
    static func stPatrickDay(year: Int) -> Date? {
        var seventeenthMar = DateComponents()
        seventeenthMar.month = 3
        seventeenthMar.day  = 17
        seventeenthMar.year = year
        return Calendar.current.date(from: seventeenthMar)
    }
    //Easter
    static func easterHoliday(year: Int) -> Date? {
        guard let dateComponents = Date.dateComponentsForEaster(year: year) else { return nil }
        return Calendar.current.date(from: dateComponents)
    }
    
    static func dateComponentsForEaster(year: Int) -> DateComponents? {
        // Easter calculation from Anonymous Gregorian algorithm
        // AKA Meeus/Jones/Butcher algorithm
        let a = year % 19
        let b = Int(floor(Double(year) / 100))
        let c = year % 100
        let d = Int(floor(Double(b) / 4))
        let e = b % 4
        let f = Int(floor(Double(b+8) / 25))
        let g = Int(floor(Double(b-f+1) / 3))
        let h = (19*a + b - d - g + 15) % 30
        let i = Int(floor(Double(c) / 4))
        let k = c % 4
        let L = (32 + 2*e + 2*i - h - k) % 7
        let m = Int(floor(Double(a + 11*h + 22*L) / 451))
        var dateComponents = DateComponents()
        dateComponents.month = Int(floor(Double(h + L - 7*m + 114) / 31))
        dateComponents.day = ((h + L - 7*m + 114) % 31) + 1
        dateComponents.year = year
        guard let easter = Calendar.current.date(from: dateComponents) else { return nil } // Convert to calculate weekday, weekdayOrdinal
        return Calendar.current.dateComponents([.year, .month, .day, .weekday, .weekdayOrdinal], from: easter)
    }
    //Mother's Days
    static func mothersDay(year: Int) -> Date? {
        var secondSunMay = DateComponents()
        secondSunMay.month = 5
        secondSunMay.weekday = 1
        secondSunMay.weekdayOrdinal = 2
        secondSunMay.year = year
        return Calendar.current.date(from: secondSunMay)
    }
    
    //Memorial Day
    static func dateComponentsForMemorialDay(year: Int) -> DateComponents? {
        guard let memorialDay = Date.memorialDay(year: year) else { return nil }
        return NSCalendar.current.dateComponents([.year, .month, .day, .weekday, .weekdayOrdinal], from: memorialDay)
    }
    static func memorialDay(year: Int) -> Date? {
        let calendar = Calendar.current
        var firstMondayJune = DateComponents()
        firstMondayJune.month = 6
        firstMondayJune.weekdayOrdinal = 1  // 1st in month
        firstMondayJune.weekday = 2 // Monday
        firstMondayJune.year = year
        guard let refDate = calendar.date(from: firstMondayJune) else { return nil }
        var timeMachine = DateComponents()
        timeMachine.weekOfMonth = -1
        return calendar.date(byAdding: timeMachine, to: refDate)
    }
    //Fathers Day
    static func fathersDay(year: Int) -> Date? {
        var thirdSunJun = DateComponents()
        thirdSunJun.month = 6
        thirdSunJun.weekday = 1
        thirdSunJun.weekdayOrdinal = 3
        thirdSunJun.year = year
        return Calendar.current.date(from: thirdSunJun)
    }
    
    //Independence Day
    static func independenceDay(year: Int) -> Date? {
        var fourthJuly = DateComponents()
        fourthJuly.month = 7
        fourthJuly.day = 4
        fourthJuly.year = year
        return Calendar.current.date(from: fourthJuly)
    }
    //Labor Day
    static func laborDay(year: Int) -> Date? {
        var firstSunSep = DateComponents()
        firstSunSep.month = 9
        firstSunSep.weekday = 2
        firstSunSep.weekdayOrdinal = 1
        firstSunSep.year = year
        return Calendar.current.date(from: firstSunSep)
    }
    //Columbus Day
    static func columbusDay(year: Int) -> Date? {
        var firstSunSep = DateComponents()
        firstSunSep.month = 10
        firstSunSep.weekday = 2
        firstSunSep.weekdayOrdinal = 2
        firstSunSep.year = year
        return Calendar.current.date(from: firstSunSep)
    }
    //Halloween
    static func halloweenDay(year: Int) -> Date? {
        var thirtyFirstOct = DateComponents()
        thirtyFirstOct.month = 10
        thirtyFirstOct.day = 31
        thirtyFirstOct.year = year
        return Calendar.current.date(from: thirtyFirstOct)
    }
    
    //Veterans
    static func veteransDay(year: Int) -> Date? {
        var eleventhNov = DateComponents()
        eleventhNov.month = 11
        eleventhNov.day = 11
        eleventhNov.year = year
        return Calendar.current.date(from: eleventhNov)
    }
    //Thanks Giving Day
    static func thanksGivingDay(year: Int) -> Date? {
        var fourthThuNov = DateComponents()
        fourthThuNov.month = 11
        fourthThuNov.weekday = 5
        fourthThuNov.weekdayOrdinal = 4
        fourthThuNov.year = year
        return Calendar.current.date(from: fourthThuNov)
    }
    //Christmas
    static func christmasDay(year: Int) -> Date? {
        var christmasDay = DateComponents()
        christmasDay.month = 12
        christmasDay.day = 25
        christmasDay.year = year
        return Calendar.current.date(from: christmasDay)
    }
    
    //New Year Eve
    static func newYearEve(year: Int) -> Date? {
        var thirtyFirstDec = DateComponents()
        thirtyFirstDec.month = 12
        thirtyFirstDec.day = 31
        thirtyFirstDec.year = year
        return Calendar.current.date(from: thirtyFirstDec)
    }
    
    
    static func getHolidayArray(year: Int) -> [Date?] {
        return [newYearEve(year:year),Date.martinLKDay(year: year),Date.valentineDay(year: year),Date.washingtonBDay(year: year),Date.stPatrickDay(year: year),Date.easterHoliday(year: year),Date.mothersDay(year: year),Date.memorialDay(year: year),Date.fathersDay(year: year),Date.independenceDay(year: year),Date.laborDay(year: year),Date.columbusDay(year: year),Date.halloweenDay(year: year),Date.veteransDay(year: year),Date.thanksGivingDay(year: year),Date.christmasDay(year: year),Date.newYearEve(year: year)]
    }
    }
    

    获取日期:

    let date = Date.easterHoliday(year: 2019)
    

    对于节日数组:

    let holidayArr = Date.getHolidayArray(year: 2019)
    

    【讨论】:

      【解决方案2】:

      谢谢基兰!我发现your code 对我正在构建的依赖于美国股市何时开市或收市的 MacOS 应用程序非常有帮助。

      在您的扩展的基础上,我添加了一些额外的功能来处理除了实际假期之外的假期观察。此外,像劳动节这样的一些假期没有被捕获,因为 switch case 正在寻找一个 DateComponent.day 为 0,只需将其更改为 '_'。

      比如我改了:

      case (9, 0, 2, 1): return true                      // Labor Day - 1st Mon in Sept
      

      到这里:

      case (9, _, 2, 1): return true                      // Labor Day - 1st Mon in Sept
      

      下面的示例是针对圣诞节的,并非总是在 12 月 25 日庆祝。如果圣诞节在星期六,则在 12 月 24 日星期五举行,如果在星期日举行,则在 12 月 26 日星期一举行。同样的逻辑也适用于任何其他假期:

      //Christmas Observed
          static func christmasObserved(year: Int) -> Date? {
              var christmasDay = DateComponents()
              christmasDay.month = 12
              christmasDay.day = 25
              christmasDay.year = year
              let christmas = Calendar.current.date(from: christmasDay) ?? Date()
              switch christmasDay.weekday {
              case 6:
                  do {
                      return Calendar.current.date(byAdding: Calendar.Component.day, value: -1, to: christmas)
                  }
              case 7:
                  do {
                      return Calendar.current.date(byAdding: Calendar.Component.day, value: 1, to: christmas)
                  }
              default:
                  do {
                      return christmas
                  }
              }
          }
      

      这可以像这样在你的 isUSHoliday 中使用:

          let christmas = Date.christmasObserved(year: year)
          let christmasDay = Calendar.current.component(.day, from: christmas ?? Date())
          switch (month, day, weekday, weekdayOrdinal) {
          // All your other cases and then...            
          case (12, christmasDay, _, _): return true                    // Christmas Observed
          default: return false
          }
      

      这样,如果日期是实际假期本身,或者如果它是周末,则结果为真。

      【讨论】:

        【解决方案3】:

        如果你只想要美国联邦假期,我写了这个方法。不过,您可以使用这些技术来计算任何假期。

        -(NSArray *)getUSHolidyas{
            NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
            formatter.dateFormat = @"yyyy";
        
            NSString *year = [formatter stringFromDate:[NSDate date]];
            formatter.dateFormat = @"M/d/yyyy";
        
            //Constant Holidays
            NSDate *newYearsDay = [formatter dateFromString:[NSString stringWithFormat:@"1/1/%@",year]]; //Use next year for the case where we are adding days near end of december.
            NSDate *indDay = [formatter dateFromString:[NSString stringWithFormat:@"7/4/%@",year]];
            NSDate *vetDay = [formatter dateFromString:[NSString stringWithFormat:@"11/11/%@",year]];
            NSDate *xmasDay = [formatter dateFromString:[NSString stringWithFormat:@"12/25/%@",year]];
        
        
            //Variable Holidays
            NSInteger currentYearInt = [[[NSCalendar currentCalendar]
                                         components:NSYearCalendarUnit fromDate:[NSDate date]] year];
        
            NSDate *mlkDay = [self getTheNth:3 occurrenceOfDay:2 inMonth:1 forYear:currentYearInt];
            NSDate *presDay = [self getTheNth:3 occurrenceOfDay:2 inMonth:2 forYear:currentYearInt];
            NSDate *memDay = [self getTheNth:5 occurrenceOfDay:2 inMonth:5 forYear:currentYearInt]; // Let's see if there are 5 Mondays in May
            NSInteger month = [[[NSCalendar currentCalendar] components:NSYearCalendarUnit fromDate:memDay] month];
            if (month > 5) { //Check that we are still in May
                memDay = [self getTheNth:4 occurrenceOfDay:2 inMonth:5 forYear:currentYearInt];
            }
            NSDate *labDay = [self getTheNth:1 occurrenceOfDay:2 inMonth:9 forYear:currentYearInt];
            NSDate *colDay = [self getTheNth:2 occurrenceOfDay:2 inMonth:10 forYear:currentYearInt];
            NSDate *thanksDay = [self getTheNth:4 occurrenceOfDay:5 inMonth:11 forYear:currentYearInt];
        
            return @[newYearsDay,mlkDay,presDay,memDay,indDay,labDay,colDay,vetDay,thanksDay,xmasDay];
        }
        
        -(NSDate *)getTheNth:(NSInteger)n occurrenceOfDay:(NSInteger)day inMonth:(NSInteger)month forYear:(NSInteger)year{
        
            NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
        
            dateComponents.year = year;
            dateComponents.month = month;
            dateComponents.weekday = day; // sunday is 1, monday is 2, ...
            dateComponents.weekdayOrdinal = n; // this means, the first of whatever weekday you specified
            return [[NSCalendar currentCalendar] dateFromComponents:dateComponents];
        }
        

        【讨论】:

          【解决方案4】:
          • Here 您会在假期找到 RSS 提要。它没有列出年份,但在文档中您会找到如何更改日期范围的信息。
          • 下载它。我建议 ASIHTTPRequest 完成该任务。
            解析 RSS 提要。您可以通过普通的 XML 解析来做到这一点,也可以使用专门的解析器。 MWFeedParser 是一种选择。
          • 保存日期。通过使用 CoreData 或 Event Kit Framework

          【讨论】:

          • 仅供参考,说 RSS 提要链接现在已过时(截至 2015 年 2 月 19 日)。