Erklärung zur Auswertung eines TimeDomain-Wertes

opening_hours, collection_times, service_times

Technisches

Die Auswerteroutine wird mit zwei Argumenten aufgerufen:

  1. der Zeitbeschreibung, dem Wert des entsprechenden Schlüssels als Zeichenkette,
  2. dem Zeitpunkt, für den der Ausdruck ausgewertet werden soll, als Objekt mit den Feldern: Jahr, Monat, Tag, Stunde, Minute; im normalen Anwendungsfall jetzt.

Die Auswerteroutine ist (noch) naiv bezüglich der Zeitzone, und geht davon aus, dass das übergebene Zeitobjekt und die Zeitbeschreibung sich auf die gleiche Zeitzone beziehen. Wenn die Zeitzone, für die die Zeitbeschreibung gilt, bekannt ist, so sollte jetzt für diese Zeitzone ausgedrückt werden.

Die Auswerteroutine liefert ein Objekt mit bis zu sechs Feldern zurück:

  1. Der Ergebniswert:
    Wert Bedeutung
    true geöffnet
    false geschlossen
    null unbekannt
  2. einer Liste der nächsten Zeiten für Leerung und Service
  3. einem Hinweistext für den Nutzer (optional)
    (zum Beispiel, warum die Öffnungszeit nicht bekannt ist),
  4. einer Liste von Fehlermeldungen (optional),
  5. einer Liste von Warnmeldungen (optional),
  6. der zur Auswertung herangezogenen Regel.

Sprachkomponenten

Allgemeines

Groß/kleinschreibung:
ist ohne Bedeutung (außer in Hinweistexten),
Blankspace:
ist ohne Bedeutung, außer es trennt Sprachelemente:
1234 ist etwas anderes als 12 34.

Elemente

Jahreszahlen:
werden vierstellig geschrieben und sind gültig ab 2000,
Monate:
werden englisch geschrieben und auf drei Buchstaben abgekürzt,
Wochentage:
werden englisch geschrieben und auf zwei Buchstaben abgekürzt,

Datum

Kalenderdatum:
ein Kalenderdatum wird in der Form 2010 Dec 25 angegeben (wobei Jahr und Monat auch fehlen können).
Ohne Jahr bezieht sich eine Datumsangabe immer auf das Jahr des angegebenen Zeitpunkts.
Ich persönlich bevorzuge das ISO-Format 2010-12-25 (und würde es gerne als einziges Format nutzen); soll ich es zumindest zusätzlich akzeptieren?
Verschieblicher Feiertag:
Zur Zeit ist nur Ostern implementiert: easter ist der Ostersonntag.
Datum als Wochentag in einem Monat:
Dec We[1] ist der erste Mittwoch im September;
Mar Su[-1] ist der letzte Sonntag im März des laufenden Jahres: Beginn der Sommerzeit.
Datum als Wochentag nach oder vor einem anderen Datum:
Dec 25 ist der erste Weihnachtstag, Dec 25 - Su ist der letzte Sonntag vor dem ersten Weihnachtstag, also der vierte Advent.
Datum im fixen Abstand zu einem anderen Datum:
easter + 1 days ist Ostermontag,
easter - 2 days ist Karfreitag,
easter - 48 days ist Rosenmontag (hochwichtig!),
Dec 25 - Su - 21 days ist der erste Advent.

Zeiträume

Zeitraum aus zwei Daten:
Mar Su[-1] - Oct Su[-1] - 1 days ist der Zeitraum der Sommerzeit.
Achtung: Oct Su[-1] - 1 days ist etwas anderes als Oct Sa[-1]!
Oct Su[-1] - Mar Su[-1] - 1 days ist der Zeitraum der Winterzeit.
→ Wenn der erste Tag nach dem zweiten Tag liegt und kein Jahr angegeben ist, wird der Zeitraum vom ersten Tag bis zum Ende des Jahres und vom Anfang des Jahres bis zum zweiten Tag angenommen.
Nov 11 - easter-47 days ist die fünfte Jahreszeit.
Liste von Zeiträumen:
Sep 15+Sa - Oct Su[1], Oct 1-3 ist der Zeitraum des Oktoberfestes.
→ Zeiträume und Einzeltage können mit , zu einer Liste zusammengefasst werden.
Die Bestandteile der Liste dürfen auch überlappen.

Kalenderwochen und Wochentage

Wochenangabe:
week 2 steht für in der zweiten Kalenderwoche,
week 10-12 steht für in der zehnten bis zur zwölften Kalenderwoche,
week 2-52/2 steht für in geraden Kalenderwochen.

Tage unabhängig von Datum

Wochentage:
Fr steht für jeden Freitag,
Fr-Mo steht für Freitag, Samstag, Sonntag, Montag,
Mo-We,Sa steht für Montag, Dienstag, Mittwoch, Samstag.
Wochentage im Monat:
Der erste Sonntag im Monat wird als Su[1] geschrieben,
erster und zweiter als Su[1,2],
erster bis dritter als Su[1-3],
erster und dritter bis letzter Su[1,3-5].
Der letzte Sonntag im Monat wird als Su[-1] geschrieben,
erster und letzter als Su[1,-1].
Tagesangaben:
ohne Bezug zu einer Datumsangabe wird ein . nachgestellt;
diese Schreibweise verhindert unangenehme Fehlinterpretationen bei häufigen Schreibfehlern.
1. – der erste jedes Monats
1.-7. – die ersten sieben Tage des Monats;
Jan-Dec: 10. – Termine für die Umsatzsteuervoranmeldung;
2.-30./2 – geparkt werden darf nur an geraden Tagen.
→ das von - bis /Schrittweite ist eine generelle Konstruktion,
die auch für Wochenangaben und bei collection_times und service_times genutzt werden wird.
Feiertage:
PH steht für public holidays, also an gesetzliche Feiertagen,
SH steht für school holidays, also in den Schulferien,
Su,PH steht für an Sonn- und Feiertagen.

Zeiten

Fixe Zeiten:
haben die Form H:MM oder HH:MM.
Variable Zeiten:
Zeitpunkt von Sonnenaufgang und Sonnenuntergang werden als sunrise und sunset angegeben.
Diese Angaben sind bei Parks und Spielplätzen beliebt: bis zum Einbruch der Dämmerung.
Variable Zeiten mit Offset:
sunrise-0:30 hours bedeutet eine halbe Stunde vor Sonnenaufgang.
Zeitbereiche:
08:00-16:00 ist der berühmte von-8-bis-4-Job.
20:00-04:00 ist der von-8-bis-4-Job bei Kernelhackern.
→ liegt die zweite Zeit vor der ersten, wird sie auf den nächsten Tag verschoben.
sunset-sunriseFrom Dusk Till Dawn → Vorsicht vor Vampiren!

Auswertung

Regeln

Die meisten Öffnungszeiten lassen sich durch einfache Regeln ausdrücken.

Regeln bestehen aus einer Folge von Uhrzeit-Bereichen, die meist durch Wochentage qualifiziert sind, mit , verbunden.

08:00-12:00
An allen Tagen von 8 bis 12.
Mo-Fr 08:00-12:00
Von Montag bis Freitag von 8 bis 12.
Fr,Sa 22:00-05:00
Freitag und Samstag abend von 22 Uhr bis 5 Uhr am Folgetag.
Mo-Fr 08:00-12:00, Sa 10:00-12:00
Von Montag bis Freitag von 8 bis 12, Samstags von 10 bis 12.

Die Angaben werden so ausgewertet, wie man intuitiv ein Praxisschild ließt: von links nach rechts und inkrementell, d.h. nachfolgende Angaben werden in die Vorausgehenden eingearbeitet:

Mo-Fr 08:00-12:00, We 14:00-16:00
Von Montag bis Freitag von 8 bis 12, Mittwochs zusätzlich von 14 bis 16 Uhr.
Mo-Fr,Sa[1] 08:00-12:00
Von Montag bis Freitag und zusätzlich am ersten Samstag des Monats von 8 bis 12.
Mo-Fr 08:00-12:00, Sa[1] 10:00-12:00
Von Montag bis Freitag von 8 bis 12 und zusätzlich am ersten Samstag eines Monats von 10 bis 12
Mo-Fr 08:00-12:00, Mo[1] 14:00-16:00
Von Montag bis Freitag von 8 bis 12, zusätzlich am ersten Montag eines Monats von 14 bis 16 Uhr
Mo-Fr 08:00-12:00, PH off
Von Montag bis Freitag von 8 bis 12, außer an gesetzlichen Feiertagen

Der Zeitangabe kann ein Öffnungsstatus angehängt werden:

  • open steht für geöffnet (default),
  • closed steht für geschlossen,
  • " ……Text…… " bildet bedingte Öffnungszeiten ab.

    Die Bedingungen können äußere Einflüsse sein, in der Person des Nutzers liegen oder auch unvollständiges Wissen abbilden. Die Auswerteroutine meldet Öffnungsstatus=unbekannt + Hinweistext. Dies bildet die in der Realität häufige Antwort hängt davon ab auf die Frage ist offen? ab:

    Mo-Fr 08:00-16:00, Sa 10:00-14:00, Sa 14:00-18:00 "bei gutem Wetter"
    Das Schwimmbad hat Samstags von 10-14 Uhr auf, bei gutem Wetter bis 18 Uhr (äußerer Einfluß)
    Mo-Fr 18:00-22:00, We 18:00-20:00 "nur Damen"
    Die Sauna ist Mo-Fr von 18 bis 22 Uhr geöffnet, Mittwochs von 18 bis 20 Uhr Damensauna. (Person des Nutzers).
    Mo-Fr 08:00-12:00, Sa 08:00-20:00 "nach Absprache"
    Die Tierarzt kommt auch Samstags zwischen 8 und 8, aber nur nach Absprache (Aktion des Nutzers erforderlich)
    So 14:00-15:00, Mo-Fr 08:00-16:00 "nur für Gruppen ab 12 Personen nach Anmeldungen"
    Der Höhlenführer kommt in der Woche nur, wenn es sich lohnt (Bedingung des Anbieters).

    Die Auswerteroutine meldet für diese Zeiträume jeweils unbekannt mit der Zusatzinformation.

Das Kleingedruckte zu den Regeln

  • Dem open und closed kann ein Text angehängt werden. Der hat keinen Einfluß auf den Status, offen bleibt offen und geschlossen bleibt geschlossen, wird aber als Kommentar mit zurückgeliefert. Darin kann z.B. der Grund für die Schließung oder eine Zusatzinformation mitgeliefert werden:
    Mo-Sa 10:00-21:00 open "Warme Küche von 11:30 bis 13:30 und von 17:30 bis 19:30"
  • Tagesangaben kann eine Ferienspezifikation vorangestellt werden:
    Fr 10:00-14:00, SH Fr off steht für Freitags von 10 bis 14 Uhr, außer an Freitagen in den Schulferien.
  • Tagesangaben kann eine Wochenspezifikation vorangestellt werden:
    week 2-52/2 Sa 10:00-16:00 steht für Der Wochenmarkt finden an geraden Wochen Samstags von 10 bis 16 Uhr statt.

Erweiterte Angaben für Fortgeschrittene

Regeln lassen sich mit ; aufreihen. Solange die Tagesbereiche sich nicht überschneiden, ist die Schreibung als mehrere Regeln äquivalent zu der Schreibung als eine Regel:

Mo-Fr 08:00-12:00; Sa 08:00-20:00
Mo-Fr 08:00-12:00, Sa 08:00-20:00
Beide haben die gleiche Bedeutung.

Die Situation ändert sich, wenn mehrere Regeln sich um einen Tag streiten; dann gilt das Alles oder Nichts-Prinzip: Die letzte Regel, die auf einen Tag passt, ist für diesen Tag ganz alleine verantwortlich.

Mo-Fr 08:00-12:00, We 14:00-16:00
Mittwochs ist zusätzlich von 2 bis 4 geöffnet.
Mo-Fr 08:00-12:00; We 14:00-16:00
Mittwochs ist ausschließlich von 2 bis 4 geöffnet

Das ist m. E. die Stelle mit dem höchsten Erklärungsbedarf: , steht für ein freundliches Miteinander, ; für Konkurrenz. Beides war bereits in der Wiki-Spec enthalten, für beides besteht Bedarf: die an bestimmten Tagen zusätzlichen Öffnungszeiten sind ein Standardanwendungsfall, während man bei Ausnahmen für Feiertage eher den ganzen Tag neu definieren will:

Mo-Fr 11:30-13:30, We 17:30-20:00; Su,PH 14:00-18:00
Montags bis Freitags Mittagsmenü, Mittwochs auch Abendessen.
An Sonn- und Feiertagen ausschließlich 14-18 Uhr.
Fällt der Feiertag auf einen Mittwoch, gilt auch da von 14-18 Uhr.

In einem Editor sollte man möglicherweise jede Regel in einer eigenen Zeile darstellen oder auf andere Art optisch voneinander separieren.

Gültigkeitszeiträume

Zu Regeln kann angegeben werden, für welchen Zeitraum sie gültig sind. Dazu wird der Zeitraum vorausgestellt und mit einem : abgeschlossen. Ein Gültigkeitszeitraum gilt für alle folgende Regeln bis zum nächsten Gültigkeitszeitraum. Regeln ohne Gültigkeitszeitraum sind immer gültig:

Jul: Sa,Su 12:00-14:00
An Samstagen und Sonntagen im Juli von 12 bis 2.
Oct-Mar: Su[1] 12:00-14:00
Von Oktober bis März am jeweils ersten Sonntag im Monat von 12 bis 2 (Jahreswrap ok).
Easter-Sep 15: 12:00-14:00
Vom Ostern bis zum 15. September täglich von 12 bis 2.
Jun: "ab Mitte Juni"; Jul-Aug: open; Sep: "bis Mitte September"
Ungenaue Öffnungszeiten einer Berghütte: in den unklaren Bereichen wird "unknown" und ein passender Hinweistext zurückgeliefert, im sicheren Bereich offen oder geschlossen.

Die Auswertung von Gültigkeitszeiträumen ist einfach: alle zum Auswertezeitpunkt ungültigen Regeln werden getilgt, sodann die übrigen nach dem bekannten Alles-oder-Nichts-Prinzip ausgewertet.

Mo-Fr 10:00-12:00; Jul,Aug: Mo-Fr 14:00-16:00
Von 10 bis 12, außer im Juli und August, dann von 2 bis 4; die erste Regel hat einen universellen Gültigkeitszeitraum, die zweite gilt von Juli bis August. Im Juli und August überschreibt die zweite Regel die erste.
Mar Su[-1]-Oct Su[-1]-1 days: …Sommerregeln…; Oct Su[-1]-Mar Su[-1]-1 days: …Winterregeln…
Unterschiedliche Regelsätze für Sommer und Winter.

Manche Gültigkeitszeiträume können nicht formal ausgedrückt werden, zum Beispiel Beispiel: Während der Spargelsaison. In diesem Fall schreibt man die Bedingung als Kommentar gefolgt von einem Doppelpunkt:

"Während der Spargelsaison": Mo-Fr 08:00-18:00

Auswertung: dieser Gültigkeitszeitraum ist immer gültig, in ihm wird aber aus einem open ein unbekannt, und der Text wird in die Bedingung aufgenommen.
Diese Form eines Gültigkeitszeitraumes sollte nur wenn unbedingt nötig verwendet werden und nur alleine stehen. Sie verträgt sich nicht gut mit dem Alles-oder-Nichts und auch nicht mit Fallback-Gruppen.

Fallbackgruppen

Mehrere Regelsätze können mit || aneinandergehängt werden. Sie werden von links nach rechts ausgewertet, bis ein Regelsatz offen liefert oder der letzte erreicht ist.

Mo-Fr 08:00-12:00, 14:00-18:00, Sa 09:00-13:00, PH off || Tu 06:00-06:00 open "Notdienst"
Diese Apotheke hat normale Öffnungszeiten und zusätzlich von Dienstag 6 Uhr bis Mittwoch 6 Uhr Notdienst. Wenn normale Öffnungszeit und Notdienst überlappen, wird normal offen gemeldet. Die normalen Öffnungszeiten entfallen an Feiertagen, nicht aber der Notdienst.
Mo-Fr 08:00-16:00, Sa 09:00-14:00, PH Off || "Außerhalb der Öffnungszeit nach telefonischer Vereinbarung"
Ein kundenfreundlicher Tierarzt.

Offene Punkte

Öffentliche Feiertage und Schulferien hängen von der Region ab.

Die Auswerteroutine akzeptiert einen Parameter region: das Auswerteformular hat dafür eine Eingabefeld, die Karten übergeben den Wert des Schlüssels addr:country. Damit ist das Problem aber nicht gelöst:

  • Wie granular sollen Regionskennungen sein?
  • Wie erzeuge ich aus Koordinaten (die ich immer habe) eine Regionskennung?
  • Wie finde ich universell zu einer Regionskennung die Feiertage und Schulferien?

Zur Zeit habe ich die bundeseinheitlichen Feiertage für Deutschland und Österreich hinterlegt und reagiere auf die Regionskennungen "de" und "at". Schulferien sind keine hinterlegt: sie sind landesabhängig und ändern sich jährlich.

Standardisierte Bedingungen für Öffnungszeiten

Es gab den Vorschlag, häufig vorkommende Bedingungen für Öffnungszeiten (auf Anfrage, nach tel. Reservierung) zu standardisieren und mit eigenen Kennungen auszudrücken, um sie automatisch übersetzen zu können.

Weil man zum jetzigen Zeitpunkt keine vollständige Liste benötigter Kennungen erstellen kann und weil ich die Syntax nicht überladen möchte, schlage ich vor, diese Kennungen innerhalb der Hinweistexte unterzubringen und zum Beispiel durch Schreibung nur in Großbuchstaben von normalen Texten zu trennen: "OR" = on request.

Das erlaubt eine unabhängige Weiterentwicklung der Liste solcher Kennungen ohne den Zwang, die Auswertesoftware immer wieder anzupassen.

Dokumentation:

Wenn ein Entwickler seine eigene Entwicklung dokumentiert, so steht ihm die Kenntnis des Innenlebens im Wege. So wird sich die Dokumentation an den internen Abläufen entlanghangeln statt von den Bedürfnissen des Nutzers auszugehen.

Wer kann eine Anleitung von Nutzern für Nutzer schreiben und dazu diesen Text verwursten?