use AppleScript
use scripting additions
use framework "Foundation"
(*
本バージョンのテーマ:
令和への改元にともない、天皇が交代。天皇誕生日を変更。祝日関連を最新アップデート
東京オリンピック(2021年)関連の超イレギュラーな休日調整は考慮していない
*)
set aList to retHolidayRec(2024) of me
–> {{date "2024年1月1日 月曜日 0:00:00", "元旦"}, {date "2024年1月8日 月曜日 0:00:00", "成人の日"}, {date "2024年2月11日 日曜日 0:00:00", "建国記念日"}, {date "2024年2月12日 月曜日 0:00:00", "振替休日"}, {date "2024年2月23日 金曜日 0:00:00", "天皇誕生日"}, {date "2024年3月20日 水曜日 0:00:00", "春分の日"}, {date "2024年5月3日 金曜日 0:00:00", "憲法記念日"}, {date "2024年5月4日 土曜日 0:00:00", "みどりの日"}, {date "2024年5月5日 日曜日 0:00:00", "こどもの日"}, {date "2024年5月6日 月曜日 0:00:00", "振替休日"}, {date "2024年7月15日 月曜日 0:00:00", "海の日"}, {date "2024年8月11日 日曜日 0:00:00", "山の日"}, {date "2024年8月12日 月曜日 0:00:00", "振替休日"}, {date "2024年9月16日 月曜日 0:00:00", "敬老の日"}, {date "2024年9月22日 日曜日 0:00:00", "秋分の日"}, {date "2024年9月23日 月曜日 0:00:00", "振替休日"}, {date "2024年10月14日 月曜日 0:00:00", "スポーツの日"}, {date "2024年11月3日 日曜日 0:00:00", "文化の日"}, {date "2024年11月4日 月曜日 0:00:00", "振替休日"}, {date "2024年11月23日 土曜日 0:00:00", "勤労感謝の日"}}
–国民の祝日を求める(属性つき)
on retHolidayRec(aYear as text)
–固定の祝日
if aYear < 2020 then
set holidayList to {{"1/1", "元旦"}, {"2/11", "建国記念日"}, {"4/29", "昭和の日"}, {"5/3", "憲法記念日"}, {"5/4", "みどりの日"}, {"5/5", "こどもの日"}, {"11/3", "文化の日"}, {"11/23", "勤労感謝の日"}}
else
–2020年から
set holidayList to {{"1/1", "元旦"}, {"2/11", "建国記念日"}, {"5/3", "憲法記念日"}, {"5/4", "みどりの日"}, {"5/5", "こどもの日"}, {"8/11", "山の日"}, {"11/3", "文化の日"}, {"11/23", "勤労感謝の日"}}
end if
–天皇誕生日の計算
set curEmpBD to getCurEmpBitrthday(aYear) of me
if curEmpBD is not equal to false then
set the end of holidayList to {curEmpBD, "天皇誕生日"}
end if
set the end of holidayList to {get_specifiedDay(aYear, 1, 2, 2), "成人の日"} –成人の日–1月の第2月曜日
set the end of holidayList to {get_specifiedDay(aYear, 7, 2, 3), "海の日"} –海の日–7月の第3月曜日
set the end of holidayList to {get_specifiedDay(aYear, 9, 2, 3), "敬老の日"} –敬老の日–9月の第3月曜日
set the end of holidayList to {get_specifiedDay(aYear, 10, 2, 2), "スポーツの日"} –体育の日–10月の第2月曜日
set the end of holidayList to {"3/" & get_ShunbunNoHi(aYear), "春分の日"} –春分の日
set the end of holidayList to {"9/" & get_ShuubunNoHi(aYear), "秋分の日"} –秋分の日
set holiDate to {}
repeat with i in holidayList
set holiD to date (aYear & "/" & (item 1 of i) as text)
set holiNum to weekday of holiD as number
–元日以外を対象とする(元旦に振替休日なし)–> いや、ある(汗)
–if ((item 1 of i) as text) is not "1/1" then
–振替休日付加処理
if holiNum = 1 then –祝祭日が日曜日だったら
–日付を動かすのではなく、振替休日を追加する
set holiD_furikae to holiD + (1 * days)
set the end of holiDate to {holiD_furikae, "振替休日"}
end if
–end if
set the end of holiDate to {holiD, item 2 of i}
end repeat
–重複した休日が発生した場合の再振替処理
–基本ルール: 振替休日を後に送る
– 「振替休日」が重複リストに入っていないかどうかをチェックし、振替休日の再配置を行う
set itemNum to 1
set holiDateDup to detectDuplicatesFromNestedList(holiDate, itemNum) of me
set huriList to {}
repeat with i in holiDateDup
set iCount to length of i
repeat with ii in i
set {aDate, aDateName} to ii
if aDateName = "振替休日" then
set the end of huriList to contents of ii
end if
end repeat
end repeat
set holiDate to shellSortListAscending(holiDate, 1) of me
set holiDateList to spritOrderedItemFromNestedList(holiDate, 1) of me
repeat with i in huriList
set {aDate, aName} to i
set j to contents of i
set offsetDate to 1
repeat
set bDate to aDate + (offsetDate * days)
if bDate is not in holiDateList then
exit repeat
end if
set offsetDate to offsetDate + 1
end repeat
set iCount to 1
repeat with ii in holiDate
set jj to contents of ii
if jj = j then
–「複数要素一括削除サブルーチン」などという高機能すぎるサブルーチンを使用。ちょっともったいない
set holiDate to itemsDelete(holiDate, {iCount}) of me
end if
set iCount to iCount + 1
end repeat
set the end of holiDate to {bDate, "振替休日"}
end repeat
–秋分の日と敬老の日の「間の日」の休日判定処理
–参考文献:
–http://ja.wikipedia.org/wiki/秋分の日
set septDL to {}
set the end of septDL to "9/" & get_ShuubunNoHi(aYear) of me –秋分の日
set the end of septDL to get_specifiedDay(aYear, 9, 2, 3) –敬老の日 –9月の第3月曜日
set septDL to shellSort(septDL) of me
if septDL = {"9/21", "9/23"} then
set kokuminShukujitu to (aYear as string) & "/9/22"
set kokuminShukujitu to date kokuminShukujitu
set the end of holiDate to {kokuminShukujitu, "国民の祝日"}
end if
–最後に、並べ替えを行って仕上げ
set holiDate to shellSortListAscending(holiDate, 1) of me
return holiDate
end retHolidayRec
–春分の日を求める
–2000年から2099年の間まで計算可能
on get_ShunbunNoHi(aYear)
set a to 20.69115
set b to (aYear – 2000) * 0.2421904
set c to round ((aYear – 2000) / 4) rounding toward zero
set d to round (a + b – c) rounding toward zero
return d
end get_ShunbunNoHi
–秋分の日を求める
–2000年から2099年の間まで計算可能
on get_ShuubunNoHi(aYear)
set a to 23.09
set b to (aYear – 2000) * 0.2421904
set c to round ((aYear – 2000) / 4) rounding toward zero
set d to round (a + b – c) rounding toward zero
return d
end get_ShuubunNoHi
–指定月の第x指定曜日に該当する日付を求める(mm/dd形式)
– 曜日の指定を数値(weekday of (current date) as number)で行えるようにした。
– 曜日を「日曜日」などの日本語ローカライズド文字列で指定するのをやめた
–パラメータ: 年, 月, 曜日番号, 順番
on get_specifiedDay(aYear as integer, aMonth as integer, Youbi as integer, orderNum as integer)
set sDat to date ((aYear & "/" & aMonth & "/1") as text)
set eDat to getMlenInternational(aYear, aMonth) of me
set countNum to 0
repeat with i from 1 to eDat
set aCal to date ((aYear & "/" & aMonth & "/" & (i as text)) as text)
set aWeekDayNum to weekday of aCal as integer
if Youbi = aWeekDayNum then
set countNum to countNum + 1
if countNum is orderNum then
set aCalText to (aMonth & "/" & i as text)
return aCalText
end if
end if
end repeat
end get_specifiedDay
–指定日の月のみ返す
on getMonth(aDat as date)
set bDate to month of aDat
return bDate as integer
end getMonth
–指定日の日付のみ返す
on getDate(aDat as date)
set bDate to day of aDat
return bDate as integer
end getDate
–指定日の年のみ返す
on getYear(aDat as date)
set bDate to year of aDat
return bDate as integer
end getYear
–現在のカレンダーで指定年月の日数を返す(getMlenから置き換えた)
on getMlenInternational(aYear, aMonth)
set theNSCalendar to current application’s NSCalendar’s currentCalendar() — do *not* use initWithCalendarIdentifier:
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:1 hour:0 minute:0 |second|:0 nanosecond:0
set theResult to theNSCalendar’s rangeOfUnit:(current application’s NSDayCalendarUnit) inUnit:(current application’s NSMonthCalendarUnit) forDate:theDate
return |length| of theResult
end getMlenInternational
–リスト中から重複項目をリストアップする
on detectDuplicates(aList)
set aCount to length of aList
set duplicationList to {}
repeat aCount times
set anItem to contents of (first item of aList)
set aList to rest of aList
if anItem is in aList then
set the end of duplicationList to anItem
end if
end repeat
return duplicationList
end detectDuplicates
–リストから重複部分を除外
on removeDuplicates(aList)
set newList to {}
repeat with i from 1 to (length of aList)
set anItem to item 1 of aList
set aList to rest of aList
if {anItem} is not in aList then set end of newList to anItem
end repeat
return newList
end removeDuplicates
–シェルソート
on shellSort(aSortList)
script oBj
property list : aSortList
end script
set len to count oBj’s list’s items
set gap to 1
repeat while (gap ≤ len)
set gap to ((gap * 3) + 1)
end repeat
repeat while (gap > 0)
set gap to (gap div 3)
if (gap < len) then
repeat with i from gap to (len – 1)
set temp to oBj’s list’s item (i + 1)
set j to i
repeat while ((j ≥ gap) and (oBj’s list’s item (j – gap + 1) > temp))
set oBj’s list’s item (j + 1) to oBj’s list’s item (j – gap + 1)
set j to j – gap
end repeat
set oBj’s list’s item (j + 1) to temp
end repeat
end if
end repeat
return oBj’s list
end shellSort
–シェルソートで入れ子のリストを昇順ソート
on shellSortListAscending(a, keyItem)
set n to length of a
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
repeat with h in cols
if (h ≤ (n – 1)) then
repeat with i from h to (n – 1)
set v to item (i + 1) of a
set j to i
repeat while (j ≥ h) and ((contents of item keyItem of item (j – h + 1) of a) > (item keyItem of v))
set (item (j + 1) of a) to (item (j – h + 1) of a)
set j to j – h
end repeat
set item (j + 1) of a to v
end repeat
end if
end repeat
return a
end shellSortListAscending
–シェルソートで入れ子のリストを降順ソート
on shellSortListDecending(a, keyItem)
set n to length of a
set cols to {1391376, 463792, 198768, 86961, 33936, 13776, 4592, 1968, 861, 336, 112, 48, 21, 7, 3, 1}
repeat with h in cols
if (h ≤ (n – 1)) then
repeat with i from h to (n – 1)
set v to item (i + 1) of a
set j to i
repeat while (j ≥ h) and ((contents of item keyItem of item (j – h + 1) of a) < (item keyItem of v))
set (item (j + 1) of a) to (item (j – h + 1) of a)
set j to j – h
end repeat
set item (j + 1) of a to v
end repeat
end if
end repeat
return a
end shellSortListDecending
–入れ子のリスト中から重複項目をアイテム番号つきでリストアップする
on detectDuplicatesFromNestedList(aList, itemNum)
set aCount to length of aList
copy aList to orig_aList
set duplicationList to {}
repeat aCount times
set anItem to contents of (first item of aList)
set aList to rest of aList
–指定アイテムだけのリストを毎回再生成して存在確認を行う
set aaList to spritOrderedItemFromNestedList(aList, itemNum) of me
if (contents of (item itemNum of anItem)) is in aaList then
set the end of duplicationList to anItem
end if
end repeat
–検出した重複データを元に、該当するデータをリストアップ
set detectList to {}
repeat with i in duplicationList
set j to contents of (item itemNum of i)
set detectItem to {}
repeat with ii in orig_aList
set jj to contents of (item itemNum of ii)
if jj = j then
set the end of detectItem to (contents of ii)
end if
end repeat
set the end of detectList to detectItem
end repeat
return detectList
end detectDuplicatesFromNestedList
–入れ子のリストの全要素から指定アイテム目の要素だけを取り出してリストで返す
on spritOrderedItemFromNestedList(aList, itemNum)
set aaList to {}
repeat with i in aList
set the end of aaList to contents of (item itemNum of i)
end repeat
return aaList
end spritOrderedItemFromNestedList
–リスト中の指定要素を削除して返す
on itemsDelete(aList, delNumList)
set delLen to length of delNumList
repeat with i from 1 to delLen
set newList to {}
set aLen to length of aList
set ii to item i of delNumList
if ii = 1 then
set maeList to items 2 thru aLen of aList
set newList to maeList
else if ii = aLen then
set maeList to items 1 thru (aLen – 1) of aList
set newList to maeList
else
set maeList to items 1 thru (ii – 1) of aList
set atoList to items (ii + 1) thru -1 of aList
set newList to maeList & atoList
end if
–アイテム指定の補正
set delNumList to adjustItemNo(ii, delNumList) of me
set aList to newList
end repeat
return newList
end itemsDelete
–itemsDeleteのサブルーチン
–リストに対して複数アイテムの削除を行う場合に、1つ削除した後にはアイテム指定が
–狂ってしまうため、毎回削除するたびにアイテム指定の補正を行う
–paramNumとelemListの間でのパラメータの衝突は関知しない
–項目要素補正をリストに対して行う
on adjustItemNo(paramNum, elemList)
–項目ゼロを指定してきた場合には、そのままelemListを戻す
if paramNum = 0 then return elemList
–プラス方向のレンジ外判定は行っていない。elemListのlengthよりも大きな値は関知しない
set retList to {}
repeat with i in elemList
set j to contents of i
if j > paramNum then
set ansNum to j – 1
else
set ansNum to j
end if
set the end of retList to ansNum
end repeat
return retList
end adjustItemNo
–現在のカレンダーで指定年月のdate objectを返す(年、月、日、時、分、秒)
on getDateInternationalYMDhms(aYear, aMonth, aDay, anHour, aMinute, aSecond)
set theNSCalendar to current application’s NSCalendar’s currentCalendar()
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:aDay hour:anHour minute:aMinute |second|:aSecond nanosecond:0
return theDate as date
end getDateInternationalYMDhms
–現在のカレンダーで指定年月のdate objectを返す(年、月、日)
on getDateInternational(aYear, aMonth, aDay)
set theNSCalendar to current application’s NSCalendar’s currentCalendar()
set theDate to theNSCalendar’s dateWithEra:1 |year|:aYear |month|:aMonth |day|:aDay hour:0 minute:0 |second|:0 nanosecond:0
return theDate as date
end getDateInternational
–天皇誕生日の計算
on getCurEmpBitrthday(targYear)
–昭和、平成、令和 の誕生日定義
set curEmperrorsBirthday to {{"4/29", {1926, 1988}}, {"12/23", {1989, 2018}}, {"2/23", {2020, 9999}}}
–浩宮氏が崩御の際には、崩御年を記入
set hitF to false
repeat with i in curEmperrorsBirthday
copy i to {targDate, {beginYear, endYear}}
if targYear ≥ beginYear and targYear ≤ endYear then
set hitF to true
exit repeat
end if
end repeat
if hitF = false then
return false
end if
return targDate
end getCurEmpBitrthday