Web based School

Chapter 16

Extending Your Web Pages with Dates and Advanced Math


Yesterday you saw how you can extend the capabilities of your Web pages by incorporating the advanced string handling built into VBScript. This is fine if you're parsing standard data, but there will be times when you want your scripts to do more. Perhaps you'll need to work with dates and provide future payment due information to your users. Maybe you'll need to provide a time estimate of when service for a certain type of car repair will be complete. Or maybe you'll need to generate random numbers on the page to implement an online slot machine. Who knows? Depending on what type of programming you are doing, the day might even come when you have to dust off the old trig guides to provide an algorithm based on trigonometric principles.

You need to go beyond string functions in situations like these. You might think that you would have to provide your own layers of support functions in such cases, but VBScript has many useful functions you can turn to in cases like these. In today's lesson you will gain full knowledge of the additional functions VBScript provides you to work with. After today's lesson, you will have been exposed to nearly all the major functions that are part of the VBScript programming language. Some of the functions, particularly date handling, you may use frequently. Others, such as advanced math, may be of use only from time to time. But when you need them, they'll be there. Easy to use and broad in function, they are one of the elements of VBScript that make it possible to piece together quick, robust Web page solutions for almost any scenario.

One sample Web page containing a collection of scripts is used to demonstrate all the functions in today's lesson. This page, AllFunc.asp, is available on the CD-ROM. The sample scripts referred to throughout the lesson can be found there. A separate command button is used to launch individual tests that focus on specific functions and display test results in a message box.


Date information can be an important part of a script. Perhaps your script receives an order request date from a user and compares it to an expected shipment date to determine if the order can be met. Maybe it collects a date of employment from a user and ensures that the date range is valid before uploading it to the server. Or your script might figure out what day of the week an appointment falls on, based on the date for which it's scheduled, to determine if the user should be warned about busy Fridays. All these tasks would be fairly difficult to perform if a date was simply a string like April 22, 1994 that you had to figure out how to analyze. Luckily, VBScript functions can come to your rescue. They provide you with a ready toolkit of functions for working with date and time information.

Working with Dates and Times

Many of the functions that follow can work with a date, a time, or a time and date. In VBScript, dates and times are often stored together. The date subtype is viewed as representing both a date and time in its own format.

Date, Time, and Now

Some of the easier functions to use are Date, Time, and Now. They simply tell you, through a character string, what the current date and time are. Date returns a string with the current date. Time returns a string with the current time. Now returns a string with the current date and time.

Date, Time, and Now lead to the same results. The difference is that while Date returns an individual date and Time returns an individual time, Now returns both the current date and time, combined into one string. Listing 16.1 shows how to use Now to provide feedback to the user.

Listing 16.1. Displaying current date and time using the Now function.
<!-------- Now Sample ------------------------------------------>
    msgbox "Current date / time is " & now, 0, "Using now"


When the user clicks on this test command button, Now is displayed, as shown in Figure 16.1.

Figure 16.1 : Using the Now function to inspect the current time.

Listing 16.2 uses Date and Time to provide feedback to the user about the current time.

Listing 16.2. Displaying current date and time using the Date and Time functions.
<!-------- Date Sample ------------------------------------------>
    msgbox "Current date / time is " & date & " " & time, _
           0, "Using date and time"


When the user clicks on the test command button, the date and time are displayed, as shown in Figure 16.2.

Figure 16.2 : Using the Date and Time functions to inspect the current time.

Year, Month, Day, Weekday, Hour, Minute, and Second

These functions allow you to easily work with pieces of a date and time string. If you need to use just the current hour figure to determine what type of data a program runs, you can easily parse out this information with the hour function. The same type of helpful function is available if you need to know what day of the week a certain date fell on. Use the Weekday function to get your answer. There is no need to write a detailed procedure to parse this information out of a date because it is already there.

Several such functions are provided for handling dates and extracting information. Year returns an integer representing the current year, Month returns an integer representing the current month, Day returns an integer representing the current day number, and Weekday returns number 1-7 to represent Sunday through Saturday, respectively. All the functions take a date specification as an argument and return data about that date supplied as an argument. The date specification argument is typically one of your variant variables, but it could also be the function Now or anything else in date and time format. Listing 16.3 shows these functions in use.

Listing 16.3. Using Year/Month/Day/Weekday to get detailed information about the current time.
<!-------- Year/Month/Day/Weekday Sample ------------------------------------->
    dim dtmCurrent

    ' Start out with current time as value to use
    dtmCurrent = now

    msgbox "Current year is " & Year(dtmCurrent) & "; month is " &_
        month(dtmCurrent) & "; day is " & day(dtmCurrent) &_
        ": weekday is " & weekday(dtmCurrent), _
        0, "Using year/month/day/weekday"


The year/month/day/weekday date information appears, as shown in Figure 16.3, after the user clicks on the test button.

Figure 16.3 : Using the date information functions to inspect characteristics of the current date.

The time-based functions work much the same. Hour, Minute, and Second can derive this information from the time supplied as an argument. Listing 16.4 shows these functions in use.

Listing 16.4. Using the Hour/Minute/Second functions.
<!-------- Hour/Minute/Second Sample ------------------------------------------>
<INPUT TYPE=BUTTON VALUE="Hour/Minute/Second Sample" SIZE=40 NAME="cmdHour">
    dim dtmCurrent

    ' Start out with current time as value to use
    dtmCurrent = now

    msgbox "Current hour is " & Hour(dtmCurrent) & "; minute is " &_
       minute(dtmCurrent) & "; second is " & second(dtmCurrent) _
       0, "Using hour/minute/second"

The hours/minutes/seconds information test appears, as shown in Figure 16.4, after the user clicks the test button. This code, like the other examples in this chapter, is easy to write because the functions are very straightforward to use.

Figure 16.4 : Using the Hour/Minute/Second information functions to inspect characteristics of the current time.

DateSerial and TimeSerial

The serial functions give you an easy way to calculate future or past dates based on an offset from today's date. With these functions at your disposal, you can make these calculations in one line of code. Suppose that you've heard that a friend's baby is due in seven months and three weeks. The code in Listing 16.5 could tell you the exact date that equates to.

Listing 16.5. Using the DateSerial function.
<!-------- Date Serial Sample ------------------------------------------>
<INPUT TYPE=BUTTON VALUE="DateSerial" NAME="cmdDateSerial">
    dim dtmCurrent

    ' Show what the will be 7 months and 3 weeks from now
    dtmCurrent = DateSerial(year(now),month(now)+7,day(now)+21)
    msgbox "The date will be " & dtmCurrent

The resulting message box, shown in Figure 16.5, provides the date 12/11/96 (when this program was run on April 20) from the date offset supplied to DateSerial.

Figure 16.5 : Using the DateSerial function to derive a future date.

DateSerial is handy at constructing a date from the year, month, and day components. The DateSerial approach can be much easier to use than building a date string by piecing together substrings.

The TimeSerial function serves the same purpose, but for times rather than dates. Assume that you want your script to remind the user that he is to meet someone exactly 2 hours and 17 minutes from now. You could use a code like that shown in Listing 16.6.

Listing 16.6. Using the TimeSerial function.
<!-------- Hour Serial Sample ------------------------------------------>
<INPUT TYPE=BUTTON VALUE="HourSerial"  NAME="cmdHour">
    dim dtmCurrent

    ' Start out with current time as value to use
    ' Show what the time will be in 2 hours and 17 minutes
    dtmCurrent = TimeSerial(Hour(Now)+2, Minute(Now)+17,0)

    msgbox "The time will be " & TimeValue(dtmCurrent)    

If you run this program at 1:03 p.m., you will see a result of 3:20 p.m., as shown in Figure 16.6. The VBScript TimeValue function is used to return just the time portion of the date and time information stored in the variant variable. Try this code without the TimeValue conversion and you will see that you get back a meaningless date along with the expected time.

Figure 16.6 : Using the TimeSerial function to derive a future time.

These functions work well going in the forward direction, but may provide results slightly different from what you might expect when going backward in time with a negative offset. Make sure you understand all aspects of their behavior if you will be using them in this manner.

The TimeSerial function, like the DateSerial function, is convenient for building an hour variable based on the hour, minute, and second numerical components. Often it is easier to build a time based on numeric expressions than on strings if calculations are involved.

Date and Time Comparisons and DateValue/TimeValue

If you do much with dates and times in your scripts, sooner or later you likely will want to compare two of them. Logical decisions can be made based on date and time comparisons. However, you have to keep a little trick in mind. The comparisons must be based on dates that are stored as date subtype variables, rather than based on string subtype variables.

Listing 16.7 can help illustrate this point. First, two different dates are assigned to variant variables. The variant variables regard the dates as string data at this point. Even though the dates are provided in a valid date format, the double quotes around them cause the VBScript run-time interpreter to assume that you want to work with string data. When the comparison is made, the two strings are compared based on, essentially, alphabetical order. The strings are ordered based on the ASCII characters. With this ordering, whichever year came first is irrelevant because the months are sufficient to separate the two strings. Therefore, the older date is regarded as the greater date.

Listing 16.7. Using the DateValue function.
<!-------- Date Comparison ---------------------------------------->
<INPUT TYPE=BUTTON VALUE="Date Compare"  NAME="cmdDateCompare">

dim DateA, DateB, strFeedback1, strFeedback2

' These dates are assigned as strings
DateA = "1/5/96"
DateB = "5/5/95"

' See which string-format date is more recent
if DateA > DateB then
  strFeedback1 = "First try - DateA is greater."
  strFeedback1 = "First try - DateB is greater."
end if

' Now store these dates in date format rather than string format
DateA = DateValue(DateA)
DateB = DateValue(DateB)

' See which date-format date is more recent
if DateA > DateB then
  strFeedback2 = "Next try - DateA is greater."
  strFeedback2 = "Next try - DateB is greater."
end if

Msgbox strFeedback1 & " " & strFeedback2,0,"Using Comparisons and DateValue"

After this comparison, the DateValue function is used to convert the string subtype variables to date subtype variables. Now the variant variables both contain date format data. When the comparison is again made after this assignment, the results are completely different. VBScript can now tell it is working with two dates, and the conditional expression correctly evaluates the fact that the new date is greater than the old date. The feedback from running this test can be seen in Figure 16.7.

Figure 16.7 : Date comparisons using DateValue.

The very same comparison rules apply to time values. String-based times will be compared as strings. Times stored in date and time format through the TimeValue function will be correctly treated as times in comparisons. Listing 16.8 illustrates how a.m. and p.m. times can be compared with this technique.

Listing 16.8. Using the TimeValue function.
<!-------- Time Comparison ---------------------------------------->
<INPUT TYPE=BUTTON VALUE="Time Compare" NAME="cmdTimeCompare">

dim TimeA, TimeB, strFeedback1, strFeedback2

' These times are assigned as strings
TimeA = "9:00 AM"
TimeB = "2:00 PM"

' See which string-format time is more recent
if TimeA > TimeB then
  strFeedback1 = "First try - TimeA is greater."
  strFeedback1 = "First try - TimeB is greater."
end if

' Now store these times in time format rather than string format
TimeA = TimeValue(TimeA)
TimeB = TimeValue(TimeB)

' See which date and time-format time is more recent
if TimeA > TimeB then
  strFeedback2 = "Next try - TimeA is greater."
  strFeedback2 = "Next try - TimeB is greater."
end if

Msgbox strFeedback1 & " " & strFeedback2,0,"Using Comparisons and TimeValue"

The result of running this script is shown in Figure 16.8.

Figure 16.8 : Time comparisons using TimeValue.

Understanding Date and Time Formats

So far you have seen some functions that work on dates, some that work on times, and some, such as Now, that work with both dates and times. You might be wondering how you tell VBScript to store a time as opposed to a date. The good news is that you don't have to. The VBScript date format is actually a date and time format. If there is pertinent time information, it gets stored as part of the date representation in a variable assignment. If you apply a date- or a time-based function to a variable, the function will work on the date or time portions of that variable as appropriate.

CDate and IsDate

Now that you have more insight into the date type, you can appreciate the role of yet another function, CDate. CDate converts an expression into a date and time. It can be used to assign a date string to a variant variable and cause that variable to represent the date with a date subtype. This may cause you to think, "Wait a minute! That's what DateValue does! Is this some conspiracy between Microsoft and authors to provide redundant functions to beef up the size of computer guides!?"

A better explanation is available, however. CDate converts date and time format data to date and time representations. DateValue converts only to date representations, and TimeValue converts only to time representations. Suppose you provide the expression 12/28/62 5:00 AM as an argument to TimeValue, DateValue, and CDate, respectively. TimeValue will return 5:00 AM, and DateValue will return 12/28/62, but CDate will return the entire date and time of
12/28/62 5:00 AM.

Since CDate has this dual date and time capability, it can also handle some formats that would cause DateValue or TimeValue to generate errors. Consider the following example:

msgbox CDate(( 96 * 365) + 0.5)

This would generate the date December 7, 1995, 12 p.m.. Date calculations start with the year 1900 as a basis. Advancing 365 days 96 times moves you forward almost 96 years. The date ends a little shy of 1996 because leap years have 366 days. Then, the 0.5 gets translated into half a day, or 12 hours. Listing 16.9 shows several more uses of Cdate.

Listing 16.9. Using CDate for date and time conversions.
<!-------- CDate Conversion ---------------------------------------->
dim strFeedback, VarA, VarB

' CDate converts days to date
strFeedback = "(1) " & CDate(( 96 * 365) + 0.5) & vbCrLf & _
       "(2) " & CDate("12/7/95 12:00") & vbCrLf & _
       "(3) " &  CDate("Dec 7, 1995 12PM") & vbCrLf & vbCrLf

VarA = "Pig"
VarB = "Dec 28, 1962"

if IsDate(VarA) then
    strFeedback = strFeedback & "VarA is " & CDate(VarA) & vbCrLf
    strFeedback = strFeedback & "VarA cannot be converted!" & vbCrLf
end if

if IsDate(VarB) then
    strFeedback = strFeedback & "VarB is " & CDate(VarB)
    strFeedback = strFeedback & "VarB cannot be converted!"
end if

msgbox strFeedback, 0, "Using CDate"

The corresponding results appear in Figure 16.9. Notice that CDate accepts date expressions in a variety of formats in addition to the numeric day specification. Valid expressions include 12/7/95 12:00 and Dec 7, 1995 12PM. However, even CDate can be brought to its knees by invalid data. Suppose you tried a function call like this:

Figure 16.9 : Using CDate to convert date and time expressions.

VarA = CDate("Pig")

This statement would cause an error. VBScript doesn't know how to map Pig to a valid date or time. This could present a bit of a problem in your scripts. How can you tell if something is in valid date and time format before you try to convert it? Fortunately, another function comes to the rescue. IsDate evaluates an expression and returns True if it can be converted to date format. Therefore, you can use code like that shown in Listing 16.9 to make sure an expression is in valid date and time format before you try to convert it.

There is one more trick to learn about date handling. How do you assign a time or date to a variable and ensure that the variant variable represents it internally as a date subtype rather than as string data? For example, this assignment just stores a string (that happens to be in valid date format) into varA:

varA = "7/6/62"

There is a symbol (#) for telling VBScript to treat a value as the date subtype when it stores it. This assignment would store date subtype information into varA:

varA = #7/6/62#

If you want to convince yourself that it works, you can write a test to display the subtype using the VBScript VarType function after each assignment.

It turns out that in most cases you can work in the string format with your dates and everything will be just fine. There are times when you may want to use #, however. For example, if you need to store a series of date values for calculations with DateSerial, the efficiency of your code will be improved by storing them as date subtype variants.

As you can see, a full range of functions supports date and time handling in your scripts. These functions make it easy to validate, compare, and calculate future dates and times. With them, the days of old when date and time information had to be sent to a server for evaluation are past. Your scripts can use these functions to take an active role in dealing with date and time information.


Ask any computer science major to summarize his educational background, and it'll come to light that hidden in the dark recesses of his past is math. Plenty of math. Many students would claim that the reason for the emphasis on math in a computer science curriculum is faculty cruelty. But many of the computer programs written require some type of math to process user data and provide results. Many require extensive mathematical operations. The ability to carry out precise calculations is an integral part of programming.

It comes as no surprise then that an important part of any programming language is the mathematical capabilities it supports. These capabilities influence the type of programs that can be easily produced in a given language. VBScript is often thought of, like many scripting languages, as a lightweight scripting language with a focus on gluing together other components rather than language features themselves. Therefore, you may have expected that you would need to incorporate controls into your Web pages to carry out advanced mathematics. However, this isn't entirely true. VBScript provides a fairly rich set of mathematical capabilities. You can accomplish a lot in your Web pages by just using the math functions that are inherently supported in VBScript. These functions are described in the sections that follow.

What Does VBScript Let You Do with Math?

The answer to this question lies in the operators and variables supported by VBScript. VBScript has a full range of mathematical operators, as introduced on Day 5, "Putting Operators to Work in VBScript." Of course, the ability to carry out operations is of little value unless you have data to act on and have somewhere to store the intermediate and final results. That is where variables come into play. The type of variables used during mathematical operations has a direct impact on the results that can be produced. On Day 4, "Creating Variables in VBScript," you learned that the variant data type is the only type used for Visual Basic variables. This also significantly shapes the approach you can take to mathematically based problems in VBScript. Just as you can't really describe the taste of a good bowl of cereal by describing the flakes and not the milk, so it is with variables and operators. Neither of these issues can be considered in a vacuum. The function of the operators is related to the variable types they act on, and variable behavior is affected by the values assigned from operators. So let's take a look at operators and the variant variable in tandem and consider how they play together.

Abs and Sgn

If you work very much with numeric data, there is a good chance that sooner or later you will have to be concerned with the issue of the mathematical sign of a number. Suppose, for example, that you have a Web page that prompts the user to enter the amount he spent on a business trip. Because of your company travel policy, users are never given money ahead of time and can only receive a reimbursement later. Suppose that some users indicate the amount they spent as a negative number, and others enter it as a positive number. You need to write a script that totals the amount and adds it to some other figures. In this case, you want your script to ignore the sign the user has entered and treat the value as a positive one. The Abs function can do this. It will return the positive representation of the number passed to it as an argument. So the following statement would display 10 10:

msgbox Abs(-10) & " " Abs(10)

Signs are essentially discarded by this function.

The Sgn function has somewhat of an opposite role. This function determines the sign of a number. The function returns an integer that provides information about the sign through the return codes, documented in Table 16.1.

Table 16.1. Return codes from the Sgn function.
Return Code
Number passed as parameter to Sgn is greater than 0
Number passed as parameter to Sgn equals 0
Number passed as parameter to Sgn is less than 0

One way this function could be used is to provide feedback about input. In the case of the expense account form example, you could encourage your users to enter information in a consistent manner. If you found that a user had entered an expense as a negative value, code like that shown in Listing 16.10 could guide him.

Listing 16.10. Using Sgn to check the sign of user input.
if Sgn(Val(txtExpense.Value)) = -1 then
    MsgBox "Please provide expense amounts as positive values in the future. "
end if

Another example of Sgn and Abs is shown in Listing 16.11. In this case, the absolute value of a number is displayed, followed by the results of checking its sign. Because the number evaluated is -10, the absolute value becomes 10. The return code from the Sgn function is -1, indicating a negative number. The results are shown in Figure 16.10.

Figure 16.10 : Using Sgn and Abs.

Listing 16.11. Using Sgn and Abs.
<!-------- Sgn and Abs ---------------------------------------->
dim strFeedback, intResult, VarA

VarA = -10
strFeedback = "VarA is " & VarA & " and the absolute value of VarA is " & _
     Abs(VarA) & vbCrLf

intResult = sgn(VarA)
if intResult = 1 then
    strFeedback = strFeedback + "VarA is more than 0"
elseif intResult = 0 then
    strFeedback = strFeedback + "VarA is 0"
elseif intResult = -1 then
    strFeedback = strFeedback + "VarA is less than 0"
end if

msgbox strFeedback, 0, "Using Abs and Sgn"

You could easily implement both the Sgn and Abs functions yourself if they were not provided for you. To carry out the interpretation provided by Sgn, you would simply need to check if a number is less than 0, equal to 0, or greater than 0. The Abs conversion can be achieved by just checking to see if a number is less than 0, and if so, multiplying by -1 to convert it to the corresponding positive number. Even though it's easy to write code that carries out the equivalent of these functions rather than use them, avoid this temptation. Using the functions provided brings several advantages. You know they work, and if you write your own functions, you might introduce silly coding errors. Just as importantly, the use of these functions provides a clear, standard approach in your code. It is easy to tell the intention of code that uses Sgn and Abs when reviewing and maintaining it.

The Logarithmic Functions-Log and Exp

The math functions examined so far today have been very straightforward in purpose. The next set may take a little more thought if your math guides have gathered some dust over the years. VBScript provides support for dealing with natural logarithms and antilogarithms of numbers. The explanation that follows is simplified to convey the power of these functions. If you are in the dusty math guide category and the time comes when you have to apply these functions in a script of your own, find a good math guide to ensure that you are clear on the purpose.

Consider the number 1,000 in the context of base 10. Suppose you want to know how many times 10 must be multiplied by itself to produce 1,000. The answer, of course, is 3(10¥10¥10). You can use the Log function to help derive this answer.

The Log function works in terms of base e. This natural logarithm has special properties, which are left to the math guides to address. The base e constant behind these special properties is approximately 2.718282. Log works in terms of this base. When you supply the following expression you will get a result of approximately 1, based on the base value of 2.718282. Another way to think of this is that a single instance of the e constant (2.718282) yields a value of 2.718282:

Msgbox Log(2.718282)

When you supply the following expression, you will get a result of approximately 3. This result reflects the fact that e * e * e (or 3 instances of multiplying e by itself) is equivalent to 20.086:

Msgbox Log(20.086)

In other words, 20.086 is approximately equal to 2.71828¥2.71828¥2.71828.

If you're not a math jockey, at this point you may be thinking, "I may have to find out how many times 2 goes into a kilobyte from time to time, but I'm never gonna care about this e stuff!" The natural logarithm is useful for something other than academic exercises. One of the neat characteristics of the natural logarithm is that it can be used to derive logarithms in other bases.

Assume that you want to find out how many times you must multiply 2 by itself to get a kilobyte, or 1,024 bytes. The problem you are faced with is how to calculate a base-2 log for the number 1,024. VBScript doesn't allow you to do this directly. But you can calculate this, or any similar problem, by combining two base e Log function calls. Simply use this:

Msgbox "The problem Log 2 (1024) is equal to:" & Log(1024) / Log(2)

The result that is displayed from this call is 10. And sure enough, 1024=2¥2¥2¥2¥2¥2¥2¥2¥2¥2.

So the natural log Log functions provide you with the means to calculate a logarithm of any base. For a base n and number x, just use this formula:

Logn(x) = Log(x)/Log(n)

You don't have to resort to exotic math libraries or server-side processing if you have an algorithm that needs to use logarithms of any base. You can use the VBScript function now that you know the secret of how to apply it.

Log has a close cousin called Exp. This function is sometimes called the antilogarithm, and it returns e raised to the given power. For example, consider this statement:

Msgbox Exp(3)

This will display 20.086, which is approximately equal to 2.71828¥2.71828¥2.71828. In the earlier example, you saw that Log(20.086)=3, so you can see that these two functions are closely related.

Note that this is different from the exponent operator discussed on Day 5. In that lesson you saw how an expression like the following evaluates to 8 because 2¥2¥2= 8:

Result = 2 ^ 3

In the case of the ^ operator, the value to the left of the operator is raised to the given power. With Exp, e itself is raised to the power provided.

Another example of the use of Log and Exp appears in Listing 16.12. This example first demonstrates the use of the natural exponent base e. The first statement raises e to a power using the Exp function. The next statement computes the corresponding log in base e, providing the result of the first calculation as the argument to the Log function. The next statement shows how to raise a number with a regular base to the given exponent by simply using the standard ^ operator. Finally, the last statement calculates the corresponding log to base 10. To do so, the Log base e of the previous statement's result is divided by the Log base e of the desired base of the solution, 10.

The results from running this example can be seen in Figure 16.11. Once you understand what these functions are doing, they are as easy to understand and apply as the other math operators covered so far. The important thing is to be aware that they exist, so when opportunities arise to make use of them, you don't have to turn any further than VBScript.

Figure 16.11 : Using Log and Exp.

Listing 16.12. Using Log and Exp.
<!-------- Log and Exp ---------------------------------------->
dim strFeedback

strFeedback = "e * e * e * e = Exp(4) = " & Exp(4) & vbCrLf & vbCrLf

strFeedback = strFeedback & "Log base e of 54.598 = Log(54.598) = " &_
    Log(54.598) & vbCrLf & vbCrLf

strFeedback = strFeedback & "10 * 10 * 10 * 10 * 10 * 10 = 10 ^ 6 = " & _
    (10 ^ 6) & vbCrLf & vbCrLf

strFeedback = strFeedback & "Log base 10 of 1,000,000 = Log(1000000)/Log(10) &_
    = "Log(1000000)/Log(10)

msgbox strFeedback, 0, "Using Log and Exp"

The Square Root Function-Sqr

In the last section you learned about the use of the standard exponentiation operator ^ to raise a number of a given base to the specified power. For example, the following statement displays a 25, the result of 5¥5:

Msgbox 5 ^ 2

A corresponding function, Sqr, returns the square root of a given number. Sqr is as straightforward as the exponentiation operator. For example, the following statement will display a result of 5, because 5¥5=25:

Msgbox Sqr(25)

Likewise, the following statement will display a result of 3, since 3¥3=9:

Msgbox Sqr(9)

The square root function returns data that is in the variant double subtype because the result can contain decimal data to a great degree of precision.

The Trig Functions-Sin, Cos, Tan, and Atn

Keep out the dusty math guide for the next set of functions. The trigonometric functions in VBScript consist of Sin, Cos, Tan, and Atn. You likely either use trig functions quite frequently in your programming and already know what they are or never use them and have long since forgotten what a hypotenuse is. If you need to brush up on your trig, refer to a good math guide. However, if you are not hypotenuse literate, there is something important to take from the discussion that follows. Realize that VBScript provides trig support. You can have local trig processing on your pages without resorting to a control. You may not be using trig today, but many types of programs do require it, and you could find yourself implementing a trig-related solution tomorrow. When that time comes, turn to Sin, Cos, Tan, and Atn.

The names of all these functions are relatively self-explanatory. They deal with the relationships of triangle angles and sides. Sin takes an angle as a parameter and returns the sine of an angle, as you might expect. The sine of the angle is the ratio of the side opposite the angle under consideration divided by the hypotenuse length. Cos takes an angle parameter and returns the ratio of the length of the side adjacent to the angle divided by the hypotenuse length. Tan returns the tangent of an angle. An angle is supplied as a parameter. Then the length of the side opposite the angle is divided by the length of the side adjacent to the angle to determine the ratio return value. Atn provides the arctangent for the given ratio. The number representing the ratio is supplied as a parameter. This ratio consists of the side opposite the angle divided by the side adjacent to the angle. The angle that corresponds to this ratio is returned.

Angles are traditionally represented in radians. When angles are used with these functions, they are represented in terms of radians. If you have a number in degrees you want to convert to radians, just multiply the degrees by 3.141593/180. If you want to convert radian results back to degrees, multiply the radians by 180/3.141593. The value 3.141593 is a special number in angular geometry called pi.

Now that you know the function names and how angles are represented, you can do anything you need with these angles. An example that demonstrates the use of these functions can be seen in Listing 16.13. The sine, cosine, and tangent of 45 degrees are all displayed by using the Sin, Cos, and Tan functions, respectively. To provide 45 degrees as an argument to the trig functions, the degrees to radians conversion factor is applied. Then, the arctangent of the ratio of two equivalent sides of a triangle is calculated. That result is returned in terms of radians by the Atn function. Therefore, it must be converted back to degrees using the radians to degrees conversion factor. The results from this sample program appear in Figure 16.12.

Figure 16.12 : Using Sin, Cos, Tan, and Atn.

Listing 16.13. Using Sin, Cos, Tan, and Atn.
<!-------- Sin, Cos, Tan, Atn ---------------------------------------->
dim strFeedback

strFeedback = "Sin of 45 degrees = " & Sin(45 * (3.141593/180)) & vbCrLf
strFeedback = strFeedback & "Cos of 45 degrees = " & _
    Cos(45 * (3.141593/180)) & vbCrLf
strFeedback = strFeedback & "Tan of 45 degrees = " & _
    Tan(45 * (3.141593/180)) & vbCrLf
strFeedback = strFeedback & "Atn of 1/1 ratio in degrees = " & _
    Atn(1) * (180/3.141593)

msgbox strFeedback, 0, "Using Sin, Cos, Tan, and Atn"

Extending the Power of VBScript Through the Log and Trig Functions

VBScript obviously is perfectly capable of performing basic trig and natural log functions. Of course, if you have some really math-intensive projects, you might wish you could get more from your scripts. Some day you may find yourself staring into space, dreamily thinking, "If only I could figure out an inverse hyperbolic tangent from VBScript…then I'd have it all." There's good news for when this day comes. It turns out that by using these functions as building blocks, you can carry out a whole host of additional functions. For example, you can code the inverse hyperbolic tangent as follows:

HyperArcTan = Log((1 + arg) / (1 - arg)) / 2

If you need the cosecant, you can get it with

CoSecant = 1 / Sin(X)

By building on the functions you already know, you can implement many more advanced functions. It is beyond the scope of this guide to describe and illustrate all these advanced functions. If you find yourself in a situation that requires them, all you'll need is a good math guide that lists the formulas and knowledge of the intrinsic functions described here to serve as the building blocks. Then your Web pages can come alive with advanced math that would warm the heart of your old math teacher, all without even leaving the confines of VBScript.

Rounding and the Integer Functions-Fix and Int

When you deal with numbers and produce results, you need to handle them in different ways. You will want to keep some results, such as the grade point average of a student, in decimal format. Other results, such as the total number of employees you need to hire to staff a factory based on average staffing history, you may need to round. After all, it could be hard to hire 20.7 workers if your company doesn't make use of part-time help. It's better just to hire 21 workers. Still other results may need to be truncated. If you are writing a program that provides billing estimates based on the number of days a patient stays at a hospital, but you only charge for full days, you might treat a total of 14.2 days or 14.9 days as simply 14 days.

VBScript provides the means to carry out all these tasks with the help of a couple easy-to-use functions. First of all, consider the case of truncating. Truncating a decimal point is essentially the same as returning the corresponding integer. The Int function serves this purpose by returning the integer portion of a number. This statement:

msgbox Int(14.9)

displays 14, as does this statement:

msgbox Int(14.2)

These statements would have worked exactly the same if the Fix function were used. Fix also truncates a number to display its integer representation. For example, the following statement would display 15:

msgbox Fix(15.7)

One difference between these two functions-and it is a subtle one related to rounding negative numbers-is that Fix truncates a negative number so that the value is greater, and Int produces the negative integer that is less than the value supplied. So the following would display -15:

msgbox Fix(-15.7)

But this statement would display -16 instead:

msgbox Int(-15.7)

If you need to round a number rather than truncate it, you can always build in the rounding yourself. If you add .5 to a decimal number and then take the integer value using Int, the result is to round it to the next higher integer if the number originally contained a decimal portion greater than .5. If VarA contains 1.7, the following statement will display the result 2.0:

msgbox Int(VarA + .5)

An easier and slightly different way to round is built into VBScript. The Cint function, which was discussed on Day 4, will round a number to the nearest integer. If decimal values are less than .5, the number is rounded down. If decimal values are greater than .5, the number is rounded up. If the decimal portion of a number is exactly equal to .5, then it is rounded to the nearest even number. For example, 7.5 would be rounded up to 8. Since 7.5 is between the two even numbers 6 and 8, 8 is the nearest even number and is selected as the rounding result. Likewise, 6.5, sandwiched between 6 and 8, would be rounded down to 6.

These functions have many potential applications in code. But it is critical to understand exactly what they are doing before making use of them. Listing 16.14 provides a series of examples to highlight the behavior of the functions.

Listing 16.14. Using Int, Fix, and Cint to truncate and round.
<!-------- Int, Fix, Cint  ---------------------------------------->
dim strFeedback, intResult, VarA

VarA = 14.5
strFeedback = "VarA = " & VarA & vbCrLf
strFeedback = strFeedback & "Int(VarA) = " & Int(VarA) & vbCrLf
strFeedback = strFeedback & "Fix(VarA) = " & Fix(VarA) & vbCrLf
strFeedback = strFeedback & "Cint(VarA) = " & Cint(VarA) & vbCrLf & vbCrLf

VarA = -6.5
strFeedback = strFeedback & "VarA = " & VarA  & vbCrLf
strFeedback = strFeedback & "Int(VarA) = " & Int(VarA) & vbCrLf
strFeedback = strFeedback & "Fix(VarA) = " & Fix(VarA) & vbCrLf
strFeedback = strFeedback & "Cint(VarA) = " & Cint(VarA) & vbCrLf & vbCrLf

VarA = -3.902
strFeedback = strFeedback & "VarA = " & VarA  & vbCrLf
strFeedback = strFeedback & "Int(VarA) = " & Int(VarA) & vbCrLf
strFeedback = strFeedback & "Fix(VarA) = " & Fix(VarA) & vbCrLf
strFeedback = strFeedback & "Cint(VarA) = " & Cint(VarA) & vbCrLf

msgbox strFeedback, 0, "Using Int, Fix, and CInt"

The result from this series of tests appears in Figure 16.13. As you can see, in many cases Int, Fix, and Cint end up providing the same result. The differences between the functions are only apparent for certain types of arguments. It helps to think of these functions in terms of a number line. If you really want a number to be rounded, rather than truncated, you should use Cint. This moves you to the closest integer on the number line and chooses the closest even integer when the choice is a toss up. If you simply want to truncate the number and you always want to truncate to a lesser value, then Int is the way to go. This always advances you left on the number line to the previous integer. If you do have a special situation where you want to truncate, but you always truncate closer to 0, then use Fix. This function will always advance you to the next closest integer to 0, moving you left on the number line when you started with a positive number, and right on the number line when you started with a negative number.

Figure 16.13 : Using Int, Fix, and Cint to truncate and round.

Randomize and Rnd

So far the discussion has focused on predictable results. But under some circumstances, you may want the behavior of your Web pages to appear random. Maybe you have a label that flashes different colors, and you want to generate those colors in a random pattern. Or perhaps you want to carry out a virtual roll of the dice each time a page is loaded, and provide the user with a different customized greeting based on the number that is generated. This would give your users a feeling of freshness. They'd feel like your pages were changing daily. Because many Web development guidelines emphasize variability as the key to keeping users coming back for repeat visits to a page, this is an especially important strategy.

It is hard to make computers perform randomly since they are essentially dumb devices that act consistently on whatever instructions are provided to them. (It is hard to remember that computers are consistent in the middle of an all-night bug-chasing session, but they are!) However, with the help of a function, Rnd, you can introduce an element of random behavior. Rnd returns a number from an internal random number sequence.

Rnd pulls numbers from the internal sequence in the same manner each time it is used. So if you had a script that made use of Rnd to display a series of random numbers, the series would look the same every time the program ran. This reduces the variability impact you would hope to achieve by using random numbers in the first place.

A statement can be used to avoid this effect, however. The Randomize statement initializes the internal sequence of numbers subsequently used by Rnd with a different sequence. The sequence used is based on the argument provided with Randomize, and is called a seed. If you do not provide this argument, then it is automatically based on a system timer. The timer value is likely to differ from one time to another when a script is run. Therefore, using Randomize with no argument prior to code that makes use of the related Rnd function is a common approach. The prior use of Randomize forces Rnd to generate a different sequence of random numbers from one time a script is run to the next.

The number returned by Rnd will vary from between greater than or equal to 0 up to less than but not equal to 1. The specific value returned depends on the random sequence in use. So the statement that follows returns a value that will never be less than 0 and never be equal to or greater than 1:

VarA = Rnd

This is somewhat of a problem if you want a random number outside this range. Suppose you're trying to simulate the role of a die. You want the code to generate a random integer between 1 and 6. If you multiply the result of Rnd by 6, you get a number that can range from 0 to 5.99999. If you add one to whatever the result, you have shifted your possible outcomes to range from 1 to 6.99999. Then, if you truncate the decimal portion of the number using the Int function, you have ensured that the result will be either 1, 2, 3, 4, 5, or 6. This statement appears as

VarA = Int(6 * Rnd + 1)

This approach to force random numbers to fall as integers within a given range can be represented more generically by the following formula:

Int((High_integer_desired - Low_integer_desired + 1) * Rnd + Low_integer_desired

You can see this formula at work in Listing 16.15. This sample program simulates the roll of six dice. The Random statement is used at the beginning of the script to ensure a different series of numbers will be provided each time the script is run. Then each specific role is generated by a call to the Rnd function. The formula listed earlier is used to massage the return value somewhere into the range of 1, 2, 3, 4, 5, or 6.

Listing 16.15. Using Rnd to simulate dice rolls.
<!-------- Rnd ---------------------------------------->
dim strFeedback, intCounter


' Perform six rolls of the dice
for intCounter = 1 to 6
   strFeedback = strFeedback & "Roll " & intCounter & ": " & Int((6 * Rnd) + 1) & chr(13)

msgbox strFeedback, 0, "Using Rnd to Simulate Dice Rolls"

The results from one trial of this script can be seen in Figure 16.14. Notice that two different rolls of six resulted. If you run this script again, you will get different results each time.

Figure 16.14 : Using Rnd to stimulate rolls of dice.

One way that Rnd is commonly used with Web pages, aside from rolling dice, is to produce random colors to liven up pages or make them appear fresh from one use to another. For example, you could have a code event associated with a timer control that is triggered every second. At each interval when it is called, that code could change the color of a label control that displayed a greeting. Listing 16.16 shows this type of code.

Listing 16.16. Code that randomly changes the color of a label.
sub timer_time
    lblGreeting.forecolor = Int (16777217 * Rnd)
end sub

The random number normally will fall between 0 and 1. Therefore, the standard range-producing formula is applied to the random number result. The formula forces the number to fall somewhere between 0 and 16777216, which is the highest color that can be represented. A color anywhere within this spectrum could appear.

The dice-rolling script and the code to produce random colors are just two of the many ways to use random numbers in your scripts. Random numbers have many other uses ranging from games, to lively screens, to random-sequence quizzes, to advertising blurbs. Two important aspects to remember when you work with random numbers are initializing the random-sequence seed number and converting the Rnd result. You initialize the random-sequence seed number by calling Randomize at the start of your script. This will ensure that you get a different series of numbers from one time the script is run to another. Also make sure that you convert the Rnd result to the desired range. You'll be able to welcome random behavior into your scripts on your own terms with this standard approach.

Working with Non-Decimal Systems-Hex and Oct

You may be able to go your entire programming career without ever having to worry about producing hexadecimal or octal numbers. Most math work tends to be our common base 10 system, rather than the base 16 hexadecimal system or base 8 octal system. On the other hand, you may not have this luxury if you work on scripts that are centered on math or computer software or hardware. If you do need to deal with hexadecimal or octal numbers, two handy VBScript functions are at your disposal. Hex returns a string containing the hexadecimal representation of the number passed as an argument. Oct returns a string containing the octal representation of the number.

You can see these functions in action in Listing 16.17. The corresponding results are shown in Figure 16.15.

Figure 16.15 : Using Hex and Oct.

Listing 16.17. Using Hex and Oct.
<!-------- Hex and Oct ---------------------------------------->
dim strFeedback, VarA

VarA = 256

strFeedback = "VarA is " & VarA & vbCrLf
strFeedback = strFeedback & "Oct(VarA) is " & Oct(VarA) & vbCrLf
strFeedback = strFeedback & "Hex(VarA) is " & Hex(VarA) & vbCrLf

msgbox strFeedback, 0, "Using Hex and Oct"

The first statement of the code assigns the value 256 to a variable. Then the variable is printed out in the default base 10 representation. 256 results, with the 2 signifying 2 units of 100, the 5 signifying 5 units of 10, and the 6 signifying 6 units of 1.

The next statement prints the base 8 octal representation of the number through the Oct function. The same value 256 is now represented by 400 octal. The 4 indicates 4 units of 64, with 0 units of 8, and 0 units of 1.

The final statement prints out the base 16 hexadecimal representation by using the Hex function. The value 256 is now represented as the number 100 hexadecimal. The 1 signifies 1 unit of 256, with 0 units of 16 and 0 units of 1.

The Hex and Oct functions give you the flexibility to easily handle the most common bases you're likely to run into. You don't need to build your own functions to convert from decimal to octal or hexadecimal. Simply apply these conversion functions, and your script has all the power and more of a hexadecimal/octal/decimal calculator.

Representation and Storage of Hex and Octal Numbers

If you want to represent a hex number directly in your code, you can do it by preceding the hex number with &H. The following statement, for example, assigns 256 to a variable by setting it to the hex equivalent:

VarA = &H100

Likewise, &O can be used to represent an octal number. This statement also assigns 256 to a variable by setting it to the octal equivalent:

VarB = &O400

These variables just contain 256, with nothing special about it. The &O and &H representation of the data is just a convenient way to describe it to VBScript. However, since all numbers are stored internally in the computer as a series of bits, there is no internal notion of which base a number was assigned in. If you print out the values of the variables used in the preceding examples, you will see the default base 10 notation. For example, the following will print out 256 256:

MsgBox VarA & " " & VarB

On the other hand, you can present the data in hexadecimal format with the Hex function:

MsgBox Hex(VarA) & " " & Hex(VarB)

This prints out 100 100, which is the hexadecimal representation of 256.

The Mod Operator

So far the focus in today's lesson has been largely on functions. Operators were covered in detail on Day 5. One operator deserves some additional coverage, however. The Mod operator is commonly used in scripts by those who understand how to use it. Mod carries out what is termed as a modulus operation. It takes two numbers, divides them, and then returns the remainder as the result.

The example in Listing 16.18 takes the grand total of days, divides by 7 to determine how many full weeks were taken, and then uses the modulus to determine the remaining number of days beyond the last full week.

Listing 16.18. Using Mod to determine the number of weeks and days that have gone by.
Dim intWeeks
Dim intDays
intWeeks = s_intTotalDays \ 7
intDays = s_intTotalDays Mod 7
MsgBox "The total time is " & intWeeks & " weeks and " & intDays " days. "

Mod is very handy for certain types of loop control as well. Suppose you have a loop that performs a lengthy series of calculations. This may keep the user waiting several minutes, so you want to provide occasional feedback on a regular basis after a given number of loops have been carried out. The code in Listing 16.19 shows one such approach. Figure 16.16 shows the corresponding results after the first period of loops.

Figure 16.16 : Using Mod.

This code carries out 1,000 loops, adding the value of every number between 1 and 1,000. After each 200 loops, a message box is provided to the user to let them know how far along the calculation is. (In a script intended for real use, you would not want to use a message box for the progress indictor since it requires user interaction. A label on the page would be better. But it makes for a nice clear example, so this approach is used here.) Now you could detect every 200th loop by checking to see if the counter variable intCounter is equal to 200, 400, 600, 800, or 1,000. This code is kind of cumbersome and not maintainable. If you modify the calculation to go up to 10,000 loops next week, just think of all the additional numbers the code would have to check. A much more elegant solution is shown in Listing 16.19. Simply take the modulus of the current counter variable. If you divide by 200 and look at what's left over, you will only find a remainder of 0 once every 200 loops. Mod becomes the perfect means to monitor a loop and takes action at a given period. It is true that Mod will make your loop take longer to execute. After all, you're doing another division every time through the loop. However, this effect is normally not a big factor in user script speed. Also, in many situations, the advantages of this approach can outweigh such considerations.

Listing 16.19. Using Mod to provide periodic feedback in loops.
<!-------- Mod ---------------------------------------->
dim intCounter, lngTotal

for intCounter = 1 to 1000

    lngTotal = lngTotal + intCounter

    if (intCounter mod 200) = 0 then
       ' This only occurs after every 200 loops.
       '   Provide the user with a progress indicator at this point
       MsgBox "Have processed " & intCounter & " records.",0,"Progress_
    end if

msgbox "Grand total is " & lngTotal, 0, "Using Mod"

Variable Representation of Numeric Data

The final area of focus in this lesson is simply a reminder of the functions available for data conversion that have already been covered. Day 4 looked at variable representation. You can use Cint, Cdbl, Clng, and Csng to convert expressions into a specific numeric data subtype of integer, double, long, and single, respectively. Also, insights from Day 15, "Extending Your Web Pages with Strings," help explain some of the considerations when converting numbers to strings and strings to numbers. Str and CStr can be used to convert numbers to strings Val, the function to convert in the opposite direction, is used to convert a string to a number of the double subtype. Coupled with the Cdbl, Csng, Clng, and Cint functions, you can control the data subtype of variables and expressions whenever needed.


Today's lesson shows you a wide variety of advanced functions that are part of the VBScript language. The first functions are the date and time functions. Dates are represented internally in a variant variable with components for both the date and the time. For date and time information, you can use Date, Time, or Now to get information on the current date, time, or date and time setting. Many functions for working with date and time components are available. They include Year, Month, Day, Weekday, Hour, Minute, and Second. DateSerial and TimeSerial provide a means to build dates and times, including those in the future as offsets from the current date or time. The functions DateValue, TimeValue, CDate, and IsDate allow for easy conversion of strings to dates.

Many math functions can save you a lot of time in math-intensive scripts, just as many date functions are supported in VBScript to make date handling easier. Trigonometric functions allow you to carry out angular geometry calculations in your code. The logarithmic functions Exp and Log allow you to calculate exponents and logarithms based on the natural log base e. Perhaps more useful is the fact that if you know how to use Log, you can apply the formula to determine the logarithm of any number, regardless of base. Supported trig functions are Sin, Cos, Tan, and Atn. Many other commonly used trig values are not directly supported by VBScript, such as the inverse hyperbolic tangent. But by using the functions that are supported as building blocks, any of the more advanced functions can be easily supported directly in code.

Techniques for producing random numbers with Randomize and Rnd are provided in today's lesson. Some common uses of random numbers in Web pages are discussed. Rounding is examined. Approaches for truncating with Int and Fix and for rounding with Cint or self-produced functions are illustrated. Many other functions are considered, including Abs, which removes negative signs, and Sgn, which tells whether a sign is present. Hex and Oct are highlighted and a sample of those functions producing hex and octal numbers is provided.


QIs using the Date and Time functions and combining the results more accurate than using the Now function?
ANo. Essentially these functions just provide different ways to access the same data. Date and Time are appropriate to use when you need to get at the individual date or time components. Now is appropriate to use when you need to reference the entire date and time format information.
QWhat is the difference between TimeValue and TimeSerial? Can you use either to calculate what the time will be in 1 hour and 15 minutes?
ATimeValue converts a string to a time format. TimeSerial provides a time-format return code that is based on the hour, minute, and second parameters. TimeSerial accepts offsets to its hour, minute, and second parameters. Therefore, it provides a powerful ability to generate future dates based on the input provided to it.
QWhat would happen if you used Rnd in a script but forgot to include Randomize?
AThe same series of numbers would be used every time the script is run. Randomize is required to set the random number generator seed and ensure it is unique. If you don't use it, any random numbers generated will follow the same sequence from one run of the script to another.


Earlier in this lesson you saw a partial example of displaying a label in varying colors, by using the Random and Rnd functions from within a timer event. Consider whether you have Web pages that would be more attractive to your users if your pages made use of a random factor to convey fresh information each time the page was visited. Perhaps you can generate a different greeting or tip based on a list of choices in your code and a random lookup. If you identify areas where you could benefit by a dose of random behavior, think about how much work it would likely take to do this.


Refer to Appendix C, "Answers to Quiz Questions," for the answers to these questions.

  1. Write a script that displays a message only if the date previously stored in a global variable s_dtmEvent is chronologically later than the current time.
  2. List the results that will be displayed for each of the following lines:
    msgbox Int(-5.5)
    msgbox Fix(-5.5)
    msgbox Cint(-5.5)
  3. Write code that determines how many players are left over if you divide up the number of players specified by s_TotalPlayers into bowling teams of nine bowlers each. Use Mod to accomplish this.