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

Last day of the month

1,288 views
Skip to first unread message

Matt Wiliamson

unread,
May 26, 2006, 1:04:18 AM5/26/06
to
In the LastDayofMonthN routine, I want it to return the last day of the
current month if the first param is blank, but I can't quite get it working,
hence the 2 separate routines. Can someone help me figure out what's wrong
or a better way to code it?

Also, does anyone have a good batch only routine for getting the last day of
any given month? The only thing I was able to come up with was this
vbscrpt/batch hybrid solution.


[1]@echo off & setlocal enableextensions enabledelayedexpansion
[2] for /L %%j in (1,1,12) do (
[3] call :LastDayofMonthN %%j eom
[4] echo !eom!)
[5] pause
[6] call :LastDayofMonth eom
[7] echo %eom%
[8] endlocal & goto :EOF

[9] :LastDayofMonthN
[10] if not exist %temp% mkdir %temp%
[11] if "%1"=="" (set d=Month^(Date^)) else (set d=%1)
[12] echo>%temp%\tmp$$$.vbs WScript.Echo DateSerial(Year(Date),%d% + 1,0)
[13] for /f %%n in ('cscript //nologo %temp%\tmp$$$.vbs') do set eom=%%n
[14] set eom=%eom:~3,2%
[15] for %%f in (%temp%\tmp$$$.vbs) do if exist %%f del %%f
[16] set %2=%eom%
[17] goto :EOF

[18] :LastDayofMonth
[19] if not exist %temp% mkdir %temp%
[20] echo>%temp%\tmp$$$.vbs WScript.Echo DateSerial(Year(Date),Month(Date)
+ 1,0)
[21] for /f %%n in ('cscript //nologo %temp%\tmp$$$.vbs') do set eom=%%n
[22] set eom=%eom:~3,2%
[23] for %%f in (%temp%\tmp$$$.vbs) do if exist %%f del %%f
[24] set %1=%eom%
[25] goto :EOF

TIA

Matt


Herbert Kleebauer

unread,
May 26, 2006, 9:24:33 AM5/26/06
to
Matt Wiliamson wrote:
>
> In the LastDayofMonthN routine, I want it to return the last day of the
> current month if the first param is blank, but I can't quite get it working,
> hence the 2 separate routines. Can someone help me figure out what's wrong
> or a better way to code it?

@echo off
setlocal

:: the format of the %date% variable must be in the following format:
:: set date=Fr 26.05.2006
:: if not, change the next two lines

set /a y=%date:~9,4%
set /a m=1%date:~6,2%-100
call :lastday

echo.
set y=2000


for /L %%j in (1,1,12) do (

set m=%%j
call :lastday)

echo.
set y=2006


for /L %%j in (1,1,12) do (

set m=%%j
call :lastday)
goto :eof


:lastday
set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))
echo %y% %m% %d%

Todd Vargo

unread,
May 26, 2006, 9:23:56 AM5/26/06
to

"Matt Wiliamson" <ih8...@spamsux.org> wrote in message
news:Esadncydi6K...@adelphia.com...


This works for me. You may need to adjust %date:~x,x% to work for you.

@echo off
setlocal
set month=%date:~4,2%
set eom=31
for %%? in (4 6 9 11) do if %month%==%%? set eom=30
if not %month%==2 goto done
set eom=28
set isleap=%date:~10,4%
set /a isleap=%isleap% %% 4
if %isleap%==0 set eom=29

:done
endlocal
echo eom=%eom%


--
Todd Vargo
(Post questions to group only. Remove "z" to email personal messages)

Matt Williamson

unread,
May 26, 2006, 10:40:43 AM5/26/06
to
Wow. can you explain your formula for :lastday? I'm having trouble getting
my head around it so I can modify it for a U.S. short date format.

Here is my test code so far

@echo off&setlocal

set dt=05/26/2006

set /a y=%dt:~6,4%
set /a m=1%dt:~0,2%-100

call :lastday d
echo %d%
endlocal&goto :eof

:lastday
set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))

set %1=%d%

Thanks

Matt

"Herbert Kleebauer" <kl...@unibwm.de> wrote in message
news:44770191...@unibwm.de...

Herbert Kleebauer

unread,
May 26, 2006, 1:22:30 PM5/26/06
to
Matt Williamson wrote:
>
> Wow. can you explain your formula for :lastday? I'm having trouble getting
> my head around it so I can modify it for a U.S. short date format.

You don't have to modify the code for the :lastday subroutine. All
you have to do is, to set the variables y and m with the year and
month. Only the setting of this variable depends on the local date
format. It doesn't matter whether you use 2006 or 6 for the year
(but no leading zero like 06).


> Here is my test code so far

Didn't it work?


> set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))

The length of a month can be written as 28 + x with 0<=x<=3.
To encode a value 0..3 we need two bits. So we can put all
12 two bit values into one 32 bit value

month: 12 11 10 9 8 7 6 5 4 3 2 1
x 11 10 11 10 11 11 10 11 10 11 00 11 00 = 62648012

To get x for the given month we have to shift 62648012
to the right by 2*month and use only the last two bits
(&3) of the shifted value. If it is a leap year
( !(%y% %% 4)) is one) and it is February ( !(%m%-2) is one)
we have to add 1.

Matt Williamson

unread,
May 26, 2006, 3:20:27 PM5/26/06
to

"Herbert Kleebauer" <kl...@unibwm.de> wrote in message
news:44773956...@unibwm.de...

>
> Didn't it work?
>
>
>> set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))
>

No, unfortunately. It returns 34 for the current date. I'm trying to break
it down to see where the failure is occuring. The actual formula that is
being evaluated when I run this is: 28+((62648012>>(2*5))&3)+((5-2))

Here is some new test code:

@echo off&setlocal

set dt=Any Date in mm/dd/yyyy format


set /a y=%dt:~6,4%
set /a m=1%dt:~0,2%-100

echo %m%%y%


call :lastday d
::echo %d%
endlocal&goto :eof

:lastday
echo 28+
set /a z=((62648012^>^>(2*%m%))^&3)
echo ((62648012^>^>(2*%m%))^&3) = %z%
set /a x=(!(%y% %% 4))*(!(%m%-2))
echo (!(%y% %% 4))*(!(%m%-2)) = %x%
set /a w=28+%z%+%x%
echo Equals 28+%z%+%x% = %w%

C:\WINDOWS>lastdaybatchonly
32004
28+
((62648012>>(2*3))&3) = 3
((3-2)) = 1
Equals 28+3+1 = 32

C:\WINDOWS>lastdaybatchonly
22000
28+
((62648012>>(2*2))&3) = 0
((2-2)) = 0
Equals 28+0+0 = 28

It doesn't look like it's seeing the "year mod 4" part?

Thanks for your assistance

Matt

foxidrive

unread,
May 26, 2006, 3:28:47 PM5/26/06
to
On Fri, 26 May 2006 15:20:27 -0400, Matt Williamson wrote:

> "Herbert Kleebauer" <kl...@unibwm.de> wrote in message
> news:44773956...@unibwm.de...
>>
>> Didn't it work?
>>
>>
>>> set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))
>>
>
> No, unfortunately. It returns 34 for the current date.

This code, as you posted, echoes 31 for me, Win XP SP2.

@echo off&setlocal

set dt=05/26/2006

set /a y=%dt:~6,4%
set /a m=1%dt:~0,2%-100

call :lastday d
echo %d%
endlocal&goto :eof

:lastday


set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))

set %1=%d%

Herbert Kleebauer

unread,
May 26, 2006, 3:43:08 PM5/26/06
to

> echo (!(%y% %% 4))*(!(%m%-2)) = %x%

> ((3-2)) = 1


Then you have enabled delayed expansion. Either disable it
(insert SETLOCAL DISABLEDELAYEDEXPANSION at the begin of your batch)
or escape the ! charcter.

Matt Williamson

unread,
May 26, 2006, 3:46:18 PM5/26/06
to
Yep, that did it.

Thanks Herbert. I'm going to play with this binary shifting some more..

Matt

"Herbert Kleebauer" <kl...@unibwm.de> wrote in message

news:44775A4C...@unibwm.de...

Dr John Stockton

unread,
May 26, 2006, 4:31:33 PM5/26/06
to
JRS: In article <Esadncydi6K...@adelphia.com>, dated Fri, 26
May 2006 01:04:18 remote, seen in news:alt.msdos.batch.nt, Matt
Wiliamson <ih8...@spamsux.org> posted :

>Also, does anyone have a good batch only routine for getting the last day of
>any given month? The only thing I was able to come up with was this
>vbscrpt/batch hybrid solution.

>[9] :LastDayofMonthN


>[10] if not exist %temp% mkdir %temp%
>[11] if "%1"=="" (set d=Month^(Date^)) else (set d=%1)
>[12] echo>%temp%\tmp$$$.vbs WScript.Echo DateSerial(Year(Date),%d% + 1,0)

That's the best algorithm, for any language that has something with
parameters behaving like those of DateSerial, with over- & under- range;
but you might do better to output Day(DateSerial(...))

In Javascript you would not need the +1.

When not using such a routine, it will be desirable to specify whether
the year range for "any given month", since the mod-4 leap algorithm is
incomplete.

--
© John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME. ©
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.

Todd Vargo

unread,
May 26, 2006, 10:36:08 PM5/26/06
to

"Herbert Kleebauer" <kl...@unibwm.de> wrote in message
news:44773956...@unibwm.de...

> > set /a d=28+((62648012^>^>(2*%m%))^&3)+(!(%y% %% 4))*(!(%m%-2))
>
> The length of a month can be written as 28 + x with 0<=x<=3.
> To encode a value 0..3 we need two bits. So we can put all
> 12 two bit values into one 32 bit value
>
> month: 12 11 10 9 8 7 6 5 4 3 2 1
> x 11 10 11 10 11 11 10 11 10 11 00 11 00 = 62648012
>
> To get x for the given month we have to shift 62648012
> to the right by 2*month and use only the last two bits
> (&3) of the shifted value. If it is a leap year
> ( !(%y% %% 4)) is one) and it is February ( !(%m%-2) is one)
> we have to add 1.

Set/? does not explain ! usage. :(

Matt Williamson

unread,
May 26, 2006, 11:38:03 PM5/26/06
to
Yeah I noticed that. It's not mentioned at all in ntcmds.chm either.

maybe Herbert will be kind enough to explain exactly what it does.


"Todd Vargo" <tlv...@sbcglobal.netz> wrote in message
news:sWOdg.98881$dW3....@newssvr21.news.prodigy.com...

Harlan Grove

unread,
May 27, 2006, 12:08:42 AM5/27/06
to
Matt Williamson wrote...

>Yeah I noticed that. It's not mentioned at all in ntcmds.chm either.
>
>maybe Herbert will be kind enough to explain exactly what it does.
...

Experimentation is a dying art. Try

for /L %n in (-3,1,3) do set /a x=!%n

Set /? shows ! as a unary operator, along with -, but doesn't describe
it. It's logical complement, just like in C, C++, awk, Perl, Java,
JavaScript, C#, which means it turns 0 and only 0 into 1 and any other
numeric value into 0. I guess the Microsoft folk thought it was obvious
what it does. All the other set /A operators correspond to C's integer
operators.

Todd Vargo

unread,
May 27, 2006, 9:40:00 AM5/27/06
to

"Harlan Grove" <hrl...@aol.com> wrote in message
news:1148702922.9...@y43g2000cwc.googlegroups.com...

You can't experiment with something you don't know exists. As I mentioned,
SET/? does not mention ! (as seen in Win95cmd ported from Windows 2000). On
examination of SET/? output on an XP machine I see this MUF is identified.
Thanks for explaining unary meaning though. Much appreciated.

Timo Salmi

unread,
May 27, 2006, 2:14:08 PM5/27/06
to
An extract from

70) Calendar elements: What weekday is December 31, 2004?
163586 May 1 2006 ftp://garbo.uwasa.fi/pc/link/tscmd.zip
tscmd.zip Useful NT/2000/XP script tricks and tips, T.Salmi

:
Finally, how many days are there in a month?


@echo off & setlocal enableextensions

:: Build a Visual Basic Script
if not exist c:\mytemp mkdir c:\mytemp
findstr "'%skip%VBS" "%~f0" > c:\mytemp\tmp$$$.vbs
::
:: Assume a local date format dd.mm.yyyy
:: Customize, if necessary
set month_=2
set year_=2004
::
:: Run the VBS script with Microsoft Windows Script Host Version 5.6
cscript //nologo c:\mytemp\tmp$$$.vbs
call c:\mytemp\tmp$$$.cmd
echo %mmdays_% days in %month_%.%year_%
::
:: Clean up
for %%f in (c:\mytemp\tmp$$$.vbs c:\mytemp\tmp$$$.cmd) do del %%f
rmdir c:\mytemp
endlocal & goto :EOF
'
'................................................................
'The Visual Basic Script
'
Const ForReading = 1, ForWriting = 2, ForAppending = 8 'VBS
Dim MyDate, mm, yyyy, DaysInMonth, fout, FSO 'VBS
'
Set WshShell = WScript.CreateObject("WScript.shell") 'VBS
mm=WshShell.ExpandEnvironmentStrings("%month_%") 'VBS
yyyy=WshShell.ExpandEnvironmentStrings("%year_%") 'VBS
'
For i = 28 to 32 'VBS
Mydate = CStr(i) & "." & CStr(mm) & "." & CStr(yyyy) 'VBS
If (IsDate(MyDate)) Then 'VBS
DaysInMonth = i 'VBS
End If 'VBS
Next 'VBS
'
Set FSO = CreateObject("Scripting.FileSystemObject") 'VBS
Set fout = FSO.OpenTextFile("c:\mytemp\tmp$$$.cmd", ForWriting,
true) 'VBS
fout.WriteLine "@set mmdays_=" & DaysInMonth 'VBS
fout.Close 'VBS
The output will be
D:\TEST>cmdfaq
29 days in 2.2004

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland
Digital photos collection at http://www.uwasa.fi/ktt/lasktoim/photo/

Dr John Stockton

unread,
May 28, 2006, 9:46:25 AM5/28/06
to
JRS: In article <447896f4$0$24868$9b53...@news.fv.fi>, dated Sat, 27
May 2006 21:14:08 remote, seen in news:alt.msdos.batch.nt, Timo Salmi
<t...@uwasa.fi> posted :

>
> For i = 28 to 32 'VBS
> Mydate = CStr(i) & "." & CStr(mm) & "." & CStr(yyyy) 'VBS
> If (IsDate(MyDate)) Then 'VBS
> DaysInMonth = i 'VBS
> End If 'VBS
> Next 'VBS

DaysInMonth = Day(DateSerial(yyyy, mm+1, 0)) ' VBS seems simpler

Timo Salmi

unread,
May 29, 2006, 5:15:09 AM5/29/06
to
Dr John Stockton wrote:
> <t...@uwasa.fi> posted :
>> For i = 28 to 32 'VBS
>> Mydate = CStr(i) & "." & CStr(mm) & "." & CStr(yyyy) 'VBS
>> If (IsDate(MyDate)) Then 'VBS
>> DaysInMonth = i 'VBS
>> End If 'VBS
>> Next 'VBS

> DaysInMonth = Day(DateSerial(yyyy, mm+1, 0)) ' VBS seems simpler

Thanks John. Note incorporated.

All the best, Timo

--
Prof. Timo Salmi ftp & http://garbo.uwasa.fi/ archives 193.166.120.5
Department of Accounting and Business Finance ; University of Vaasa
mailto:t...@uwasa.fi <http://www.uwasa.fi/~ts/> ; FIN-65101, Finland

Useful script files and tricks ftp://garbo.uwasa.fi/pc/link/tscmd.zip

0 new messages