Rob van der Woude's Scripting Pages

Date and Time in Windows NT 4 and later

Parsing Date and Time

We often want to get the value for the day, month or year instead of the complete date string.
To achieve this, we can choose between FOR /F or SET's substring functionality.
All following code assumes we got the values for Today and Now using one of the techniques described before in The Basics.

FOR /F

To use FOR /F we must know what delimiter is used. For date values, either dash or forward slash is a safe guess:

FOR /F "tokens=1-3 delims=/-" %%A IN ("%Today%") DO (
	SET DayMonth=%%A
	SET MonthDay=%%B
	SET Year=%%C
)

Now all we need to do is find out which value contains the day and which one the month.

There are two ways to find the date format used by the current user, and thus the order of day and month: the DATE command itself, or the registry. The first is simpler, but still language dependent, the latter is safer but more complex.

The DATE command displays the date order when it prompts for input:

C:\>date
The current date is: 21-11-2024 
Enter the new date: (dd-mm-yy)

Or:

C:\>date
The current date is: Thu 11/21/2024 
Enter the new date: (m/d/yy)

The same string designating the order can be found in the registry value HKEY_CURRENT_USER\Control \International\sShortDate.

Note that this string is still language dependent, as in Dutch it will be dd-MM-jjjj, and in French it will probably be something like jj-MM-aaaa.
Both designate the same order of day and month, but the strings are completely different.

Only use this method if you are 100% certain of the system language.

If you are, you can use this technique to read and set the values in the correct order:

:: For REG.EXE 3.0 (Windows XP) and later versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International" /v sShortDate 2ˆ>NUL') DO (
	SET sShortDate=%%A
)
:: For earlier REG.EXE versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International\sShortDate"    2ˆ>NUL') DO (
	SET sShortDate=%%A
)
ECHO.%sShortDate% | FINDSTR /R /B /I /C:"dd*[-/]mm*[-/]yyyy$" >NUL
IF NOT ERRORLEVEL 1 (
	SET Day=%%A
	SET Month=%%B
	SET Year=%%C
)
ECHO.%sShortDate% | FINDSTR /R /B /I /C:"mm*[-/]dd*[-/]yyyy$" >NUL
IF NOT ERRORLEVEL 1 (
	SET Day=%%B
	SET Month=%%A
	SET Year=%%C
)
ECHO.%sShortDate% | FINDSTR /R /I /C:"yy*[-/]mm*[-/]dd" >NUL
IF NOT ERRORLEVEL 1 (
	SET Day=%%C
	SET Month=%%B
	SET Year=%%A
)

Registry

A safer way is using the registry values iDate and sDate for date values, and iTime and sTime for time values. These values can be found in HKEY_CURRENT_USER\Control \International too.
The "s" in sDate and sTime stands for separator (delimiter). The "i" in iDate and iTime probably stands for international setting.

 

Date/Time Format Settings
Name 0 1 2
iDate MM/DD/YYYY DD/MM/YYYY YYYY/MM/DD
iTime 12 hour clock 24 hour clock N/A
iTLZero no leading zero (9:15) leading zero (09:15) N/A

 

We can read the value of iDate using REG.EXE, native as of Windows 2000, or available for NT4 in one of the Resource Kits:

:: For REG.EXE 3.0 (Windows XP) and later versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International" /v iDate 2ˆ>NUL') DO (
	SET iDate=%%A
)
:: For earlier REG.EXE versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International\iDate"    2ˆ>NUL') DO (
	SET iDate=%%A
)
ECHO HKEY_CURRENT_USER\Control Panel\International\iDate=%iDate%

Using two similar REG commands makes sure that we will get the required value, no matter which version of REG.EXE is available.

 

Date/Time Format Settings
Name Value
s1159 AM or any other designation you choose for the morning (ignored if iTime = 1)
s2359 PM or any other designation you choose for the afternoon (ignored if iTime = 1)
sDate - or / or whatever date separator you choose
sTime : or . or whatever time separator you choose

 

The code to retrieve the value of sDate looks familiar:

:: For REG.EXE 3.0 (Windows XP) and later versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International" /v sDate 2ˆ>NUL') DO (
	SET sDate=%%A
)
:: For earlier REG.EXE versions
FOR /F "tokens=3" %%A IN ('REG QUERY "HKCU\Control Panel\International\sDate"    2ˆ>NUL') DO (
	SET sDate=%%A
)
ECHO HKEY_CURRENT_USER\Control Panel\International\sDate=%sDate%

Now let's build on what we found so far:

FOR /F "tokens=1-3 delims=%sDate%" %%A IN ("%Today%") DO (
	IF "%iDate%"=="0" (
		SET Day=%%B
		SET Month=%%A
		SET Year=%%C
	)
	IF "%iDate%"=="1" (
		SET Day=%%A
		SET Month=%%B
		SET Year=%%C
	)
	IF "%iDate%"=="2" (
		SET Day=%%C
		SET Month=%%B
		SET Year=%%A
	)
)
Note: So far, I think this method and the DEBUG RTC method are the only true batch solutions that will give you 100% accuracy (unfortunately, running DEBUG requires a 32-bit OS and administrator privileges).
It is possible to screw up the registry settings and break this method too, but that situation is highly unlikely!
All other methods assume at least either a known day/month order or a known language.

Parsing time values requires similar techniques.
For more details, have a look at my various versions of SortDate.bat and SortTime.bat.

SET

Often the date format will be known, at least partly.
We may know the order of day and month, but even then there may be some systems that use leading zeroes, and others that don't.
Or we may be unsure of the separators used.

Note: In large networks it is advisable to use group policies to enforce a single enterprise wide standard date and time format.

Parse the time, ensure leading zeroes:

SET Now=%Time: =0%
SET Hours=%Now:~0,2%
SET Minutes=%Now:~3,2%
ECHO.%Now% | FIND /I "P" >NUL && SET /A Hours += 12

Would fail for 12 hour clocks that do not use a "P" in their PM designation.

Parse the time, strip leading zeroes:

FOR /F "tokens=1,2 delims=:." %%A IN ("%Time%") DO (
	SET /A Hours   = 100%%A %% 100
	SET /A Minutes = 100%%B %% 100
)

The code above would fail on 12 hour clocks with AM/PM designation appended to the minutes without a space, or on systems that use a different separator (not a dot nor a colon). Actually, this method ignores AM/PM completely.

FOR /F "tokens=1,2 delims=:." %%A IN ("%Time%") DO (
	SET Hours=%%A
	SET Minutes=%%B
)
SET /A Hours = 100%Hours% %% 100
ECHO.%Minutes% | FIND /I "P" >NUL && SET /A Hours += 12
SET Minutes=%Minutes:~0,2%
SET /A Minutes = 100%Minutes% %% 100

A little more code, and a little safer. Still, the code above would fail half the time for 12 hour clocks that do not use a "P" in their PM designation.

Parse the (US) date, ensure leading zeroes

SET Today=%Date: =0%
SET Year=%Today:~-4%
SET Month=%Today:~-10,2%
SET Day=%Today:~-7,2%
Note: Date parsing method by Ildar Shaimordanov.

The code above would fail if the day does not have 2 digits.
A quick-and-really-dirty solution for that problem, not for the faint of heart, could be:

SET Today=%Date: =0%
SET Year=%Today:~-4%
:: Include 1 extra character, which will be either a leading zero or a trailing separator
SET Month=%Today:~-10,3%
:: Remove separator
SET Month=%Month:-=%
SET Month=%Month:/=%
:: Clear leading zeroes
SET /A Month = 100%Month% %% 100
:: And add one again, if necessary
SET /A Month = 100 + %Month%
SET Month=%Month:~-2%
SET Day=%Today:~-7,2%
:: Remove separator
SET Day=%Day:-=%
SET Day=%Day:/=%
:: Clear leading zeroes, as there may be 2 leading zeroes
SET /A Day = 100%Day% %% 100
:: And add one again, if necessary
SET /A Day = 100 + %Day%
SET Day=%Day:~-2%

(I warned you it would get ugly...)

 

 


page last modified: 2016-03-16; loaded in 0.0020 seconds