|
» myCSharp.de Diskussionsforum |
|
|
|
Autor
 |
|
|
Beschreibung:
Jedoch kann bei dieser Feiertagsberechnung das jeweilige Land mit berücksichtigt werden
C#-Code: |
using System;
using System.Collections.Generic;
using System.Collections;
using System.Text;
namespace BlackDragon.FeierTage {
public class FeierTage {
private List<FeierTag> feiertage = new List<FeierTag>();
public FeierTage() {
Initial();
}
public String GetFeiertag(DateTime datum, Land land) {
foreach (FeierTag f in feiertage) {
if (datum.ToShortDateString().Equals(f.GetDatum(GetOstersonntag(datum.Year)).ToShortDateString())) {
foreach (Land l in f.Länder) {
if (land == l) {
return f.Feiertag;
}
}
}
}
return "";
}
public Boolean IsFeiertag(DateTime date, Land land) {
return (GetFeiertag(date, land).Length > 0);
}
private DateTime GetOstersonntag(int jahr) {
int c;
int i;
int j;
int k;
int l;
int n;
int OsterTag;
int OsterMonat;
c = jahr / 100;
n = jahr - 19 * ((int)(jahr / 19));
k = (c - 17) / 25;
i = c - c / 4 - ((int)(c - k) / 3) + 19 * n + 15;
i = i - 30 * ((int)(i / 30));
i = i - (i / 28) * ((int)(1 - (i / 28)) * ((int)(29 / (i + 1))) * ((int)(21 - n) / 11));
j = jahr + ((int)jahr / 4) + i + 2 - c + ((int)c / 4);
j = j - 7 * ((int)(j / 7));
l = i - j;
OsterMonat = 3 + ((int)(l + 40) / 44);
OsterTag = l + 28 - 31 * ((int)OsterMonat / 4);
return Convert.ToDateTime(OsterTag.ToString() + "." + OsterMonat + "." + jahr);
}
private void Initial() {
Land[] alle = new Land[] { Land.Baden_Würtenberg, Land.Bayern, Land.Berlin, Land.Brandenburg, Land.Bremen, Land.Hamburg, Land.Hessen, Land.Mecklenburg_Vorpommern, Land.Niedersachsen, Land.Nordrhein_Westfalen, Land.Rheinland_Pfalz, Land.Saarland, Land.Sachsen, Land.Sachsen_Anhalt, Land.Schleswig_Holstein, Land.Thüringen };
feiertage.Add(new FeierTag("Neujahr","01.01", FeiertagsArt.Fester_Feiertag, alle));
feiertage.Add(new FeierTag("Heiligen Drei Könige", "06.01", FeiertagsArt.Fester_Feiertag, new Land[] { Land.Baden_Würtenberg, Land.Bayern, Land.Sachsen_Anhalt }));
feiertage.Add(new FeierTag("Karfreitag", -2, FeiertagsArt.Bewegliche_Feiertag, alle));
feiertage.Add(new FeierTag("Ostersonntag", 0, FeiertagsArt.Bewegliche_Feiertag, alle));
feiertage.Add(new FeierTag("Ostermontag", 1, FeiertagsArt.Bewegliche_Feiertag, alle));
feiertage.Add(new FeierTag("Tag der Arbeit", "01.05", FeiertagsArt.Fester_Feiertag, alle));
feiertage.Add(new FeierTag("Christi Himmelfahrt", 39, FeiertagsArt.Bewegliche_Feiertag , alle));
feiertage.Add(new FeierTag("Pfingstsonntag", 49, FeiertagsArt.Bewegliche_Feiertag, alle));
feiertage.Add(new FeierTag("Pfingstmontag", 50, FeiertagsArt.Bewegliche_Feiertag, alle));
feiertage.Add(new FeierTag("Fronleichnam", 60, FeiertagsArt.Bewegliche_Feiertag, new Land[] { Land.Baden_Würtenberg, Land.Bayern, Land.Hessen, Land.Nordrhein_Westfalen, Land.Rheinland_Pfalz,Land.Saarland}));
feiertage.Add(new FeierTag("Mariä Himmelfahrt", "15.08", FeiertagsArt.Fester_Feiertag, new Land[] { Land.Saarland }));
feiertage.Add(new FeierTag("Tag der dt. Einheit", "03.10", FeiertagsArt.Fester_Feiertag, alle ));
feiertage.Add(new FeierTag("Allerheiligen", "01.11", FeiertagsArt.Fester_Feiertag, new Land[] { Land.Baden_Würtenberg,Land.Bayern,Land.Nordrhein_Westfalen,Land.Rheinland_Pfalz,Land.Saarland }));
feiertage.Add(new FeierTag("1. Weinachtstag", "25.12", FeiertagsArt.Fester_Feiertag, alle));
feiertage.Add(new FeierTag("2. Weinachtstag", "26.12", FeiertagsArt.Fester_Feiertag, alle));
}
}
internal class FeierTag {
private FeiertagsArt art;
private string feiertag;
private DateTime datum;
private string testDatum;
private int tageHinzu;
private Land[] länder;
public String Feiertag {
get {
return this.feiertag;
}
}
public DateTime Datum {
get {
return this.datum;
}
}
public Land[] Länder {
get {
return länder;
}
}
internal FeierTag(String feiertag, String testDatum, FeiertagsArt art, Land[] länder) {
this.feiertag = feiertag;
this.testDatum = testDatum;
this.tageHinzu = 0;
this.art = art;
this.länder = länder;
}
internal FeierTag(String feiertag, int tageHinzu, FeiertagsArt art, Land[] länder) {
this.feiertag = feiertag;
this.tageHinzu = tageHinzu;
this.art = art;
this.länder = länder;
}
public DateTime GetDatum(DateTime osterSonntag) {
if (this.art != FeiertagsArt.Fester_Feiertag) {
datum = osterSonntag.AddDays(this.tageHinzu);
} else {
datum = DateTime.Parse(testDatum + "." + osterSonntag.Year);
}
return DateTime.Parse(datum.Day.ToString() + "." + datum.Month.ToString() +"."+ osterSonntag.Year);
}
}
public enum Land {
Baden_Würtenberg,
Bayern,
Berlin,
Brandenburg,
Bremen,
Hamburg,
Hessen,
Mecklenburg_Vorpommern,
Niedersachsen,
Nordrhein_Westfalen,
Rheinland_Pfalz,
Saarland,
Sachsen,
Sachsen_Anhalt,
Schleswig_Holstein,
Thüringen
}
public enum FeiertagsArt {
Fester_Feiertag,
Bewegliche_Feiertag
}
}
|
Schlagwörter: Feiertage, Osterformel
Quelle: .NET-Snippets
|
|
30.04.2007 10:13
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Zwischen diesen beiden Beiträgen liegen mehr als 6 Monate. |
juetho
myCSharp.de-Mitglied
Dabei seit: 23.10.2006
Beiträge: 3.331
Entwicklungsumgebung: #D NET 2.0 / Firebird (Win10) Herkunft: Berlin
|
|
Hallo,
das ist eine schöne Zusammenstellung. Ich möchte sie gerne erweitern:
* bundesweite Feiertage vereinfacht bestimmen
* als Singleton-Klasse
* mit statischen Abfragen
Wenn ich sowieso schon dabei bin, würde ich die Bundesländer nach den Nummern des Statistischen Bundesamtes indizieren.
Gibt es Interesse daran, diese Änderungen hier bereitzustellen? Jürgen
|
|
29.11.2007 17:15
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
herbivore
myCSharp.de-Poweruser/ Experte
Dabei seit: 11.01.2005
Beiträge: 49.483
Entwicklungsumgebung: csc/nmake (nothing is faster) Herkunft: Berlin
|
|
Hallo juetho,
für mich klingt das nach zwar nicht nach Erweiterungen, sondern "nur" nach Änderungen, aber es spricht auch nichts dagegen, deinen "Konkurrenzentwurf" hier zu veröffentlichen.
herbivore
|
|
29.11.2007 17:31
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
blackman1983
myCSharp.de-Mitglied
Dabei seit: 20.06.2007
Beiträge: 114
Entwicklungsumgebung: Visual Studio 2008
|
|
Hallo,
also is ja an sich nur Rechnerei, weil ja wohl durch Kirche u. Co alles irgendwie von Ostern ausgeht. Aber sehr interessant find ich ja wie du überhaupt auf das Datum vom Ostersonntag kommst. Is doch eigentlich vom Mond abhängig oder gibts da ne allgemeine Regel für?
Bräuchte das auch für nen Projekt.
Hast da vlt ma nen Algorithmus im Wortlaut bzw nich so böse hingecodet?
Konnte bisher rausfinden wieviele Tage von Ostern die anderen Feiertage entfernt sind, aber halt nich Ostern an sich.
Gruß
Black
|
|
30.11.2007 22:12
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
juetho
myCSharp.de-Mitglied
Dabei seit: 23.10.2006
Beiträge: 3.331
Entwicklungsumgebung: #D NET 2.0 / Firebird (Win10) Herkunft: Berlin
|
|
Überlegungen für Änderungen
Wie ich schon schrieb, wollte ich Blackcoin's Lösung ergänzen. Die folgenden Überlegungen haben mich dabei zu entsprechenden Änderungen geführt.
Art der Feiertage
Das habe ich zu einer bool-Variable "beweglich" vereinfacht. Andere Varianten gibt es schließlich nicht. Außerdem habe ich zur Vereinfachung der Prüfungen die bool-Variable "bundesweit" hinzufügt.
Für die Bezeichnung eines Feiertags (bei Blackcoin als "feiertag" bzw. "GetFeiertag" bezeichnet) benutze ich "name" bzw. "Name" oder "GetName".
Singleton-Klasse
Für die Feiertagsberechnung gibt es "inhaltlich" innerhalb einer Anwendung (eigentlich: in einem lokalen Netzwerk) zwangsläufig nur eine Variante. Es bietet sich deshalb an, den Aufruf über eine Singleton-Klasse zu steuern. Beim erstmaligen Aufruf wird die interne Klasse erstellt. Alle Methoden für Prüfungen stehen als "Schnittstelle" in der Singleton-Klasse.
C#-Code: |
public sealed class Feiertagsprüfung
{
private static Feiertagsprüfung
instance = new Feiertagsprüfung();
private Feiertage interna;
public static Feiertagsprüfung Instance {
get {
if (instance == null)
instance = new Feiertagsprüfung();
return instance;
}
}
private Feiertagsprüfung()
{
interna = new Feiertage();
}
}
|
Prüfmethoden
Ausgehend von Blackcoin's Konzept habe ich die folgenden Verfahren übernommen und für bundesweite Feiertage ergänzt sowie in die Singleton-Klasse eingebaut.
C#-Code: |
public static bool IsFeiertag(DateTime datum, bool bundesweit) { }
public static bool IsFeiertag(DateTime datum, Land land) { }
public static bool IsTeilweiseFeiertag(DateTime datum) { }
public static string GetName(DateTime datum) { }
public static string GetName(DateTime datum, Land land) {
return Instance.interna.GetName(datum, land);
}
|
Diese Methoden leiten (wie im letzten Beispiel) die Parameter an die entsprechenden Methoden in der internen Klasse weiter. Beispielhaft wird die letzte Prüfung so ausgeführt:
C#-Code: |
public string GetName(DateTime datum, Land land) {
string Result = String.Empty;
Feiertag f = GetFeiertag(datum);
if (f != null) {
if (f.Bundesweit || Array.IndexOf(f.Länder, land) >= 0)
Result = f.Name;
}
return Result;
}
|
Interne Liste als List<T> oder Dictionary<string, T>
Blackcoin's Verfahren, bei dem "Datümer" per String verglichen werden und die Strings in jedem Schritt der foreach-Schleife neu erstellt werden, gefiel mir nicht besonders. Das Verfahren kann hingenommen werden, weil es sich nur um wenige Einträge handelt und die beweglichen Feiertage für jedes Jahr getrennt berechnet werden müssen.
Aber genau wegen der Berechnung pro Jahr scheint mir die getrennte Speicherung sinnvoll zu sein. Dann können die Listen auch konsequent als Nachschlagetabellen genutzt werden, auch wenn ihre Erstellung ein klein wenig umständlicher aussieht.
C#-Code: |
private Dictionary<string, Feiertag> festeFeiertage
= new Dictionary<string, Feiertag> ();
festeFeiertage.Add("01.01.", new Feiertag("Neujahr", "01.01."));
private Dictionary<int, Dictionary<DateTime, Feiertag>> beweglicheFeiertage
= new Dictionary<int, Dictionary<DateTime, Feiertag>> ();
DateTime ostern = GetOstersonntag(jahr);
aktuelleFeiertage.Add(ostern.AddDays(-2),
new Feiertag("Karfreitag", ostern, -2));
|
Die eigentliche Prüfung wird durch den Dictionary-Aufbau erheblich vereinfacht und jeweils in der folgenden Methode erledigt:
C#-Code: |
private Feiertag GetFeiertag(DateTime datum)
{
Feiertag Result = null;
string ttmm = datum.ToString("dd.MM.");
if (! festeFeiertage.TryGetValue(ttmm, out Result)) {
Dictionary<DateTime, Feiertag> beweglich = null;
int jahr = datum.Year;
if (! beweglicheFeiertage.TryGetValue(jahr, out beweglich)) {
InitBeweglicheFeiertage(jahr);
beweglich = beweglicheFeiertage[jahr];
}
beweglich.TryGetValue(datum, out Result);
}
return Result;
}
|
Besondere Feiertage
Fronleichnam und Mariä Himmelfahrt sind in manchen Bundesländern nur teilweise Feiertag. Dafür habe ich in der Enumeration der Bundesländer an Position Null die Angabe "teilweise" hinzugefügt. Ein solcher Feiertag muss also bei Bedarf genauer geprüft werden.
Diese Länder können in den Methoden InitFesteFeiertage() und InitBeweglicheFeiertage() anstatt "teilweise" eingetragen werden.
Der Buß- und Bettag ist nur noch in Sachsen Feiertag und errechnet sich auf besondere Weise; dafür gibt es also analog zu GetOstersonntag() eine eigene Berechnungsmethode.
Wenn der 1. Mai gleichzeitig Tag der Arbeit und Christi Himmelfahrt ist, wird nur der feste Feiertag angezeigt, weil dies in der o.g. Prüfung Vorrang hat.
Außerdem entspricht die Reihenfolge der Liste der Bundesländer jetzt dem Gemeindeverzeichnis des Stat. Bundesamtes.
Die vollständige, aktuelle Version habe ich als Anlage beigefügt. (Die Anlage enthält außerdem eine Anwendung, die alle Methoden für alle Bundesländer in den Jahren 2006, 2007, 2008 demonstriert.)
Jürgen Thomas (juetho)
Urheber
Sowohl der Hauptgedanke mit den beiden Klassen "Einzelner Feiertag" und "Alle Feiertage" sowie den Prüfungsvorgängen und den Klassenelementen als auch die unabdingbar notwendige, wichtige und saubere Berechnung des Ostersonntags stammen von blackcoin. Die Ergänzungen mit Dictionary und Singleton-Klasse sowie dadurch einfacheren Prüfmethoden stammen von juetho.
Unabhängig davon gelten natürlich die Nutzungsbedingungen von myCSharp.de.
Nachtrag: (2016) Die Anlage Feiertage.zip wurde ersetzt durch die korrigierte Version im folgenden Beitrag.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von juetho am 14.07.2016 16:30.
|
|
02.12.2007 17:17
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Zwischen diesen beiden Beiträgen liegen mehr als 8 Jahre. |
juetho
myCSharp.de-Mitglied
Dabei seit: 23.10.2006
Beiträge: 3.331
Entwicklungsumgebung: #D NET 2.0 / Firebird (Win10) Herkunft: Berlin
|
|
Wichtiger Hinweis: Die vorstehende Berechnung genügt nicht: Zwei Ausnahmeregeln wurden bei den obigen Lösungen nicht in die Gaußsche Formel eingearbeitet. Der Ordnung halber folgt hier die berichtigte Berechnung:
C#-Code: |
private DateTime GetOstersonntag(int jahr)
{
int x = jahr;
int k;
int m;
int s;
int a;
int d;
int r;
int og;
int sz;
int oe;
int os;
int OsterTag;
int OsterMonat;
k = x / 100;
m = 15 + (3 * k + 3) / 4 - (8 * k + 13) / 25;
s = 2 - (3 * k + 3) / 4;
a = x % 19;
d = (19 * a + m) % 30;
r = (d + a / 11) / 29;
og = 21 + d - r;
sz = 7 - (x + x / 4 + s) % 7;
oe = 7 - (og - sz) % 7;
os = og + oe;
OsterMonat = 2 + (int)(os + 30) / 31;
OsterTag = os - 31 * ((int)OsterMonat / 4);
return Convert.ToDateTime(OsterTag.ToString() + "." + OsterMonat + "." + jahr);
}
|
[offtopic]Auf diesen Fehler wurde ich kürzlich durch eine Änderung bei der Wikibooks-Algorithmensammlung aufmerksam gemacht.[/offtopic]
Die hier stehende Version von Feiertage.zip habe ich entsprechend ergänzt.
Quelle: Gaußsche Osterformel (mit Ergänzung)
Hinweis: Der letzte Beitrag bei Osterformel nach Carl Friedrich Gauß enthält die vollständige Lösung.
Nachtrag: Die Anlage Feiertage.zip wurde ersetzt durch die korrigierte Version in meinem nächsten Beitrag (27.09.2016).
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von juetho am 27.09.2016 12:56.
|
|
14.07.2016 16:28
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Zwischen diesen beiden Beiträgen liegt mehr als ein Monat. |
sheitman
myCSharp.de-Mitglied
Dabei seit: 02.11.2005
Beiträge: 1.047
|
|
Hallo,
wollte noch anmerken das die Buß und Bettag Berechnung auch fehlerhaft ist.
Ist mir für 2000, 2006, 2017 und 2023 aufgefallen. Es ist jedes mal der 15. statt der 22.
Laut Buß- und Bettag ist der Feiertag so definiert das es der Mittwoch vor dem 23. November ist. D.h. der Code kann auch sehr stark vereinfacht werden.
Mit folgender Hilfsmethode
C#-Code: |
public static DateTime GetLastWeekday(this DateTime startDate, DayOfWeek targetDayOfWeek) {
DayOfWeek startDayOfWeek = startDate.DayOfWeek;
if (startDayOfWeek == targetDayOfWeek) {
return startDate;
}
int diff = 0;
if (startDayOfWeek < targetDayOfWeek) {
diff = targetDayOfWeek - startDayOfWeek - 7;
} else if (startDayOfWeek > targetDayOfWeek) {
diff = targetDayOfWeek - startDayOfWeek;
}
return startDate.AddDays(diff);
}
|
Lässt sich der Buß und Bettag dann so berechnen
C#-Code: |
DateTime GetBussUndBettag(int year) {
return new DateTime(year, 11, 22).GetLastWeekday(DayOfWeek.Wednesday);
}
|
@juetho
bei GetOstersonntag, die letzte Zeile, da würde ich anstelle
C#-Code: |
return Convert.ToDateTime(OsterTag.ToString() + "." + OsterMonat + "." + jahr);
|
einfach den Konstruktor von DateTime verwenden
C#-Code: |
return new DateTime(jahr, OsterMonat, OsterTag);
|
Gruß
Sven
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von sheitman am 01.09.2016 12:21.
|
|
01.09.2016 12:21
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Zwischen diesen beiden Beiträgen liegt mehr als ein Monat. |
p!lle
myCSharp.de-Mitglied
Dabei seit: 22.02.2007
Beiträge: 1.032
Entwicklungsumgebung: Visual Studio (Community) 2019
|
|
Grade mitbekommen, dass der Reformationstag 2017 in ganz Deutschland gefeiert werden soll, siehe auch Wikipedia.
|
|
28.10.2016 14:54
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Zwischen diesen beiden Beiträgen liegen mehr als 2 Monate. |
live2
myCSharp.de-Mitglied
Dabei seit: 14.11.2005
Beiträge: 33
|
|
Zu diesem Thema gibt es auch ein C# Projekt auf Github. Die Feiertage werden auch Dynamisch berechnet und es werden derzeit 23 Länder unterstützt. Deutschland ist eines davon, die Bundesländer werden auch berücksichtigt
https://github.com/tinohager/Nager.Date
C#-Code: |
var publicHolidays = DateSystem.GetPublicHoliday("DE", 2017);
foreach (var publicHoliday in publicHolidays)
{
Console.WriteLine(publicHoliday.Name);
}
|
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von live2 am 05.01.2017 14:47.
|
|
05.01.2017 14:46
|
E-Mail |
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
|
|