====== std.datetime ======
Datum und Uhrzeit rund um einen **Unix-Zeitstempel in Sekunden**: formatieren (ISO 8601, RFC 2822, eigene Muster), parsen, rechnen, prüfen. Die Unit arbeitet durchgehend in **UTC** und braucht keine externen Bibliotheken.
→ [[lyx_-_programmiersprache:units:time|std.time]] · [[lyx_-_programmiersprache:units:string|std.string]] · [[lyx_-_programmiersprache:units|Standard Library]]
Alle Beispiele dieser Seite sind mit ''lyxc 1.1.2E'' übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben und gegen Pythons ''datetime'' geprüft.
> **Die Erweiterungen aus [[https://github.com/SEOLizer/LyX-Compiler/issues/1601|#1601]], [[https://github.com/SEOLizer/LyX-Compiler/issues/1602|#1602]], [[https://github.com/SEOLizer/LyX-Compiler/issues/1603|#1603]] und [[https://github.com/SEOLizer/LyX-Compiler/issues/1605|#1605]] stecken in der Repo-Fassung der Standardbibliothek.** Die unter ''/usr/include/lyx/units'' ausgelieferte Fassung hinkt hinterher ([[https://github.com/SEOLizer/LyX-Compiler/issues/1578|#1578]]). Wer ''undefined function 'DatetimeFromYmdHms''' sieht, übersetzt gegen die Repo-Fassung:
>
>
lyxc --std-path=/pfad/zum/compiler-repo programm.lyx -o programm
**Einsatz:** Protokolle und Audit-Trails, HTTP-Kopfzeilen (''Date:'', ''Last-Modified:''), Kalender- und Buchungslogik, Datenbank-Zeitstempel, SMTP/IMAP.
> **Datetime-Werte und Ergebniszeiger nicht verwechseln.** Beide Parametersorten stehen in den Signaturen als ''int64'', meinen aber Verschiedenes:
>
> * ''FormatIso(datetime, output)'' und die übrigen ''Format…''-Funktionen erwarten den **Wert** — einen Unix-Zeitstempel in Sekunden.
> * ''ParseIso(input, result)'' und die übrigen ''Parse…''-Funktionen erwarten einen **Zeiger** auf einen Speicherbereich, in den das Ergebnis geschrieben wird.
>
> Beim Verketten also den Wert auslesen:
>
>
var dt: int64 := alloc(8);
ParseIso("2026-08-10T14:30:45"c, dt); // schreibt nach dt
var ts: int64 := peek64(dt); // Wert holen
FormatIso(ts, ausgabe); // -> 2026-08-10T14:30:45Z
>
> Wird versehentlich der Zeiger an ''FormatIso'' übergeben, meldet der Compiler nichts (beide sind ''int64'') — die Ausgabe ist dann ein Datum irgendwo im Jahr 587.
**Ausgabepuffer stellt der Aufrufer.** Jede ''Format…''-Funktion schreibt in einen übergebenen Puffer und hängt ein Nullbyte an; zurück kommt die Zahl der Zeichen ohne dieses Nullbyte. 64 Byte reichen für alle festen Formate, für ''Format'' mit eigenem Muster entsprechend mehr.
----
===== Formatieren =====
^ Signatur ^ Ergebnis ^
| ''FormatIso(datetime, output)'' | ''2026-08-17T07:45:12Z'' |
| ''FormatRfc2822(datetime, output)'' | ''Mon, 17 Aug 2026 07:45:12 +0000'' |
| ''Format(datetime, fmt, output)'' | frei über Platzhalter — siehe Tabelle |
| ''FormatDate(year, month, day, output)'' | ''2026-08-17'' — nimmt **Einzelwerte**, keinen Zeitstempel |
| ''FormatTime(hour, minute, second, output)'' | ''07:45:12'' — ebenfalls Einzelwerte |
| ''FormatLocale(datetime, locale, output)'' | ''17.08.2026 14:30:00'' (de) — siehe Kasten |
==== Platzhalter für ''Format'' ====
^ Platzhalter ^ Bedeutung ^ Beispiel ^
| ''%Y'' | Jahr, vierstellig | ''2026'' |
| ''%y'' | Jahr, zweistellig | ''26'' |
| ''%m'' | Monat, zweistellig | ''08'' |
| ''%d'' | Tag, zweistellig | ''17'' |
| ''%H'' | Stunde, 00–23 | ''07'' |
| ''%M'' | Minute | ''45'' |
| ''%S'' | Sekunde | ''12'' |
| ''%w'' | Wochentag als Ziffer, 0 = Sonntag | ''1'' |
| ''%W'' | Wochentag ausgeschrieben | ''Monday'' |
| ''%b'' | Monatskürzel | ''Aug'' |
| ''%B'' | Monat ausgeschrieben | ''August'' |
| ''%p'' | ''AM'' / ''PM'' | ''AM'' |
| ''%z'' | Zeitzonenversatz aus ''TZ'' | ''+0000'' |
| ''%Z'' | Zonenname — **immer ''UTC''** | ''UTC'' |
| ''%I'' | Stunde im 12-Stunden-Format, 01–12 | ''02'' |
| ''%j'' | Tag im Jahr, dreistellig | ''229'' |
| ''%%'' | ein wörtliches Prozentzeichen | ''%'' |
| ''%f'' | Mikrosekunden — **immer ''000000''** | ''000000'' |
Ein **unbekannter Platzhalter wird weiterhin wörtlich ausgegeben** — ''%e'' erscheint als ''%e'' im Ergebnis. Stumm ist das seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1602|#1602]] nicht mehr: der **Rückgabewert ist dann negativ**, sein Betrag bleibt die Zahl der geschriebenen Zeichen. Wer ihn wie bisher ignoriert, bekommt dieselbe Zeichenkette wie zuvor.
%p %I -> PM 02 rc=5
%j -> 229 rc=3
100%% fertig -> 100% fertig rc=11
%e %s -> %e %s rc=-5
import std.datetime;
import std.alloc;
import std.string;
fn main(): int64 {
var out: int64 := alloc(256);
var o: pchar := out as pchar;
// 2026-08-17T07:45:12Z
var ts: int64 := 1786952712;
FormatIso(ts, o); PrintLn(StrConcat("ISO 8601: ", o));
FormatRfc2822(ts, o); PrintLn(StrConcat("RFC 2822: ", o));
Format(ts, "%d.%m.%Y %H:%M:%S"c, o); PrintLn(StrConcat("deutsch: ", o));
Format(ts, "%W, %d. %B %Y"c, o); PrintLn(StrConcat("lang: ", o));
Format(ts, "%y-%m-%d %I%p"c, o); PrintLn(StrConcat("gemischt: ", o));
Format(ts, "%Z %z %w %b %f"c, o); PrintLn(StrConcat("Rest: ", o));
FormatLocale(ts, "de_DE"c, o); PrintLn(StrConcat("Locale de: ", o));
// Roundtrip: ISO parsen und zurueck
var buf: int64 := alloc(8);
var ok: int64 := ParseIso("2026-08-13T09:45:12Z"c, buf);
PrintLn(StrConcat(StrConcat("ParseIso ok=", IntToStr(ok)), StrConcat(" ts=", IntToStr(peek64(buf)))));
FormatIso(peek64(buf), o);
PrintLn(StrConcat("zurueck: ", o));
return 0;
}
ISO 8601: 2026-08-17T07:45:12Z
RFC 2822: Mon, 17 Aug 2026 07:45:12 +0000
deutsch: 17.08.2026 07:45:12
lang: Monday, 17. August 2026
gemischt: 26-08-17 %IAM
Rest: UTC +0000 1 Aug 000000
Locale de: 2026-08-17T07:45:12Z
ParseIso ok=1 ts=1786614312
zurueck: 2026-08-13T09:45:12Z
> **''FormatLocale'' lokalisiert seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1415|#1415]] wirklich.** Unterstützt werden die Sprachkennungen ''de'', ''at'', ''ch'', ''en'', ''fr'', ''es'', ''it'' und ''pt'' — geprüft werden nur die ersten beiden Zeichen. ''en_US'' bekommt als einziges Locale die US-Schreibweise mit 12-Stunden-Zählung; alles Übrige folgt der Tag-vor-Monat-Ordnung.
>
> Ein **nicht unterstütztes** Locale ist kein Fehler: die Funktion fällt still auf ''FormatIso'' zurück. Ob ein Locale erkannt wird, beantwortet ''LocaleSupported(locale): bool'' vorab.
>
>
de_DE : 17.08.2026 14:30:00
en_US : 8/17/2026 2:30:00 PM
fr_FR : 17/08/2026 14:30:00
ja_JP : 2026-08-17T14:30:00Z <- Rückfall auf FormatIso
LocaleSupported(de_DE) : true
LocaleSupported(ja_JP) : false
>
> Die Wochentags- und Monatsnamen (''%W'', ''%B'', ''WeekdayLong'', ''MonthLong'') sind weiterhin ausschließlich **englisch**.
----
===== Parsen =====
^ Signatur ^ Erwartet ^ Rückgabe ^
| ''ParseIso(input, result)'' | ''YYYY-MM-DDTHH:MM:SS'' (mindestens 19 Zeichen) | ''1'' / ''0'' |
| ''ParseRfc2822(input, result)'' | ''Www, DD Mon YYYY HH:MM:SS ±HHMM'' (mindestens 25 Zeichen) | ''1'' / ''0'' |
| ''ParseFlexible(input, result)'' | vier Formate, siehe Kasten | ''1'' / ''0'' |
| ''ParseDate(input, year, month, day)'' | ''YYYY-MM-DD'' | ''1'' / ''0'' |
| ''ParseTime(input, hour, minute, second)'' | ''HH:MM'' oder ''HH:MM:SS'' | ''1'' / ''0'' |
''result'', ''year'', ''month'', ''day'', ''hour'', ''minute'' und ''second'' sind **Zeiger** auf je acht Byte, in die das Ergebnis geschrieben wird.
Alle fünf Parser setzen das Ziel seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1603|#1603]] **vorab auf 0**. Ein übersehener Rückgabewert-Test endet damit bei ''1970-01-01'' statt bei einem plausibel aussehenden Altwert.
import std.datetime;
import std.alloc;
import std.string;
fn main(): int64 {
var out: int64 := alloc(256);
var o: pchar := out as pchar;
var buf: int64 := alloc(8);
// RFC 2822 parsen, auch mit Zeitzonenversatz
PrintLn(StrConcat("ParseRfc2822 ok=", IntToStr(ParseRfc2822("Mon, 17 Aug 2026 07:45:12 +0000"c, buf))));
FormatIso(peek64(buf), o); PrintLn(StrConcat(" -> ", o));
ParseRfc2822("Mon, 17 Aug 2026 09:45:12 +0200"c, buf);
FormatIso(peek64(buf), o); PrintLn(StrConcat("+0200 -> UTC: ", o));
// ParseFlexible nimmt beides
PrintLn(StrConcat("ParseFlexible(ISO): ", IntToStr(ParseFlexible("2026-08-17T07:45:12Z"c, buf))));
PrintLn(StrConcat("ParseFlexible(RFC): ", IntToStr(ParseFlexible("Mon, 17 Aug 2026 07:45:12 +0000"c, buf))));
PrintLn(StrConcat("ParseFlexible(dt.): ", IntToStr(ParseFlexible("17.08.2026"c, buf))));
PrintLn(StrConcat("ParseFlexible(Datum):", IntToStr(ParseFlexible("2026-08-17"c, buf))));
poke64(buf, 0 - 1);
PrintLn(StrConcat("ParseFlexible(Unsinn):", IntToStr(ParseFlexible("kein Datum"c, buf))));
PrintLn(StrConcat(" Zielwert danach: ", IntToStr(peek64(buf))));
// Einzelteile
var y: int64 := alloc(8); var m: int64 := alloc(8); var d: int64 := alloc(8);
PrintLn(StrConcat("ParseDate('2026-08-17') ok=", IntToStr(ParseDate("2026-08-17"c, y, m, d))));
PrintLn(StrConcat(" Jahr/Monat/Tag: ", StrConcat(IntToStr(peek64(y)), StrConcat("/", StrConcat(IntToStr(peek64(m)), StrConcat("/", IntToStr(peek64(d))))))));
PrintLn(StrConcat("ParseDate('2026-13-01') ok=", IntToStr(ParseDate("2026-13-01"c, y, m, d))));
// Zeitzonenversatz der Umgebung
PrintLn(StrConcat("GetTimezoneOffset(): ", IntToStr(GetTimezoneOffset())));
FormatTimezoneOffset(GetTimezoneOffset(), o); PrintLn(StrConcat(" formatiert: ", o));
FormatTimezoneOffset(0 - 18000, o); PrintLn(StrConcat(" -18000 s: ", o));
// Namen
PrintLn(StrConcat(StrConcat("WeekdayLong(1)=", WeekdayLong(1)), StrConcat(" MonthLong(8)=", MonthLong(8))));
return 0;
}
ParseRfc2822 ok=1
-> 2026-08-17T07:45:12Z
+0200 -> UTC: 2026-08-17T07:45:12Z
ParseFlexible(ISO): 1
ParseFlexible(RFC): 1
ParseFlexible(dt.): 1
ParseFlexible(Datum):1
ParseFlexible(Unsinn):0
Zielwert danach: 0
ParseDate('2026-08-17') ok=1
Jahr/Monat/Tag: 2026/8/17
ParseDate('2026-13-01') ok=0
GetTimezoneOffset(): 0
formatiert: +00:00
-18000 s: -05:00
WeekdayLong(1)=Monday MonthLong(8)=August
Der Zeitzonenversatz aus RFC 2822 wird korrekt herausgerechnet: ''09:45:12 +0200'' ergibt denselben Zeitstempel wie ''07:45:12 +0000''.
> **''ParseFlexible'' probiert vier Formate** in dieser Reihenfolge ([[https://github.com/SEOLizer/LyX-Compiler/issues/1603|#1603]]): ISO 8601 mit Zeitanteil, RFC 2822, ISO-Datum ohne Zeit (Zeitanteil ''00:00:00'') und die deutsche Schreibweise ''17.08.2026'' mit optionalem '' 14:30'' oder '' 14:30:00''. Ein US-amerikanisches ''8/17/2026'' scheitert weiterhin.
>
> **Die Parser prüfen die Trennzeichen an festen Stellen**, nicht die Semantik: ''ParseIso'' verlangt ''-'' an Position 4 und 7, ''T'' an 10, '':'' an 13 und 16. Ein Leerzeichen statt ''T'' (wie in SQL-Zeitstempeln) wird abgewiesen. Angehängte Bruchteile oder Zonenversätze (''…:12.500+02:00'') werden dagegen **ignoriert**, nicht ausgewertet — die Zeit gilt als UTC.
----
===== Zeitstempel bauen und zerlegen =====
Bis [[https://github.com/SEOLizer/LyX-Compiler/issues/1601|#1601]] führte der Weg von Kalenderwerten zu einem Zeitstempel nur über eine Zeichenkette — ISO-String zusammensetzen, ''ParseIso'' aufrufen. Beide Richtungen gibt es jetzt direkt:
^ Signatur ^ Beschreibung ^
| ''DatetimeFromYmdHms(year, month, day, hour, minute, second)'' | Zeitstempel aus Einzelwerten |
| ''DatetimeFromYmd(year, month, day)'' | wie oben, Zeitanteil ''00:00:00'' |
| ''YearOf(dt)'' / ''MonthOf(dt)'' / ''DayOf(dt)'' | Kalenderwerte aus dem Zeitstempel |
| ''HourOf(dt)'' / ''MinuteOf(dt)'' / ''SecondOf(dt)'' | Uhrzeitwerte aus dem Zeitstempel |
| ''DayOfWeek(dt)'' | Wochentag zum Zeitstempel, 0 = Sonntag |
| ''DayOfWeekYmd(year, month, day)'' | Wochentag aus Einzelwerten |
| ''WeekYear(year, month, day)'' | Jahr, zu dem die ISO-Kalenderwoche gehört |
| ''StartOfDay(dt)'' / ''EndOfDay(dt)'' | ''00:00:00'' bzw. ''23:59:59'' desselben Tages |
| ''StartOfMonth(dt)'' / ''EndOfMonth(dt)'' | Monatserster bzw. Monatsletzter |
import std.io;
import std.string;
import std.alloc;
import std.datetime;
fn main(): int64 {
var ts: int64 := DatetimeFromYmdHms(2026, 8, 17, 14, 30, 0);
Print("DatetimeFromYmdHms : "); PrintLn(IntToStr(ts));
Print("YearOf/MonthOf/DayOf : ");
Print(IntToStr(YearOf(ts))); Print(" ");
Print(IntToStr(MonthOf(ts))); Print(" ");
PrintLn(IntToStr(DayOf(ts)));
Print("HourOf/MinuteOf/SecondOf : ");
Print(IntToStr(HourOf(ts))); Print(" ");
Print(IntToStr(MinuteOf(ts))); Print(" ");
PrintLn(IntToStr(SecondOf(ts)));
Print("DayOfWeek : "); Print(IntToStr(DayOfWeek(ts)));
Print(" -> "); PrintLn(WeekdayLong(DayOfWeek(ts)));
Print("WeekNumber/WeekYear 29.12.2025 : ");
Print(IntToStr(WeekNumber(2025, 12, 29))); Print(" / ");
PrintLn(IntToStr(WeekYear(2025, 12, 29)));
Print("StartOfDay/EndOfMonth : ");
Print(IntToStr(StartOfDay(ts))); Print(" ");
PrintLn(IntToStr(EndOfMonth(ts)));
Print("DiffMonths 2026-01-31 -> 2026-08-17 : ");
PrintLn(IntToStr(DiffMonths(DatetimeFromYmd(2026, 1, 31), ts)));
return 0;
}
DatetimeFromYmdHms : 1786977000
YearOf/MonthOf/DayOf : 2026 8 17
HourOf/MinuteOf/SecondOf : 14 30 0
DayOfWeek : 1 -> Monday
WeekNumber/WeekYear 29.12.2025 : 1 / 2026
StartOfDay/EndOfMonth : 1786924800 1788220799
DiffMonths 2026-01-31 -> 2026-08-17 : 6
> **''WeekNumber'' allein reicht für eine Datumsangabe nicht.** Der 29.12.2025 liegt in **KW 1 des Jahres 2026** — genau dafür gibt es ''WeekYear''. Wer „KW ''x'' / Jahr aus ''%Y''" schreibt, produziert an jedem Jahreswechsel eine falsche Angabe.
>
> **''DiffMonths'' und ''DiffYears'' zählen volle Einheiten**, angefangene nicht. Ein Alter aus dem Geburtsdatum stimmt damit auch am Tag vor dem Geburtstag.
----
===== Rechnen und Prüfen =====
^ Signatur ^ Beschreibung ^
| ''AddSeconds(datetime, seconds)'' | schlichte Addition |
| ''AddMinutes(datetime, minutes)'' | ''minutes × 60'' |
| ''AddHours(datetime, hours)'' | ''hours × 3600'' |
| ''AddDays(datetime, days)'' | ''days × 86400'' |
| ''AddWeeks(datetime, weeks)'' | ''weeks × 604800'' |
| ''AddMonths(datetime, months)'' | kalendarisch, mit **Klemmung** auf den Monatsletzten |
| ''AddYears(datetime, years)'' | kalendarisch, klemmt den 29. Februar auf den 28. |
| ''DiffSeconds(datetime1, datetime2)'' | ''datetime2 − datetime1'' — Reihenfolge beachten |
| ''DiffDays(y1, m1, d1, y2, m2, d2)'' | Tagesdifferenz aus Einzelwerten |
| ''DiffMonths(von, bis)'' / ''DiffYears(von, bis)'' | volle Monate bzw. Jahre zwischen zwei Zeitstempeln |
| ''DaysInMonth(year, month)'' | 28–31, mit Schaltjahresregel |
| ''DayOfYear(year, month, day)'' | 1–366 |
| ''WeekNumber(year, month, day)'' | ISO-8601-Kalenderwoche |
| ''WeekYear(year, month, day)'' | Jahr zur Kalenderwoche — siehe oben |
| ''IsValidDate'' / ''IsValidTime'' / ''IsValidDateTime'' | kalendarische Prüfung, liefert ''bool'' |
| ''ToUnixTimestamp'' / ''FromUnixTimestamp'' | Gleichheitsabbildung — der Datetime-Wert **ist** der Zeitstempel |
| ''ToMilliseconds'' / ''FromMilliseconds'' | ''× 1000'' bzw. ''/ 1000'' |
import std.datetime;
import std.alloc;
import std.string;
fn J(b: bool): pchar { if (b) { return "gueltig"; } return "ungueltig"; }
fn main(): int64 {
var out: int64 := alloc(256);
var o: pchar := out as pchar;
// Kalenderrechnen
PrintLn(StrConcat("DaysInMonth(2024, 2): ", IntToStr(DaysInMonth(2024, 2))));
PrintLn(StrConcat("DaysInMonth(2026, 2): ", IntToStr(DaysInMonth(2026, 2))));
PrintLn(StrConcat("DaysInMonth(1900, 2): ", IntToStr(DaysInMonth(1900, 2))));
PrintLn(StrConcat("DayOfYear(2026, 8, 13):", IntToStr(DayOfYear(2026, 8, 13))));
PrintLn(StrConcat("WeekNumber(2026, 8, 13):", IntToStr(WeekNumber(2026, 8, 13))));
PrintLn(StrConcat("DiffDays(2026-08-13 -> 2026-12-24): ", IntToStr(DiffDays(2026, 8, 13, 2026, 12, 24))));
// Gueltigkeit
PrintLn(StrConcat("IsValidDate(2026, 2, 29): ", J(IsValidDate(2026, 2, 29))));
PrintLn(StrConcat("IsValidDate(2024, 2, 29): ", J(IsValidDate(2024, 2, 29))));
PrintLn(StrConcat("IsValidTime(24, 0, 0): ", J(IsValidTime(24, 0, 0))));
// Arithmetik am Monatsende
var buf: int64 := alloc(8);
ParseIso("2026-01-31T12:00:00Z"c, buf);
var jan31: int64 := peek64(buf);
FormatIso(AddMonths(jan31, 1), o); PrintLn(StrConcat("31.01. + 1 Monat: ", o));
FormatIso(AddMonths(jan31, 13), o); PrintLn(StrConcat("31.01. + 13 Monate:", o));
FormatIso(AddDays(jan31, 1), o); PrintLn(StrConcat("31.01. + 1 Tag: ", o));
ParseIso("2024-02-29T12:00:00Z"c, buf);
FormatIso(AddYears(peek64(buf), 1), o); PrintLn(StrConcat("29.02.2024 + 1 Jahr:", o));
// Dauer
FormatDuration(93784, o); PrintLn(StrConcat("FormatDuration(93784): ", o));
FormatDurationShort(93784, o); PrintLn(StrConcat("FormatDurationShort(93784): ", o));
FormatDuration(45, o); PrintLn(StrConcat("FormatDuration(45): ", o));
return 0;
}
DaysInMonth(2024, 2): 29
DaysInMonth(2026, 2): 28
DaysInMonth(1900, 2): 28
DayOfYear(2026, 8, 13):225
WeekNumber(2026, 8, 13):33
DiffDays(2026-08-13 -> 2026-12-24): 133
IsValidDate(2026, 2, 29): ungueltig
IsValidDate(2024, 2, 29): gueltig
IsValidTime(24, 0, 0): ungueltig
31.01. + 1 Monat: 2026-02-28T12:00:00Z
31.01. + 13 Monate:2027-02-28T12:00:00Z
31.01. + 1 Tag: 2026-02-01T12:00:00Z
29.02.2024 + 1 Jahr:2025-02-28T12:00:00Z
FormatDuration(93784): 26h 03m 04s
FormatDurationShort(93784): 26:03:04
FormatDuration(45): 45s
Die Schaltjahresregel stimmt bis zur Jahrhundertausnahme (1900 hatte 28 Tage, 2024 hat 29), Wochennummer und Tagesnummer decken sich mit Pythons ''isocalendar()'' und ''timetuple()''.
> **''AddMonths'' klemmt, statt überzulaufen.** 31.01. + 1 Monat ergibt den 28.02., nicht den 03.03. Das ist die übliche Kaufmannsregel — aber **nicht umkehrbar**: ''%%AddMonths(AddMonths(t, 1), -1)%%'' liefert den 28.01., nicht den 31.01. Wer Fristen rechnet, sollte das Ausgangsdatum getrennt aufheben.
----
===== Relative Zeit und Dauer =====
^ Signatur ^ Beispielausgabe ^
| ''FormatRelative(datetime, output)'' | ''2 hours ago'', ''in 3 days'' — gegen die **aktuelle** Zeit |
| ''FormatDuration(seconds, output)'' | ''26h 03m 04s'', ''-26h 03m 04s'', ''12345h'' |
| ''FormatDurationShort(seconds, output)'' | ''26:03:04'', ''-00:45'' |
**Negative Dauern und Dauern ab 1000 Stunden** ergaben bis [[https://github.com/SEOLizer/LyX-Compiler/issues/1605|#1605]] stumm Müllzeichen oder einen Leerstring. Beide Funktionen rechnen jetzt mit dem Betrag und stellen ein ''-'' voran; die Stundenzahl ist nicht mehr auf drei Stellen begrenzt:
FormatDuration(-93784) -> -26h 03m 04s
FormatDuration(1000*3600) -> 1000h
FormatDurationShort(-45) -> -00:45
''FormatRelative'' holt die Gegenwart über ''clock_gettime''; bis lyxc 1.0.17C rechnete es wegen einer nicht gebundenen Zeitquelle gegen die Epoche und lieferte deshalb Abstände von über 50 Jahren (#1179). Die Ausgabe ist **englisch**.
----
===== Zeitzonen =====
^ Signatur ^ Beschreibung ^
| ''GetTimezoneOffset(): int64'' | Versatz zu UTC in Sekunden, aus der Umgebungsvariablen ''TZ'' |
| ''FormatTimezoneOffset(offset_seconds, output)'' | ''+02:00'' / ''-05:00'' |
Ohne gesetztes ''TZ'' ist der Versatz ''0''. ''FormatIso'' und ''FormatRfc2822'' schreiben grundsätzlich UTC (''Z'' bzw. ''+0000'') — der Versatz wirkt nur über den Platzhalter ''%z'' und über ''FormatTimezoneOffset''.
^ ''TZ'' ^ Ergebnis ^
| ''CET-1'' | 3600 |
| ''EST5'' | −18000 |
| ''UTC'' oder nicht gesetzt | 0 |
| ''IST-5:30'' | **18000** statt 19800 |
| ''CET-1CEST,M3.5.0,M10.5.0/3'' | 3600 — Sommerzeitregel bleibt unbeachtet |
> **Der Minutenanteil wird verschluckt.** Zonen mit halber oder viertelstündiger Abweichung — Indien (+05:30), Iran (+03:30), Nepal (+05:45), Neufundland (−03:30), Teile Australiens — bekommen einen falschen Versatz, ohne Fehlermeldung ([[https://github.com/SEOLizer/LyX-Compiler/issues/1416|#1416]]).
>
> **Sommerzeit gibt es nicht.** Eine ''TZ''-Angabe mit Umstellungsregel liefert immer den Standardversatz, unabhängig vom Datum. Wer lokale Zeit anzeigen muss, rechnet den Versatz selbst und behandelt die Umstellung außerhalb dieser Unit.
----
===== Namen =====
^ Signatur ^ Wertebereich ^ Ergebnis ^
| ''WeekdayShort(weekday)'' | 0–6, 0 = Sonntag | ''Mon'' |
| ''WeekdayLong(weekday)'' | 0–6 | ''Monday'' |
| ''MonthShort(month)'' | 1–12 | ''Aug'' |
| ''MonthLong(month)'' | 1–12 | ''August'' |
Alle vier liefern **englische** Namen und geben einen internen Zeiger zurück — nicht freigeben. Den Wochentag zu einem Zeitstempel liefert ''DayOfWeek(dt)'' als Zahl — damit sind ''WeekdayShort'' und ''WeekdayLong'' ohne Umweg über ''Format'' benutzbar. Für Einzelwerte gibt es ''DayOfWeekYmd(year, month, day)''.
----
===== Fallstricke =====
* **Alles ist UTC.** Es gibt keine lokale Zeitrechnung; ''TZ'' wirkt nur über ''%z''.
* **''DiffSeconds(a, b)'' rechnet ''b − a''** — die umgekehrte Reihenfolge der Namen.
* **''FormatDate'' und ''FormatTime'' nehmen Einzelwerte**, keinen Zeitstempel. Wer versehentlich einen Zeitstempel übergibt, bekommt eine Ziffernfolge ohne Fehlermeldung.
* **''ToUnixTimestamp'' und ''FromUnixTimestamp'' tun nichts** — der Datetime-Wert ist bereits der Zeitstempel. Sie stehen nur der Lesbarkeit halber da.
* **Jahr vierstellig — aber kein Müll mehr.** ''FormatDate'' und die ''%Y''-Ausgabe rechnen mit vier Stellen; Jahre außerhalb 1000–9999 fallen seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1605|#1605]] auf die vollständige Zahl in abweichender Breite zurück, statt Steuerzeichen zu erzeugen.
* **Keine Mikrosekunden.** ''%f'' liefert immer ''000000'', ''ToMilliseconds'' multipliziert schlicht mit 1000.
* **Ausgabepuffer großzügig bemessen** — keine ''Format…''-Funktion kennt eine Obergrenze und keine prüft, wie viel Platz vorhanden ist.
----
**Weiterführend:** [[lyx_-_programmiersprache:units:time|std.time — Uhr, Schlafen, Messung]] · [[lyx_-_programmiersprache:units:env|std.env]] · [[lyx_-_programmiersprache:units|Standard Library]]
**Quelle:** ''std/datetime.lyx'' · **Autor:** Andreas Röne · **Copyright:** 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-08-18 — nachgezogen auf ''lyxc 1.1.2E'': neuer Abschnitt „Zeitstempel bauen und zerlegen" ([[https://github.com/SEOLizer/LyX-Compiler/issues/1601|#1601]]), Platzhalter ''%I'', ''%j'' und ''%%'' sowie negativer Rückgabewert bei unbekanntem Spezifizierer ([[https://github.com/SEOLizer/LyX-Compiler/issues/1602|#1602]]), ''ParseFlexible'' mit vier Formaten und vorab genulltem Ziel ([[https://github.com/SEOLizer/LyX-Compiler/issues/1603|#1603]]), Vorzeichen- und Bereichsprüfung der Dauerausgabe ([[https://github.com/SEOLizer/LyX-Compiler/issues/1605|#1605]]), ''FormatLocale'' lokalisiert wirklich ([[https://github.com/SEOLizer/LyX-Compiler/issues/1415|#1415]]).
Vorherige Aktualisierung: 2026-08-13 — Seite gegen ''std/datetime.lyx'' überarbeitet: drei lauffähige Beispiele mit echter Ausgabe (gegen Pythons ''datetime'' geprüft), vollständige Platzhalter-Tabelle für ''Format'', Parser-Erwartungen, Klemmverhalten von ''AddMonths''/''AddYears'', Zeitzonen-Tabelle und Fallstricke. Belegt und als Issue erfasst: ''FormatLocale'' ignoriert den Locale ([[https://github.com/SEOLizer/LyX-Compiler/issues/1415|#1415]]), ''GetTimezoneOffset'' verschluckt den Minutenanteil ([[https://github.com/SEOLizer/LyX-Compiler/issues/1416|#1416]]). Geprüft mit ''lyxc 1.0.21A''.