AutoHotkey: Adding Months to an Arbitrary Date

After the third or fourth time typing date += 1,months in a script and coming up empty, I decided I needed to implement this apparently nonexistent functionality. I did few Google searches for this purpose and was met with a similar lack of success, so I figured I’d share my results here.

This function will take an arbitrary date and add (or subtract) a given number of months from it. If you want to return the date three months from today, throw today’s date and a positive 3 at the function. If you wanted to return what the date was 3 months ago, just make it a negative 3 instead. It’s fully fleshed out in the comments if you are interested.

The script is available at my GitHub. You can grab it here. Be sure to throw it in your Program Files/AutoHotkey/lib folder to make it available for any future scripts.

PS: Thanks go to my friend Joe, without whom I’d have forgotten to deal with leap years. Please let me know if you find any issues with the script, or even better, if you have found/made something more elegant.

One thought on “AutoHotkey: Adding Months to an Arbitrary Date

  1. Roy

    There are several problems with this routine.

    First if your subtracting months then day doesn’t remain the same. I.E. 20151216 minus 1 month should be 20151116 instead the routine returned 20151115

    Second: there is no provision for dealing with the last day of the month, like if you subtract 2 months from 20151231 then I would expect to arrive at 20151031, instead the routine returns 20151030, this is even more noticeable when passing through February.

    Third: using a loop to iterate each month may be fast for short ranges, but the efficiency drops sharply when dealing with 100s or 1,000s of months.

    Fourth: the “if array contains” block costs more cpu time than if you had just used an object and asked for the days in the given month:
    ; this is declared at the start of the routine
    DaysInMonths := {1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31, 13:31}
    ; this is used in the loop
    DaysInMonths[2] := Leap = 0 ? 29 : 28
    Days := DaysInMonths[month]

    Fifth: the leap year test is not complete.
    if (year is not exactly divisible by 4) then (it is a common year)
    if (year is not exactly divisible by 100) then (it is a leap year)
    if (year is not exactly divisible by 400) then (it is a common year)
    else (it is a leap year)

    Sixth: after line 40 ‘date += days,days’ there is no need to further normalize months as these values are recreated on the next iteration, or are not returned.


Leave a Reply

Your email address will not be published. Required fields are marked *