Pitfall: Rechnen mit Calendar

Eigentlich eine ganz einfache Aufgabe: Erzeuge ein Calendar-Objekt der einen Monat zurückliegt. Das geht doch so:

import static java.util.Calendar.*
 
def cal = new GregorianCalendar()
cal[MONTH] -= 1

Aber irgendwie funktionierte das gestern an Halloween nicht so. Mit folgendem Code kann man es ganz einfach nachvollziehen:

import static java.util.Calendar.*
 
def halloween = new GregorianCalendar(2011, OCTOBER, 31)
println halloween[MONTH] // -> 9 
halloween[MONTH] -= 1
println halloween[MONTH] // -> 9 ???

Beide print-Anweisungen geben 9 aus, obwohl das Monatsfeld um eins verkleinert wurde.

Was ist passiert?

Die Ursache liegt in der Nachsichtigkeit (Leniency) der Java-Klasse Calendar. D.h. einzelne Datumsfelder dürfen auch außerhalb ihres Geltungsbereiches liegen. Und genau das ist hier auch passiert. Das Monatsfeld wurde um eins verringert und es entstand damit das Datum 31.09.2011 was es ja nicht gibt, da der September nur 30 Tage hat. Durch die Nachsichtigkeit wird es jedoch richtig interpretiert als 01.10.2011.

Diese Verhalten der Calendar-Klasse kann man abschalten und in unserem Beispiel erhält man dann eine Exception:

import static java.util.Calendar.*
 
def halloween = new GregorianCalendar(2011, OCTOBER, 31)
 
halloween.setLenient(false) // Nachsichtigkeit ausschalten
 
println halloween[MONTH] // -> 9 
halloween[MONTH] -= 1 // -> java.lang.IllegalArgumentException: MONTH

Um die Aufgabe nun richtig zu lösen könnte man DAY_OF_MONTH auf 1 setzen:

import static java.util.Calendar.*
 
def halloween = new GregorianCalendar(2011, OCTOBER, 31)
 
halloween[DAY_OF_MONTH] = 1
 
println halloween[MONTH] // -> 9 
halloween[MONTH] -= 1
println halloween[MONTH] // -> 8

Anregungen und Hinweise sind herzlich willkommen, schreibt mir unter @code_hx


Büro

ImpactHub Dresden
Bayrische Straße 8
01069 Dresden

Post

Dr.-Ing. Stefan Urbansky
HxCode
Dresdner Landstr. 30e
01728 Bannewitz