Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Naming files or folders with current date and time

5 views
Skip to first unread message

William Allen

unread,
Mar 1, 2002, 7:11:46 AM3/1/02
to
=======Naming files or folders with Current Date and/or Time
Windows 95/98/ME users only

With the advent of Long Filenames in Windows 95+, a frequent question is:
How can I include the current Date and/or Time in a file or folder name?
(and without using anything not already in all Win9xME installations).

For example, how to create a file name such as:
MyFile20020301-120130.EXT

embedding current Date= 2002 March 1st and current Time= 12:01:30
or in any other format, using separate two-digit tokens for
Century, Year, Month, Day, Hour, Minute, Second.

It's _not_ elementary to write a Batch script to do this, but we've
often published (and steadily refined) a Batch Subroutine for this
task (see Note at end on definition of "Batch Subroutine").

Previous posts have documented how earlier versions work, but steady
refinements to slim down the script, and make it more general at the
same time, mean the old documentation is a little hard to relate to
the current code we're now using.

A current version of the Subroutine is included in this demo with a
few example lines showing how to use the variables it SETs. For those
interested, a detailed explanation follows of how the Subroutine works,
so anyone with fair Batch skills can trace through the code and see
how it operates.

Demo script to write current Date and Time tokens to separate variables:

====Begin cut-and-paste (omit this line)
@ECHO OFF
IF (GOTO:)==(%1) %1%2 (Subroutine handler)

CALL %0 GOTO: _DATM1A 2 (Code 2 = Load Time tokens HR MIN SEC)
CALL %0 GOTO: _DATM1A 4 (Code 4 = Load Date tokens CY YR MON DAY)

ECHO. Use of the individual date and time tokens:
ECHO. Current date: Century=%CY% Year=%YR% Month=%MON% Day=%DAY%
ECHO. Current time: Hour=%HR% Minute=%MIN% Second=%SEC%
ECHO.
ECHO. Example using tokens in command (remove ECHO.{demo!} to activate)
ECHO.{demo!}REN SomeFile.DOC MyFile%CY%%YR%%MON%%DAY%-%HR%%MIN%%SEC%.EXT
FOR %%V IN (HR MIN SEC CY YR MON DAY) DO SET %%V=

GOTO EOF (=Subroutine code follows=)
:_DATM1A (Usage: CALL %0 GOTO: _DATM1A 2=Time/4=Date)
ECHO.e100 b4 %3 cd 1a 89 e 12 0 89 16 14 0 c3>%TEMP%.\_S
FOR %%C IN (g "d12 15" q) DO ECHO.%%C>>%TEMP%.\_S
debug<%TEMP%.\_S | find ":0010">%TEMP%.\_S.BAT
ECHO.e100'CALL %%1 %%2 %%3 %%4'>%TEMP%.\_S
FOR %%C IN (w q) DO ECHO.%%C>>%TEMP%.\_S
debug %TEMP%.\_S.BAT<%TEMP%.\_S>NUL
CALL %TEMP%.\_S.BAT %0 GOTO: 1_DATM1A %3
FOR %%F IN (_S.BAT _S) DO DEL %TEMP%.\%%F
GOTO EOF
:1_DATM1A
IF (%3)==(2) FOR %%V IN ("HR=%5" "MIN=%4" "SEC=%7") DO SET %%V
IF (%3)==(4) FOR %%V IN ("CY=%5" "YR=%4" "MON=%7" "DAY=%6") DO SET %%V
:EOF (End-of-file)

====End cut-and-paste (omit this line)
Cut-and-paste text between the ==== lines into file with extension .BAT
(and suitable base name). Lines that don't begin with two spaces have
wrapped accidentally. The code sample is purely for demonstration and
study purposes. It was written/tested in the Win9x GUI.


======Analysis of the above Batch code:

This Batch demo uses a Subroutine _DATM1A (stands for DAte and Time
from Interrupt 1A) that builds a tiny Debug script to extract the
current Date or Time from CMOS RAM.

The lines that build the core Debug script are as follows:
ECHO.e100 b4 %3 cd 1a 89 e 12 0 89 16 14 0 c3>%TEMP%.\_S
FOR %%C IN (g "d12 15" q) DO ECHO.%%C>>%TEMP%.\_S

You can get Debug itself to tell you what this code is doing like this:

Remove the %TEMP%.\ path specifier (which is just a simple way to
make the temporary script file in your Windows TEMP folder instead
of the current folder), and these lines become:

ECHO.e100 b4 %3 cd 1a 89 e 12 0 89 16 14 0 c3>_S
FOR %%C IN (g "d12 15" q) DO ECHO.%%C>>_S

Make two stand-alone Batch scripts, one with the %3 replaced
with code 4 (date tokens version), and one with the %3 replaced
with code 2 (time tokens version).

Run the two-line Batch for, say the Date tokens version (code 4),
to create a Debug script file _S that consists of:

======Script starts (not including this line)
e100 b4 4 cd 1a 89 e 12 0 89 16 14 0 c3
g
d12 15
q

======Script ends (not including this line)

This e(100)=Enters a tiny program in memory and g=Go (runs) it.
The tiny program executes the Get Date subfunction 04 of BIOS
INTerrupt 1A. This subfunction loads the day month year and
century tokens from RealTimeClock CMOS RAM into registers
CX and DX as follows:
CH (high byte of CX) =Century (two digits) in BCD
CL (low byte of CX) =Year (two digits) in BCD
DH (high byte of DX) =Month (two digits) in BCD
DX (low byte of DX) =Day (two digits) in BCD

BCD stands for Binary Coded Decimal. A side effect of numbers
stored in this format is that when viewed in HEX, they
look exactly like their intended DECIMAL equivalent. (The main
Batch script goes on to take advantage of this to avoid having
to convert HEX to DECIMAL).

Alter the Debug script to add an Unassemble command to
disassemble the program to assembler source code like this:

======Script starts (not including this line)
e100 b4 4 cd 1a 89 e 12 0 89 16 14 0 c3
u100 10C
g
d12 15
q
======Script ends (not including this line)

Run the new script through Debug like this:
debug<_S
and it runs the script and disassembles the HEX bytes to assembler
source as follows (run made 1st March 2002, read in fixed-width font):

============Screen capture (;lines are explanatory comments added by us)
C:\WORK>debug<_S
-e100 b4 4 cd 1a 89 e 12 0 89 16 14 0 c3
-u100 10C
0F14:0100 B404 MOV AH,04 ;Set for subfunction 04
0F14:0102 CD1A INT 1A ;Call the Interrupt code
0F14:0104 890E1200 MOV [0012],CX ;Store CX in bytes 12 and 13
0F14:0108 89161400 MOV [0014],DX ;Store DX in bytes 14 and 15
0F14:010C C3 RET ;RETurn from subroutine (see **)
-g

Program terminated normally ;Effect of RET (without prior CALL)
-d12 15 ;Display the locations to STDOUT
; bytes:12 13 14 15 ;FIND "0010" finds line below
0F14:0010 02 20 01 03 . ..
;read bytes as: Yr Cy Dy Mn (Yr=Year Cy=Century Dy=Day Mn=Month)

-q ;=quit debug (this line must have Carriage-Return Linefeed at end)

C:\WORK>
============End screen capture
(nnnn varies with memory layout)

** Since no subroutine was called, a zero return address is popped
from the stack by RET. Debug prepares for this by loading an INT 20
(a "Program terminated normally" return to MS-DOS at location zero).

The D=Display bytes command writes the BCD bytes to STDOUT where
the FIND "0010" command in the main script snips this line with
the answers. Standard batch techniques are then used to extract the
four tokens in bytes: 12 13 14 15 from that line (the four tokens
are Year, Century, Day, Month in that order).

You have to be careful about which bytes you MOVe the CX and DX contents
to, or they'll get mixed up with the - (dash) that debug writes in
its display of the bytes. That's why locations 12 through 14 are chosen.
They come far enough along the debug d=(Display memory) line for the Batch
script to be able to retrieve them as command-line parameters, but not
so far as to get mixed up with the dash. The :0010 in relevant (D)isplay
line is an invariant of the way the Debug script lays out the program,
and which FIND can filter on. The rest of the Subroutine overwrites line:
0F14:0010 02 20 01 03 . ..
to make it become:
CALL %1 %2 %3 %4 02 20 01 03 . ..

This is then used as a temporary Batch script to reCALL the Subroutine
with parameters:
CALL %0 GOTO: 1_DATM1A (code) 02 20 01 03
(where code=4 for an original Date call and 2 for original Time call)

The recall code then retrieves the four tokens: 02 20 01 03
into the appropriate environment variables.

The Time version of the Code works similarly (since the two INT 1A
subfunctions are almost identical), and the Subroutine uses the 2/4
code to decide what variables to load. It means that one Subroutine
does two jobs: extracting either Time tokens or Date tokens depending
on the code parameter (2 or 4 respectively) it's called with.

In the Demo Batch script, the two calling lines are:
CALL %0 GOTO: _DATM1A 2 (Code 2 = Load Time tokens HR MIN SEC)
CALL %0 GOTO: _DATM1A 4 (Code 4 = Load Date tokens CY YR MON DAY)
The codes 2 and 4 are used by the Batch Subroutine, but the text
in (parentheses) merely serves as a functionless explanatory comment.

The Batch code uses only what's available in all Windows 95/98/ME systems
The advantages of avoiding third-party utility clutter where possible are:
1) You're learning about (and making fuller use of) the Operating System
2) No need for permission from anyone to install non-standard utilities
3) No third-party copyright worries that may arise in a commercial setting.
4) No need to download anything you don't have already

--
(pp) William Allen
(Posted to encourage more Batch use among Windows 95/98/ME-ers :-)

Note:
===Batch Subroutines

A Batch subroutine is a chunk of Batch code, isolated from
the rest of the script by a GOTO EOF instruction. This "jumps"
over it, so it doesn't runs unless specifically invoked.

The initial Subroutine handler line:
IF (GOTO:)==(%1) %1%2 (Subroutine handler)

is transparent to normal Batch parameters, but intercepts all
Subroutine calls by checking for Subroutine flag GOTO: in %1
and uses Subroutine ID in %2 to execute appropriate Subroutine.

To include any of our Batch subroutines in your own code,
simply ensure your code begins with our two standard lines:
@ECHO OFF
IF (GOTO:)==(%1) %1%2 (Subroutine handler)

and ends with our standard End-of-file label line:
:EOF (End-of-file)

Include the code for the Subroutine (usually better in a section at
the end of your script). Subroutine code is introduced by the lines:

GOTO EOF (=Subroutine code follows=)
:_SRNAME (Usage: CALL %0 GOTO: _SRNAME parameters)

where _SRNAME is the Subroutine ID (the Usage instructions will
normally include the CALLing protocol).

There can be many such Subroutines in any particular Batch script;
they remain independent of each other when properly written.


Rik D'haveloose

unread,
Mar 3, 2002, 9:06:42 AM3/3/02
to
William Allen wrote
==8<

> ======Analysis of the above Batch code:
==8<

> ** Since no subroutine was called, a zero return address is popped
> from the stack by RET. Debug prepares for this by loading an INT 20
> (a "Program terminated normally" return to MS-DOS at location zero).

i would prefer some int 20 directly in the code (educational), which
would have the same effect.

==8<


> You have to be careful about which bytes you MOVe the CX and DX
contents
> to, or they'll get mixed up with the - (dash) that debug writes in
> its display of the bytes. That's why locations 12 through 14 are
chosen.
> They come far enough along the debug d=(Display memory) line for the
Batch
> script to be able to retrieve them as command-line parameters, but not
> so far as to get mixed up with the dash.

to be more precise: the - (dash) is located between every xx7 and xx8
location.
And although this use of debug does not use it (except for the
return...), the 00-ff memory within debug is normally reserved for
passing info from OS to the (com)prog or enable to bypass bugs (the
return at the end ... int 20 at location 00+01 (CD 20). Unless knowing
very good the use of this area, i would not recommend to use this area
for other debug applications (or .com progs created with debug)

--
TUF Greetings from Rumbeke
Belgium


0 new messages