Search code examples
datebatch-filecmd

Get the difference between current date and a previous date


If I enter echo %date% in cmd I will get the date it is today. Let us say that today is Wednesday, 21/11/2018. If I type echo %date% cmd will print Wed 11/21/2018. Yesterday, it would have returned Tue 11/20/2018. The difference between these two dates (in days) is 1.

Is there any way I can do this kind of subtraction in command prompt? Something like:

set previous_date=Tue 11/20/2018
echo %date% - %previous_date%

I know this should be very easy to do in a programming language like python or VBScript, but I don't want to use any of those, unless it is absolutely necessary. I can download and use custom command line tools, but I want to do this with a batch file.

Anyone who knows how?


Solution

  • (I have previously posted this in the comments because the question was locked. Since it is now unlocked I am submitting this as an answer)

    Batch scripting language does not have any built-in means to calculate time difference. This problem may be solved through various means such as:

    • Write it using other scripting languages such as VBS, AutoIt, PowerShell, etc.
    • Download existing external program such as unix date utility from gnuwin32 coreutils (manual, recipe). Use for to get output of date "+%%s" into a variable, then use set /a to calculate the difference.
    • Parse output from built-in date command or %date% variable. This is discussed in great detail elsewhere (A, B, C, D, E) but be aware that it may be affected by OS locale time/date representation, and it is also hard to take leap years into account properly if you need precision.

    I'd like to share another trick: using file creation date difference. It is still a somewhat of a hack, but is arguably more portable than parsing %date% by hand.

    Here is an example, explanation below:

    if not exist "c:\some\marker.txt" goto RunTheJob
    robocopy /minage:7 "c:\some\marker.txt" "c:\some\test.txt"
    if exist "c:\some\test.txt" goto RunTheJob
    goto SkipTheJob
    
    :RunTheJob
    del /y "c:\some\test.txt"
    echo 1 >"c:\some\marker.txt"
    rem ... THIS RUNS ONCE IN 7 DAYS ...
    
    :SkipTheJob
    

    Whenever we run the job (i.e. once in 7 days) we also create (or update) a "marker" file (c:\some\marker.txt in the example). Contents and location of this file do not matter, only date of its modification does, so I just write character 1 into it with echo 1 >YOUR_FILENAME

    This also neatly solves the problem of storing date information somewhere.

    Now to test if at least 7 days passed since the job last ran you need to check if the file is at least 7 days old. Easiest way is with robocopy utility - its /minage:NNN parameter only copies the file if it is at least NNN days old.

    So we periodically try to copy the file and see if it succeeds. We do this by checking if copied file (c:\some\test.txt) exists like this: if exist YOUR_FILENAME goto YOUR_LABEL

    Finally, if the file was copied it is no longer needed and we need to delete it with del /y YOUR_FILENAME. /y overrides confirmations just in case and may normally be omitted.

    If the marker file is ever deleted for any reason, the first line in the example makes sure that job (I'm assuming some kind of backup or something like that) is started right away. If it wasn't there, the file would never be copied because the original would not exist in the first place, so the job would never run in this situation.

    Quirks:

    If some program updates the modification date of a "marker" file for some reason, the job will be delayed. If this is undesired you should put this file somewhere out of reach, such as %AppData%\Roaming\YOUR_SCRIPT_NAME folder. Same thing may happen if the file gets restored from a backup.

    To work around such a problem you may consider compressing the marker file into an archive such as zip, but this also requires external programs, VBS or PowerShell. It might be possible to somehow abuse built-in Windows Backup utility (sdclt) instead but I have not found a way.