Windows batch event reminder for next day

前端 未结 2 1762
孤街浪徒
孤街浪徒 2020-12-20 10:24

How do I write a batch script, that would search in Dates.txt file of this format:

EventName1 : dd.mm.yyyy

EventName2 : dd.mm.yyyy

相关标签:
2条回答
  • 2020-12-20 10:57

    Well, I have finally figured it myself!

    @echo off
    
    setlocal DisableDelayedExpansion
    
    if not exist Dates.txt goto not_found_dates
    
    for /F "usebackq tokens=1,2 delims==" %%i in (`wmic os get LocalDateTime /VALUE 2^>NUL`) do if '.%%i.'=='.LocalDateTime.' set ldt=%%j
    set d=%ldt:~6,2%
    set m=%ldt:~4,2%
    set y=%ldt:~0,4%
    set ldt=%d%.%m%.%y%
    
    echo ************************
    echo * Today:    %ldt% *
    
    :loop
    set /a d=1%d%-99
    
    if %d% gtr 31 (
        set d=1
        set /a m=1%m%-99
    
        if %m% gtr 12 (
            set m=1
            set /a y+=1
        )
    )
    xcopy /d:%m%-%d%-%y% /l . .. >nul 2>&1 || goto loop
    
    set td=0%d%
    set td=%td:~-2%
    set tm=0%m%
    set tm=%tm:~-2%
    set ty=%y%
    
    set tomorrow=%td%.%tm%.%ty%
    
    echo * Tomorrow: %tomorrow% *
    echo ************************
    
    for /f "tokens=1,2 delims=:" %%A in (Dates.txt) do (
        if "%%B"==" %tomorrow%" echo # You have %%Atomorrow!
    )
    
    goto :EOF
    
    :not_found_dates
    echo Dates.txt not found!
    goto :EOF
    

    It works for the Dates.txt file, that uses dates in this format:

    EventName1 : 31.05.2016
    EventName2 : 30.05.2016
    EventName3 : 31.05.2016
    EventName4 : 01.06.2016
    EventName5 : 31.05.2016
    EventName6 : 02.06.2016
    EventName7 : 01.06.2016

    (Shouldn't forget about single empty spaces before and after colon, and about leading zeros for days and months that are less than 10.)


    UPDATE:

    At first, set /a d+=1 adds a day.

    Then, this line:

    xcopy /d:%m%-%d%-%y% /l . .. >nul 2>&1 || goto loop
    

    checks if the date that was formed by set /a d+=1 part, actually exists in the calendar. If the date that was formed doesn't exist, it just "skips" the date, moving to the beginning of the loop to add one more day. This way, the date that doesn't exist can't be set as tomorrow's date.

    The if %d% gtr 31 ( part is not doing anything unless it is actually 31st day of month today.

    So, despite the if %d% gtr 31 ( part that looks somewhat confusing, this code still works well for months that have less than 31 days in them.

    To understand it all better, turn @echo on and trace the changes in the date values.

    For example, if we use:

    set d=30
    set m=04
    set y=2016
    

    Output is:

    ************************
    * Today:    30.04.2016 *
    * Tomorrow: 01.05.2016 *
    ************************
    

    Also, for:

    set d=28
    set m=02
    set y=2015
    

    Output:

    ************************
    * Today:    28.02.2015 *
    * Tomorrow: 01.03.2015 *
    ************************
    
    0 讨论(0)
  • 2020-12-20 11:03

    Here is a pure batch file solution to calculate tomorrow's date from current date with remarks explaining the code. The lines with remark command rem can be removed for faster processing the batch file by Windows command processor.

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    if "%~1" == "" (
        rem Get local date and time in a region independent format.
        for /F "skip=1 tokens=1 delims=." %%D in ('%SystemRoot%\System32\wbem\wmic.exe OS get LocalDateTime') do set "LocalDateTime=%%D" & goto GetDate
    ) else (
        rem This is for fast testing determining the date of tomorrow from any
        rem date specified as parameter in format yyyyMMdd on calling this batch
        rem file from within a command prompt window. The parameter string is
        rem not validated at all as this is just for testing the code below.
        set "LocalDateTime=%~1"
    )
    
    rem Get day, month and year from the local date/time string (or parameter).
    :GetDate
    set "Day=%LocalDateTime:~6,2%"
    set "Month=%LocalDateTime:~4,2%"
    set "Year=%LocalDateTime:~0,4%"
    
    rem Define a variable with today's date in format dd.MM.yyyy
    set "Today=%Day%.%Month%.%Year%"
    
    rem Increase the day in month by 1 in any case.
    
    rem It is necessary to remove leading 0 for the days 08 and 09 as
    rem those two days would be otherwise interpreted as invalid octal
    rem numbers and increment result would be 1 instead of 9 and 10.
    rem if "%Day:~0,1%" == "0" set "Day=%Day:~1%"
    rem set /A Day+=1
    
    rem Faster is concatenating character 1 with the day string to string
    rem representing 101 to 131 and subtract 99 to increment day by one.
    set /A Day=1%Day%-99
    
    rem The tomorrow's date is already valid if the day of month is less than 29.
    if %Day% LSS 29 goto BuildTomorrow
    
    rem Tomorrow is next month if day is equal (or greater) 32.
    if %Day% GEQ 32 goto NextMonth
    
    rem Day 31 in month is not possible in April, June, September and November.
    rem In February it can't occur that day in month increased from 30 to 31
    rem except on calling this batch file with invalid date string 20160230.
    if %Day% EQU 31 (
        if %Month% == 04 goto NextMonth
        if %Month% == 06 goto NextMonth
        if %Month% == 09 goto NextMonth
        if %Month% == 11 goto NextMonth
    )
    
    rem The day 29 and 30 in month is valid for all months except February.
    if NOT %Month% == 02 goto BuildTomorrow
    
    rem Determine if this year is a leap year with 29 days in February.
    set /A LeapYearRule1=Year %% 400
    set /A LeapYearRule2=Year %% 100
    set /A LeapYearRule3=Year %% 4
    
    rem The current year is always a leap year if it can be divided by 400
    rem with 0 left over (1600, 2000, 2400, ...). Otherwise if the current
    rem year can be divided by 100 with 0 left over, the current year is NOT
    rem a leap year (1900, 2100, 2200, 2300, 2500, ...). Otherwise the current
    rem year is a leap year if the year can be divided by 4 with 0 left over.
    rem Well, for the year range 1901 to 2099 just leap year rule 3 would be
    rem enough and just last IF condition would be enough for this year range.
    
    set "LastFebruaryDay=28"
    if %LeapYearRule1% == 0 (
        set "LastFebruaryDay=29"
    ) else if NOT %LeapYearRule2% == 0 (
        if %LeapYearRule3% == 0 (
             set "LastFebruaryDay=29"
        )
    )
    if %Day% LEQ %LastFebruaryDay% goto BuildTomorrow
    
    rem Tomorrow is next month. Therefore set day in month to 1, increase the
    rem month by 1 and if now greater than 12, set month to 1 and increase year.
    :NextMonth
    set "Day=1"
    set /A Month=1%Month%-99
    if %Month% GTR 12 (
        set "Month=1"
        set /A Year+=1
    )
    
    rem The leading 0 on month and day in month could be removed and so both
    rem values are defined again as string with a leading 0 added and next just
    rem last two characters are kept to get day and month always with two digits.
    :BuildTomorrow
    set "Day=0%Day%"
    set "Day=%Day:~-2%"
    set "Month=0%Month%"
    set "Month=%Month:~-2%"
    
    rem Define a variable with tomorrow's date in format dd.MM.yyyy
    set "Tomorrow=%Day%.%Month%.%Year%"
    
    echo Today is:    %Today%
    echo Tomorrow is: %Tomorrow%
    
    endlocal
    

    Please read my answer on Why does %date% produce a different result in batch file executed as scheduled task? It explains in full details the FOR command line using WMIC to get current date in region independent format.

    For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

    • echo /?
    • endlocal /?
    • for /?
    • goto /?
    • if /?
    • rem /?
    • set /?
    • setlocal /?
    • wmic OS get /?
    0 讨论(0)
提交回复
热议问题