|
Auf dieser Seite finden sie einige Artikel zur Verwendung von Basic (LibreOffice-Basic,
Visual Basic, VBA) mit Datum und Zeit. Dazu gehören Umwandlungen wichtiger interner Datenformate (Y1900, UNIX Timestamp, JD) und die Codierung von Standard-Texten nach ISO-8859. |
Viel Arbeit muss man leider für Weltzeit UTC, Zeitzonen und Sommerzeit aufwenden -
Themen die von Basic wenig unterstützt werden. Alle Live-Beispiele dieser Seite werden mit Javascript berechnet, d.h. Basic wird hier simuliert. |
Basic
|
Die Programmiersprache Basic (LibreOffice-Basic, Visual Basic, VBA) |
| Datum & Zeit | Datum und Zeit |
| Datentyp | Die interne Darstellung von Datum und Zeit in Basic |
| System | Datum & Zeit aus dem Betriebssystem des PC |
| Bestandteile | Zusammensetzung und Zerlegung von Datum & Zeit in Basic |
| Weltzeit | Angaben zu Weltzeit (UTC) Zeitzone, Offset |
| Sommerzeit | Berücksichtigung von Normalzeit und Sommerzeit |
| ZeitStempel | Unix-Timestamp: Sekunden seit 1970-01-01 |
| JD & MJD | Julianischer Tag (JD) und Modifizierter julianischer Tag (MJD) |
| Anzeigeformat und kulturspezifische Unterschiede | |
|
Das international standardisierte Format:
YYYY-MO-DD hh:mi:ss
|
|
Monatsnamen, Wochentage, Kalenderwoche, ... |
|
| OnTime | Das Basic-Ereignis (Event) OnTime |
| Links |
|
| Verwandte Themen | |
| Datum & Zeit | in der Informatik, Grundlagen (Astronomie) |
| NTP | Die Synchronisation der PC-Systemzeit |
| Oster-Formel | Berechnung der fixen und beweglichen christlichen Feiertage |
| Umrechnung | verschiedener Datum & Zeit-Systeme in Basic |
| Programmiersprachen | Datum & Zeit in C/C++, Javascript, Perl, PHP, SQL, Linux (Shell-Konsole), Windows-(cmd-Konsole), ... |
Datum & Zeit |
|
Kalender■ Heute gilt in den meisten Teilen der Welt der → Gregorianische Kalender.■ Die Basic-Eigenschaft Calendar entspricht dem verwendeten Kalender. Calendar = vbCalGreg
setzt den Gregorianischen Kalender.
|
■
In anderen Kulturen werden teilweise andere Kalender verwendet, jedoch angesichts der
Globalisierung mit geringer Bedeutung. Die Unterschiede reduzieren sich dann auf die
Berechnung lokaler Feiertage. ■ Andere Kalender-verwandte Daten wie Monatsnamen, Wochentag oder Kalenderwoche sind → kulturspezifisch und daher selbst für das gleiche Datum → unterschiedlich ! ♦ Details zum Thema Datum und Zeit |
Zeit:■ Die aktuelle Zeit ist vom Standort auf der Erdoberfläche abhängig. Daraus ergibt sich die jeweilige → Zeitzone.■ Eine internationsl einheitliche Weltzeit ist die → Universal Time Coordinated (UTC): die Zeit am Nullmeridian (Greenwich), früher GMT. |
■ Die lokale Zeit wird darüber hinaus in einigen Staaten im Rahmen der → Sommerzeit (daylight savings) 2mal jährlich an unterschiedlichen Tagen geändert. ♦ Details zum Thema Datum und Zeit |
Interne Darstellung & Daten-Typ |
|
Interne DarstellungDamit man mit Datum & Zeit auch rechnen kann, wird dieser Datentyp in den meisten Betriebssystemen und Programmen intern (!) als Zahl geführt. |
Das bedingt die willkürliche Festlegung auf einen Nullpunkt. Aus dem intern verwendeten Datentyp (Bit-Anzahl) ergeben sich die Unter- und Obergrenzen für das darstellbare Datum. |
Das Y1900-System :► Basic verwendet für Datum und Zeit das 'Y1900'-System:Der Nullpunkt dieser Zeitskala liegt 'ungefähr' am Beginn des Jahres 1900: 1899-12-30 00:00:00
►
Ab diesem Datum wird der Zahlenwert um die Zahl 1 pro Tag
erhöht.► Test: Tragen sie in zwei Zellen eines Kalkulations-Programms (LibreOffice, OpenOffice, MS-Excel) die gleiche Formel =HEUTE() ein. Formatieren sie eine der beiden Zellen als Standard-Zahl (Menü ). Live-Ergebnis:
HEUTE() = 0
HEUTE() = 0000-00-00 |
► Die Tageszeit wird als Gleitkomma-Anteil des Datum-Zeit-Typs festgelegt. Den Zeiten 0:00, 12:00, 24:00 entsprechen die Zahlenwerte 0.00, 0.50, 1.00 So ist gewährleistet, dass Differenzen zwischen Datum-. und Zeit-Angaben rasch und einfach berechnet werden können. ► Test: Wiederholen sie den links beschriebenen Datum-Test mit der Funktion =JETZT(), welche Datum und aktuelle Zeit liefert. Live-Ergebnis:
JETZT() = 0
JETZT() = 0000-00-00 00:00:00 |
|
► Grenzen:
Negative Zahlenwerte bezeichnen Tage vor 1900.
LibreOffice und
OpenOffice erlauben jedes Datum der Jahre 1..32767
und damit die Arbeit mit den meisten historischen DatenDie Obergrenze wurde in MS-Excel ebenfalls willkürlich mit 9999-12-31 festgelegt, das entspricht dem Y1900-Zahlenwert 2958465 |
► MS-Programme für Apple's MacOS verwenden 1904-01-01 als Nullpunkt. Auch hier liegt die Obergrenze bei 9999-12-31, das entspricht dem Y1900-Zahlenwert 2957003. ► Andere Programme und Betriebssysteme verwenden für Datum und Zeit andere Systeme als Y1900 ! Sie müssen daher Datum und Zeit für den Transport der Daten umrechnen oder in ein → Standard-Textformat bringen ! |
|
|
Wegen der Untergrenze bei 1900 betrifft das zum Glück nur eine kleine Anzahl weniger wichtiger Tage. Es ist allerdings bezeichnend, dass der Hersteller offenbar nicht daran denkt, einen Fehler auch einmal zu korrigieren. |
Basic Daten-Typ "Date":▲ Variablen vom Typ Date werden als 64-Bit-Gleitkommazahlen (8 Byte) nach → IEEE-754 gespeichert und können ein Datum im Bereich vom 0100-01-01 bis zum 9999-12-31 (inkl. der Uhrzeit) darstellen.Ein Unterschied zum Typ Double ist nicht erkennbar. Alle vorgestellten Beispiele funktionieren mit Double ▲ Ein Datums-"Literal" muss man in # Zeichen einschließen, z.B.:
#January 1, 2000#
#1 Jan 2000#. ▲ Date verwendet zur Darstellung des Datums das auf dem PC eingestellte 'kurze Datumsformat'. Die Zeit wird mit dem eingestellten Zeitformat dargestellt. |
▲ Bei Umwandlung anderer Zahlen-Typen in Date-Werte ergeben die Vorkommastellen das Datum, die Nachkommastellen die Uhrzeit. ▲ Negative Zahlen repräsentieren ein Datum vor 1900 (unter Berücksichtigung des M$-Kalender-Fehlers 1899-12-30). Damit entspricht das Format dem z.B. von üblichen Kalkulations-Programmen verwendeten (Gleitkomma-Zahl, Double Precision), jedoch ohne die genannte Untergrenze. In LibreOffice und OpenOffice kann man auch mit negativen Y1900-Werten ab Y1900(1582-12-01)=-115811 problemlos arbeiten. Lediglich MS-Excel kann mit historischen Daten vor 1900 weder rechnen, noch kann man diese eingeben oder anzeigen. ▼ Eine Möglichkeit zum Speichern der Zeitzone oder zur Umrechnung der Daten in/von Weltzeit UTC ist leider weder in Kalkulations-Programmen noch in Basic vorgesehen. Man müss diese Daten selbst verwalten und die Umrechnung selbst programmieren. ♦ Details dazu auf dieser Seite unter ↓ UTC |
ZonenzeitDas Y1900-Datum wird in der lokalen Zeitzone angegeben. Daher gibt es Zeit-Sprünge, die sowohl vom Ort (Zeitzone) als auch vom Datum (Normalzeit / Sommerzeit) abhängen.● Aus diesem Grund sind Daten im Y1900-Format international nicht vergleichbar. Man kann Y1900-Daten aus unterschiedlichen Zeitzonen in Weltzeit UTC umrechnen oder besser gleich den global eindeutigen ↓ UNIX-Timestamp verwenden. |
Umrechnung mit der Differenz zwischen lokaler Zeitzone und Weltzeit UTC in Stunden. Dieser Wert beträgt in Mitteleuropa (CET, MEZ) bei Normalzeit tzoh=1 und bei Sommerzeit tzoh=2
Y1900_utc = Y1900_cet - tzoh/24
Y1900_cet = Y1900_utc + tzoh/24 |
| ♦ Details zu diesem Thema auf der Seite Datum und Zeit | |
Bestandteile - Jahr, Monat, Tag, Stunde, Minute, Sekunde |
|
Y1900-Datum
In diesem Basic-Beispiel wird ein Y1900-Datum mydate durch
die Funktion y1900_to_ymdhms() in seine ganzzahligen Bestandteile
zerlegt. Das Ergebnis wird in einem Alarmfenster (MsgBox)
angezeigt und als String (Text) zurückgegeben. |
Function y1900_to_ymdhms(mydate)
Dim s As String
s = "Year = " & Year(mydate)
End Function
s = s & Chr(13) & "Month = " &_ Month(mydate)
s = s & Chr(13) & "Day = " &_
Day(mydate)
s = s & Chr(13) & "Hour = " &_
Hour(mydate)
s = s & Chr(13) & "Minute = " &_
Minute(mydate)
s = s & Chr(13) & "Second = " &_
Second(mydate)
MsgBox (s)y1900_to_ymdhms = s |
yyyy,mo,dd,hh,mi,ss
In diesem Beispiel wird eine Y1900-Variable (Basic-Datum+Zeit) aus den ganzzahligen
Bestandteilen zusammengesetzt. |
Function ymdhms_to_y1900(yyyy, mo, dd, hh, mi, ss)
ymdhms_to_y1900 = DateSerial(yyyy, mo, dd) _
End Function
+ TimeSerial(hh, mi, ss)
|
|
Die gleiche Funktion, jedoch etwas aufwändiger programmiert
und sowohl mit LibreOffice-Basic als auch MS-VBA kompatibel: • Alle Argumente sind optional, d.h. man kann beliebig viele davon weglassen. Man muss allerdings die Reihenfolge der Argumente einhalten. Alle nicht angegebenen Argumente erhalten Standard-Werte. • Wenn man ein optionales Argument weglässt, dann wird an seiner Stelle ein Standard-Wert iyy...iss eingesetzt. • Wenn man auch das Jahr weglässt, dann wird der 1.Tag des aktuellen Jahres zurückgegeben. • Wenn ein Argument den sinnvollen Werte-Bereich überschreitet, dann rechnet die Funktion sinngemäß. Beispiel: Wenn man für die Stunden hh=-1 angibt, dann wird die Zeit des Vortags um 23:00 verwendet. • Man kann die Zeilen-Verlängerung mit _ Underline-Zeichen weglassen und die entsprechenden Funktion kürzer, jedoch weniger übersichtlich formulieren. • Die Funktion IsMissing() gibt an, ob ein optionales Argument übergeben wurde oder nicht. Sie wird von MS-VBA offenbar nur auf Variable des Typs Variant angewendet. |
Function ymdhms_to_y1900( _
Optional yyyy As Variant, _
Dim iyy, imo, idd, ihh, imi, iss As IntegerOptional mo As Variant, _ Optional dd As Variant, _ Optional hh As Variant, _ Optional mi As Variant, _ Optional ss As Variant) As Double Dim y1900 As Double
iyy = Year(Date)
End Function
imo = 1 idd = 1 ihh = 0 imi = 0 iss = 0 If (Not IsMissing(yyyy)) Then iyy = yyyy If (Not IsMissing(mo)) Then imo = mo If (Not IsMissing(dd)) Then idd = dd If (Not IsMissing(hh)) Then ihh = hh If (Not IsMissing(mi)) Then imi = mi If (Not IsMissing(ss)) Then iss = ss y1900 = DateSerial(iyy, imo, idd) y1900 = y1900 + TimeSerial(ihh, imi, iss) ymdhms_to_y1900 = y1900 |
Weltzeit (Universal Time Coordinated, UTC) und lokale Zonenzeit |
|||||||
|
Die Weltzeit UTC (früher GMT) ist der weltweit eindeutige Standard für die
Tageszeit. UTC ist unabhängig von Ort (Zeitzone) und Datum (Sommerzeit). ● Alle wichtigen Server sind auf UTC eingestellt, nicht auf die lokale Zeitzone. Darüber hinaus wird ein Server-PC periodisch mit einem Zeit-Standard synchronisiert (→ Network Time Protocol, NTP). Der Server liefert selbst die Zeit für alle PC eines lokalen Netzwerks. |
Alle Live-Daten dieser Seite folgen der Zeit des Webservers.
Zum Vergleich die aktuelle Zeit ihres PC, des Servers, und die Weltzeit UTC.
|
||||||
|
|
Korrekturen sind mindestens dann notwendig, wenn man Daten aus mehreren Zeitzonen verwendet, oder Daten mit PC anderer Zonen austauscht, oder wenn man Zeit-Differenzen über die Grenzen der Sommerzeit-Umstellung berechnen will. | ||||||
|
Es ist absurd, dass man diese wichtigen Daten mühsam suchen muss, um die Weltzeit zu berechnen. |
Hier werden getrennte Methoden für Linux und Windows vorgestellt. |
||||||
WindowsDas Programm regedit.exe ist in jedem Windows-System enthalten und bietet einen manuellen Zugang zur Registry-Datenbank. ► In disem Registry-Objekt befinden sich die Schlüssel (keys):
HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentontrolSet \ Control \ TimeZoneInformation
Schlüssel:► Namen StandardName, DaylightName der Zeitzone: Hier sind kaum brauchbare deutschen Langnamen enthalten ('Westeuropäische Sommerzeit' statt 'MEZ' oder 'CET'). ► Schlüssel Bias enthält den Timezone Offset in Minuten, das ist für CET (konstant) -60. ► Schlüssel DaylightBias enthält die zusätzliche (!) Differenz bei Sommerzeit in Minuten, das ist für fast alle Zonen -60. ► Schlüssel ActiveBias enthält die aktuelle Differenz zur Weltzeit UTC in Minuten. Dieser Wert beträgt für CET @ Normalzeit -60, bei Sommerzeit -120. ► Umrechnung (Einheiten berücksichtigen):
UTC = Zonenzeit - Bias - DaylightBias
►
Vorzeichen der Differenz: Je weiter östlich ein Ort, desto später ist es dort.
Der Zahlenwert der CET (MEZ) ist daher stets um 1 oder 2 Stunden größer als
UTC (Greenwich).
UTC = Zonenzeit - ActiveBias |
Es gibt mehrere Möglichkeiten, mit Basic Daten aus der Registry zu lesen. Dieses Beispiel liefert die aktuelle Differenz zur Weltzeit UTC in Stunden:
Function windows_current_tzoh() As Integer
Die Hilfs-Funktion registry_read() kann (nur auf Windows !)
beliebige Daten der Registry lesen und für Basic-Funktionen verfügbar machen.
Dim rk As String
rk = "HKEY_LOCAL_MACHINE\SYSTEM\"
End Functionrk = rk & "CurrentControlSet\Control\" rk = rk & "TimeZoneInformation\ActiveTimeBias" windows_current_tzoh = -registry_read(rk) / 60 Private Function registry_read(key As String) Dim wsh
Set wsh = CreateObject("WScript.Shell")
End Function
registry_read = wsh.RegRead(key) |
||||||
|
Ein anderes Registry-Objekt enthält einen Vorrat an Informationen
über zahlreiche Zeitzonen:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\TimeZones
|
In diesem Schlüssel (key) des Objekts sind die Details der
Mitteleuropäischen Zeit (MEZ, CET) enthalten:
Central Europe Standard Time
|
||||||
LinuxAuf Lunux gibt es keine Registry-Datenbank und - ebenso wie auf Windows - keine Möglichkeit, die Ausgabe von Konsolen-Programmen (date) zu lesen.Hier wird gezeigt, wie man eine Umgebungs-Variable TZOH definiert, die man mit beliebigen Programmen lesen kann, z.B. in Basic mit der Standard-Funktion ENVIRON() Linux Arbeits-PC:
Suchen sie das Start-Programm der Linux-Shell. Das ist (wenn sie als
Administrator root angemeldet sind) z.B. eine
Text-Datei /etc/bash.bashrc oder als User eine
Datei /home/username/.bashrc
oder /home/username/.profile - Konsultieren sie dazu das
Manual ihrer Linux-Distribution.Die in dieser Datei enthaltenen Anweisungen werden bei System-Start, bei der User-Anmeldung oder bei jedem Öffnen einer Linux Shell-Konsole ausgeführt. • Fügen sie diese Zeile am Ende der Shell-Start-Datei an: declare -x TZOH=$(($(date "+%H")-$(date -u "+%H")))
Damit wird die Differenz zwischen den Stunden von Lokalzeit und Weltzeit berechnet und an
die Umgebungs-Variable TZOH zugewiesen.Ein Linux-Server läuft meist lange Zeit ohne Unterbrechung. In diesem Fall tragen sie die Zeile in eine Text-Datei ein, z.B. als /usr/local/bin/tzoh #!/bin/sh
declare -x TZOH=$(($(date "+%H")-$(date -u "+%H")))exit 0 ♦ Details zur Programmierung der Linux cron-Funktionen |
Wenn die Umgebungs-Variable eingerichtet wurde, dann kann man ihren aktuellen Wert an einer Linux-Konsole ausgeben lassen: # export | grep TZ
sollte mindestens diese Zeile ausgeben
declare -x TZ="1"
Der Wert beträgt für Mitteleuropa/Normalzeit "1",
für Sommerzeit "2"• Mit dieser Basic-Funktion kann man den aktuellen Wert des TimeZoneOffset in Stunden lesen:
Function linux_current_tzoh() As Integer
Die Basic-Funktion linux_current_tzoh() lässt sich intern
(von anderen Basic-Funktionen) oder als 'Benutzer-definierte Funktion' in jedem
Kalkulations-Programm (z.B. LibreOffice) verwenden.linux_current_tzoh = environ("TZOH")
End Function
• Man kann auch auf Windows eine Umgebungs-Variable TZOH einrichten. In diesem Fall ist die Basic-Funktion sogar ohne Änderung portabel. Das gilt allerdings nur dann, wenn auf allen verwendeten PC die Umgebungs-Variable TZOH eingerichtet wurde, und wenn ihr Wert korrekt (2mal jährlich) aktualisiert wird. |
||||||
Aktuelle Weltzeit UTCEine Variante der Funktion current_tzoh() (↑ Windows- und ↑ Linux-Beispiele) gibt die aktuelle (!) Differenz der (Windows)-PC-Systemzeit zur Weltzeit UTC in Stunden zurück.Damit können sie (nur) das aktuelle Datum in UTC umrechnen:
Now = 0
current_tzoh = 0 utc = Now - tzoh/24 = 0 |
● Der links gezeigte Algorithmus gilt leider nur für aktuelle Daten: Die Umrechnung beliebigerDaten in UTC ist vergleichsweise kompliziert. Dazu müssen sie feststellen, ob am betreffenden Zeitpunkt gerade Sommerzeit gilt / galt (nächstes ↓ Kapitel). |
||||||
Normalzeit und Sommerzeit |
|
| Die Länge eines Tages beträgt 24 Stunden. Im Sommer geht die Sonne früher auf und später unter. Daran ändert sich nichts, wenn man Mitternacht rechnerisch um 1 Stunde verschiebt. Diese Maßnahme nützt niemandem, kostet jedoch einen enormen Aufwand, um alle Zeiten umzurechnen, alle Uhren umzustellen, Züge anzuhalten, usw. | Wenn die Befürworter dieses Schwachsinns für die Folgen bezahlen müssten, dann wäre die Sommerzeit (Daylight savings) wohl bald Vergangenheit. Mittlerweile ist es auch um die damit angeblich eingesparte Energie still geworden... |
Sommerzeit UmstellungDas Beispiel rechts (vereinfacht) berechnet die Umstellungs-Zeitpunkte auf / von Sommerzeit nach derzeitigen EU-Regeln.► Der Wechsel von Normalzeit auf Sommerzeit erfolgt am letzten Sonntag im März um 01:00 UTC = 02:00 CET ► Der Wechsel von Sommerzeit auf Normalzeit erfolgt am letzten Sonntag im Oktober um 01:00 UTC = 03:00 CET(Sommerzeit). • Die Hilfs-Funktion dls_refdate() benötigt als Argumente Jahr, Monat (nur 3 oder 10) und einen Options-Schalter. • Zuerst wird ein anderes Bezugsdatum berechnet, nämlich für Monat mo=3 der 1.April, für mo=10 der 1.November. • Von diesem Tag wird der Wochentag wref nach ISO-Standard berechnet. • Daraus lässt sich mit der Standardfunktion DateSerial() der vorangegangene Sonntag berechnen, mit Funktion TimeSerial() die Zeit 01:00:00. • Damit ist der gewünschte Umstellungs-Zeitpunkt in UTC (!) berechnet. Der Rest des Beispiels rechnet den Zeitpunkt ref auf Lokalzeit um, wenn das Argument utc_loc>0 ist. Dazu wird mit Funktion get_current_tzoh() die Differenz der lokalen Zeitzone in Stunden gelesen, für Oktober zusätzlich die Differenz der Sommerzeit. Beispiele für diese Hilfs-Funktion finden sie im ↑ vorigen Kapitel, leider getrennt für Linux und Windows. |
Function dls_refdate(yyyy, mo, utc_loc)
Dim ref As Double Dim tzoh, wref As Integer Dim rk As String ' Calculate RefDate UTC
ref = DateSerial(yyyy, mo + 1, 1)
wref = Weekday(ref, vbMonday)
End Function
ref = DateSerial(yyyy, mo + 1, 1 - wref) ref = ref + TimeSerial(1, 0, 0) ' Calculate LocalTime
If (utc_loc> 0) Then
tzoh = get_current_tzoh()
End IfIf mo = 10 Then tzoh = tzoh + get_dloh()
End Ifref = ref + TimeSerial(tzoh, 0, 0) dls_refdate = ref |
|
Hilfsfunktion get_dloh() berechnet die konstante
zusätzliche Differenz der Sommerzeit in Stunden. Auch dieser Wert wird
zweckmäßig nur einmal gelesen und gespeichert. Derzeit beträgt dieser Wert für ganz Europa und die meisten anderen Staaten 1 Stunde, unabhängig von der Zeitzone. Mit dem Ende der Sommerzeit-Regel wird dieser Wert wieder 0 betragen. |
Function get_dloh As Integer
Dim rk As String
rk = "HKEY_LOCAL_MACHINE\SYSTEM\"
End Function
rk = rk & " CurrentControlSet\Control\" rk = rk & " TimeZoneInformation\DaylightBias" get_dloh = - registry_read(rk) / 60 |
|
Live-Beispiel: Umstellung auf Sommerzeit in UTC:
ref3 = dls_refdate(0000,3,0) = 0
Die Funktion gibt ein Datum im Y1900-Format zurück, dieses wird zur Anzeige in
das Standard → ISO-8601-Format
umgewandelt.
y1900_to_iso(ref3) = 0000-00-00 00:00:00 |
Live-Beispiel: Umstellung auf Normalzeit in Lokalzeit (!):
ref10 = dls_refdate(0000,10,1) =
0
Das Datum im Y1900-Format können sie sowohl in Basic als auch in
einem Kalkulations-Programm direkt weiter verarbeiten.
y1900_to_iso(ref10) = 0000-00-00 00:00:00 |
Umrechnung Lokalzeit → UTC► Die konstante Differenz der lokalen Zeitzone wird in jedem Falle korrigiert, das ist für CET +1 Stunde.► Bei Sommerzeit wird zusätzlich die Sommerzeit-Differenz (+1 Stunde) korrigiert. Dazu vergleicht man den betreffenden Zeitpunkt mit den Sommerzeit-Umstellungs-Daten (s.o.). • In der Praxis wird diese Funktion komplizierter ausgeführt, läuft jedoch wesentlich schneller: Für die Monate 1..2 und 11..12 gilt immer die Normalzeit, für die Monate 4..9 immer die Sommerzeit. • Nur März und Oktober erfordern eine genauere Analyse: Bis 24.März gilt immer Normalzeit, bis 24.Oktober immer Sommerzeit. • Nur für die wenigen verbleibenden Tage muss tatsächlich der Vergleich mit einem der beiden Umstellungs-Daten berechnet werden. |
Function localdate_to_utc(localdate)
Dim yyyy, tzoh As Integer Dim ref3, ref10 As Double
tzoh = get_tzoh()
End Function
yyyy = Year(localdate) ref3 = dls_refdate(yyyy, 3, 1) ref10 = dls_refdate(yyyy, 10, 1) If (localdate - ref3) > 0 And (localdate - ref10) < 0 Then tzoh = tzoh + get_dloh()
End Iflocaldate_to_utc = localdate - TimeSerial(tzoh, 0, 0) |
Umrechnung UTC → LokalzeitDie Funktion arbeitet ganz ähnlich wie das oben vorgestellte Beispiel localdate_to_utc()Die Umstellungs-Daten für den Vergleich müssen in diesem Fall als UTC-Zeiten vorliegen, also jeweils um 01:00:00 UTC. • Auch diese Funktion wird in der Praxis anders ausgeführt: Die meisten Fälle werden mit Hilfe einfacher bedingter Verzweigungen wesentlich rascher erledigt. Nur wenige Tage erfordern tatsächlich den Vergleich mit einem der beiden Umstellungs-Daten. |
Function utc_to_localdate(utc)
Dim yyyy, tzoh As Integer Dim ref3, ref10 As Double
tzoh = get_tzoh()
End Function
yyyy = Year(localdate) ref3 = dls_refdate(yyyy, 3, 0) ref10 = dls_refdate(yyyy, 10, 0) If (utc - ref3) > 0 And (utc - ref10) < 0 Then tzoh = tzoh + get_dloh()
End Ifutc_to_localdate = utc + TimeSerial(tzoh, 0, 0) |
Unix-Timestamp: Sekunden seit 1970-01-01 00:00:00 UTC |
|
|
UNIX-Systeme (z.B. Linux), Datenbanken und die meisten modernen Programmiersprachen
verwenden zur internen Darstellung und zur Berechnung von Datum & Zeit UNIX-Zeitstempel
(TimeStamp). Sie geben die Anzahl Sekunden seit 1970-01-01 UTC an. Durch Verwendung der Weltzeit UTC ist ein Timestamp unabhängig von Ort (Zeitzone) und Datum (Sommerzeit). Das Beispiel rechts berechnet einen Unix-Timestamp aus dem aktuellen Y1900-Datum Lokalzeit: ► Der Faktor 25569 entspricht dem Y1900-Wert von 1970-01-01, 86400 ist die Anzahl Sekunden pro Tag, tzoh die Zeitdifferenz zwischen Lokalzeit und UTC in Stunden (timezone offset). ► Da Y1900 keine Information von Zeitzone und Sommerzeit enthält, muss diese zur Umrechnung zusätzlich herangezogen werden - In diesem Fall durch das Argument tzoh, welches in Mitteleuropa (CET, MEZ) bei Normalzeit 1 beträgt, bei Sommerzeit 2. |
Berechnung eines UNIX-Timestamp aus einem Y1900-Datum:
Function y1900_to_uts(y1900, tzoh)
uts = (y1900 - tzoh / 24 - 25569) * 86400
End Function
Live-Ergebnis:
y1900_to_uts(Now,0) = 0
|
| Dieses Beispiel berechnet ein Y1900-Datum in Weltzeit UTC aus einem Unix-Timestamp. |
Function uts_to_y1900_utc(uts)
uts_to_y1900_utc = uts / 86400 + 25569
End Function
Live-Ergebnis:
uts = 0
uts_to_y1900_utc(uts) = 0 |
|
Dieses Beispiel berechnet ein Y1900-Datum in Lokalzeit aus einem Unix-Timestamp. Zur Berechnung ist die Angabe der jeweils gültigen Zeitdifferenz notwendig - abhängig von der Sommerzeit ! ♦ Details dazu finden sie auf dieser Seite in den Kapiteln ↑ Zeitzonen und ↑ Sommerzeit. |
Function uts_to_y1900_loc(uts, tzoh)
uts_to_y1900_loc = uts / 86400 + 25569 + tzoh / 24
End Function
Live-Ergebnis:
uts = 0
uts_to_y1900_loc(uts,0) = 0 |
| ♦ Details zu diesem Thema finden sie auf den Seiten Datum und Zeit und SQL-Timestamp | |
Julianischer Tag (Julian Day, JD) und Modifizierter julianischer Tag (MJD) |
|||||||||||||||||||||||||
|
Der Julianische Tag (JD) ist ein System zur gemeinsamen Darstellung
von Datum und Zeit in einer einzigen Gleitkomma-Zahl. Dieses System verwendet als Einheit Tage (ebenso wie Y1900), als Nullpunkt -4712-01-01. JD wird immer in Weltzeit UTC angegeben und ist daher unabhängig von Ort (Zeitzone) und Datum (Sommerzeit). Mit JD kann man besonders gut über sehr lange Zeiträume hinweg rechnen. |
In der Astronomie wird zur Angabe von Datum und Zeit häufig der
Julianische Tag (Julian Day, JD) verwendet. In der Astro-Literatur und in Astro-Webs finden sie Algorithmen (Rechen-Vorschriften) zur Berechnung des JD aus den Bestandteilen (yy-mo-dd hh:mi:ss) und umgekehrt. Der Modifizierte Julianische Tag (MJD) ist eine Praxis-freundliche Variante von JD, die vorwiegend für neuere historische Daten verwendet wird. |
||||||||||||||||||||||||
Y1900
Für jedes Datum >= 1900-03-01 kann man den Julianischen Tag bequem aus dem
Y1900-Wert berechnen, der von allen gängigen Microsoft-Programmen geliefert wird. |
Function y1900_to_jd(y1900)
Anwendung in einem Kalkulations-Programm:y1900_to_jd = y1900 + 2415018.5
End Function
(Aktuelle Daten mit Taste F9)
|
||||||||||||||||||||||||
JD
Aus dem Julianischen Tag JD kann man umgekehrt auch den Y1900-Wert
ab den gleichen Untergrenzen berechnen, wie oben angegeben.
|
Function jd_to_y1900(jd)
jd_to_y1900 = jd - 2415018.5
End Function
|
||||||||||||||||||||||||
yyyy,mo,dd,hh_utc,mi,ss
Dieses Beispiel berechnet den JD aus den Bestandteilen |
Function jd( _
yyyy As Double, mo As Double, dd As Double, _ Optional hh As Double = 0, _ Optional mi As Double = 0, _ Optional ss As Double = 0) As Double ' Use UTC !
Dim gregdat, ja, ma, t As Double
gregdat = 588828
End Function
' year
If (yyyy<0) Then yyyy = yyyy + 1
' month
ma = 0If (mo>2) Then ma = mo + 1
Else
yyyy = yyyy - 1
End If
ma = mo + 13 ' calculate jd
jd = Int(365.25 * yyyy) + Int(30.6001 * ma) + dd + 1720995
' correct greg
If ((dd+31*(mo+12*yyyy)) >= gregdat) Then
ja = symfloor(yyyy / 100)
End If
jd = jd + 2 - ja + symfloor(ja / 4) ' time
t = (hh + mi / 60 + ss / 3600) / 24jd = jd - 0.5 + t |
||||||||||||||||||||||||
JD
Dieses Beispiel berechnet die ganzzahligen Datum und Zeit-Bestandteile aus einem JD. |
Function jd_to_iso(jd) As String
Dim rest, y400, y100, y4, y1, mx As Double Dim yyyy, mo, dd, hh, mi, ss As Double Dim iso As String ' Schaltjahre
rest = jd + 32044y400 = Int(rest / 146097) rest = dmod(rest, 146097) y100 = mymin(3, Int(rest / 36524)) rest = rest - 36524 * y100 y4 = Int(rest / 1461) rest = dmod(rest, 1461) y1 = mymin(3, Int(rest / 365)) rest = rest - 365 * y1 ' Datum
yyyy = (y400 - 12) * 400 + y100 * 100 + y4 * 4 + y1mx = Int((rest * 111 + 41) / 3395) rest = rest - 30 * mx - Int((mx + 1) * 7 / 12) + 1 dd = Int(rest + 0.5) mx = mx + 3 mo = ((mx + 11) Mod 12) + 1 yyyy = yyyy + Int(mx / 13) ' Zeit
rest = (rest - dd) * 24hh = Int(rest) rest = (rest - hh) * 60 mi = Int(rest) rest = (rest - mi) * 60 ss = Round(rest) hh = hh + 12 ' String
jd_to_iso = ymdhms_to_iso(yyyy, mo, dd, hh, mi, ss)
|
||||||||||||||||||||||||
Y1900
Gültige Y1900-Werte und gültige MJD-Werte kann man direkt
umrechnen. Lediglich für außerhalb liegende Daten muss
man den Umweg über JD (nächster Absatz) wählen.
|
Function y1900_to_mjd(y1900)
y1900_to_mjd = y1900 + 15018
End Function
Function mjd_to_y1900(mjd)
mjd_to_y1900 = mjd - 15018
End Function
|
||||||||||||||||||||||||
yyyy,mm,dd
Das Modifizierte Julianische Datum (MJD) ist eine Praxis-nahe Variante des JD.
Sie beschreibt ein Datum im Bereich 1858-11-17 .. 2132-08-31
mit einer 5stelligen ganzen Dezimalzahl. |
Function mjd(yy, mo, dd)
mjd = jd(yy, mo, dd, 0, 0, 0) - 2400000.5
End Function
Live-Test (hier mit Javascript berechnet): MJD(Heute) = 0
|
||||||||||||||||||||||||
MJD
Da eine Funktion nur einen einzigen Wert zurückgeben kann, weren die
Datum-Bestandteile als Text (String) nach Standard
→ ISO-8601 verpackt.
|
Function mjd_to_iso(mjd)
Dim jd As Double
jd = mjd - 2400000.5
End Function
mjd_to_iso = jd_to_iso(jd) |
||||||||||||||||||||||||
|
Diese Hilfsfunktionen werden von den JD-Beispielen verwendet:
Private Function symfloor(x)
If (x < 0) Then
End Function
symfloor = -Int(-x)
Else
symfloor = Int(x)
End If
|
Private Function dmod(a, b)
dmod = a - Int(a / b) * b
End FunctionPrivate Function mymin(a, b)
If (b < a) Then
End Function
mymin = b
Else
mymin = a
End If
|
||||||||||||||||||||||||
| ♦ Details zum Thema Datum und Zeit und zu Funktionen ganzer Zahlen (floor, modulo, ...) | |||||||||||||||||||||||||
ISO 8601 - Der Internationale Standard für Datum und Zeit |
|
| Dieser Standard ist das Ergebnis der Bestrebungen, die Formulierung von Datum und Zeit international einheitlich und unmissverständlich festzulegen. ISO-8601 ist unabhängig von Sprache, Kultur, Betriebssystem, Hersteller oder Programm. |
Datum und Zeit haben das String-Format
YYYY-MM-TT hh:mm:ss
Live (Lokalzeit):
0000-00-00 00:00:00
|
|
ISO-8601 wird von allen modernen Programmen unterstützt, z.B. von LibreOffice. |
Immerhin kann man das ISO-Format in jedem Fall als Benutzer-spezifisches Format JJJJ-MM-TT hh:mm:ss eingeben. |
| ♣ Tipp: Um Datum und/oder Zeit in der Zelle eines Kalkulations-Blatts anzuzeigen, ist es nicht notwendig, einen String zu erstellen. Tragen sie den Wert als Y1900-Gleitkomma-Zahl ein und formatieren sie die Zelle mit Menü . | ♣ Tipp: Zur Codierung und Decodierung von Datum- und Zeit-Strings eignen sich besonders gut → Reguläre Ausdrücke ! - Diese Methoden werden von allen modernen Programmiersprachen ausser von Basic unterstützt ... |
|
Dieses Beispiel kann man verwenden, um Basic-Datum-Zeit-Daten in das ISO-Format
umzuwandeln. Als Varianten kann man Funktionen erstellen, um nur das Datum oder nur die Zeit nach ISO-8601 zu codieren, bzw. um diese Strings aus einem ISO-8601-Datum zu extrahieren. |
Function y1900_to_iso(mydate) As String
Dim iso As String
iso = Year(mydate)
End Function
iso = iso & "-" & _ Right("00" & Month(mydate), 2)
iso = iso & "-" & _
Right("00" & Day(mydate), 2)
iso = iso & " " & _
Right("00" & Hour(mydate), 2)
iso = iso & ":" & _
Right("00" & Minute(mydate), 2)
iso = iso & ":" & _
Right("00" & Second(mydate), 2)
y1900_to_iso = iso
|
| ♦ Details zu diesem Thema auf der Seite ISO-8601t | |
Kulturspezifische Unterschiede bei Datum und Zeit |
|||||||||||||||
|
►
Verwenden sie bei der Erstellung eigener Programme keinesfalls kultur-spezifische Teile,
sondern folgen sie in allen Fällen dem internationalen Standard
→ ISO-8601. Auch ihre KundInnen werden früher oder später vorteilhaft das ISO-Format verwenden. |
►
Falls sie davon abweichende Formate/Regeln verwenden wollen/müssen,
dann leiten sie diese in Zusatz-Funktionen aus dem Standard ab. ► So können sie später problemlos weitere Formate hinzufügen, oder überholte Formate wieder entfernen. |
||||||||||||||
|
Die Namen der Monate und Wochentage
sind naturgemäß je nach verwendeter Sprache verschieden. Kleine Feinheiten bleiben manchmal unentdeckt: In Deutschland wird z.B. 'Januar' verwendet, in Österreich 'Jänner'. Bei Import oder Eingabe von Text-Daten in ein Kalkulations-Programm (z.B. MS-Excel) wird z.B. 'Januar 2000' als Datum erkannt, 'Jänner 2000' jedoch manchmal als Text - das ergibt schwer zu findende Fehler. |
► Für den Transport / Austausch bestimmte Daten dürfen daher weder Monats- noch Tages-Namen enthalten ! Verwenden sie vorzugsweise den international eindeutigen Standard → ISO-8601 oder gar keine Strings, sondern ↑ Ganze Zahlen für die üblichen 6 Bestandteile (yyyy, mo, dd, hh, mi, ss). |
||||||||||||||
Jahr, Monat und Tag.► Die Reihenfolge der Bestandteile in Datum-Strings ist kulturspezifisch:► In Europa verwendet man Tag-Monat-Jahr, in den USA Monat-Tag-Jahr, sowie unterschiedliche Trennzeichen. ► Bei Tages-Zahlen<=12 kann das zu unangenehmen Verwechslungen führen. ► Eine salomonische und weltweit eindeutige Lösung ist die hierarchische Angabe nach → Standard ISO-8601: JJJJ-MM-TT |
Live: Das heutige Datum:
|
||||||||||||||
Kalenderwoche:Im kommerziellen Bereich ist die Angabe der Kalenderwoche (z.B. für Liefertermine) üblich. Das Beispiel rechts berechnet die KW nach ISO-Standard (ohne Gewähr !):
►
Weltweit und nach ISO-Standard beginnt die Woche am Montag
► Nach Standard ISO-8601 ist die erste Kalenderwoche eines Jahres diejenige, von welcher mindestens 4 Tage im neuen Jahr liegen. Ein Jahr kann 52 ... 53 KW umfassen. ► Manche Staaten (USA, einige neue EU-Mitglieder) verwenden abweichende Definitionen, in ca. 3% aller Jahre gibt es sogar KW54. Die USA verwenden natürlich andere Regeln:
►
US-Wochen beginnen am Sonntag
► Die erste Kalenderwoche beginnt am 1.Jänner ► Deshalb kann es am Anfang und am Ende eines Jahres kürzere Wochen-Fragmente geben. ► Lassen sie die Kalenderwoche beim Transport von Daten weg und überlassen sie dem Zielprogramm die Berechnung der jeweiligen Kalenderwoche aus dem Datum. |
Function kw(y1900) As Integer
Dim dref As Long
dref = kw_ref(Year(y1900))
End Functionkw = (y1900 - dref) \ 7 + 1 If kw < 1 Then
dref = kw_ref(Year(y1900) - 1)
End If
kw = (y1900 - dref) \ 7 + 1 Function kw_ref(yyyy) As Integer Dim wref As Integer Dim dref As Long
dref = DateSerial(yyyy, 1, 4)
End Function
wref = Weekday(dref, vbMonday) kw_ref = dref - wref + 1 Live-Daten:
|
||||||||||||||
Tag des Jahres:Dieser Wert ist nicht kultur-spezifisch, zumindest für alle Staaten, in welchen der international übliche Gregorianische Kalender verwendet wird. Die Funktion passt jedoch in dieses Kapitel.Live: day_of_year = 0 |
Function day_of_year(y1900) As Integer
Dim y1 As Integer Dim d1 As Long
d1 = DateSerial(Year(y1900), 1, 1)
End Function
day_of_year = y1900 - d1 + 1 |
||||||||||||||
Wochentag:Es ist klar, dass die Namen der Wochentage verschieden je nach Sprache sind. Deren unterschiedliche Zählung ist weniger bekannt:► Die laufende Wochentag-Nr wird nach Standard ISO-8601 von Mo→1, Di→2, ... So→7 gezählt. ► Die USA verwenden So→1 bis Sa→7, manche Programme So→0 bis Sa→6. Die Basic-Function Weekday(date,f) muss daher mit f=2 verwendet werden, ähnlich wie die Kalkulations-Funktion WOCHENTAG(). ► Wochentags-Nr lassen sich gut aus dem JD berechnen. Das funktioniert auch für Jahre<1900 und >10000. Rechts ein Muster für den einfachen Algorithmus. ► Lassen sie die Wochentag-Nummer beim Transport von Daten weg und überlassen sie dem Zielprogramm die Berechnung des jeweiligen Wochentages nach den jeweiligen lokalen Vorgaben. ► Wenn sie den Wochentag nur anzeigen, jedoch nicht berechnen wollen, dann bieten Kalkulations-Programme dazu das Format 'TTT': Von jedem Datum (im internen Y1900-Format) wird dann nur der Wochentag angezeigt. |
Ermittlung des aktuellen Wochentags:
Function weekday_now() As String
Dim wdnr as Integer
wdnr = Weekday(Now, 2)
End Function
weekday_now = Choose(wdnr, _ "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So") Berechnung der Wochentags-Nummer aus dem JD (Julian Day):
Function jd_to_wdnr(jd)
As Integer
jd_to_wdnr = (jd + 1.5) Mod 7
End Function
If (jd_to_wdnr = 0) Then jd_to_wdnr = 7 Heute ist ?Tag, daher
|
||||||||||||||
Tageszeit:► Die Angabe der Tageszeit erfolgt weltweit im Standard 24-Stunden-Format.► Nur die USA verwenden immer noch das 12-Stunden-Format mit den Zusätzen "AM" (vormittags) und "PM" (nachmittags). ► Vor 12:00 gilt "AM", danach "PM" ► Erst ab 13:00 wird die Stunde um 12 vermindert angezeigt. ► Von 00:00 bis 00:59 früh werden 12 Stunden angezeigt. Viel Geld ist bereits für die Umrechnung dieser Angaben verschwendet worden, viel wird wohl noch nachfolgen. Hier wird kein Basic-Beispiel gezeigt, da Kalkulations-Programme wie LibreOffice oder MS-Excel die Zeit sowohl im Standard- als auch im US-Format anzeigen können. |
Die aktuelle Zeit und einige charakteristische Zeiten:
|
||||||||||||||
| ♦ Details zu diesem Thema im Kapitel Datum und Zeit | |||||||||||||||
Das Basic-Ereignis (Event) OnTime
|
|
Application.OnTimeMit dem → Event OnTime kann man Aktionen zu einem vor-bestimmten Zeitpunkt auslösen.► Das erste Beispiel legt fest, das Sub test() zur 'absoluten Zeit' um 17:00 aufzurufen. Als Argumente setzt man die frühest-gewünschte Ausführungszeit und das auszuführende Sub ein. Ein Programm kann zum gewünschten Zeitpunkt beschäftigt (busy) sein - In diesem Fall wartet die Ausführung (sie können zusätzlich auch einen spätesten Zeitpunkt angeben). ► Das 2. Beispiel zeigt, wie man ein gesetztes OnTime-Event ändert - Hier wird das Ereignis mit Schedule=False wieder gelöscht. ► Wenn man sich auf die korrekte Einstellung einer (fremden) PC-Uhr nicht verlassen kann, dann ist die Angabe relativer Zeiten vorteilhaft. Sie sehen das im Beispiel 'Ausführung nach 15 Sekunden'. |
' Ausfuehrung um 12:30
Application.OnTime TimeValue("17:00:00"), "test"' Aenderung (Loeschen des Auftrags):
Application.OnTime EarliestTime:=_
TimeValue("12:30:00"), _
Procedure:="test", _ Schedule:=False ' Ausfuehrung nach 15 Sekunden:
Application.OnTime Now + TimeValue("00:00:15"), "test"
' Mehrere Events ausloesen:
Application.OnTime Now + TimeValue("00:00:30"), "test"Application.OnTime Now + TimeValue("00:01:00"), "test" Sub test() MsgBox ("Jetzt = " & Now)
End Sub
|
Jede Sekunde ...Das Beispiel schreibt laufend die aktuelle Zeit in eine Zelle eines Kalkulations-Blatts.► Vergeben sie den Namen zeit für eine Zelle: Zelle markieren, Menübefehl Tragen sie die Zahl 0,5 ein und formatieren sie mit Menübefehl (oder ähnlich). Die Zelle sollte 12:00:00 anzeigen. ► Tragen sie die Beispiele in ein Basic-Modul ein: Die globale Variable run steuert die laufende Anzeige. Sub do_start() startet die Anzeige, Sub do_stop() beendet sie. Sub jede_sekunde() trägt die aktuelle Zeit in Zelle zeit ein und ruft sich nach Ablauf von 1 sec mit Methode OnTime selbst auf. ► Erzeugen sie 2 Bildschirm-Tasten: Menübefehl , Klicken sie auf und ziehen sie mit der Maus eine Tasten-Objekt auf. Die erste Taste erhält die Ausfschrift Start und mit das Programm do_start() An die zweite Taste mit der Aufschrift Stop wird das Programm do_stop() zugewiesen. ► Das Programm jede_sekunde() führt die eigentliche Arbeit aus und schreibt die aktuelle Zeit in die Zelle. Danach wird ein Timer gesetzt, der das Programm nach 1 sec erneut startet usw. ► Bei jedem automatisch ablaufenden Programm sollte ein Abbruch vorgesehen werden. Das Sub do_stop() setzt die globale Variable run=False und stoppt damit die laufende Anzeige. |
Dim run As Boolean
Sub do_start()
run = True
End SubCall jede_sekunde Sub do_stop() run = False
End SubSub jede_sekunde()
If run Then
End Sub
Range("zeit").Value = Time
End If
Application.OnTime Now + TimeValue("00:00:01"), "jede_sekunde" |
TimeValue()Die verwendete Funktion TimeValue() wandelt einen Zeit-String in eine Y1900-Variable um. Sie wird für bessere Anschaulichkeit verwendet. Wenn das nicht notwendig ist, verwendet man besser direkt die Y1900-Zahlen. |
TimeValue("12:00:00") = 12/24 = 0.5
TimeValue("01:00:00") = 1/24 = 0.0416667 TimeValue("00:01:00") = 1/24/60 = 0.0006944 |
|
|
| ● Visual Basic 2005 Handbuch (Andreas Kühnel / Galileo) - .NET-DateTime | |
|
Letzte Änderung dieser Seite: 2012-02-29 23:01:56
|