Created
January 16, 2015 23:58
-
-
Save cypres/ba70f6252a8038a82b9a to your computer and use it in GitHub Desktop.
Holiday calculation for iOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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