Mit dem ISO-Kalender arbeiten

(Auszug aus "XSLT Kochbuch" von Sal Mangano)

Problem

Sie müssen mit Datumsangaben im international standardisierten ISO-8601-Kalender arbeiten. ISO ist die International Organization for Standardization. (ISO geht nicht nur besser von der Zunge, sondern es stammt auch von dem griechischen Wort isos, das »gleich« bedeutet.)

Achtung!
Leser, die mit XML Schema vertraut sind, dürfen den ISO-Kalender nicht mit dem ISO-Format für standardisierte gregorianische Datumsangaben verwechseln (z. B. 2002-04-12 oder 2002-04-12T09:26:00). Sowohl der Kalender als auch der Formatierungsstandard werden in Standard 8601 behandelt. Dieses Rezept befasst sich mit dem ISO-Kalender.

Lösung

Eine der Grundlagen, die Sie zum Arbeiten mit ISO-Daten (und später zum Feststellen bestimmter Feiertage) benötigen, ist eine Funktion zum Ermitteln des absoluten Tages des kten Tages an oder vor einem bestimmten absoluten Tag. Zum Beispiel ist der erste Montag (k = 1) an oder vor dem 4. Januar 2004 (absoluter Tag 731.584) der 29. Dezember 2003 (absoluter Tag 731.578):

<xsl:template name="ckbk:k-day-on-or-before-abs-day">
  <xsl:param name="abs-day"/>
  <xsl:param name="k"/>
  <xsl:value-of select="$abs-day - (($abs-day - $k) mod 7)"/>
</xsl:template>

Sie können nun ISO-Daten in absolute Tage umwandeln. Dazu müssen Sie nur die Anzahl der absoluten Tage in früheren Jahren feststellen und die verbleibenden Tage im angegebenen ISO-Datum hinzufügen:

<xsl:template name="ckbk:iso-date-to-absolute-day">
  <xsl:param name="iso-week"/>
  <xsl:param name="iso-day"/>
  <xsl:param name="iso-year"/>
  <xsl:variable name="jan-4-of-year">
    <xsl:call-template name="ckbk:date-to-absolute-day">
      <xsl:with-param name="year" select="$iso-year"/>
      <xsl:with-param name="month" select="1"/>
      <xsl:with-param name="day" select="4"/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="days-in-prior-yrs">
    <xsl:call-template name="ckbk:k-day-on-or-before-abs-day">
      <xsl:with-param name="abs-day" select="$jan-4-of-year"/>
      <xsl:with-param name="k" select="1"/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="days-in-prior-weeks-this-yr" select="7 * ($iso-week - 1)"/>
  <xsl:variable name="prior-days-this-week" select="$iso-day - 1"/>
  <xsl:value-of select="$days-in-prior-yrs + $days-in-prior-weeks-this-yr + $prior-days-this-week"/>
</xsl:template>

Um absolute Tage in ein ISO-Datum umzuwandeln, versucht der Code zuerst, das Jahr zu ermitteln, indem er schätzt, dass es das gleiche ist wie beim gregorianischen Kalender minus 3 Tage. Diese Schätzung kann falsch sein, wenn der absolute Tag tatsächlich auf den 1. bis 3. Januar des folgenden Jahres fällt. Um einen möglichen Fehler zu korrigieren, wird mit Hilfe des bereits existierenden iso-date-to-absolute-day-Codes ein Vergleich mit dem 1. Januar des folgenden Jahres durchgeführt. Wenn das ISO-Jahr dann festgelegt wurde, folgen Woche und Tag, indem der Offset vom 1. Januar dieses Jahres berechnet wird. Wir liefern das ISO-Datum dann formatiert als Jahr-Woche-Tag. Dieses Format ist eine ISO-Konvention, um zu vermeiden, dass ISO-Daten mit gregorianischen Daten verwechselt werden:

<xsl:template name="ckbk:absolute-day-to-iso-date">
  <xsl:param name="abs-day"/>
  <xsl:variable name="d">
    <xsl:call-template name="ckbk:absolute-day-to-date">
      <xsl:with-param name="abs-day" select="$abs-day - 3"/>
    </xsl:call-template>
  </xsl:variable>
  <xsl:variable name="approx" select="substring-before($d,'/')"/>
  <xsl:variable name="iso-year">
    <xsl:variable name="a">
      <xsl:call-template name="ckbk:iso-date-to-absolute-day">
        <xsl:with-param name="iso-week" select="1"/>
        <xsl:with-param name="iso-day" select="1"/>
        <xsl:with-param name="iso-year" select="$approx + 1"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$abs-day &gt;= $a">
        <xsl:value-of select="$approx + 1"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$approx"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:variable name="ckbk:iso-week">
    <xsl:variable name="a">
      <xsl:call-template name="ckbk:iso-date-to-absolute-day">
        <xsl:with-param name="iso-week" select="1"/>
        <xsl:with-param name="iso-day" select="1"/>
        <xsl:with-param name="iso-year" select="$iso-year"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="1 + floor(($abs-day - $a) div 7)"/>
  </xsl:variable>
  <xsl:variable name="iso-day">
    <xsl:variable name="a" select="$abs-day mod 7"/>
    <xsl:choose>
      <xsl:when test="not($a)">
        <xsl:value-of select="7"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$a"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>
  <xsl:value-of select="concat($iso-year,'-W',$iso-week,'-',$iso-day)"/>
</xsl:template>

Diskussion

In europäischen kommerziellen und industriellen Anwendungen ist oft ein Verweis auf die Woche eines Jahres erforderlich. Der ISO-Kalender gibt Daten an, indem er das gregorianische Jahr, die Wochennummer (1–53) innerhalb des Jahres und die Ordnungszahl des Wochentages (1–7, wobei ISO verlangt, dass Montag der erste Tag der Woche ist) verwendet. Eine Woche, die in das nachfolgende Jahr übergeht, wird dem Jahr zugewiesen, in dem die meisten Tage dieser Woche liegen. Entsprechend dieser Regel kann die erste Woche des ISO-Kalenders auch erst am 4. Januar oder bereits am 29. Dezember des vorhergehenden Jahres beginnen. Ebenso kann die letzte Woche eines ISO-Kalenderjahres schon am 28. Dezember oder erst am 3. Januar des folgenden Jahres enden. Beispielsweise begann ISO-Woche 1 im Jahre 2004 tatsächlich schon am 29. Dezember 2003! (Und Sie dachten, Standards sollten Ihr Leben vereinfachen!) Um dann den Anfang der ISO-Woche zu ermitteln, müssen Sie den Montag am oder vor dem 4. Januar finden.

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema XSLT bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:

Copyright © 2006 O'Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "XSLT Kochbuch" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O'Reilly Verlag GmbH & Co. KG, Balthasarstraße 81, 50670 Köln, kommentar(at)oreilly.de