Handling the Date with your Sharp Pocket Computer
Helper functions
One function we might need is the modulo
function. This is the rest of
an integer division, e.g. the result of 5 MOD 3
is 2
. The
BASIC representation of Y = A MOD B
is
10 Y=A-B*INT(A/B)
Storing the Date in BASIC variables
The easiest way to do this is to use three standard variables, like Y
for year, M
for month and D
for day. The advantages of this
are
-
Easy to understand
-
The date may be printed with e.g.
10 PRINT "Date is";D;M;STR$ Y
The disadvantages are
-
Takes three variables for only one date
-
It is hard to create a sequence of dates
-
It is also hard to determine the weekday or the difference of days between two dates
Another way to store the date is to use a single variable and store the date as difference in
days to a fixed date, e.g. to the 15.Oct.1582 (which is the start of the gregorian calendar).
The advantages of this
are
-
Takes only one variable to represent one date
-
It is easy to create a sequence of dates
-
It is also easy to determine the weekday or the difference of days between two dates
The disadvantages are
-
Hard to understand
-
Hard to print
Which one would be the best reference date?
A good reference date would be the 15.Oct.1582 (start of the gregorian calendar), the difference is
always positive for all valid gregorian calendar dates then and the values are simpler to
understand then. As you will see, it is easier to calculate with the 1. March 0000 as reference
day. Note that this is only a virtual difference of days, because the gregorian calendar was
not valid this time (and the first year was one, not zero).
Because both representation format have their advantages, it would be nice to convert
them one to another. This leads us directly to the
Conversion Subroutines for Date formats
Converting D,M,Y to a Difference of Days to a fixed Date
The fixed date will be the 1. March 0000 in all further calculations.
First let's convert the month (Jan.- Dec. or 1- 12) as shown in the following table:
Month
|
converted
|
Offset in days to 1. March
|
January (1)
|
10
|
306
|
February (2)
|
11
|
337
|
March (3)
|
0
|
0
|
April (4)
|
1
|
31
|
May (5)
|
2
|
61
|
June (6)
|
3
|
92
|
July (7)
|
4
|
122
|
August (8)
|
5
|
153
|
September (9)
|
6
|
184
|
October (10)
|
7
|
214
|
November (11)
|
8
|
245
|
December (12)
|
9
|
275
|
The calculation to to this is MC = (M + 9) MOD 12
.
MC
stands for "Month converted" here.
In BASIC this is
10 MC=M+9-12*INT((M+9)/12)
Why? Because we will not have to respect februarys with 29 days. The month offset in
days to the 1. March (you can see it in the third column of the table) is the same
for years with 365 days and years with 366 days.
Now, we're able to calculate the difference in days to the 1. March in a single
year. It is the month offset from the table plus the day part of the date minus one.
How is it possible to represent the month offset table in the sharp? The simplest
approach would be to create an array and fill it with the offset at program start.
This is very memory-consuming, but fortunately I found a function, which is able to
calculate this:
INT(MC*30,6+0,5)
Let's have a look at the year now: If the month is January or February, we have to
reduce the number of years by one year, because these two month belong to the past year
due to the month conversion calculation. In BASIC this would be (YC
stands
for "Year corrected")
10 YC=Y:IF M<3 LET YC=YC-1
Without years with 366 days it would be simple: The offset in days would
be diff = YC * 365
.
With respecting the years with 366 days it
is diff = INT(YC * 365,25)
.
But there are some extra rules for years with 366 days:
-
If the year is (integer-) dividable (without rest) by 100, the year has 365 days, except
-
if the year is dividable by 400, the year has 366 days.
The function, which respects this, looks like this (in BASIC):
10 DI= INT (YC*365.25)- INT (YC/100)+ INT (YC/400)
Now, let's respect the days: The difference of days to the first day of the month is
simply the number minus one.
Here is a complete subroutine, which calculates the difference in days to
the 1. March 0000:
10 rem CONVERT DATE IN D,M,Y TO NUMBER OF DAYS
20 rem SINCE 1.MARCH 0000; RESULT IS IN A
30 A=Y:if M<3 let A=A-1
40 A=int (A*365.25)-int (A/100)+int (A/400)+D-1
50 A=A+int (.5+30.6*(M+9-12*int ((M+9)/12))):return
Note, that this is very efficient, it is straight forward, there are no loops and
there is no array for determining the number of days for a month.
Converting the Difference of Days (to the 1. March 0000) to Day, Month and Year
First, let's have a look at the year: Calculating the year is rather complicated,
because the INT operation is not reversible. But Y = diff / 365,2425
will
give a value that will match in most cases. If you add two to the difference
(Y = (diff + 2) / 365,2425
), the result will
-
match in most cases
-
if it doesn't match, the result will be greater than the real year (this is easier to
handle, because you must not respect years with 366 days)
After we've calculated this value, we have to
-
Calculate the real number of days this number of years causes
-
Decrease the number of years, if it causes more days than the given value
In BASIC this would be:
10 Y=INT((DI+2)/365.2425)
20 D=INT(Y*365.25)-INT(Y/100)+INT(Y/400):IF D>DI LET Y=Y-1:GOTO 10
30 DI=DI-D
Note, that we have to add one to the year, if the month is less than 3 (March), but
to do this, we'll first calculate the month. This is most similar to calculating the number
of years. Just calculate a nearby-value, an then correct it. In BASIC this would be
40 M=INT(DI/30)
50 D=INT(.5+30.6*M):IF D>DI LET M=M-1:GOTO 40
60 DI=DI-D
You must correct the month with
70 M=M+3-12*INT((M+2)/12)
And correct the year.
80 IF M<3 LET Y=Y+1
The day is the remaining difference plus one:
90 D=DI+1
Here's a full code example:
10 rem CONVERT NUMBER OF DAYS SINCE 1.MARCH 0000
20 rem (STD.VAR. A) TO D,M,Y; CONTENT OF VAR. A IS DESTROYED
30 Y=INT((A+2)/365.2425)
40 D=INT(Y*365.25)-INT(Y/100)+INT(Y/400):IF D>A LET Y=Y-1:GOTO 40
50 A=A-D:M=INT(A/30)
60 D=INT(.5+30.6*M):IF D>A LET M=M-1:GOTO 60
70 D=A-D+1:M=M+3-12*INT((M+2)/12):IF M<3 LET Y=Y+1
80 RETURN
Getting the Day of Week for a given Date
For doing this, you need the date as number of days since 1.March 0000.
Then you calculate (diff + 2) modulo 7
. In BASIC this is
10 WD=A+2-7*INT((A+2)/7)
The monday is 0, the duesday is 1 and so on.