DatetimeMinus — Find the datetime that comes some time before the given one.
DatetimeMinus DatetimeVariable TimeAmount
Return Value
Datetime got by subtracting a time amount from the given datetime.
DatetimeVariableDatetime to subtract from.
TimeAmountHow much to subtract. See More Info and Examples for format.
More Info
This command will multiply each component by -1 and then call

The rest can be summarized as follows: it works pretty much the same as OO Calc, which is based on Excel, but in various scenarios what you get back may not be what you would have expected. So we will go over how it works and specific cases where what you get back may seem odd.

If you subtract one month from a datetime, then the month will go back by one, so long as the day is the 28th or earlier. If the datetime you subtract from starts on the 1st and you subtract one month then you will get back a date that is on the 1st of the previous month, 2nd goes to the 2nd, 3rd to 3rd, and so on. The exception is when the month it would be going to does not have the day you are subtracting from. In that case, it will go forward again, over into the next month. So if you are at the 31st, and subtract one month, and the next month has only 30 days then it will go back to the 1st of the current month. For example, DatetimeMinus {2000-05-31 00:00:00} {0Y 1M 0W 0D 0H 0M 0S} returns 2000-05-01 00:00:00 because we would have had April 31st, but April has only 30 days, and so we take that extra day and go forward again to May 1st.

But suppose you call DatetimeMinus {2000-06-01 00:00:00} {0Y 1M 0W 1D 0H 0M 0S}? Will it first subtract the day and go to May 31st, and then go to May 1st as before? No, you will get back April 30th. What actually happens is that the months and years are subtracted first and then clock scan is called to convert that datetime into to seconds (since start of epoch), then the rest of the components are subtracted.

It may well be that, say, subtracting one month 12 times gives you a different result than adding 12 months one time. (Of course, it is also possible to avoid using months or years if you do not think they will work and use some number of days instead).

But still, overall, this way is good in that you can schedule something to happen on the 1st of the month and then use this to get the 1st of the next month, etc. It is only in cases of days after the 28th that they may not work.

Likewise, for the years it will first add to the year component of the date before converting to seconds. This means if you subtract one year from February 29th (a leap year) then you will get back March 1st, but if you instead subtract four years, then you will get back February 29th again.

Note that in various instances you could add a month and then subtract it or add a year and then subtract it and you will not get back to the start. For instance, if you add a year to February 29th, 2000 then you get back March 1st, 2001. If you then subtract a year, you get back March 1st, 2000. There is no way for the code to know you wanted to have February 29, 2000 (certainly not without complications). So this command is not intended for use in those scenarios. But, again, this is consistent with OO Calc and Excel (most likely).

As far as daylight savings goes, it handles it the same as clock scan / clock format do. So it may well be that you subtract some number of months from a datetime and find that it has also changed by an hour due to daylight savings.

For serious and critical applications for this command, it is recommended you review the source code, the tests, and the examples to get a strong feeling for exactly how it behaves.

Most likely the behavior of this command will remain simple in future releases. If you want complex datetime handling, you might use this simple command to get going, figure out what you want, and then find or make your own functionality to give you the complexities you need.

Note that this command uses IsDatetime to validate the input datetime. That command is, in turn, (currently) only as good as clock scan. So if clock scan allows an invalid date, then this will as well.

Finally, note that you may simply want to use a combination of clock scan, expr, and clock format to get the behavior you want. This command was created to be able support, for instance, scheduling things on the same day each month, regardless of how many days are in the month.

For information regarding exceptions / errors, see
% DatetimeMinus {2001-02-10 04:05:06} {1Y 1M 1W 1D 1H 1M 1S}

2000-01-02 03:04:05
% set MyVar {2001-02-10 04:05:06}
2001-02-10 04:05:06
% DatetimeMinus @MyVar {1Y 1M 1W 1D 1H 1M 1S}
2000-01-02 03:04:05
% puts $MyVar
2000-01-02 03:04:05