Unsafe year argument for ‘DateTime’ constructor¶
ID: cs/unsafe-year-construction
Kind: path-problem
Security severity:
Severity: warning
Precision: medium
Tags:
- quality
- reliability
- correctness
Query suites:
- csharp-security-and-quality.qls
Click to see the query in the CodeQL repository
When creating a System.DateTime object by setting the year, month, and day in the constructor by performing an arithmetic operation on a different DateTime object, there is a risk that the date you are setting is invalid.
On a leap year, such code may throw an ArgumentOutOfRangeException with a message of "Year, Month, and Day parameters describe an unrepresentable DateTime."
Recommendation¶
Creating a System.DateTime object based on a different System.DateTime object, use the appropriate methods to manipulate the date instead of arithmetic.
Example¶
In this example, we are incrementing/decrementing the current date by one year when creating a new System.DateTime object. This may work most of the time, but on any given February 29th, the resulting value will be invalid.
using System;
public class UnsafeYearConstructionBad
{
public UnsafeYearConstructionBad()
{
DateTime Start;
DateTime End;
var now = DateTime.UtcNow;
// the base-date +/- n years may not be a valid date.
Start = new DateTime(now.Year - 1, now.Month, now.Day, 0, 0, 0, DateTimeKind.Utc);
End = new DateTime(now.Year + 1, now.Month, now.Day, 0, 0, 1, DateTimeKind.Utc);
}
}
To fix this bug, we add/subtract years to the current date by calling AddYears method on it.
using System;
public class UnsafeYearConstructionGood
{
public UnsafeYearConstructionGood()
{
DateTime Start;
DateTime End;
var now = DateTime.UtcNow;
Start = now.AddYears(-1).Date;
End = now.AddYears(-1).Date.AddSeconds(1);
}
}