#ifndef YAMA_SCHEDULER_H #define YAMA_SCHEDULER_H #include // 调度模式定义 #define SCH_MODE_NONE 0 // 默认模式:不自动执行 (仅手动) #define SCH_MODE_STARTUP 1 // 启动执行模式 #define SCH_MODE_DAILY 2 // 每日定时模式 #define SCH_MODE_WEEKLY 3 // 每周定时模式 #define SCH_MODE_MONTHLY 4 // 每月定时模式 #define SCH_MODE_YEARLY 5 // 每年定时模式 #define SCH_MODE_OFF 6 // 关闭 #pragma pack(push, 1) // 严格定义 16 字节结构 typedef struct { unsigned char Mode; // [1 字节] 0=None, 1=Startup, 2=Daily... unsigned char Flags; // [1 字节] 标志位 (bit0:禁用) union { // Mode 1: 启动执行 + 间隔控制 struct { unsigned int Interval; } Startup; // Mode 2 & 3: 定时模式 struct { unsigned short TargetMin; unsigned char DaysMask; unsigned char Reserved; } Timed; } Config; uint64_t LastRunTime; unsigned char CurrentCount; unsigned char MaxCount; } ScheduleParams; #pragma pack(pop) #ifdef _WIN32 #include class YamaTaskEngine { public: static bool ShouldExecute(const ScheduleParams* p) { // --- 1. 默认与基础拦截 --- if (p->Mode == SCH_MODE_OFF) return false; if (p->Mode == SCH_MODE_NONE) return false; // Mode为0,默认不执行 if (p->Flags & 0x01) return false; // 显式禁用拦截 if (p->MaxCount > 0 && p->CurrentCount >= p->MaxCount) return false; unsigned __int64 now = GetCurrentFT(); // --- 2. 启动执行模式 (Mode 1) --- if (p->Mode == SCH_MODE_STARTUP) { // 检查时间间隔限制 if (p->Config.Startup.Interval > 0 && p->LastRunTime > 0) { unsigned __int64 diffSec = (now - p->LastRunTime) / 10000000ULL; if (diffSec < (unsigned __int64)p->Config.Startup.Interval) { return false; } } return true; } // --- 3. 每日定时逻辑 (Mode 2) --- if (p->Mode == SCH_MODE_DAILY) { SYSTEMTIME st; GetLocalTime(&st); unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute); // TargetMin=0 表示 0:00 执行 if (curMin >= p->Config.Timed.TargetMin) { if (!IsSameDay(p->LastRunTime, now)) return true; } return false; } // --- 4. 每周定时逻辑 (Mode 3) --- if (p->Mode == SCH_MODE_WEEKLY) { SYSTEMTIME st; GetLocalTime(&st); unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute); // DaysMask=0 表示周日 (wDayOfWeek: 0=周日, 1=周一, ...) unsigned char targetDay = p->Config.Timed.DaysMask; if (st.wDayOfWeek == targetDay && curMin >= p->Config.Timed.TargetMin) { if (!IsSameWeek(p->LastRunTime, now)) return true; } return false; } // --- 5. 每月定时逻辑 (Mode 4) --- if (p->Mode == SCH_MODE_MONTHLY) { SYSTEMTIME st; GetLocalTime(&st); unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute); // DaysMask=0 表示每月第 1 天 unsigned char targetDay = p->Config.Timed.DaysMask == 0 ? 1 : p->Config.Timed.DaysMask; if (st.wDay == targetDay && curMin >= p->Config.Timed.TargetMin) { if (!IsSameMonth(p->LastRunTime, now)) return true; } return false; } // --- 6. 每年定时逻辑 (Mode 5) --- if (p->Mode == SCH_MODE_YEARLY) { SYSTEMTIME st; GetLocalTime(&st); unsigned short curMin = (unsigned short)(st.wHour * 60 + st.wMinute); // DaysMask=0, Reserved=0 表示 1月1日 unsigned char targetMonth = p->Config.Timed.DaysMask == 0 ? 1 : p->Config.Timed.DaysMask; unsigned char targetDay = p->Config.Timed.Reserved == 0 ? 1 : p->Config.Timed.Reserved; if (st.wMonth == targetMonth && st.wDay == targetDay && curMin >= p->Config.Timed.TargetMin) { if (!IsSameYear(p->LastRunTime, now)) return true; } return false; } return false; } static void MarkExecuted(ScheduleParams* p) { p->LastRunTime = GetCurrentFT(); if (p->MaxCount > 0 && p->CurrentCount < 255) { p->CurrentCount++; } } private: static unsigned __int64 GetCurrentFT() { FILETIME ft; GetSystemTimeAsFileTime(&ft); return ((unsigned __int64)ft.dwHighDateTime << 32) | ft.dwLowDateTime; } static bool IsSameDay(unsigned __int64 ft1, unsigned __int64 ft2) { if (ft1 == 0 || ft2 == 0) return false; SYSTEMTIME st1, st2; FTToST(ft1, &st1); FTToST(ft2, &st2); return (st1.wYear == st2.wYear && st1.wMonth == st2.wMonth && st1.wDay == st2.wDay); } static bool IsSameWeek(unsigned __int64 ft1, unsigned __int64 ft2) { if (ft1 == 0 || ft2 == 0) return false; // 转换为本地时间的天数,再判断是否在同一周 SYSTEMTIME st1, st2; FTToST(ft1, &st1); FTToST(ft2, &st2); // 计算两个日期各自所在周的周日日期,相同则同一周 int days1 = DaysSinceEpoch(st1.wYear, st1.wMonth, st1.wDay); int days2 = DaysSinceEpoch(st2.wYear, st2.wMonth, st2.wDay); // 回退到本周周日 (wDayOfWeek: 0=周日) int weekStart1 = days1 - st1.wDayOfWeek; int weekStart2 = days2 - st2.wDayOfWeek; return (weekStart1 == weekStart2); } static bool IsSameMonth(unsigned __int64 ft1, unsigned __int64 ft2) { if (ft1 == 0 || ft2 == 0) return false; SYSTEMTIME st1, st2; FTToST(ft1, &st1); FTToST(ft2, &st2); return (st1.wYear == st2.wYear && st1.wMonth == st2.wMonth); } static bool IsSameYear(unsigned __int64 ft1, unsigned __int64 ft2) { if (ft1 == 0 || ft2 == 0) return false; SYSTEMTIME st1, st2; FTToST(ft1, &st1); FTToST(ft2, &st2); return (st1.wYear == st2.wYear); } static void FTToST(unsigned __int64 ft, SYSTEMTIME* pSt) { FILETIME ftUtc, ftLocal; ftUtc.dwLowDateTime = (DWORD)ft; ftUtc.dwHighDateTime = (DWORD)(ft >> 32); FileTimeToLocalFileTime(&ftUtc, &ftLocal); FileTimeToSystemTime(&ftLocal, pSt); } // 简易计算从某基准日开始的天数 (用于周计算) static int DaysSinceEpoch(int year, int month, int day) { // 简化算法:相对于 2000-01-01 的天数 int y = year - 2000; int leapYears = (y > 0) ? ((y - 1) / 4 - (y - 1) / 100 + (y - 1) / 400 + 1) : 0; int days = y * 365 + leapYears; static const int daysBeforeMonth[] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; days += daysBeforeMonth[month - 1] + day - 1; // 闰年 2 月后加 1 天 if (month > 2 && IsLeapYear(year)) days++; return days; } static bool IsLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); } }; #endif #endif