From 3b76146d532b1ffabedf82b421e3a579af45aebf Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Fri, 24 Apr 2026 17:48:44 +0200 Subject: [PATCH] Implement time conversion routines for Unix and XT epoch formats --- sdk/xtdk/rtlfuncs.h | 12 ++++ xtoskrnl/includes/rtl.hh | 1 + xtoskrnl/includes/rtl/time.hh | 36 ++++++++++ xtoskrnl/rtl/data.cc | 12 ++++ xtoskrnl/rtl/exports.cc | 46 ++++++++++++ xtoskrnl/rtl/time.cc | 129 ++++++++++++++++++++++++++++++++++ xtoskrnl/xtoskrnl.spec | 2 + 7 files changed, 238 insertions(+) create mode 100644 xtoskrnl/includes/rtl/time.hh create mode 100644 xtoskrnl/rtl/time.cc diff --git a/sdk/xtdk/rtlfuncs.h b/sdk/xtdk/rtlfuncs.h index 0d4733a..e68aa72 100644 --- a/sdk/xtdk/rtlfuncs.h +++ b/sdk/xtdk/rtlfuncs.h @@ -297,6 +297,18 @@ BOOLEAN RtlTestBit(IN PRTL_BITMAP BitMap, IN ULONG_PTR Bit); +XTCLINK +XTAPI +XTSTATUS +RtlTimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, + OUT PLONGLONG UnixTime); + +XTCLINK +XTAPI +XTSTATUS +RtlTimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, + OUT PLARGE_INTEGER XtTime); + XTCLINK XTAPI PCHAR diff --git a/xtoskrnl/includes/rtl.hh b/xtoskrnl/includes/rtl.hh index 8b28b89..d293344 100644 --- a/xtoskrnl/includes/rtl.hh +++ b/xtoskrnl/includes/rtl.hh @@ -22,6 +22,7 @@ #include #include #include +#include #include #endif /* __XTOSKRNL_RTL_HH */ diff --git a/xtoskrnl/includes/rtl/time.hh b/xtoskrnl/includes/rtl/time.hh new file mode 100644 index 0000000..00a3e30 --- /dev/null +++ b/xtoskrnl/includes/rtl/time.hh @@ -0,0 +1,36 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/time.hh + * DESCRIPTION: Time conversion support + * DEVELOPERS: Aiken Harris + */ + +#ifndef __XTOSKRNL_RTL_TIME_HH +#define __XTOSKRNL_RTL_TIME_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class Time + { + private: + STATIC CUSHORT DaysInMonth[2][12]; + STATIC CUSHORT DaysPrecedingMonth[2][12]; + + public: + STATIC XTAPI XTSTATUS TimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, + OUT PLONGLONG UnixTime); + STATIC XTAPI XTSTATUS TimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, + OUT PLARGE_INTEGER XtTime); + + private: + STATIC XTFASTCALL BOOLEAN LeapYear(SHORT Year); + + }; +} + +#endif /* __XTOSKRNL_RTL_TIME_HH */ diff --git a/xtoskrnl/rtl/data.cc b/xtoskrnl/rtl/data.cc index 03f2057..6110d38 100644 --- a/xtoskrnl/rtl/data.cc +++ b/xtoskrnl/rtl/data.cc @@ -11,3 +11,15 @@ /* This is required for floating numbers to keep LLVM happy */ XTCLINK INT _fltused = 0xFEEDBULL; + +/* Lookup table for days in a month, Index 0 is normal year, Index 1 is leap year */ +CUSHORT RTL::Time::DaysInMonth[2][12] = { + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} +}; + +/* Lookup table for days preceding a month, Index 0 is normal year, Index 1 is leap year */ +CUSHORT RTL::Time::DaysPrecedingMonth[2][12] = { + {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, + {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} +}; diff --git a/xtoskrnl/rtl/exports.cc b/xtoskrnl/rtl/exports.cc index f5158fd..c2e5f74 100644 --- a/xtoskrnl/rtl/exports.cc +++ b/xtoskrnl/rtl/exports.cc @@ -1033,6 +1033,52 @@ RtlTestBit(IN PRTL_BITMAP BitMap, return RTL::BitMap::TestBit(BitMap, Bit); } +/** + * Converts a TIME_FIELDS calendar structure to a 64-bit Unix timestamp. + * + * @param TimeFields + * Supplies a pointer to a fully populated TIME_FIELDS structure. + * + * @param UnixTime + * Supplies a pointer to a 64-bit integer that receives the number of + * seconds elapsed since January 1, 1970. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCLINK +XTAPI +XTSTATUS +RtlTimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, + OUT PLONGLONG UnixTime) +{ + return RTL::Time::TimeFieldsToUnixEpoch(TimeFields, UnixTime); +} + +/** + * Converts a TIME_FIELDS calendar structure to a 64-bit XT timestamp. + * + * @param TimeFields + * Supplies a pointer to a fully populated TIME_FIELDS structure. + * + * @param Time + * Supplies a pointer to variable that receives the converted time value in 100-nanosecond + * intervals since January 1, 1601. + * + * @return This routine returns the status code. + * + * @since XT 1.0 + */ +XTCLINK +XTAPI +XTSTATUS +RtlTimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, + OUT PLARGE_INTEGER XtTime) +{ + return RTL::Time::TimeFieldsToXtEpoch(TimeFields, XtTime); +} + /** * Finds the next token in a NULL-terminated string. * diff --git a/xtoskrnl/rtl/time.cc b/xtoskrnl/rtl/time.cc new file mode 100644 index 0000000..0d6cfb0 --- /dev/null +++ b/xtoskrnl/rtl/time.cc @@ -0,0 +1,129 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/time.cc + * DESCRIPTION: Time conversion support + * DEVELOPERS: Aiken Harris + */ + +#include + + +/** + * Determines if a given year is a leap year in the Gregorian calendar. + * + * @param Year + * Supplies the year to be checked. + * + * @return This routine returns TRUE if the year is a leap year, FALSE otherwise. + * + * @since XT 1.0 + */ +XTFASTCALL +BOOLEAN +RTL::Time::LeapYear(SHORT Year) +{ + return ((Year % 4 == 0 && Year % 100 != 0) || (Year % 400 == 0)) ? TRUE : FALSE; +} + +/** + * Converts a TIME_FIELDS calendar structure to a 64-bit Unix timestamp. + * + * @param TimeFields + * Supplies a pointer to a fully populated TIME_FIELDS structure. + * + * @param UnixTime + * Supplies a pointer to a 64-bit integer that receives the number of + * seconds elapsed since January 1, 1970. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::Time::TimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, + OUT PLONGLONG UnixTime) +{ + LONGLONG TotalSeconds; + LARGE_INTEGER XtTime; + XTSTATUS Status; + + /* Convert to XT Epoch */ + Status = TimeFieldsToXtEpoch(TimeFields, &XtTime); + if(Status != STATUS_SUCCESS) + { + /* Failed to convert to XT Epoch, return error code */ + return Status; + } + + /* Convert 100-nanosecond intervals (TICKS) to whole seconds */ + TotalSeconds = XtTime.QuadPart / TICKS_PER_SECOND; + + /* Subtract the number of seconds between January 1, 1601 and January 1, 1970 */ + *UnixTime = TotalSeconds - 11644473600LL; + + /* Return success */ + return STATUS_SUCCESS; +} + +/** + * Converts a TIME_FIELDS calendar structure to a 64-bit XT timestamp. + * + * @param TimeFields + * Supplies a pointer to a fully populated TIME_FIELDS structure. + * + * @param Time + * Supplies a pointer to variable that receives the converted time value in 100-nanosecond + * intervals since January 1, 1601. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +RTL::Time::TimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, + OUT PLARGE_INTEGER XtTime) +{ + ULONG Leap, ElapsedYears, ElapsedDays; + ULONGLONG TotalSeconds; + + /* Check leap year */ + Leap = LeapYear(TimeFields->Year) ? 1 : 0; + + /* Validate input data */ + if(TimeFields->Hour < 0 || TimeFields->Hour > 23 || + TimeFields->Minute < 0 || TimeFields->Minute > 59 || + TimeFields->Second < 0 || TimeFields->Second > 59 || + TimeFields->Milliseconds < 0 || TimeFields->Milliseconds > 999 || + TimeFields->Year < 1601 || TimeFields->Year > 30827 || + TimeFields->Month < 1 || TimeFields->Month > 12 || + TimeFields->Day < 1 || TimeFields->Day > DaysInMonth[Leap][TimeFields->Month - 1]) + { + /* Invalid input data, return error code */ + return STATUS_INVALID_PARAMETER; + } + + /* Calculate days elapsed in previous years */ + ElapsedYears = (ULONG)(TimeFields->Year - 1601); + ElapsedDays = (ElapsedYears * 365) + (ElapsedYears / 4) - (ElapsedYears / 100) + (ElapsedYears / 400); + + /* Add days elapsed in previous months of the current year */ + ElapsedDays += DaysPrecedingMonth[Leap][TimeFields->Month - 1]; + + /* Add days elapsed in the current month */ + ElapsedDays += (TimeFields->Day - 1); + + /* Calculate a total number of seconds */ + TotalSeconds = ((ULONGLONG)ElapsedDays * SECONDS_PER_DAY) + + ((ULONGLONG)TimeFields->Hour * SECONDS_PER_HOUR) + + ((ULONGLONG)TimeFields->Minute * SECONDS_PER_MINUTE) + + (ULONGLONG)TimeFields->Second; + + /* Convert to 100-ns intervals and slap milliseconds on top */ + Time->QuadPart = (TotalSeconds * TICKS_PER_SECOND) + ((ULONGLONG)TimeFields->Milliseconds * TICKS_PER_MILLISECOND); + + /* Return success */ + return STATUS_SUCCESS; +} diff --git a/xtoskrnl/xtoskrnl.spec b/xtoskrnl/xtoskrnl.spec index 8be25b5..433be95 100644 --- a/xtoskrnl/xtoskrnl.spec +++ b/xtoskrnl/xtoskrnl.spec @@ -90,6 +90,8 @@ @ stdcall RtlStringLength(str long) @ stdcall RtlStringToWideString(wstr str long) @ stdcall RtlTestBit(ptr long) +@ stdcall RtlTimeFieldsToUnixEpoch(ptr ptr) +@ stdcall RtlTimeFieldsToXtEpoch(ptr ptr) @ stdcall RtlTokenizeString(str str str) @ stdcall RtlTokenizeWideString(wstr wstr wstr) @ stdcall RtlToLowerCharacter(long)