首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

巧用 Windows API 計算任意日期星期幾:SystemTime 與 SetSystemTime 技巧

     編輯:關於C++

核心思路:借用系統日期時間轉換功能

Windows API GetSystemTime/SetSystemTime 可存取系統即時時鐘。SYSTEMTIME 結構包含 wDayOfWeek 欄位 (0=星期日 ... 6=星期六)。我們可暫時修改系統時間為目標日期,讀取 wDayOfWeek,再還原系統時間,即得星期幾。此法避免自行實作 Zeller 公式等演算法。

完整實作 (C++Builder / Win32 API)


void __fastcall TForm1::Button1Click(TObject *Sender)
{
    const char* WeekName[7] = {
        "星期日", "星期一", "星期二", "星期三",
        "星期四", "星期五", "星期六"
    };

    SYSTEMTIME Now, Tmp;
    GetSystemTime(&Now);           // 備份目前系統時間

    // 設定欲查詢的目標日期時間 (任意合法值)
    Tmp.wYear         = 2024;      // 年
    Tmp.wMonth        = 12;        // 月
    Tmp.wDay          = 25;        // 日
    Tmp.wHour         = 12;        // 時 (建議非 0 避免邊界問題)
    Tmp.wMinute       = 0;
    Tmp.wSecond       = 0;
    Tmp.wMilliseconds = 0;

    // 嘗試設定系統時間 (需管理員權限)
    if (SetSystemTime(&Tmp)) {
        GetSystemTime(&Tmp);       // 讀回系統時間 (含 wDayOfWeek)
        ShowMessage(WeekName[Tmp.wDayOfWeek]);
    } else {
        DWORD err = GetLastError();
        ShowMessage("設定失敗,錯誤碼: " + IntToStr(err) +
                    (err == 87 ? " (參數錯誤,檢查日期合法性)" : ""));
    }

    SetSystemTime(&Now);           // 還原系統時間 (需管理員權限)
}

關鍵注意事項

權限需求系統影響日期合法性執行緒安全時區
項目說明
SetSystemTime 需 管理員權限 (Vista+ UAC)。普通使用者執行會失敗 (ERROR_ACCESS_DENIED = 5)。
暫時修改系統時間會影響所有執行中程式的時間相關操作 (日誌、定時器、SSL 憑證驗證等)。極不建議在生產環境使用。
傳入非法日期 (如 2 月 30 日) 會導致 SetSystemTime 失敗,回傳 ERROR_INVALID_PARAMETER (87)。
多執行緒同時呼叫會互相干擾系統時間。
SYSTEMTIME 為 UTC 時間,wDayOfWeek 同 UTC。若需本地時區星期,請用 GetLocalTime/SetLocalTime (同樣需管理員權限)。

更佳替代方案:純演算法計算 (無副作用、無權限需求)

Zeller 同餘公式 (Gregorian 曆)


int DayOfWeek(int year, int month, int day) {
    if (month < 3) { month += 12; year--; }
    int c = year / 100;
    int y = year % 100;
    int w = (y + y/4 + c/4 - 2*c + 26*(month+1)/10 + day - 1) % 7;
    return (w + 7) % 7; // 0=週日 ... 6=週六
}

C++11 <chrono> (現代標準庫)


#include 
#include 

int DayOfWeekModern(int y, int m, int d) {
    using namespace std::chrono;
    auto dp = year_month_day{year(y), month(m), day(d)};
    auto wd = weekday{dp};
    return (static_cast(wd) + 6) % 7; // 0=週日
}

Windows API GetDateFormat (無需改系統時間)


int GetDayOfWeekAPI(int year, int month, int day) {
    SYSTEMTIME st = {0};
    st.wYear = year; st.wMonth = month; st.wDay = day;
    char buf[16];
    GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, "ddd", buf, 16);
    // buf 為 "Sun", "Mon" 等,需映射表轉數字
    // 較繁瑣,不推薦
}

總結與建議

  • 教學/測試用:SetSystemTime 技巧展示 Windows 日期時間結構與系統服務互動,理解 SYSTEMTIME.wDayOfWeek 來源。
  • 實際專案:嚴禁使用修改系統時間法。請採用 Zeller 公式、C++11 <chrono>、Boost.Date_Time 或 Howard Hinnant 的 date.h 單一標頭庫,皆為純計算、執行緒安全、無權限需求、跨平台。
  • 歷史遺產:此技巧源自早期 DOS/Win16 時代無標準庫支援時期,現已屬反模式。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved