警告 C26861
日付/時刻オブジェクト
var
のフィールドが、適切な閏年チェックせずに変更されました。expr
この規則は、Visual Studio 2022 17.8 で追加されました。
解説
グレゴリオ暦では、毎年 4 で正確に割り切れる年は閏年です。ただし、100 で正確に割り切れる年を除きます。 百年も閏年は、400 で正確に割り切れる場合です。
閏年のバグは、ソフトウェアがこの閏年ロジックを考慮しない場合、または欠陥のあるロジックを使用する場合に発生します。 信頼性、可用性、または影響を受けるシステムのセキュリティに影響を与える可能性があります。
閏年を考慮せずに、日付/時刻オブジェクトの年、月、または日のフィールドに対して数値を加算または減算しても安全ではありません。 この計算は、たとえば、証明書の有効期限を決定するために一般的に実行されます。 多くの日付では、単純な計算で目的の結果が生成される場合があります。 ただし、結果が 2 月 29 日 (閏日) で、その年が閏年でない場合、結果は無効になります。
たとえば、年を 2020-01-31 に追加すると、2021-01-31 が生成されます。 ただし、2020-02-29 に年を追加すると 2021-02-29 が生成されます。これは、2021 が閏年ではないので有効な日付ではありません。
日付値を表す変数を操作するときは注意してください。 閏年と閏日を適切に処理するか、日付の算術演算を安全に処理する API またはライブラリを使用します。
コード分析名: DATETIME_MANIPULATION_WITHOUT_LEAPYEAR_CHECK
例
次のコードは、システム時刻を表す日付/時刻オブジェクトの年フィールドをインクリメントすることによって、システム時刻を年単位で進めます。 ただし、次の年は閏年ではないので、変更前の日付が 2 月 29 日であった場合は、無効な日時オブジェクトが生成される可能性があります。
SYSTEMTIME st;
GetSystemTime(&st);
st.wYear++; // warning C26861
閏年が原因で無効な日時オブジェクトが作成されないようにするには、次の例のように、結果の日付がまだ有効かどうかをチェックし、有効にするために必要な調整を行います。
SYSTEMTIME st;
GetSystemTime(&st);
st.wYear++;
if (st.wMonth == 2 && st.wDay == 29)
{
// move back a day when landing on Feb 29 in a non-leap year
bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
if (!isLeapYear)
{
st.wDay = 28;
}
}
ヒューリスティック
現時点では、この規則は Windows SYSTEMTIME
構造体と C tm
構造体のみを認識します。
このルールでは、簡略化されたヒューリスティックを使用して、リスクの高い可能性のある変更を検出し、適切な閏年または閏日のチェックがない限り警告を報告します。 変更された日時オブジェクトに対して閏年または閏日チェックが正しく実行されているかどうかを確認しようとはしません。
このルールはオプトイン ルールです。つまり、コード分析ではルール セット ファイルを使用する必要があり、ルールはルール セット ファイルに明示的に含め、適用できるように有効にする必要があります。 コード分析用のカスタム ルールセットの作成の詳細については、「ルール セットを使用して実行するルールをC++
指定する」を参照してください。