@@ -278,6 +278,28 @@ _PyTime_AsCLong(PyTime_t t, long *t2)
278278#define SECS_BETWEEN_EPOCHS 11644473600LL /* Seconds between 1601-01-01 and 1970-01-01 */
279279#define HUNDRED_NS_PER_SEC 10000000LL
280280
281+ // Calculate day of year (0-365) from SYSTEMTIME
282+ static int
283+ _PyTime_calc_yday (const SYSTEMTIME * st )
284+ {
285+ // Cumulative days before each month (non-leap year)
286+ static const int days_before_month [] = {
287+ 0 , 31 , 59 , 90 , 120 , 151 , 181 , 212 , 243 , 273 , 304 , 334
288+ };
289+ int yday = days_before_month [st -> wMonth - 1 ] + st -> wDay - 1 ;
290+ // Account for leap day if we're past February in a leap year.
291+ if (st -> wMonth > 2 ) {
292+ // Leap year rules (Gregorian calendar):
293+ // - Years divisible by 4 are leap years
294+ // - EXCEPT years divisible by 100 are NOT leap years
295+ // - EXCEPT years divisible by 400 ARE leap years
296+ int year = st -> wYear ;
297+ int is_leap = (year % 4 == 0 && year % 100 != 0 ) || (year % 400 == 0 );
298+ yday += is_leap ;
299+ }
300+ return yday ;
301+ }
302+
281303// Convert time_t to struct tm using Windows FILETIME API.
282304// If is_local is true, convert to local time. */
283305// Fallback for negative timestamps that localtime_s/gmtime_s cannot handle.
@@ -325,28 +347,9 @@ _PyTime_windows_filetime(time_t timer, struct tm *tm, int is_local)
325347 tm -> tm_sec = st_result .wSecond ;
326348 tm -> tm_wday = st_result .wDayOfWeek ; /* 0=Sunday */
327349
328- /* Calculate day of year using Windows FILETIME difference */
329- // SYSTEMTIME st_jan1 = {st_result.wYear, 1, 0, 1, 0, 0, 0, 0};
330- // FILETIME ft_jan1, ft_date;
331- // if (!SystemTimeToFileTime(&st_jan1, &ft_jan1) ||
332- // !SystemTimeToFileTime(&st_result, &ft_date)) {
333- // PyErr_SetFromWindowsErr(0);
334- // return -1;
335- // }
336- // ULARGE_INTEGER jan1, date;
337- // jan1.LowPart = ft_jan1.dwLowDateTime;
338- // jan1.HighPart = ft_jan1.dwHighDateTime;
339- // date.LowPart = ft_date.dwLowDateTime;
340- // date.HighPart = ft_date.dwHighDateTime;
341- // /* Convert 100-nanosecond intervals to days */
342- // LONGLONG days_diff = (date.QuadPart - jan1.QuadPart) / (24LL * 60 * 60 * HUNDRED_NS_PER_SEC);
343-
344- // tm->tm_yday = (int)days_diff;
345-
346- // datetime doesn't rely on tm_yday, so set invalid value and skip calculation
347- // time.gmtime / time.localtime will return struct_time with out of range tm_yday
348- // time.mktime doesn't support pre-epoch struct_time on windows anyway
349- tm -> tm_yday = -1 ;
350+ // `time.gmtime` and `time.localtime` will return `struct_time` containing this
351+ // not currently used by `datetime` module
352+ tm -> tm_yday = _PyTime_calc_yday (& st_result );
350353
351354 /* DST flag: -1 (unknown) for local time on historical dates, 0 for UTC */
352355 tm -> tm_isdst = is_local ? -1 : 0 ;
0 commit comments