|
Jonathan E. Sisk's Pick/BASIC: A Programmer's Guide WWW Edition January, 2000
Chapter 7 |
In this example. the principles of converting and formatting are covered. Topics, statements, and functions covered include print (format) masking, GOTO, ICONV, OCONV(D,MT), SPACE, DATE(), TIME(), and TIMEDATE().
Enter Program Example 5, shown in Fig. 7-1.
The ICONV function is used to convert data from its external format to its internal format. To explain external versus internal is relatively easy; external format is the form in which a piece of data is readable to humans; internal format, as briefly introduced in Chapter 1 , most often makes sense only to the computer.
Notice that the ICONV function has two arguments. The first argument is the string of numbers or characters that are to be converted. The second argument is the conversion code. One example of a conversion code is the date, or "D" conversion:
027 INTERNAL.BIRTHDAY = ICONV(BIRTHDAY,"D")
The Pick System stores dates in an internal format which is a number representing the number of days that have elapsed since December 31, 1967. (Day zero on the Pick Calendar). Every night at midnight, a counter is incremented by 1. Consequently, if you were to find an item in a file which had the number 7777 stored in an attribute, it could be a date in internal format, or an amount of money, or a street address. The only person who knows for sure is the programmer who put it there.
Fig. 7-1. Program Example 5.
001 * EX.005
002 * PRINT MASKING, INTERNAL AND
EXTERNAL CONVERSIONS
003 * mm/dd/yy: date last
modified
004 * JES: author's initials
005 *
006 PROMPT
":"
007 *
008 * GET FIRST AND LAST NAME
009
*
010 PRINT
011 PRINT "ENTER YOUR FIRST NAME
:
012 INPUT FIRST.NAME
013 IF FIRST.NAME = "QUIT"
THEN STOP
014 *
015 PRINT
016 PRINT "ENTER
YOUR LAST NAME " :
017 INPUT LAST.NAME
018 IF
LAST.NAME = "QUIT" THEN STOP
019 *
020 * GET
BIRTHDAY
021 *
022 LOOP
023 PRINT
024
PRINT "ENTER YOUR BIRTHDAY (MM-DD-YY) " :
025 INPUT
BIRTHDAY
026 IF BIRTHDAY = "QUIT" THEN STOP
027
INTERNAL.BIRTHDAY = ICONV(BIRTHDAY,"D")
028 UNTIL
INTERNAL.BIRTHDAY # "" DO
029 PRINT "SEPARATE MONTH
DAY AND YEAR WITH DASHES!"
030 REPEAT
031
*
032 * NOW LET'S SHOW OFF
033 *
034
PRINT
035 PRINT "HELLO THERE " : FIRST.NAME
036
PRINT
037 PRINT "THE CURRENT DATE IS ":
OCONV(DATE(),"D2/")
038 PRINT "THE CURRENT TIME IS ":
OCONV(TIME(),"MTH")
039 PRINT
040 PRINT "IF YOU
WERE BORN ON " : BIRTHDAY :
041 PRINT ", THEN THE DAY
OF THE WEEK WAS " :
042 PRINT
OCONV(INTERNAL.BIRTHDAY,"DWA")
043 PRINT "THIS WAS
DAY " : OCONV(INTERNAL.BIRTHDAY,"DJ") :
044 PRINT " OF
THE YEAR "
045 PRINT
046 PRINT "THAT MAKES YOU " :
DATE() - INTERNAL.BIRTHDAY : " DAYS OLD"
047 *
048 *
GET NUMBER FOR SPACE TEST
049 *
050 PRINT
051
PRINT "LET'S TEST THE SPACE FUNCTION."
052 LOOP
053
PRINT "ENTER A NUMBER BETWEEN 5 AND 20 " :
054 INPUT
YOUR.NUMBER
055 UNTIL NUM(YOUR.NUMBER) OR
YOUR.NUMBER = "QUIT" DO REPEAT
056 IF YOUR.NUMBER
= "QUIT" THEN STOP
057 *
058 * SHOW FIRST AND LAST
NAME WITH SPACES BETWEEN
059 *
060 PRINT
061
PRINT "HERE'S YOUR NAME WITH " : YOUR.NUMBER: "
EMBEDDED SPACES"
062 PRINT FIRST.NAME:
SPACE(YOUR.NUMBER) : LAST.NAME
063 *
064 * SHOW
TIMEDATE() AND MASKING
065 *
066 PRINT
067
PRINT "HERE' S TIME AND DATE LEFT JUSTIFIED IN 40
SPACES"
068 PRINT "*" : TIMEDATE() "L#40" : "*"
069
PRINT
070 PRINT "HERE'S TIME AND DATE RIGHT JUSTIFIED
IN 40 SPACES"
071 PRINT "*": TIMEDATE() "R#40": "*"
072
END
Users see only the output of all the work performed by the computer. Now that you are the programmer, you need to know what type of data will be received in a program, because you have to make sure that the data is converted to its proper internal format. Otherwise, many strange things may occur.
With this first example, the ICONV statement is used to take the BIRTHDAY variable and converts it with the D (for "Date") conversion. This takes care of the "internal number of days" calculation, so it produces one of two results: Either the number of days since 12/31/67 if the date is "valid," or a null if it is determined to be "invalid." In the Pick System, a date is considered valid if it is received with consistent delimiters between the month, day and year. A date is invalid if the conversion fails.
Here are some valid dates for the date conversion function:
1-1-97 1.1.97 01/01/1997 01 JAN 97 1JAN1997
(Note that leading zeros are optional.)
Now here are two invalid dates for the date conversion function:
1197 010197
The reason they are considered invalid is that they already appear to be in internal format.
The same set of conversion codes that are available to ACCESS are also available to PICK/BASIC. The conversions used most often are covered in this book.
Here's what happens when a date is convened from its external format to its internal format:
External Date Result Format Conversion Provided 12/12/97 D 10939 12 DEC 1997 D2 10939
Figure 7-2 illustrates the various date conversions that may be applied to internal dates.
There are many benefits in storing dates this way. First, it makes sorting easier because it's easy to compare two numbers to see which is greater. Second, it makes performing calculations on dates much easier. This might not seem significant until you have to figure out your own algorithm for calculating what 90 days is from any particular date. Finally, it is more efficient, in terms of storage, than its external counterpart.
On line 28, the contents of the variable, INTERNAL.BIRTHDAY, is examined to determine if it is null, which indicates that the internal conversion process failed. A valid external format is one in which the month, day, and year are each separated by any consistent non-numeric character. If the variable is determined to be null, then the response entered is definitely not a date, so a message is displayed and the birthday is again requested.
Internal Date Format Conversion Result 10939 D 12 DEC 1997 10939 D2/ 12/12/97 10939 D2- 12-12-97 10939 D- 12-12-1997 10939 (julian date) DJ 346 10939 (numeric month) DM 12 10939 (alpha month) DMA DECEMBER 10939 (numeric day/week) DW 5 10939 (alpha day/week) DWA FRIDAY 10939 (4 digit year) DY 1997 10939 (quarter) DQ 4
Fig. 7-2. Sample external date conversions.
On the other hand, if there is a value in INTERNAL.BIRTHDAY, then program execution continues from line 31.
The OCONV statement is exactly the opposite of the ICONV statement. It takes data in its internal format and converts it to external format, using the same set of conversion codes available to the ICONV function and the ACCESS retrieval language:
037 PRINT "THE CURRENT DATE IS ": OCONV(DATE(),"D2/")
A reserved system function, called DATE(), retrieves the current system date in its internal format. On line 37, the system date is retrieved and output converted using the "D2/" conversion. This takes the date and formats it in the form mm/dd/yy. Note for European readers: Many versions of Pick allow the date format to be "toggled" to European format, which this conversion formats as dd/mm/yy.
Time, like dates, is also stored in an internal format representing the number of seconds that have elapsed since midnight. This provides many of the same benefits as the date conversion, particularly with doing calculations:
038 PRINT "THE CURRENT TIME IS ": OCONV(TIME(),"MTH")
Figure 7-3 illustrates what happens when a time is converted from its external format to its internal format, as well as the various time conversions that may be applied to internal times.
On Line 38 of the example, the message, "THE CURRENT TIME IS ", displays, followed by the current time in the format hh:mmAM or hh:mmPM, depending on whether or not you are doing this before or after lunch.
External format Conversion Result 12:30 MT 45000 10:00 MT 36000 Internal format Conversion Result 61200 MT 17:00 61200 MTS 17:00:00 61200 MTH 05:00PM 61200 MTHS 05:00:00PM
Fig. 7-3. Time conversions.
Once a date is converted to its internal equivalent, it may be output formatted with any of the many types of date conversions. This statement takes the INTERNAL.BIRTHDAY variable and converts it to the external format using the DWA conversion, which spells out the day of the week:
042 PRINT OCONV(INTERNAL.BIRTHDAY,"DWA")
Line 43 does the same with the DJ conversion, which returns the date in its Julian date format. The Julian date is the sequential number of the day within the year. For example, January 15 is the 15th day of the year and February 15 is the 46th day. This is how you may calculate the number of shopping days left until Christmas. Just for fun, the program to do just that is provided in Appendix C. It's called EX.005A.
On line 46, your age in days is calculated and displayed. This is done by taking the internal system date, DATE(), and subtracting your birthday, which is stored in INTERNAL. BIRTHDAY. Incidentally, days before December 31, 1967 (day zero on the Pick calendar) are stored internally as negative numbers.
The SPACE function is used to produce or display a string of spaces. The number of spaces is determined by the result of the numeric expression, in this case, the number you entered into YOUR.NUMBER:
062 PRINT FIRST.NAME: SPACE(YOUR.NUMBER) : LAST.NAME
If the value of YOUR. NUMBER were 15, for example, the statement would be equivalent to:
PRINT SPACE(15)
This prints 15 spaces at the current cursor or printer position.
The SPACE function comes in handy when formatting output on reports and screens. (Another way of doing output formatting is through the use of print masks, to be discussed shortly.)
When the TIME( ) and DATE( ) functions were discussed earlier, it was noted that both of these functions retrieve their respective current values in internal format. The TIMEDATE( ) function retrieves the current system time and date in its external format.
For example, the instruction:
PRINT TIMEDATE()
produces output in the form:
10:17:36 12 DEC 1997
Line 68 of Program Example 5 uses it in this form:
068 PRINT "*" : TIMEDATE() "L#40" : "*"
Print masking is the process of taking an expression and presenting it in a particular output format, typically either left- or right-justified. Print masks are composed of several elements: the justification indicator, a "fill" or "pad" character, and a number to indicate the length of the output.
068 PRINT "*" : TIMEDATE() "L#40" : "*"
Together, these three elements comprise a print mask. The print mask immediately follows the output-producing expression that it is to format.
The justification is usually either an L for left-justified or R for right- justified. Some systems additionally support extra justification codes, such as D for date justification, which effectively produces the same result as an OCONV function; only the L and R are covered here.
The second of the three elements is the single character to "pad" the output. There are three "standard" characters available:
* Fills output with asterisks. # Fills output with blanks. % Fills output with zeros.
The third and final element of the print mask expression is an integer number which indicates the maximum length of the output.
On line 68, an asterisk (*) is displayed. This is to indicate the beginning position of the output. It is immediately followed by the current system time and date, produced with the TIMEDATE( ) function. Notice that the output is displayed left-justified in a field of 40 blanks and followed immediately by another asterisk to indicate the "end" of the output.
This appears as:
*08:15:34 12 DEC 1997 *
On line 71, an asterisk is displayed, followed by the current system time and date, right-justified in a field of 40 blanks, followed by another asterisk. This appears as:
* 08:15:34 12 DEC 1997*
Here's a very important note about print masking: Did you notice that there is no character, other than an optional space, between the expression being printed and the mask expression? This is extremely important, because it directs the program to treat the "first" expression as an object of the "second" expression, which is considered a "masking" expression. Shown below are correct and incorrect use of print masking:
PRINT "*" : "HI THERE " "L#15" : "*"
outputs
*HI THERE *
whereas, the statement:
PRINT "*" : "HI THERE" : "L#15" : "*"
outputs
*HI THEREL#15*
Not exactly what you wanted ....
The moral of this story is that you may use print masking anytime you need it, but remember to separate the expression being printed from its mask expression with only a space, or, of course, the ever-popular null.
1) What does internal format mean? What does external format mean?
2) What instruction and conversion code is required to convert a date from its external format to its internal format?
3) Suppose you have a variable called BILL.DATE. In this variable is the value "12-12-1999." How could you find out what day of the week it was? If this bill were due in 30 days, how could you determine when it should be paid?
4) What instruction and conversion prints the system time in its external format?
5) What does the SPACE function DO?
6) What is print masking?
7) What output do the following examples produce?
PRINT "NAME" "L#15" : "ADDRESS"
PRINT "123" "R#8": "456" "R#8"
PRINT "NAME" : "L#15" : "ADDRESS"
8) What function retrieves the current system time and date?
9) How do you really know when you are a programmer?
Previous chapter
Next chapter
Top