Thanks, this makes sense. I agree there is a real gap here, because DateTime currently lets you read components and add/subtract time, but it does not give an easy way to create a new DateTime from specific components.
I am not sure SetYear / SetMonth is the right approach though, because DateTime behaves like a value type. Set... sounds like it mutates the existing value, but the API should probably return a new DateTime.
A possible API would be shared factories:
DateTime.FromComponents(year As Integer, month As Integer, day As Integer) As DateTime
DateTime.FromComponents(year As Integer, month As Integer, day As Integer, hour As Integer, minute As Integer, second As Integer) As DateTime
DateTime.FromComponents(year As Integer, month As Integer, day As Integer, hour As Integer, minute As Integer, second As Integer, millisecond As Integer) As DateTime
And perhaps convenience methods that copy the existing value but replace one part:
d.WithYear(year As Integer) As DateTime
d.WithMonth(month As Integer) As DateTime
d.WithDay(day As Integer) As DateTime
d.WithDate(year As Integer, month As Integer, day As Integer) As DateTime
d.WithTime(hour As Integer, minute As Integer, second As Integer) As DateTime
So your example would become:
Var now As DateTime = DateTime.Now
Var changed As DateTime = now.WithYear(2000)
For invalid dates, I think these should throw an InvalidArgument error rather than silently guessing. For example, changing 2024-02-29 to year 2025 is ambiguous: should that become 2025-02-28, 2025-03-01, or fail? My instinct is that the standard library should fail, and user code can decide how to recover.
What do others think? Is WithYear / WithDate clearer than SetYear, and should invalid dates throw or clamp?