Date Time: Unterschied zwischen den Versionen
Jochen (Diskussion | Beiträge) |
Jochen (Diskussion | Beiträge) |
||
| Zeile 1: | Zeile 1: | ||
__TOC__ | |||
== Ordinalzahl eines Wochetags innerhalb eines Monats == | == Ordinalzahl eines Wochetags innerhalb eines Monats == | ||
Aktuelle Version vom 18. Dezember 2018, 08:34 Uhr
Ordinalzahl eines Wochetags innerhalb eines Monats
Die folgende Methode zeigt eine Möglichkeit, die Ordinalzahl eines Wochentags bzgl. des jeweiligen Monats zu berechnen (z.B. 1. Montag im Januar, 4. Dienstag im April, 5. bzw. letzter Sonntag im Dezember). Der Algorithmus stammt aus der Klasse Java Bibliothek “Joda Time”.
public static int getWeekOfWeekDay(Date date)
{
return ((date.getDate() - 1) / 7) + 1;
}
Exception bei monatlicher Wiederholung
Bei einer monatlichen Wiederholung kann es unter folgenden Vorausetzungen zu Exceptions kommen:
Monatliche Wiederholung an einem Tag des Monats, welcher nicht in allen zu wiederholenden Monaten existiert (z.B. 29., 30 oder 31 eines Monats). Die Exception wird durch einen Log-Eintrag ausgelöst und wird nur dann geworfen, wenn das Loglevel (log4j Adapter) auf TRACE oder ALL steht. Ab DEBUG oder höher existiert das Problem nicht.
In Version 1.0.5.2 stellt sich dieses Problem wie folgt dar:
Die Klasse net.fortuna.ical4j.model.Recur enthält die Methode getMonthDayVariants(). Diese ermittelt die sich monatlich wiederholenden Termine. Nehmen wir eine monatliche Wiederholung am 30. des Monats an. Im Monat Februar versucht der Java Calendar via cal.set(Calendar.DAY_OF_MONTH...) den 30.02. zu setzen. Dies gelingt nicht und eine Exception wird geworfen. Zusätzlich vermerkt sich die Calendar Instanz intern, dass ein ungültiges Datum gespeichert ist. Durch das Werfen der Exception wird der catch-Handler aufgerufen. Ist das Loglevel TRACE oder ALL konfiguriert, versucht ical4j diesen Umstand im Log zu dokumentieren. Hierbei wird jedoch cal.getTime() aufgerufen. Da sich die jeweiligen Calendar Instanz merkte, dass sie ein ungültiges Datum speichert, wirft dieser Aufruf erneut eine Exception. Diese hat nun keinen catch-Handler und fliegt bis zum Aufrufer durch.
/**
* Applies BYMONTHDAY rules specified in this Recur instance to the specified date list. If no
* BYMONTHDAY rules are
* specified the date list is returned unmodified.
* @param dates
* @return
*/
private DateList getMonthDayVariants(final DateList dates) {
if (getMonthDayList().isEmpty()) {
return dates;
}
final DateList monthDayDates = getDateListInstance(dates);
for (final Iterator i = dates.iterator(); i.hasNext();) {
final Date date = (Date) i.next();
final Calendar cal = getCalendarInstance(date, false);
for (final Iterator j = getMonthDayList().iterator(); j.hasNext();) {
final Integer monthDay = (Integer) j.next();
try {
cal.set(Calendar.DAY_OF_MONTH, Dates.getAbsMonthDay(cal.getTime(), monthDay.intValue()));
monthDayDates.add(Dates.getInstance(cal.getTime(), monthDayDates.getType()));
}
catch (IllegalArgumentException iae) {
if (log.isTraceEnabled()) {
log.trace("Invalid day of month: " + Dates.getAbsMonthDay(cal
.getTime(), monthDay.intValue()));
}
}
}
}
return monthDayDates;
}
Jährliche Wiederholung am 29. Februar
Eine jährliche Wiederholung am 29. Februar liefert ein unvorhergesehenes Ergebnis. Das Ergebnisset enthält den als Startdatum spezifizierten 29. Februar. Danach ist ausschließlich der 28. Februar aller Folgejahre enthalten.
Beispiel:
29.02.2016 00:00:00 (Schaltjahr)
28.02.2017 00:00:00
28.02.2018 00:00:00
28.02.2019 00:00:00
28.02.2020 00:00:00 (Schaltjahr)
28.02.2021 00:00:00
Dieser Umstand ist in der ical4j Klasse net.fortuna.ical4j.model.Recur begründet. Diese enthält die Methode increment(). Diese addiert das jeweils spezifizierte Wiederholungsintervall. D.h. in diesem Fall ein Jahr. Die Java Calendar Klasse liefert den 28.02. des Folgejahr, wenn zum 29.02. ein Jah addiert wird. Ab diesem Punkt wird zum 28.02. jeweils ein Jahr hinzuaddiert. Daher verbleibt die Wiederholung auf dem 28.02.
/**
* Increments the specified calendar according to the frequency and interval specified in this recurrence rule.
* @param cal a java.util.Calendar to increment
*/
private void increment(final Calendar cal) {
// initialise interval..
final int calInterval = (getInterval() >= 1) ? getInterval() : 1;
cal.add(calIncField, calInterval);
}
Wiederholung in Lücke zwischen Winter- und Sommerzeit
Daily
Trifft die tägliche Wiederholung auf einen nicht existierenden Termin (sprich nicht existierendes Datum bzw. Uhrzeit), wirkt sich dies auf alle Folgetermine aus. Dies ist bei einer täglichen Wiederholung meist dann gegeben, wenn der zu wiederholende Termin die Lücke des Wechsels von Winter- auf Sommerzeit trifft (z.B. in Deutschland 02:30 Uhr am letzten Sonntag im März). Alle Folgetermine in Sommerzeit fangen bereits eine Stunde früher an (im Beispiel: 01:30 Uhr). Dies passiert, obwohl es sich bei den Zeiten um Floating Date/Times handelt.
Beispiel – Floating Date/Times:
28.03.2014 02:30
29.03.2014 02:30
30.03.2014 01:30
31.03.2014 01:30
32.03.2014 01:30
Weekly
Trifft die wöchentliche Wiederholung auf einen nicht existierenden Termin (sprich nicht existierendes Datum bzw. Uhrzeit), wirkt sich dies auf alle Folgetermine aus. Dies ist bei einer wöchentlichen Wiederholung meist dann gegeben, wenn der zu wiederholende Termin die Lücke des Wechsels von Winter- auf Sommerzeit trifft (z.B. in Deutschland 02:30 Uhr am letzten Sonntag im März). Alle Folgetermine in Sommerzeit fangen bereits eine Stunde früher an (im Beispiel: 01:30 Uhr). Dies passiert, obwohl es sich bei den Zeiten um Floating Date/Times handelt.
Beispiel – Floating Date/Times:
16.03.2014 02:30
23.03.2014 02:30
30.03.2014 01:30
06.04.2014 01:30
13.04.2014 01:30
Monthly
Trifft die monatliche Wiederholung auf einen nicht existierenden Termin (sprich nicht existierendes Datum bzw. Uhrzeit), wirkt sich dies auf alle Folgetermine aus. Dies ist bei einer monatlichen Wiederholung meist dann gegeben, wenn der zu wiederholende Termin die Lücke des Wechsels von Winter- auf Sommerzeit trifft (z.B. in Deutschland 02:30 Uhr am letzten Sonntag im März). Alle Folgetermine in Sommerzeit fangen erst eine Stunde später an (im Beispiel: 03:30 Uhr). Dies passiert, obwohl es sich bei den Zeiten um Floating Date/Times handelt.
Beispiel – Floating Date/Times - alle zwei Monate:
30.01.2014 02:30
30.03.2014 03:30
30.05.2014 03:30
30.07.2014 03:30
How to detect an ambiguous DST overlap in Joda Time?
Take advantage of withEarlierOffsetAtOverlap().
public static boolean isInOverlap(LocalDateTime ldt, DateTimeZone dtz)
{
DateTime dt1 = ldt.toDateTime(dtz).withEarlierOffsetAtOverlap();
DateTime dt2 = dt1.withLaterOffsetAtOverlap();
return dt1.getMillis() != dt2.getMillis();
}
public static void test()
{
// CET DST rolls back at 2011-10-30 2:59:59 (+02) to 2011-10-30 2:00:00 (+01)
final DateTimeZone dtz = DateTimeZone.forID("CET");
LocalDateTime ldt1 = new LocalDateTime(2011,10,30,1,50,0,0); // not in overlap
LocalDateTime ldt2 = new LocalDateTime(2011,10,30,2,50,0,0); // in overlap
System.out.println(ldt1 + " is in overlap? " + isInOverlap(ldt1, dtz));
System.out.println(ldt2 + " is in overlap? " + isInOverlap(ldt2, dtz));
}