Skip to content

Instantly share code, notes, and snippets.

@cypres
Created January 16, 2015 23:58
Show Gist options
  • Save cypres/ba70f6252a8038a82b9a to your computer and use it in GitHub Desktop.
Save cypres/ba70f6252a8038a82b9a to your computer and use it in GitHub Desktop.
Holiday calculation for iOS
// Playground - noun: a place where people can play
// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// This playground calculates a set of opening hours keys, such as "every friday",
// "2. day in month friday", "easter sunday" etc, which can be used to figure out
// when something is open or closed, taking holidays etc into account
import Foundation
// The Anonymous Gregorian algorithm
func easter(Y : Int) -> NSDateComponents {
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))
let components = NSDateComponents()
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 = NSTimeZone(forSecondsFromGMT: 0)
return components
}
// Compare two date components
func compareDate(a : NSDateComponents, b : NSDateComponents) -> Bool {
return a.day == b.day && a.month == b.month && a.year == b.year
}
// Calculate which date keys a date belongs to
func dateKey(date: NSDate) -> Array<String> {
var keys = Array<String>()
let cal = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
let dateflags: NSCalendarUnit = .DayCalendarUnit | .MonthCalendarUnit | .YearCalendarUnit
let com = cal.components(dateflags, fromDate: date)
if com.day == 1 && com.month == 1 {
keys.append("Hver 1. januar")
} else if com.day == 31 && com.month == 12 {
keys.append("Hver 31. december")
} else if com.day == 26 && com.month == 12 {
keys.append("Hver 26. december")
} else if com.day == 25 && com.month == 12 {
keys.append("Hver 25. december")
} else if com.day == 24 && com.month == 12 {
keys.append("Hver 24. december")
} else { // continue to easter calculations
// Calculate all the danish holidays that depend on easter
let easterSunday = easter(com.year)
let easterDate = cal.dateFromComponents(easterSunday)!
let a = NSDateComponents()
a.day = -3
let maundyThursday = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!)
a.day = -2
let goodFriday = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!)
a.day = 1
let easterMonday = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!)
a.day = 3*7+5
let greatPrayerDay = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!)
a.day = 5*7+4
let ascensionThursday = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!)
a.day = 7*7
let pentecostDate = cal.dateByAddingComponents(a, toDate: easterDate, options: nil)!
let pentecostDay = cal.components(dateflags, fromDate: pentecostDate)
a.day = 1
let whitMonday = cal.components(dateflags, fromDate: cal.dateByAddingComponents(a, toDate: pentecostDate, options: nil)!)
if compareDate(easterSunday, com) {
keys.append("Hver Påskedag")
} else if compareDate(maundyThursday, com) {
keys.append("Hver Skærtorsdag")
} else if compareDate(goodFriday, com) {
keys.append("Hver Langfredag")
} else if compareDate(easterMonday, com) {
keys.append("Hver 2. påskedag")
} else if compareDate(greatPrayerDay, com) {
keys.append("Hver St. Bededag")
} else if compareDate(ascensionThursday, com) {
keys.append("Hver Kr. Himmelfartsdag")
} else if compareDate(pentecostDay, com) {
keys.append("Hver Pinsedag")
} else if compareDate(whitMonday, com) {
keys.append("Hver 2. pinsedag")
} else if com.day == 5 && com.month == 6 {
keys.append("Hver Grundlovsdag (5/6)")
} else if com.day == 1 && com.month == 5 {
// make sure easter based holidays are checked first
// this may collide, ie. in 2015
keys.append("Hver 1. maj")
} else { // continue to normal weekdays
let danishweekdays = [ "", "Søndag", "Mandag", "Tirsdag", "Onsdag", "Torsdag", "Fredag", "Lørdag" ] // 1 indexed, sunday first
let ordinals = [ "", "1. i måneden", "2. i måneden", "3. i måneden", "4. i måneden", "5. i måneden" ]
let weekdayflags: NSCalendarUnit = .WeekdayCalendarUnit | .WeekdayOrdinalCalendarUnit
let weekday = cal.components(weekdayflags, fromDate: date)
keys.append("Hver \(danishweekdays[weekday.weekday])")
keys.append("\(ordinals[weekday.weekdayOrdinal]) \(danishweekdays[weekday.weekday])")
// Calculate the every other weekday of this year
let newyear = NSDateComponents()
newyear.day = 1
newyear.month = 1
newyear.year = com.year
newyear.timeZone = NSTimeZone(forSecondsFromGMT: 0)
let newyearDate = cal.dateFromComponents(newyear)!
let newyearWeekday = cal.components(weekdayflags, fromDate: newyearDate)
let weekdayOffset = weekday.weekday-newyearWeekday.weekday
let a = NSDateComponents()
for i in 0..<27 {
a.day = 14*i+weekdayOffset
let t = cal.dateByAddingComponents(a, toDate: newyearDate, options: nil)
let datecom = cal.components(dateflags, fromDate: t!)
if compareDate(datecom, com) {
keys.append("Hver anden \(danishweekdays[weekday.weekday])")
break
}
}
}
}
return keys
}
func dateFrom(year: Int, month: Int, date: Int) -> NSDate {
let a = NSDateComponents()
a.day = date
a.month = month
a.year = year
a.timeZone = NSTimeZone(forSecondsFromGMT: 0)
let cal = NSCalendar(calendarIdentifier: NSGregorianCalendar)!
return cal.dateFromComponents(a)!
}
println(dateKey(dateFrom(2015, 1, 2)))
println(dateKey(dateFrom(2015, 1, 9)))
println(dateKey(dateFrom(2015, 5, 1)))
// Expected output:
//[Hver Fredag, 1. i måneden Fredag, Hver anden Fredag]
//[Hver Fredag, 2. i måneden Fredag]
//[Hver St. Bededag]
println(dateKey(NSDate()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment