From 439ea891ca9e6f7ac24633ea4293ae96a98deb1a Mon Sep 17 00:00:00 2001 From: Aiken Harris Date: Fri, 24 Apr 2026 23:27:25 +0200 Subject: [PATCH] Replace lookup-based time logic with direct epoch calculation formulas --- xtoskrnl/includes/rtl/time.hh | 1 - xtoskrnl/rtl/data.cc | 6 --- xtoskrnl/rtl/time.cc | 87 ++++++++++++++++++++++++----------- 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/xtoskrnl/includes/rtl/time.hh b/xtoskrnl/includes/rtl/time.hh index 00a3e30..c28c042 100644 --- a/xtoskrnl/includes/rtl/time.hh +++ b/xtoskrnl/includes/rtl/time.hh @@ -19,7 +19,6 @@ namespace RTL { private: STATIC CUSHORT DaysInMonth[2][12]; - STATIC CUSHORT DaysPrecedingMonth[2][12]; public: STATIC XTAPI XTSTATUS TimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, diff --git a/xtoskrnl/rtl/data.cc b/xtoskrnl/rtl/data.cc index 6110d38..16bb0dd 100644 --- a/xtoskrnl/rtl/data.cc +++ b/xtoskrnl/rtl/data.cc @@ -17,9 +17,3 @@ 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/time.cc b/xtoskrnl/rtl/time.cc index c8eb36b..350aeee 100644 --- a/xtoskrnl/rtl/time.cc +++ b/xtoskrnl/rtl/time.cc @@ -45,23 +45,49 @@ XTSTATUS RTL::Time::TimeFieldsToUnixEpoch(IN PTIME_FIELDS TimeFields, OUT PLONGLONG UnixTime) { - LONGLONG TotalSeconds; - LARGE_INTEGER XtTime; - XTSTATUS Status; + LONGLONG ElapsedDays, TotalSeconds; + LONG Month, Year; + ULONG Leap; - /* Convert to XT Epoch */ - Status = TimeFieldsToXtEpoch(TimeFields, &XtTime); - if(Status != STATUS_SUCCESS) + /* Check leap year */ + Leap = LeapYear(TimeFields->Year) ? 1 : 0; + + /* 2. Validate input data */ + if(TimeFields->Hour < 0 || TimeFields->Hour > 23 || + TimeFields->Minute < 0 || TimeFields->Minute > 59 || + TimeFields->Second < 0 || TimeFields->Second > 59 || + TimeFields->Year < 0 || TimeFields->Year > 30827 || + TimeFields->Month < 1 || TimeFields->Month > 12 || + TimeFields->Day < 1 || TimeFields->Day > DaysInMonth[Leap][TimeFields->Month - 1]) { - /* Failed to convert to XT Epoch, return error code */ - return Status; + /* Invalid input data, return error code */ + return STATUS_INVALID_PARAMETER; } - /* Convert 100-nanosecond intervals (TICKS) to whole seconds */ - TotalSeconds = XtTime.QuadPart / TIME_TICKS_PER_SECOND; + /* Copy year and month */ + Year = (LONG)TimeFields->Year; + Month = (LONG)TimeFields->Month; - /* Subtract the number of seconds between January 1, 1601 and January 1, 1970 */ - *UnixTime = TotalSeconds - 11644473600LL; + /* Put February at the end of the calculation cycle, making leap day handling implicit in the year division */ + if(0 >= (LONG)(Month -= 2)) + { + /* Adjust month and year */ + Month += 12; + Year -= 1; + } + + /* Calculate absolute elapsed days */ + ElapsedDays = (LONGLONG)(Year/4 - Year/100 + Year/400 + 367*Month/12 + TimeFields->Day) + + (LONGLONG)Year*365 - 719499LL; + + /* Calculate total seconds */ + TotalSeconds = (ElapsedDays * TIME_SECONDS_PER_DAY) + + ((LONGLONG)TimeFields->Hour * TIME_SECONDS_PER_HOUR) + + ((LONGLONG)TimeFields->Minute * TIME_SECONDS_PER_MINUTE) + + (LONGLONG)TimeFields->Second; + + /* Output the final Unix timestamp */ + *UnixTime = TotalSeconds; /* Return success */ return STATUS_SUCCESS; @@ -86,8 +112,9 @@ XTSTATUS RTL::Time::TimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, OUT PLARGE_INTEGER XtTime) { - ULONG Leap, ElapsedYears, ElapsedDays; - ULONGLONG TotalSeconds; + LONGLONG ElapsedDays, TotalSeconds; + LONG Month, Year; + ULONG Leap; /* Check leap year */ Leap = LeapYear(TimeFields->Year) ? 1 : 0; @@ -105,25 +132,31 @@ RTL::Time::TimeFieldsToXtEpoch(IN PTIME_FIELDS TimeFields, return STATUS_INVALID_PARAMETER; } - /* Calculate days elapsed in previous years */ - ElapsedYears = (ULONG)(TimeFields->Year - 1601); - ElapsedDays = (ElapsedYears * 365) + (ElapsedYears / 4) - (ElapsedYears / 100) + (ElapsedYears / 400); + /* Copy year and month */ + Year = (LONG)TimeFields->Year; + Month = (LONG)TimeFields->Month; - /* Add days elapsed in previous months of the current year */ - ElapsedDays += DaysPrecedingMonth[Leap][TimeFields->Month - 1]; + /* Put February at the end of the calculation cycle, making leap day handling implicit in the year division */ + if(0 >= (LONG)(Month -= 2)) + { + /* Adjust month and year */ + Month += 12; + Year -= 1; + } - /* Add days elapsed in the current month */ - ElapsedDays += (TimeFields->Day - 1); + /* Calculate absolute elapsed days */ + ElapsedDays = (LONGLONG)(Year/4 - Year/100 + Year/400 + 367*Month/12 + TimeFields->Day) + + (LONGLONG)Year*365 - 584725LL; - /* Calculate a total number of seconds */ - TotalSeconds = ((ULONGLONG)ElapsedDays * TIME_SECONDS_PER_DAY) + - ((ULONGLONG)TimeFields->Hour * TIME_SECONDS_PER_HOUR) + - ((ULONGLONG)TimeFields->Minute * TIME_SECONDS_PER_MINUTE) + - (ULONGLONG)TimeFields->Second; + /* Calculate total seconds */ + TotalSeconds = (ElapsedDays * TIME_SECONDS_PER_DAY) + + ((LONGLONG)TimeFields->Hour * TIME_SECONDS_PER_HOUR) + + ((LONGLONG)TimeFields->Minute * TIME_SECONDS_PER_MINUTE) + + (LONGLONG)TimeFields->Second; /* Convert to 100-ns intervals and slap milliseconds on top */ XtTime->QuadPart = (TotalSeconds * TIME_TICKS_PER_SECOND) + - ((ULONGLONG)TimeFields->Milliseconds * TIME_TICKS_PER_MILLISECOND); + ((LONGLONG)TimeFields->Milliseconds * TIME_TICKS_PER_MILLISECOND); /* Return success */ return STATUS_SUCCESS;