Entwickler-Ecke

Basistechnologien - Feiertag überprüfen


Delete - Sa 13.01.18 14:08
Titel: Feiertag überprüfen
- Nachträglich durch die Entwickler-Ecke gelöscht -


Christian S. - Sa 13.01.18 14:30

Hallo,

hast Du die Zeiten, was wie lange braucht, mal gemessen? Das Erzeugen von ganzen 15 Instanzen des DateTime-Structs sollte auf jeden Fall keine drei Sekunden brauchen. Wie sollte irgendein .NET Programm jemals benutzbar sein, wenn solche Basisoperationen so lange brauchen?

Du brauchst aber auch keine Liste von DateTime-Instanzen. Wenn das gegebene Datum einem der Feiertage entspricht, muss ich die anderen ja nicht mehr prüfen. Irgendwie so kann man es machen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
        private static readonly Tuple<intint>[] staticHolidays = new Tuple<intint>[] {
            new Tuple<intint>(1,1),
            new Tuple<intint>(1,6),
            new Tuple<intint>(5,1),
            new Tuple<intint>(8,15),
            new Tuple<intint>(10,26),
            new Tuple<intint>(11,1),
            new Tuple<intint>(12,8),
            new Tuple<intint>(12,25),
            new Tuple<intint>(12,26),
        };

        // Feiertage für WIEN
        private static bool IsHoliday(DateTime date)
        {
            if (date > DateTime.MinValue)
            {
                foreach (var monthDay in staticHolidays)
                    if (date.Month == monthDay.Item1 && date.Day == monthDay.Item2)
                        return true;
                
                DateTime easter = EasterGregDate(date.Year);
                sbyte[] easterDiff = { -21395060 };
                // Ostersonntag - 2   = Karfreitag 
                // Ostersonntag + 1   = Ostermontag 
                // Ostersonntag + 39  = Christi Himmelfahrt 
                // Ostersonntag + 50  = Pfingstmontag 
                // Ostersonntag + 60  = Fronleichnam 

                for (int i = 0; i < easterDiff.Length; i++)
                    if (date == easter.AddDays(easterDiff[i]))
                        return true;
            }
            return false;
        }


Grüße
Christian


//edit: Es macht natürlich keinen Sinn, die Elemente im Array easterDiff per LINQ (Count()) zu zählen, wenn man einfach die Length-Eigenschaft des Arrays benutzen kann ;)


Delete - Sa 13.01.18 14:43

- Nachträglich durch die Entwickler-Ecke gelöscht -


Christian S. - Sa 13.01.18 15:20

Ach ja, ich würde bei der Methode EasterGregDate übrigens bei einem Jahr <= 1582 auch eine ArgumentOutOfRange-Exception werfen anstatt DateTime.Min zurückzugeben. Irgendwelche "magischen Werte" als Fehlerwerte zu verwenden, fällt einem irgendwann mal auf die Füße. Alternativ kann man noch über einen nullable DateTime als Rückgabewert nachdenken und für die ungültigen Jahre dann null zurückgeben. Favorisieren würde ich aber die Exception, weil man ja tatsächlich den Bereich gültiger Argumente (für diese Methode) verlässt.

Ein paar der Casts auf int in der Methode kannst Du Dir übrigens sparen, weil die Division zweier Integer immer einen Integer zurückgibt.


Delete - Sa 13.01.18 15:35

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Sa 13.01.18 15:43

Aus Neugier da ich deinen Test am Anfang der Methode sehe, wie bekommt man einen DateTime kleiner MinValue hin?
Und nach der Neugierfrage jetzt noch eine gemeine Bemerkung ;) Du berücksichtigst die Zeitzone und den Zeitpunkt des DateTime nicht. Dir mag das vordergründig egal sein aber spätestens das DateTime.Equals das beim Aufruf von List.Contains verwendet wird ist das nicht egal und in deine Methode lässt du jeden DateTime rein. Beispielsweise ein Zeitpunkt am erste Januar in UTC muss in deiner Zeitzone noch lange nicht (oder bezogen auf Mitteleuropa eher nicht mehr) Neujahr sein. Zeitzonen/Kalendersysteme sind doch immer ein Quell steter Freude. Was würden wir den Spaß vermissen wenn es das nicht gebe :roll:

Zitat:
Eigenschaften wie DateTime.Date usw. lassen sich nur lesen, nicht schreiben. :motz:


Wenn du mal das Thema mutable structs nachliest und was das für Konsequenzen hätte wirst du ganz schnell zu dem Schluss kommen das das eine gute Sache ist das das nicht geht ;)
Obwohl wenn es ginge hätten wir hier wieder reichlich zu tun um tolle fragen zu beantworten wie
"Warum ändert sich das Datum in der Liste nicht wenn ich 'dates[0].date = DateTime.Now' aufrufe?"


Delete - Sa 13.01.18 16:10

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Sa 13.01.18 16:30

Zitat:
Für die Zeitzone habe ich keinen Bedarf gesehen, denn ich arbeite hier nu mit einem Datum und nicht mit einer genauen Uhrzeit. Die Feiertage sind auch nur lokal (für Wien) gültig und würden für andere Ortschaften mit anderen Zeitzonen sowieso keinen Sinn ergeben.


Dann wäre das eine sinnvolle Eingangsprüfung für den DateTime anstatt auf MinDate zu prüfen.
Also das der DateTime.Kind auf Local (für UTC funktioniert der Code nur bedingt) steht und je nach Code ob der DateTime einen Zeitanteil enthält. Dein ursprünglicher Code hätte dann auch ein Problem. Bei einer Lösung wie bei Christian wäre das unproblematisch.


Delete - So 14.01.18 03:22

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - So 14.01.18 13:35

Readonly bezieht sich auf die Variable und nicht den Inhalt der Variablen an der es steht. Durch das ReadOnly kannst du also dem staticHolidays keine neues Tuple Array im Code zuweisen. Die Tuples in dem vorhandenen Array kannst du aber weiterhin beliebig austauschen. Und wenn Tuple änderbar wären (was sie nicht sind) könnte man die natürlich auch ändern egal ob da readonly steht. Wenn man das auch will müsste man z.b. eine ReadOnlyCollection verwenden anstatt einem Array.