Y2K-BugFix für JavaScript

von Thomas Salvador.

Tatsächlich ist die Datumsfunktion in einigen Browsern fehlerhaft, in der Form, dass sie nicht Jahr-2000-fest ist.

D.h.für das Jahr wird statt 2000 den Wert 100 geliefert, 101 statt 2001, usw.

Wer z.B. die "Einführung in Datum und Zeit" gelesen hat weiß, dass Date.getYear() für Jahre vor 2000 zweistellige Werte lieferte (z.B. 99 für 1999) und ab 2000 vierstellige liefern sollte (z.B. 2000 für 2000).

Etliche Browser halten sich auch daran, doch hat der Fehlerteufel bei anderen kräftig zugeschlagen.

Wer meine anderen Scripte bzw. Artikel betrachtet hat, hat gesehen, dass ich eine Funktion t4() verwendete, um stets eine vierstellige Jahreszahl zu liefern.

function t4(y) {
  return (y < 100 ? y+1900 : y);
}

Zu Werten kleiner 100 (die somit zweistellig sind) wurde 1900 addiert, alles andere unverändert zurückgegeben.

Betroffene Browser

Nach Angaben im Newsletter 'The Tribune' sind folgende Browser fehlerhaft:

  • NS 2
  • NS 4.06+
  • IE 2
  • Andere Browser und Versionen (NS 3, NS 4.0 bis NS 4.05, IE 4+) sollen in Ordnung sein.

BugFix

Ursprünglicher Fix

Mit einer kleinen Änderung an der obigen Funktion t4(), kann man aus ihr einen Fix für den Y2K-Bug der betroffenen Browser machen:

function t4(y) { //y2k-BUGFIX fuer Browser
  return (y < 1000 ? y+1900 : y);
}

Ist der Browser nicht fehlerhaft, so ist y >= 2000 und wird unverändert zur&u uml;ckgegeben. Ist er fehlerhaft, so ist y nun 100, 101, usw. also kleiner 1000.

Durch die Additon wird daraus y+1900=2000, 2001, usw., also der korrekte Wert.

Natürlich ist das nur ein Pflaster, da Sie ja auch mit einem (echten) nur zweistelligen Jahr arbeiten könnten.

Besserer Fix

Aufgrund dieses Vorfalls und der Tatsache, dass ein solches Pflaster nie 100%-ig korrekt sein kann, entschied man sich für zwei Dinge:

  • Man änderte die Bedeutung von getYear(), so dass diese nun immer Jahr-1900 liefern soll. D.h. genau für die Jahre 19xx ist der Wert zweistellig, sonst auch größer 100 oder negativ.
  • Man führte eine neue Funktion getFullYear() ein, die das Jahr immer vollständig, i.a. also vierstellig liefert. Eine zweistellige Antwort ist auch eine zweistrllige Jahreszahl.

Was heißt das für Sie?

Wenn Sie vor dem 23. Januar 2000 hier meine Scripte gezogen haben:

  • Updaten Sie bitte.
  • Alternativ können Sie natürlich auch rasch aus der 100 jeweils eine 1000 machen. Da ich selbst ausgerechnet den Communicator 4.05 (und ggf. IE5) verwende, war ich nie von diesem Bug betroffen.
  • Oder ändern ein getYear() in ein getFullYear().

Bitte updaten Sie folgende Scripte bzw. Artikel:

Wenn Sie selbst Scripte schreiben, sollten Sie einen der vorgestellen BugFixes verwenden, um für alle Besucher das korrekte Datum zu gewährleisten.

Ich empfehle Ihnen jedoch die Verwendung von getFullYear().

Als Surfer mit einem derzeit fehlerhaften Browser, können Sie auf einen funktionierenden wechseln, wenn Ihnen das irgendwie wichtig ist.

Und setYear()?

Völlig analog.

Die setzende Funktion setYear() hat seine ursprünglich Bedeutung behalten. Ist der Wert zweistellig, ist es 1900+wert, sonst der Wert selbst.

datum.setYear(1999); // jahr 1999
datum.setYear(99);   // jahr 1999
datum.setYear(10);   // jahr 101
datum.setYear(-1);   // jahr -1

Sie wurde jedoch ebenso umdefiniert, um zu getYear() zu passen. Ein setYear(101) setzt also das Jahr 2001.

Entsprechend wurde auch eine setFullYear() eingeführt, die zu getFullYear() passt. setFullYear(101) setzt so das Jahr 101.

Bei der Konstruktion eines Date-Objektes eine Mischung. Zweistellige Jahreszahlen bedeutet 19xx, sonst ist es die Jahreszahl:

datum = new Date(1999,1,1); // jahr 1999
datum = new Date(99,1,1);   // jahr 1999
datum = new Date(101,1,1);  // jahr 101
datum = new Date(-1,1,1);   // jahr -1

Ihr Browser

Schauen wir uns Ihren Browser an.

<script type="text/javascript"><!--
function ausgabe(jahr, datum) {
  document.write('<li>', jahr, ': ',
    'getYear: ', datum.getYear(), '; ',
    'getFullYear: ',datum.getFullYear(), '</li>');
}

function test() {
  var y1999a = new Date(99,1,1);
  var y1999b = new Date(1999,1,1);
  var y2000 = new Date(2000,1,1);
  var y1950 = new Date(1950,1,1);
  var y1850 = new Date(1850,1,1);
  var isOk = true
    && y1999a.getFullYear() == 1999 && y1999a.getYear() == 99
    && y1999b.getFullYear() == 1999 && y1999b.getYear() == 99
    && y2000.getFullYear() == 2000 && y2000.getYear() == 100
    && y1950.getFullYear() == 1950 && y1950.getYear() == 50
    && y1850.getFullYear() == 1850 && y1850.getYear() == -50;
  document.write('<li>',
    'Ihr Browser arbeitet ',
    ( isOk ? 'richtig' : 'falsch' ),
    '.</li>');
}

var now = new Date();
document.write('<ul>');
test();
ausgabe(now.getFullYear(), now);
ausgabe(1999, new Date(1999, 4, 10));
ausgabe(99, new Date(99, 4, 10));
ausgabe(2001, new Date(2001, 4, 10));
ausgabe(1899, new Date(1899, 4, 10));

now.setYear(101); ausgabe(101,now);
now.setYear(2001); ausgabe(2001, now);
now.setFullYear(101); ausgabe(101, now);
now.setFullYear(2001); ausgabe(2001, now);

document.write('</ul>');
//-->
</script>

liefert

Für neue Skripte empfehle ich Ihnen die Verwendung von getFullYear() und setFullYear(). Um die (besondere) Bedeutung der zweistelligen Werte bei Konstruktion zu umgehen, könnten Sie entweder mit einem Datumsstring arbeiten, oder direkt setFullYear() auf das erzeugte Objekt anwenden.