Time left before scheduled shutdown?

Question was interesting so I wrote batch that can do job for you.

Basically it is countdown timer, i did not include shutdown command to this but leaved it as homework. Calculations is not accurate, this does not care about leap years, length of month, ... this is mainly for readability as I wanted to keep it easy to learn.

There is currently two files doing job together, one starts timer and other, when called, tells how much time elapsed from timer start. These two files can fairly easily combined into one cmd script, this way you can make some lines reusable (like defined methods) too.

Okay, let's take a look at scripts,

Here is StartTimer.cmd:

@ECHO OFF
FOR /F "skip=1 tokens=1-6" %%a IN ('wmic Path Win32_Localtime GET year^,month^,day^,hour^,minute^,second /format:TABLE ^| findstr /r "."') DO (
  SET DateD=%%a
  SET TimeH=%%b
  SET TimeM=%%c
  SET DateM=%%d
  SET TimeS=%%e
  SET DateY=%%f
)
SET /A EPOCH=((%DateY%-1970)*365*24*60*60)+(%DateM%*30*24*60*60)+(%DateD%*24*60*60)+(%TimeH%*60*60)+(%TimeM%*60)+%TimeS%
ECHO %EPOCH% > Timer.start.state

In line starting with FOR /F "skip=1 ...:
1. Ask wmic for current time and date.
2. Skip first line of output, which is headings, by skip=1
3. Read values using tokens=1-6 meaning %%a-%%f separated by SpaceorTAB.
4. Store values to variables %DateY%, ... %TimeH%, %TimeM%, ...

After that at line starting SET /A EPOCH=... we use expression that calculates seconds elapsed from 1.1.1970 (this is simple approximate, not real unix time. See Google if you need accurate).

Then at last line ECHO %EPOCH% > ... writes calculated time to file called "Timer.start.state".

And here GetTimerValue.cmd:

@ECHO OFF

GOTO CHECKFILE

:TIMEOUT
FOR /F "skip=1 tokens=1-6" %%a IN ('wmic Path Win32_Localtime GET year^,month^,day^,hour^,minute^,second /format:TABLE ^| findstr /r "."') DO (
    SET DateD=%%a
    SET TimeH=%%b
    SET TimeM=%%c
    SET DateM=%%d
    SET TimeS=%%e
    SET DateY=%%f
)
SET /P Timer=<"Timer.start.state"
SET /A EPOCH=((%DateY%-1970)*365*24*60*60)+(%DateM%*30*24*60*60)+(%DateD%*24*60*60)+(%TimeH%*60*60)+(%TimeM%*60)+%TimeS%
SET /A Elapsed=%EPOCH%-%Timer%
ECHO "Seconds since timer started: %Elapsed%"
GOTO EOF

:CHECKFILE
IF EXIST "Timer.start.state" (
  GOTO TIMEOUT
) ELSE (
  ECHO "Timer not started. Start timer by running Timer.cmd"
)

:EOF

Here code flow is not linear from top to bottom. First we GOTO CHECKFILE label so execution commands really starts at line that says :CHECKFILE. Many things here is just same as with StartTimer.cmd so I only explain new or changed lines.

First we check if state file Timer.start.state exists, if not then terminate wit message. If timer started and files exists then we continue and do some math:
1. Jump to :TIMEOUT where we output elapsed seconds. You can choose better label for that...
2. SET /P %Timer% ... reads start time from file and assign value to %Timer% variable.
3. SET /A Elapsed ... calculates seconds between start time and now.
4. ECHO "Seconds ... echoes out calculated value (seconds since timer startup.

How to get remaining time:

You can substract %Elapsed% from %MaxTime%:

@ECHO OFF
GetTimerValue
SET /A TimeLeft=%MaxTime%-%Elapsed%
ECHO "You have %TimeLeft% seconds remaining"

OK, explained enough. Here is full script Timer.cmd:

At this point, forgot everything already said. This batch file here is working on it's own so there is no separate StartTimer.cmd or GetTimerValue.cmd but only this Timer.cmd. Basically it is still same but code flow is different and usage is also completely different. This however does not save state to file so you cant anymore get timer value after logoff/reboot, if you need this use example above to save/read state to/from file.

Usage/help for Timer.cmd is printed when run without arguments. I have not fully tested this and there may be some typos etc., args are not foolproof checked.

@ECHO OFF

GOTO TimerUser%1

:: ===================================
:: Operation is start, (re)start timer
:: ===================================
:TimerUserstart
ECHO %2 | FINDSTR /R "^[1-9]"
IF %ERRORLEVEL%==0 (
  SET Timer.max=%2
  GOTO TimerStart
) ELSE (
  ECHO.
  ECHO   !! ERROR !!
  ECHO   You must specify maximum value.
  ECHO   ===============================
  GOTO TimerUser
)

:: =============================================
:: Operation is get, get values if timer running
:: =============================================
:TimerUserget
IF DEFINED Timer.start.state (
  GOTO TIMEOUT
) ELSE (
  ECHO.
  ECHO   !! ERROR !!
  ECHO   Timer is not started, start timer first.
  ECHO   ========================================
  GOTO TimerUser
)

:: ============
:: Usage / Help
:: ============
:TimerUser
  ECHO.
  ECHO Timer.cmd Usage: Timer.cmd operation [options]
  ECHO.
  ECHO - Operations
  ECHO   start    Start new timer, n must be specified.
  ECHO   get      Get current value of started timer.
  ECHO.
  ECHO - Options:
  ECHO   n        Max value in seconds, used to calculate remaining time.
  ECHO.
GOTO EOF

:: =============================
:: Update %Timer.epoch% variable
:: =============================
:TimerUpdateEpoch
FOR /F "skip=1 tokens=1-6" %%a IN ('wmic Path Win32_Localtime GET year^,month^,day^,hour^,minute^,second /format:TABLE ^| findstr /r "."') DO (
    SET DateD=%%a
    SET TimeH=%%b
    SET TimeM=%%c
    SET DateM=%%d
    SET TimeS=%%e
    SET DateY=%%f
)
SET /A Timer.epoch=((%DateY%-1970)*365*24*60*60)+(%DateM%*30*24*60*60)+(%DateD%*24*60*60)+(%TimeH%*60*60)+(%TimeM%*60)+%TimeS%
GOTO %Timer.Callback%

:: ===========================================
:: Start new timer destoying/resetting old one
:: ===========================================
:TimerStart
SET Timer.Callback=TimerStartC1
GOTO TimerUpdateEpoch
:TimerStartC1
SET Timer.start.state=%Timer.epoch%
GOTO EOF

:: =============================
:: Echo out current timer values
:: =============================
:TIMEOUT
SET Timer.Callback=TimerEchoJ1
GOTO TimerUpdateEpoch
:TimerEchoJ1
SET /A Timer.elapsed=%Timer.epoch%-%Timer.start.state%
SET /A Timer.remaining=%Timer.max%-%Timer.elapsed%
ECHO "Seconds since timer started: %Timer.elapsed% Time remaining %Timer.remaining%"
GOTO EOF

:EOF

Integrate with shutdown or any other command:

File poweroff.cmd:

@ECHO OFF
Timer start %1
shutdown -t %1 -s

Usage: poweroff <wait_seconds> to start timed shutdown and Timer get to get elapsed/remaining time.