Wednesday, September 15, 2004

how to get last day of month in VBScript

To get today's date, we can use now or date function in VBScript. Actually now function returns current date and time of your computer (i.e. Wednesday, September 15, 2004 13:09:23), while date returns only the date in mm/dd/yyyy (i.e. 9/15/2004). That's how we get current date.
So how to get the last day of this month? First, let's see DateSerial(Year, Month, Day) function. DateSerial(2004,9,15) returns 9/15/2004. We could use this function to get the last day of this month. The following codes show how to do this.
theday = date
lastdayofthemonth = DateSerial(Year(theday), _
   Month(theday) + 1, 0)
My explaination for this is we want to define a date where the date is the 0th date of next month, or in other words the last date of the month before next month (this month). You can also use this code to find the last day of another month by changing theday variable.
The next topic I want to discuss from this paragraph is a little bit different from the above paragraphs. It's about how to get the last day of each month from the database. For example, I have a table that contains date and how many visitors I have until that date. I want to have data of total visitors I have until the last day of each month. Not only that, I also want to have data of total visitors until the last day of each year, and data of visitors each day. The following code is under assumption that the data already ordered by date descending (for the latest to the oldest)
dim county1, countm1, countd1
dim countylast, countmlast, countdlast 
dim tgl2
tgl2 = date
countylast = Year(tgl2)
countmlast = Month(tgl2)
countdlast = Day(tgl2)

Dim arramt, arrctr
arramt = 1 
arrctr = 0
Redim arrdt0(arramt)
Redim arrdt1(arramt)

do while not rs.EOF
   if radioch="permonth" or radioch="peryear" then
      county1 = Year(rs.Fields("xdate"))
      countm1 = Month(rs.Fields("xdate"))
      countd1 = Day(rs.Fields("xdate"))
   end if
   if ((radioch="peryear" and county1<=countylast) or _
      (radioch="permonth" and county1<=countylast and _
      countm1<=countmlast) or radioch="perday") then
      if radioch="peryear" then
         if county1<countylast then 
            countylast = county1 - 1
         else
            countylast = countylast - 1 
         end if		
      elseif radioch="permonth" then
         if countm1<countmlast then
            countmlast = countm1 - 1
         else
            countmlast = countmlast -1
         end if
         if countmlast=0 then 
            if county1<countylast then 
               countylast = county1 - 1
            else
               countylast = countylast - 1 
            end if
            countmlast=12
         end if
      end if
     
      if arrctr>=arramt then
         arramt = arramt+5
         redim preserve arrdt0(arramt)
         redim preserve arrdt1(arramt)
      end if
      arrdt0(arrctr)=rs.fields("xdate").Value
      arrdt1(arrctr)=cLng(rs.fields("xvisitor").Value)
      arrctr = arrctr+1
   end if

   rs.MoveNext
loop
I keep the data I want into an array. If variable radioch is set to "perday" then data total visitor each day will be kept. If variable radioch is set to "permonth" then data total visitor on last day for each month will be kept. If variable radioch is set to "peryear" then data total visitor on last day for each year will be kept.
Critics, suggestions, and comments always welcomed.

Tuesday, September 14, 2004

Keeping temporary data using array in VBScript

To declare an array, use the following expression:
dim arrdt()
or
dim arrdt2(20)
for 1-dimension array that can contain 20 variables
or
dim arrdt3(3,10)
for 2-dimension array that can contain 3*10 variables.
You can set an array up to 60 dimensions. If I don't know how big the data will be, so I don't know how big should I set the array size, what should I do? First, just set the array size to 1 (you could set this into 5, or 10 or whatever you want though). Then, set array counter into 0 (because the lower bound of an array is 0).
Dim arramt, arrctr
arramt = 1 
arrctr = 0
After that, resize the array size.
Redim arrdt(arramt)
Everytime you insert a variable into the array, make sure whether the array is big enough to keep the variable. If it is not big enough, make it bigger by resizing the array, remember to use the "preserve" keyword to keep the data inside the array. Also make sure that the number that will be used to resize the array is bigger than the original array size.
if arrctr>=arramt then
   arramt = arramt + 5
   ReDim Preserve arrdt(arramt)	
end if 
And then, set the array content and increase arrctr (add arrctr by one).
arrdt(arrctr) = something_you_want_to_keep
arrctr = arrctr + 1 
After you insert all the variables into the array, you'll know that you have (arrctr-1) variables inside the array.

Friday, September 10, 2004

Using JavaScript Cookies and ASP Session to Maintain Last Page Accessed By Each User

We know that we could just use Request.ServerVariables("URL") to find out the url accessed by user in ASP page. If a user opens more than one ASP page, what should we do? Keep it in a session variable, for example:
Session("lastpage") = Request.ServerVariables("URL") _
 & "?" & Request.ServerVariables("QUERY_STRING")
The variable behind the question mark (?) is server variables called query string which is used by calling Request.queryString("the_var_we_made"). So now we already have variable that keeps last pages accessed by user on the server side. Then, I want to use this variable so I can check if the page being viewed is the last page user accessed from the server. May be you would say, hey, the page being viewed IS the last page user accessed. Nope, a user can click the "back" button in a browser, or open a new window and then return to the first page without notices that it's not the last page he/she accessed from the server. And I have a problem with my web services which is the excel data that will be created in my web services is only the last data requested in the last page accessed from the server, coz I use session to keep the last data. My solution to resolve this problem is by keeping a variable on client side using javascript cookies, then give warning to user is the page clicked and lastpage are not the same and reload the page that is clicked by user. Put this code in each page:
<% Session("lastpage") = Request.ServerVariables("URL") _
   & "?" & Request.ServerVariables("QUERY_STRING") %>
<SCRIPT type=text/javascript>
<!--
document.cookie="lastpage="+"<% = Session("lastpage) %>";
//-->
</script>
Then, in the create_excel page (To create an excel file, user have to click on a link and then create_excel.asp page will be opened) I put this code:
<SCRIPT type=text/javascript>
<!--
function to_reload()
{
   var search2="lastpage=";
   offset=document.cookie.indexOf(search2);
   if (offset != -1) 
   { 
      offset += search2.length
      end = document.cookie.indexOf(";", offset);
      if (end == -1) end = document.cookie.length;
      if (document.cookie.substring(offset,end)
         !="<% =Session("lastpage") %>") 
      {
         window.opener.location.reload();
         alert("Data not ready! Please wait " 
            + "until finish reloading the page " 
            + "then click 'create excel' again")
         window.close();
      }
   }
}
to_reload();
//-->
</script>
The disadvantage of this solution is, user using browser that doesn't support cookies or the cookies is not enabled can not use this feature. One more thing, if you ask me, why don't you just use Request.Cookies in ASP instead of javascript cookies. Well, that time (when I create the above script) I didnn't know that there is cookies usage in ASP. Silly me :P

Thursday, September 09, 2004

formatting number in VBScript

My current work is to display data statistics or data reporting, so my work always shows tables of numbers and charts. The numbers involved here could be millions, billions or even trillions. For a user friendly looks (display), I have to convert from 123456789.01 into 123,456,789.01 (using commas). I'm using ASP with VBScript for my current work and here is my source code for converting numbers into numbers with commas.
function commanum (valori)
   dim retval0, val0, val0temp
   if inStr(valori,".")>0 then
      val0=Left(valori, inStr(valori,".")-1)
      val0temp = _
         Right(valori, len(valori)-inStr(valori,".")+1)
   else	
      val0 = valori
      val0temp=""
   end if
   if val0<>"-" and val0<>"" and isNumeric(val0) then
      if val0 >= 1000 then
         dim n, valtemp, i, deltemp, valx
         valtemp = val0
         n = 0
         while valtemp>=1000
            valtemp = int(valtemp/1000)
            n = n + 1
         wend
         deltemp = 1000
         for i=1 to n
            retval0 = commanum1(val0, deltemp, ",") _
               & retval0
            val0 = int( val0 / 1000)
            if (val0>0) then
               valx = val0
            end if
         next
         retval0 = valx & retval0
      else 
         retval0 = val0
      end if
   else
      retval0 = val0
   end if
   commanum = retval0&val0temp
end function

function commanum1 (val1, delim, comma)
   if val1 >= delim then
      commanum1 = comma & right(val1,len(delim)-1)
   else 
      commanum1 = val1
   end if
end function
To use the function, first you have to convert the variable into number (using cDbl or cLng) if the variable is not a number. For example:
Response.write commanum(cDbl("50549455490260"))
And the result will be: 50,549,455,490,260 Okay, formating numbers using commas is done. How about rounding off a number with 2 decimal behind a dot? You can say that it's so easy. Just use round function that already defined in VBScript. But I have my own problem. Using VBScript's round function, if the last decimal (behind the dot) is "0", then that "0" is removed. For example, round(1234.50123,2) will results 1234.5 Where is my last zero here? Why should I concern about this zero? Well, as I've told you, my works involved table of numbers, if the zero is not shown, numbers in a column which are justified to the right will have a bumpy-looks. For example:
70.71
 13.5
12.34
 3.45
Looks bad, huh? This is my solution for the zero problem:
function round_into(val1, val2, val3)
   dim tempround
   tempround = round(val1,val2) & ""
   if val3>0 then
      if inStr(tempround,".")=0 then
         tempround=tempround & "."
      end if
      do while (len(tempround)-inStr(tempround,"."))<val3
         tempround = tempround & "0"
      loop
   end if
   round_into = tempround
end function      

function round_into_kus(val1, val2)
   round_into_kus = round_into(val1, val2, val2)
end function
Gee, don't know if this is the best solution, but it works. Okey then, jyaaa ne.

Wednesday, September 01, 2004

how to create MS-DOS batch for deleting file/folder

Creating batch for deleting file/folder sounds so easy. So what's the problem here? Well, the problem is, I want to have a batch file to create folder once a day, with folder naming rule: yyyy-mm-dd (i.e.: 2004-09-01 for August 1, 2004) and to delete a 2-days-ago-folder (i.e.: today is 2004-09-01, I want to delete folder 2004-08-30). What made me confuse at first is how to get the date with format date I want. The code below is the answer:
for /f "tokens=2-4 delims=/ " %%f in ('date /t') do (
  set mm=%%f
  set dd=%%g
  set yyyy=%%h
)
The second step is how to get 2 days ago date. I searched the internet (google.com) and found experts-exchange.com In that page, there is solution for getting 4 days ago date. Thanks to them (TrueBlue and SteveGTR) who contributed for the question and the solution in that page, I managed to finish my batch file. Here is the batch file:
@echo off
::Get todays date
call :mmddnt

:: remember to change the path you want
:: attempting to delete old directory 
::   (..\dirs\%yyyy%-%mm%-%dd%)
del "..\dirs\%yyyy%-%mm%-%dd%\*.xls"
rmdir "..\dirs\%yyyy%-%mm%-%dd%"
echo attempting to make directory
mkdir "..\dirs\%yyyy0%-%mm0%-%dd0%"

goto :eof

:mmddnt

::begin SteveGTR source code

for /f "tokens=2-4 delims=/ " %%f in ('date /t') do (
  set mm=%%f
  set dd=%%g
  set yyyy=%%h
)

set dd0=%dd%
set mm0=%mm%
set yyyy0=%yyyy%

REM Substract 2 days 
set /A dd=1%dd% - 102
set /A mm=1%mm% - 100

if /I %dd% GTR 0 goto DONE

set /A mm=%mm% - 1

if /I %mm% GTR 0 goto ADJUSTDAY

set /A mm=12
set /A yyyy=%yyyy% - 1

:ADJUSTDAY

if %mm%==1 goto SET31
if %mm%==2 goto LEAPCHK
if %mm%==3 goto SET31
if %mm%==4 goto SET30
if %mm%==5 goto SET31
if %mm%==6 goto SET30
if %mm%==7 goto SET31
if %mm%==8 goto SET31
if %mm%==9 goto SET30
if %mm%==10 goto SET31
if %mm%==11 goto SET30
if %mm%==12 goto SET31

:SET31

set /A dd=31 + %dd%

goto DONE

:SET30

set /A dd=30 + %dd%

goto DONE

:LEAPCHK

set /A tt=%yyyy% %% 4

if not %tt%==0 goto SET28

set /A tt=%yyyy% %% 100

if not %tt%==0 goto SET29

set /A tt=%yyyy% %% 400

if %tt%==0 goto SET29

:SET28

set /A dd=28 + %dd%

goto DONE

:SET29

set /A dd=29 + %dd%

:DONE

if /i %dd% LSS 10 set dd=0%dd%
if /i %mm% LSS 10 set mm=0%mm%

::end SteveGTR source code
I've been thinking lately, I always depends on google when I'm stuck with my source code. Sometimes I think that this is not good, I mean, it looks like I copy paste some part of other's source code for my works, and you can say that it's not my own works 100%. Or in rude sentence, you can say it's like stealing some part of other's source code. That's why usually, I search it from tutorial pages, because that's what the purpose of the pages anyway. Anyone can learn from tutorial pages, but not to copy 100% from the source code, plus I should write the author name if there is GPL license for the code, right guys ^_~