JMeh 2018-04-03: This is a small algorithm for calculating German holidays. The basis is that all Catholic holidays depend on the date of Easter Sunday. The formula for calculating Easter Sunday was developed by German mathematician Carl Friedrich Gauss in 1800. Heiner Lichtenberg corrected this formula in 1997 and thus made the exemptions to the Gauss formula unnecessary.
proc Feiertage {y} {
set defs {
Neujahr 01.01.
Karfreitag -2
Ostersonntag +0
Ostermontag +1
{Erster Mai} 01.05.
{Christi Himmelfahrt} +39
Pfingstmontag +50
Fronleichnam +60
{Tag der deutschen Einheit} 03.10.
Allerheiligen 01.11.
{Erster Weihnachtstag} 25.12.
{Zweiter Weihnachtstag} 26.12.
}
# Lichtenberg-Formel (korrigierte Gauss-Formel) zur Berechnung des Ostersonntags (Offset zum 1. März):
set a [expr {$y % 19}] ;# Mondparameter
set k [expr {$y / 100}] ;# Säkularzahl
set m [expr {15 + (3 * $k + 3) / 4 - (8 * $k + 13) / 25}] ;# säkulare Mondschaltung
set d [expr {(19 * $a + $m) % 30}] ;# Keim für den ersten Vollmond im Frühling
set s [expr {2 - (3 * $k + 3) / 4}] ;# säkulare Sonnenschaltung
set r [expr {$d / 29 + ($d / 28 - $d / 29) * $a / 11}] ;# kalendarische Korrekturgröße (beseitigt die Gaußschen Ausnahmeregeln)
set og [expr {21 + $d - $r}] ;# Ostergrenze (Märzdatum des Ostervollmonds)
set sz [expr {7 - ($y + $y / 4 + $s) % 7}] ;# erster Sonntag im März
set oe [expr {7 - ($og - $sz) % 7}] ;# Entfernung des Ostersonntag von der Ostergrenze in Tagen
set o [expr {$og + $oe - 1}] ;# Datum des Ostersonntags als Märzdatum (32. März = 1. April usw.)
set os [clock add [clock scan $y-03-01] $o days]
set feiertage [dict create]
dict for {name tag} $defs {
if {[regexp {^[+\-]} $tag]} {
dict set feiertage $name [clock format [clock add $os $tag days] -format %d.%m.%Y]
} else {
dict set feiertage $name $tag$y
}
}
return $feiertage
}
set today [clock format [clock seconds] -format %d.%m.%Y]
set year [string range $today end-3 end]
dict for {name day} [Feiertage $year] {
puts "$name = $day"
if {$day eq $today} {
puts "Heute ist ein Feiertag!"
}
}
ALX 2018-09-04 extended to the federal states; non-statutory holidays; meteorological and astronomical events; daylight saving
#
# Ereignisse jahr bundesland
# returns with a data tripple (name date type)
#
proc Ereignisse {y {bl {}}} {
# Julianisch -> Gregorianisch
proc J2G { jda } {
set jd [expr {floor($jda + 0.5)}]
set z [expr {$jda - $jd + 0.500001}]
set tz [expr {$jd - 1721117}]
if {$jd > 2299160} {
set tz [expr {$tz + (floor(($tz + 2) / 36524.25) - floor(($tz + 2) / 146097) - 2)}]
}
set y [expr {floor(($tz - 0.2) / 365.25)}]
set r [expr {$tz - floor($y * 365.25)}]
set m [expr {floor(($r - 0.5) / 30.6)}]
set d [expr {$r - floor($m * 30.6 + 0.5)}]
set m [expr {$m + 3}]
if {$m > 12} {
set m [expr {$m - 12}]
set y [expr {$y + 1}]
}
set h1 [expr {$z * 24}]
set ho [expr {floor($h1)}]
set mi [expr {floor(($h1 - $ho) * 60)}]
return [format {%04d-%02d-%02d %02d:%02d} [expr {int($y)}] [expr {int($m)}] [expr {int($d)}] [expr {int($ho)}] [expr {int($mi)}]]
}
# BW Baden-Württemberg
# BY Bayern
# BE Berlin
# BB Brandenburg
# HB Bremen
# HH Hamburg
# HE Hessen
# MV Mecklenburg-Vorpommern
# NI Niedersachsen
# NW Nordrhein-Westfalen
# RP Rheinland-Pfalz
# SL Saarland
# SN Sachsen
# ST Sachsen-Anhalt
# SH Schleswig-Holstein
# TH Thüringen
# g gesetzlicher Feiertag
# f|F Festtag
# e|E Ereigniss
# a alle Bundesländer
set defs {
Neujahr 01-01 g a
"Heilige drei K\u00f6nige" 01-06 g {BW BY ST}
Karfreitag O-2 g a
Ostersonntag O+0 g BB
Ostermontag O+1 g a
{Tag der Arbeit} 05-01 g a
{Christi Himmelfahrt} O+39 g a
Pfingstsonntag O+49 g BB
Pfingstmontag O+50 g a
Fronleichnam O+60 g {BW BY HE NW RP SL}
"Mari\u00e4 Himmelfahrt" 08-15 g {BY SL}
{Tag der deutschen Einheit} 10-03 g a
Reformationstag 10-31 g {BB HB HH MV NI SN ST SH TH}
Allerheiligen 11-01 g {BW BY NW RP SL}
"Bu\u00df- und Bettag" A-32 g SN
{1. Weihnachtstag} 12-25 g a
{2. Weihnachtstag} 12-26 g a
Weiberfastnacht O-52 f a
Fastnachtssamstag O-50 f a
Fastnachtssonntag O-49 f a
{Rosenmontag, Fastnacht} O-48 f a
Aschermittwoch O-46 f a
Valentinstag 02-14 f a
Frauentag 03-08 f a
Palmsonntag O-7 f a
Gr\u00fcndonnerstag O-3 f a
Karsamstag O-1 f a
Walpurgisnacht 04-30 f a
Muttertag MT f a
{17. Juni 1953} 06-17 f a
Johannistag 06-24 f a
Siebenschl\u00e4fertag 06-27 f a
{Peter und Paul} 06-29 f a
{Augsburger Friedensfest} 08-08 f BY
Michaelistag 09-29 f a
Erntedankfest ED f a
Halloween 10-31 f a
Allerseelen 11-02 f a
Martinstag 11-11 f a
Volkstrauertag A-35 f a
Totensonntag A-28 f a
Barbara 12-04 f a
Nikolaus 12-06 f a
{1. Advent} A-21 f a
{2. Advent} A-14 f a
{3. Advent} A-7 f a
{4. Advent} A-0 f a
Heiligabend 12-24 F a
Silvester 12-31 F a
"meteo. Fr\u00fchlingsanfang" 03-01 e a
Fr\u00fchlingsanfang FaB E a
Sommerzeitbeginn SZB e a
{meteo. Sommeranfang} 06-01 e a
{Sommeranfang, Sommersonnenwende} SaB E a
{meteo. Herbstanfang} 09-01 e a
Herbstanfang HaB E a
Sommerzeitende SZE e a
{meteo. Winteranfang} 12-01 e a
{Winteranfang, Wintersonnenwende} WaB E a
}
# astronomische Jahreszeiten
set Y [expr {($y - 2000) / 1000.0}]
# März-Äquinoktium (Beginn des astronomischen Frühlings):
set FaB [J2G [expr {2451623.80984 + 365242.37404 * $Y + 0.05169 * pow($Y,2) - 0.00411 * pow($Y,3) - 0.00057 * pow($Y,4)}]]
# Juni-Solstitium (Beginn des astronomischen Sommers):
set SaB [J2G [expr {2451716.56767 + 365241.62603 * $Y + 0.00325 * pow($Y,2) + 0.00888 * pow($Y,3) - 0.00030 * pow($Y,4)}]]
# September-Äquinoktium (Beginn des astronomischen Herbstes)
set HaB [J2G [expr {2451810.21715 + 365242.01767 * $Y - 0.11575 * pow($Y,2) + 0.00337 * pow($Y,3) + 0.00078 * pow($Y,4)}]]
# Dezember-Solstitium (Beginn des astronomischen Winters):
set WaB [J2G [expr {2451900.05952 + 365242.74049 * $Y - 0.06223 * pow($Y,2) - 0.00823 * pow($Y,3) + 0.00032 * pow($Y,4)}]]
# Advent = 4. Advent am Sonntag vor Heilig Abend oder wenn Heilig Abend Sonntag an Heilig Abend
set diff [expr {[clock format [set a4 [clock scan ${y}-12-24]] -format %u] * -1}]
if {$diff != -7} {
set a4 [clock add $a4 $diff days]
}
# Lichtenberg-Formel (korrigierte Gauss-Formel) zur Berechnung des Ostersonntags (Offset zum 1. März):
set a [expr {$y % 19}] ;# Mondparameter
set k [expr {$y / 100}] ;# Säkularzahl
set m [expr {15 + (3 * $k + 3) / 4 - (8 * $k + 13) / 25}] ;# säkulare Mondschaltung
set d [expr {(19 * $a + $m) % 30}] ;# Keim für den ersten Vollmond im Frühling
set s [expr {2 - (3 * $k + 3) / 4}] ;# säkulare Sonnenschaltung
set r [expr {$d / 29 + ($d / 28 - $d / 29) * $a / 11}] ;# kalendarische Korrekturgröße (beseitigt die Gaußschen Ausnahmeregeln)
set og [expr {21 + $d - $r}] ;# Ostergrenze (Märzdatum des Ostervollmonds)
set sz [expr {7 - ($y + $y / 4 + $s) % 7}] ;# erster Sonntag im März
set oe [expr {7 - ($og - $sz) % 7}] ;# Entfernung des Ostersonntag von der Ostergrenze in Tagen
set o [expr {$og + $oe - 1}] ;# Datum des Ostersonntags als Märzdatum (32. März = 1. April usw.)
set os [clock add [clock scan $y-03-01] $o days]
set ereignisse {}
foreach {name tag typ land} $defs {
if {$bl ne {} && $bl ni $land && $land ne {a}} {
set typ f
}
switch -glob -- $tag {
FaB {
# astronomischer Frühlingsbeginn nordhemisphäre; südhemisphäre: Herbst
lappend ereignisse $name [string range $FaB 0 9] $typ
}
SaB {
# astronomischer Sommerbeginn nordhemisphäre; südhemisphäre: Winter
lappend ereignisse $name [string range $SaB 0 9] $typ
}
HaB {
# astronomischer Herbstbeginn nordhemisphäre; südhemisphäre: Frühling
lappend ereignisse $name [string range $HaB 0 9] $typ
}
WaB {
# astronomischer Winterbeginn nordhemisphäre; südhemisphäre: Sommer
lappend ereignisse $name [string range $WaB 0 9] $typ
}
ED {
# Erntedankfest = erster Sonntag im Oktober
set diff [expr {7 - [clock format [set ct [clock scan ${y}-10-01]] -format %u]}]
lappend ereignisse $name [clock format [clock add $ct $diff days] -format %Y-%m-%d] $typ
}
MT {
# Muttertag = zweiter Sonntag im Mai, wenn Pfingsten und Muttertag gleich, dann Muttertag eine Woche früher
set diff [expr {7 - [clock format [set ct [clock scan ${y}-05-01]] -format %u] + 7}]
set muttertag [clock add $ct $diff days]
if {$muttertag == [clock add $os +49 days]} {
set muttertag [clock add $muttertag -7 days]
}
lappend ereignisse $name [clock format $muttertag -format %Y-%m-%d] $typ
}
SZB {
# Sommmerzeitbeginn = letzter Sonntag im März
set diff [expr {[clock format [set ct [clock scan ${y}-03-31]] -format %u] * -1}]
if {$diff == -7} {
set diff 0
}
lappend ereignisse $name [clock format [clock add $ct $diff days] -format %Y-%m-%d] $typ
}
SZE {
# Sommmerzeitende = letzter Sonntag im Oktober
set diff [expr {[clock format [set ct [clock scan ${y}-10-31]] -format %u] * -1}]
if {$diff == -7} {
set diff 0
}
lappend ereignisse $name [clock format [clock add $ct $diff days] -format %Y-%m-%d] $typ
}
O* {
# abhängig von Ostern
lappend ereignisse $name [clock format [clock add $os [string range $tag 1 end] days] -format %Y-%m-%d] $typ
}
A* {
# abhängig vom Advent
lappend ereignisse $name [clock format [clock add $a4 [string range $tag 1 end] days] -format %Y-%m-%d] $typ
}
default {
lappend ereignisse $name $y-$tag $typ
}
}
}
return $ereignisse
}
BSD-3 license
See Also:
https://tcl.sowaswie.de/repos/fossil/snippets/dir?name=calendar