Time is set incorrectly after midnight

Usage of dynamic variables DATE and TIME

The usage of the dynamic variables DATE and TIME with string substitutions as explained very detailed by my answer on the question What does %date:~-4,4%%date:~-10,2%%date:~-7,2%_%time:~0,2%%time:~3,2% mean? is very fast, but has the disadvantage that the format of the date and the time string depends on region (country) configured for the account used on running the batch file.

The date can be without or with abbreviated weekday at beginning and without or with a comma appended after abbreviated weekday. The date string can be in the format year/month/day or month/day/year or day/month/year with / or . or - or   as separator. See also the Wikipedia article about date format by country.

The time can be in 12 or 24 hour format. The hour can be without or with a leading 0 on being less than 10.

It was not posted what is output on running echo %DATE% %TIME% before ten o’clock in the morning and at three o’clock in the afternoon to know the local date/time format.

It looks like it is possible to use the following code with : as separator in time string:

if "%TIME:~1,1%" == ":" (
    set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[0%TIME:~0,1%-%TIME:~2,2%]"
) else (
    set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[%TIME:~0,2%-%TIME:~3,2%]"
)

If the second character in time string is a colon, the condition is true and the first expression is used with 0 added left to single digit hour, otherwise the ELSE block is used with the two digit hour.

Another solution with separator in time string being either a colon or a dot or a space would be:

for /F "tokens=1,2 delims=:. " %%I in ("%TIME%") do set "Hour=0%%I" & set "Minute=%%J"
set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[%Hour:~-2%-%Minute%]"

The hour left to : or . or   is assigned to environment variable Hour with a leading zero. The minute right to : or . or   is assigned to variable Minute. The date/time string is built with taking only the last two digits of Hour to have the hour finally always with two digits in date/time string assigned to environment variable bdate.


Usage of WMIC to get current date/time

Much better would be getting current date and time region (country) independent and reformat them to wanted format using string substitutions.

A region independent date/time string can be get using Windows Management Instrumentation Command line tool WMIC.

The command line

wmic OS GET LocalDateTime /VALUE

outputs UTF-16 Little Endian encoded for example:



LocalDateTime=20200208124514.468000+060


There are two empty lines, then the line with the current local date/time in format yyyyMMddHHmmss.microsecond±UTC offset in minutes and two more empty lines.

The data can be used with a batch code like this:

@echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "DateTime=%%I"
set "bdate=[%DateTime:~6,2%-%DateTime:~4,2%-%DateTime:~0,4%]-[%DateTime:~8,2%-%DateTime:~10,2%]"

Of interest is here only the date/time string between the equal sign and the decimal point which is the reason for using for /F options tokens=2 delims==. to get just 20200208124514 assigned to loop variable I of which value is assigned next to environment variable DateTime.

The environment variable DateTime is reformatted using string substitutions to get the date/time string in format [dd-MM-yyyy]-[HH-mm] resulting in environment variable bdate being defined with [08-02-2020]-[12-45].

It would be of course possible to use bdate everywhere instead of DateTime to use just one environment variable instead of two variables.

The advantage of using WMIC to get local date/time is its independence on Windows region settings and that it is working even on Windows XP. The disadvantage is that the command execution takes a quite long time (one to two seconds on Windows XP, more than 50 ms on Windows Vista a newer Windows versions) in comparison to the usage of the DATE and TIME dynamic variables of the Windows command processor which are accessed in a few microseconds.

The command FOR has problems parsing UTF-16 LE encoded Unicode output correct. It interprets the byte sequence 0D 00 0A 00 (carriage return + line-feed) of the WMIC output wrong as 0D 0D 0A, i.e. as two carriage returns and one line-feed. This results in interpreting the last two empty lines at end of WMIC output as two lines with a single carriage return as string.

That is very often a problem because the result of set "EnvironmentVariable=%%I" is with %%I expanding to just carriage return the deletion of the environment variable already defined before with the correct value.

There are multiple solutions to work around this Unicode parsing error of command FOR. It is possible to append & goto Label to exit the loop with a jump to :Label below the FOR loop once the value is assigned to the environment variable to avoid running into this problem at all.

Another solution is using if not defined DateTime set "DateTime=%%I" with set "DateTime=" above the FOR command line to make sure the command SET is executed only once.

One more solution is the one used in this code. The name of the property and its value are output on same line because of using WMIC option /VALUE. The command FOR runs the command SET because of tokens=2 only when it could split up the current line into at least two substrings (tokens) using equal sign and dot as delimiters because of delims==.. But the wrong parsed empty lines of WMIC output is for FOR just a line containing only a carriage return and therefore has no second token. For that reason the wrongly parsed empty lines are also ignored here by the command FOR.

See How to correct variable overwriting misbehavior when parsing output? and cmd is somehow writing Chinese text as output for details on parsing problem of FOR on UTF-16 Little Endian encoded output.


Usage of ROBOCOPY to get current date/time

Another solution to get current date and time region independent is using ROBOCOPY which is available since Windows Vista and Windows Server 2003 in system directory of Windows, but is by default not available on Windows XP. robocopy.exe of Windows Server 2003 can be copied to %SystemRoot%\System32 of Windows XP to use this executable also on Windows XP, but it is not available by default on Windows XP.

ROBOCOPY is executed with invalid source directory string "C:\|" and valid destination directory string . (could be also something other valid) and argument /NJH to suppress the output of the header information.

robocopy "C:\|" . /NJH

This execution produces the error message:


2020/02/08 12:45:14 ERROR 123 (0x0000007B) Accessing Source Directory C:\|\
The filename, directory name, or volume label syntax is incorrect.

The format of current date/time at beginning of second line after the empty line is region independent.

This output can be processed with:

set "bdate="
for /F "tokens=1-5 delims=/: " %%G in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do if not defined bdate set "bdate=[%%I-%%H-%%G]-[%%J-%%K]"

FOR starts in this case one more command process in background with %ComSpec% /c and the command line between the two ' appended as additional arguments which results in Windows being installed into C:\Windows in the execution of:

C:\Windows\System32\cmd.exe /c C:\Windows\System32\robocopy.exe "C:\|" . /NJH

The first five slash or colon or space separated strings of the first non-empty line of the error message output to handle STDOUT of the background command process captured by FOR are assigned to:

  • G … year
  • H … month
  • I … day
  • J … hour
  • K … minute

The five data strings are concatenated to the date/time string in the wanted format.

But FOR would run the command SET once again for the second error message line. For that reason the environment variable bdate is explicitly undefined before running FOR. The environment variable bdate is defined first with the date/time string and is next not modified anymore on FOR processing the second non-empty line because of the additional IF condition to avoid overwriting the date/time string of interest with an unwanted string.

The advantage of the ROBOCOPY solution in comparison to the WMIC solution is its much faster execution time.


Additional information

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 /?
  • for /?
  • if /?
  • robocopy /?
  • set /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

PS: There are lots of other solutions to get current date/time in a specific format independent on country configured for the used account. All those alternative solutions can be found in the answers on:

How do I get current date/time on the Windows command line in a suitable format for usage in a file/folder name?

Leave a Comment