Редагувати

Поділитися через


Warning C26864

Day field of a date-time object var has been modified assuming 365 days per year without proper leap year checking: expr

This rule was added in Visual Studio 2022 17.8.

Remarks

In the Gregorian calendar, every year exactly divisible by four is a leap year--except for years that are exactly divisible by 100. The centurial years are also leap years if they're exactly divisible by 400.

A leap year bug occurs when software doesn't account for this leap year logic, or uses flawed logic. The can affect reliability, availability, or even the security of the affected system.

You must take leap years into account when you perform arithmetic operations on a variable that represents a date. It's not safe to assume that a year is 365 days long. A leap year has 366 days because of the 'leap day' added as a 29th day in February.

To correctly advance a year, determine whether the time span contains a leap day, then perform the calculation using the correct number of days. It's better if the year is directly advanced, with an appropriate leap day check on the resulting date. Alternatively, use an established library routine that handles leap years correctly.

Code analysis name: DATETIME_MANIPULATION_ASSUMING_365_DAYS_WITHOUT_LEAPYEAR_CHECK

Example

The following code tries to get current system time, advance the day by one year by adding 365 days to the day field, and adjusting the date per leap year rule. However, the result may not fall on the same month/date of the next year:

#include <Windows.h> 
 
void foo() 
{ 
    SYSTEMTIME st; 

    GetSystemTime(&st); 

    // Advance a year by adding 365 days 
    st.wDay += 365;    // C26864 
}

To fix this problem, advance the year field directly and adjust the date per the leap year rule:

#include <Windows.h> 
 
void foo() 
{ 
    SYSTEMTIME st; 
    GetSystemTime(&st); 

    st.wYear++; // Advance a year 

    // Adjust the date
    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; 
        } 
    } 
}

Heuristics

This rule only recognizes the Windows SYSTEMTIME struct and C tm struct.

This rule is enforced if the date field is directly modified by 365 days. It doesn't consider if the value of date field is assigned to another variable and then manipulated, and so can miss equivalent mistakes.

This rule is an opt-in rule, meaning that code analysis should use a ruleset file, and the rule should be explicitly included in the ruleset file, and enabled for it to be applied. For more information on creating a custom ruleset for code analysis, see Use Rule Sets to Specify the C++ Rules to Run.

See also

C6393
C6394
C26861
C26862
C26863