使用NSDate获取复活节的日期

时间:2015-06-15 01:15:42

标签: swift nsdate

我正在处理一个需要使用国家法定日期的申请。

下面,我能够获得阵亡将士纪念日:

// Set the components for Memorial Day (last Monday of May)

let memorialDayComps = NSDateComponents()
memorialDayComps.weekday = 2
memorialDayComps.month = 5
memorialDayComps.year = currentYear

var mondaysOfMay = [NSDate]()

for var i = 1; i <= 5; i++ {
    memorialDayComps.weekdayOrdinal = i
    let monday = calendar.dateFromComponents(memorialDayComps)
    let components = calendar.components(.CalendarUnitMonth, fromDate: monday!)
    if components.month == 5 {
        mondaysOfMay.append(monday!)
    }
}
let memorialDayDate = mondaysOfMay.last

由于日期设置得很好,我可以在以下假期成功创建NSDate个实例:

  • 新年
  • Martin Luther King,Jr。Day
  • 总统&#39;一天
  • 阵亡将士纪念日
  • 独立日
  • 劳动节
  • 感恩节
  • 圣诞节

然而,我唯一一个难以弄清楚如何得到的是复活节。它每年都有所不同,所以我很好奇其他人是否能够通过API或其他方式如此成功地获得复活节的约会。

5 个答案:

答案 0 :(得分:3)

我能够在GitHub上找到一个gist,它有一个准确计算并返回复活节By css = By.cssSelector("body.loading-complete")); (new WebDriverWait(driver, 10)).until(ExpectedConditions.presenceOfElementLocated(css)) 的解决方案。

以下代码是gist包含的内容:

NSDate

答案 1 :(得分:1)

复活节算法效果很好! 使用Swift 4.0和模式匹配。模式匹配使我更容易根据月,日,工作日,工作日的日期添加其他日期。

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, 0, 2, 3): return true                      // MLK - 3rd Mon in Jan
        case (2, 0, 2, 3): return true                      // Washington - 3rd Mon in Feb
        case (easterMonth, easterDay, _, _): return true    // Easter - rocket science calculation
        case (5, memorialDay, _, _): return true            // Memorial Day
        case (7, 4, _, _): return true                      // Independence Day
        case (9, 0, 2, 1): return true                      // Labor Day - 1st Mon in Sept
        case (10, 0, 2, 2): return true                     // Columbus Day - 2nd Mon in Oct
        case (11, 11, _, _): return true                    // Veterans Day
        case (11, 0, 5, 4): return true                     // Happy Thanksgiving - 4th Thurs in Nov
        case (12, 25, _, _): return true                    // Happy Holidays
        case (12, 31, _, _): return true                    // New years Eve
        default: return false
        }

    }

    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)
    }

    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)
    }

}

答案 2 :(得分:0)

斯威夫特4:

func easter(Y : Int) -> Date {
    let a = Y % 19
    let b = Int(floor(Double(Y) / 100))
    let c = Y % 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 components = DateComponents()
    components.year = Y
    components.month = Int(floor(Double(h + L - 7*m + 114) / 31))
    components.day = ((h + L - 7*m + 114) % 31) + 1
    components.timeZone = TimeZone(secondsFromGMT: 0)
    return Calendar.autoupdatingCurrent.date(from: components)!
}

print(easter(Y: 2018)) // "2018-04-01 00:00:00 +0000"

答案 3 :(得分:0)

目标-C!

{{1}}

答案 4 :(得分:0)

这是O'Beirne's algorithm的Swift 5实现,带有内联文档。

该代码比其他提供的答案更紧凑,因为它利用了整数算法,因此无需显式舍入数字并在FloatInt之间进行转换。 / p>

/// **How ten divisions lead to Easter** *by T. H. O'Beirne, New Scientist, march 30 1961 - Vol. 9,Nr. 228*
func easter(in year: Int) -> (day: Int, month: Int) {
    /// Identify the position of the `year` in a 19-year cycle, to use this later to determine the principal constituent of the changes of full-moon dates from year to year
    let a = year % 19

    /// Take note of the corrections which the Gregorian calendar introduces in century years
    let (b, c) = year.quotientAndRemainder(dividingBy: 100)

    /// Take account of the leap-year exceptions in century years
    let (d, e) = b.quotientAndRemainder(dividingBy: 4)

    /// Provide similarly for the century years auxiliary corrections to the new-moon and full-moon dates
    let g = (8*b + 13) / 25

    /// Determine the number of days between 21 March and the coincident or next full moon, if no special exceptions arise
    let h = (19*a + b - d - g + 15) % 30

    /// Determine the position of the year in the ordinary leap-year cycle of four years
    let (i, k) = c.quotientAndRemainder(dividingBy: 4)

    /// Determine number of days (between 0 and 6) until the Sunday *after* full moon
    let l = (2*e + 2*i - h - k + 32) % 7

    /// The exceptions which make a 29-day month interrupt the regularity of a simpler pattern need here be considered *only* when they transfer the full moon *from a Sunday to a Saturday*: the *Easter date* is unaffected in other cases. When appropriate — 1954 and 1981 are quite rare examples — we have m=1; otherwise m=0 : this permits the necessary correction (failing which the Easter date *would* be 26 April in 1981.
    let m = (a + 11*h + 19*l) / 433

    /// Determine days between March 22 and Easter
    let relativeDayCount = h + l - 7*m

    /// Convert relative day count into absolute month and day index
    let month = (relativeDayCount + 90) / 25
    return (day: (relativeDayCount + 33*month + 19) % 32, month)
}

func easterDate(in year: Int) -> Date {
    let (day, month) = easter(in: year)
    let components = DateComponents(
        timeZone: TimeZone(secondsFromGMT: 0),
        year: year, month: month, day: day
    )
    return Calendar(identifier: .gregorian).date(from: components)!
}