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.
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 )
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.
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. |
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.
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.
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