Search code examples
c#exceptionevent-handlingdatetimepicker

How can I make a date time picker always contain the last day of the month while showing month and year only?


I have a DateTimePicker which I have set to only show the month and year as follows:

myDateTimePicker.Format = DateTimePickerFormat.Custom;
myDateTimePicker.CustomFormat = "MMMM yyyy";
myDateTimePicker.ShowUpDown = true;

However, I want the value of the date to always be the last day of the selected month, so I set the DateTime in the ValueChanged event using:

DateTime selectedDate = myDateTimePicker.Value;
DateTime lastDayOfMonth = new DateTime(
    selectedDate.Year,
    selectedDate.Month,
    DateTime.DaysInMonth(selectedDate.Year, selectedDate.Month));
myDateTimePicker.Value = lastDayOfMonth;

The problem is, if I have a month like March selected, and I change the month to February using the up/down controls, I get the following error before I can handle the ValueChanged event:

ArgumentOutOfRangeException was unhandled
Year, Month, and Day parameters describe an un-representable DateTime.

This is understandable because the date was 31 March and it is being changed to 31 February which is an invalid date. However, I want to change it to 28 February (or 29 February).

How can I achieve this?


Solution

  • Very strange, I tried to reproduce your problem, and when I switch from March to February, my control just doesn't display anything... Maybe we have different framework versions, who handle the same error differently.

    Anyway, one solution would be to set the datetime picker to the first of each month, and when you need the value, you can just use your code as it currently is:

    DateTime lastDayOfMonth = new DateTime(
        selectedDate.Year, 
        selectedDate.Month, 
        DateTime.DaysInMonth(selectedDate.Year, selectedDate.Month)); 
    

    Since you never use the day value of your dattime picker, you can just set it to 1, which will always give an existing date.

    This solution leaves me with a bad feeling somehow, since you are using a date that differs from the date you get from your control - always a possible source of errors, IMO. Remember to put comments into your code, explaining why you are doing it this way ;-)