GAO Associates
87 Andrews Way
Plymouth, MA 02360-1641
This page contains source code lists of routines in ASCII text format that may be
of interest to programmers who code in the basic language. The routines
are in Visual Basic format and have all been tested for validity, however GAOA
assumes no responsibility for their use by anyone, since they are provided free of
charge. The routines are copyright free and may be used for
personal or business purposes. The only limitations are that they cannot be sold
as individual items, but can be included as components is applications that are sold.
Also, if any of the routines are redistributed, it is requested that the user indicate their
source as GAO Associates.
More functions and subroutines will be added here on a regular basis.
The source code listing below can simply be copied using any word processor that can
export text such as WordPerfect, or a simple text processor like Wordpad.
An equation for generating a value for PI
In programs the require the value for pi, one can either write out the number and
equate it to a global constant, or generate with the following expression
PI = 4 * ATN(1)
where ATN is the ordinary arctangent function which is included
in all programming languages.
General Date Computation Routines
The two functions and one subroutine that follow can all be used together for handling
time and date problems. The function "date_to_jd(year, month, day+fraction)" converts
input consisting of 3 variables to the full julian day number. This number is used for setting time
differentials of various types. For example, to get the exact time span between any two dates,
including time of day, input year (must be error free), month, and day where day can include
a fraction (e.g. for the 13th at 08:30, the input day is approximately 13.3541667), find the julian
day number for each date/time of interest and the difference between them is the desired time
span in days and fraction of a day.
If the date format in a program is not perfectly predictable the function Gendate(x) can
be used to produce the julian day number.
This is a very forgiving function that can handle several errors in the input data, such as
extraneous spaces, 1, 2 and 4 digit years, use of / or - as separators, etc. It cannot handle
fractional days, however a simple change in the input requirement to allow for another input
variable which contains only the fraction could be added "Gendate(x, df as double)"
would suffice and then change the line d2 = d, to d2 = d + df.
Function date_to_jd(yr%, mo%, d#)
'Converts calendar date to full Julian day number
'can be used over any calendar date if 4 digit year is input
'as presented here, the dates are Gregorian calendar only
'y is 1, 2 or 4 digit year, but if 1 or 2 digits, zeroyear is required
'zeroyear is a 1 or 2 digit integer for the function and should
'be a global constant set in the declarations of some module
'Note 1: With 1 or 2 digits for yr, the function can only be used
'during a 100 year span between 1900 and 2099
'Note 2: since yr is an integer, 2 digit representation for 2000-2009 is simply 0-9
'Example 1: if zeroyear is 0 then all 2 digit years are from 1900 to 1999
'Example 2: if zeroyear is 1 then all 2 digit years are from 1901 to 2000
'Example 2: if zeroyear is 5 then all 2 digit years are from 1905 to 2004
'Example 3: if zeroyear is 93 then all 2 digit years are from 1993 to 2092
'*****************************************************************************
Dim temp As String
temp = Trim(Str(yr))
If Len(temp) < 4 Then 'year is not in 4 digit form
If yr < zeroyear Then
yr = yr + 2000
Else
yr = yr + 1900
End If
End If
Dim jd#, y%, m%, a%, b%
If mo <= 2 Then
y = yr - 1
m = mo + 12
Else
y = yr
m = mo
End If
a = Fix(y / 100)
b = 2 - a + Fix(a / 4)
jd = Fix(365.25 * (y + 4716)) + Fix(30.6001 * (m + 1))
jd = jd + d + b - 1524.5
date_to_jd = jd
End Function
Sub Jd_to_date(jd#, yr%, mo%, da%, hr%, min%, sec!)
'Converts jd to date/time
'jd need not be an integer and can include fraction of day
'works for any positive julian day number
'produces positive as well as negative (BC) years
'*************************************************
Dim jdc#, z&, f#, alph&, a&, b&, c&
Dim d&, e%, dom#, hrs#, mins#
jdc = jd + 0.5
z = Fix(jdc)
f = jdc - z
alph = Fix((z - 1867216.25) / 36524.25)
a = z + 1 + alph - Fix(alph / 4)
b = a + 1524
c = Fix((b - 122.1) / 365.25)
d = Fix(365.25 * c)
e = Fix((b - d) / 30.6001)
dom = b - d - Fix(30.6001 * e) + f
da = Fix(dom) 'day out
hrs = (dom - da) * 24
hr = Fix(hrs) 'hour out
mins = (hrs - hr) * 60
min = Fix(mins) 'minute out
sec = (mins - min) * 60
If e < 14 Then
mo = e - 1 'month out
Else
mo = e - 13
End If
If mo > 2 Then 'year out
yr = c - 4716
Else
yr = c - 4715
End If
End Sub
Function GenDate(x As String)
Rem Handles a variety of date inputs to generate Julian Day number
Rem if x includes 4 digits for the year, the function can
Rem handle years from 0001 to any date
Rem for routine to handle dates from 4716 BC contact GAO Associates
Rem if x includes only 2 digits for the year
Rem the function can handle any 100 year span between 1900 and 2099
Rem 2 digit year requires global constant "zeroyear"
Rem Assumes either / or - as separators
Rem Can have extraneous spaces anywhere in the string
Dim z As String, m As Integer, d As Integer, y As Integer
Dim pos1 As Integer, pos2 As Integer, sym1 As String, sym2 As String
Dim d2 As Double
'remove any spaces at either end of the date
z = Trim$(x)
'check for and remove internal extraneous spaces
sym1 = " " 'a space, or use chr(32)
pos1 = InStr(1, z, sym1)
'if any internal paces, then pos1>0
Do While pos1
z = Left(z, pos1 - 1) & Mid(z, pos1 + 1, 14)
pos1 = InStr(1, z, sym1)
Loop
'search for / separator locations
sym1 = "/"
sym2 = "/"
pos1 = InStr(1, z, sym1)
pos2 = InStr(pos1 + 1, z, sym2)
If pos1 = 0 Then 'search for - separator locations
sym1 = "-" 'a negative sign, or use chr(45)
sym2 = "-"
pos1 = InStr(1, z, sym1)
pos2 = InStr(pos1 + 1, z, sym2)
If pos1 = 0 Then
'generate an error message and exit the function
Exit Function
End If
End If
Select Case Len(z)
Case 5 'z/z/z
m = Int(Val(Left(z, 1)))
d = Int(Val(Mid(z, 3, 1)))
y = Int(Val(Right(z, 1)))
If y < zeroyear Then
y = y + 2000
Else
y = y + 1900
End If
Case 6 'z/z/zz
m = Int(Val(Left(z, 1)))
d = Int(Val(Mid(z, 3, 1)))
y = Int(Val(Right(z, 2)))
If y < zeroyear Then
y = y + 2000
Else
y = y + 1900
End If
Case 7 'z/zz/zz or zz/z/zz
If pos1 = 2 Then 'format is z/zz/zz
m = Int(Val(Left(z, 1)))
d = Int(Val(Mid(z, 3, 2)))
y = Int(Val(Right(z, 2)))
If y < zeroyear Then
y = y + 2000
Else
y = y + 1900
End If
Else 'format is zz/z/zz
m = Int(Val(Left(z, 2)))
d = Int(Val(Mid(z, 4, 1)))
y = Int(Val(Right(z, 2)))
If y < zeroyear Then
y = y + 2000
Else
y = y + 1900
End If
End If
Case 8 'zz/zz/zz or z/z/zzzz or zzzz/z/z
If pos1 = 2 Then 'Format is z/z/zzzz
m = Int(Val(Left(z, 1)))
d = Int(Val(Mid(z, 3, 1)))
y = Int(Val(Right(z, 4)))
ElseIf pos1 = 3 Then 'format is zz/zz/zz
m = Int(Val(Left(z, 2)))
d = Int(Val(Mid(z, 4, 2)))
y = Int(Val(Right(z, 2)))
If y < zeroyear Then
y = y + 2000
Else
y = y + 1900
End If
Else 'format is zzzz/z/z
m = Int(Val(Right(z, 1)))
d = Int(Val(Mid(z, 6, 1)))
y = Int(Val(Left(z, 4)))
End If
Case 9 'z/zz/zzzz or zzzz/z/zz or zz/z/zzzz or zzzz/zz/z
If pos1 = 2 Then 'format is z/zz/zzzz
m = Int(Val(Left(z, 1)))
d = Int(Val(Mid(z, 3, 2)))
y = Int(Val(Right(z, 4)))
ElseIf pos1 = 3 Then 'format is zz/z/zzzz
m = Int(Val(Left(z, 2)))
d = Int(Val(Mid(z, 4, 1)))
y = Int(Val(Right(z, 4)))
ElseIf pos2 = 7 Then 'format is zzzz/z/zz
m = Int(Val(Mid(z, 6, 1)))
d = Int(Val(Right(z, 2)))
y = Int(Val(Left(z, 4)))
Else 'format is zzzz/zz/z
m = Int(Val(Mid(z, 6, 2)))
d = Int(Val(Right(z, 1)))
y = Int(Val(Left(z, 4)))
End If
Case 10 'zz/zz/zzzz or zzzz/zz/zz
If pos1 = 3 Then
m = Int(Val(Left(z, 2)))
d = Int(Val(Mid(z, 4, 2)))
y = Int(Val(Right(z, 4)))
Else
m = Int(Val(Mid(z, 6, 2)))
d = Int(Val(Right(z, 2)))
y = Int(Val(Left(z, 4)))
End If
Case Else
'A non-useable input, provide messagebox
Exit Function
End Select
'change d from integer to double to satisfy input requirement of function
d2 = d
GenDate = date_to_jd(y, m, d2)
End Function
