Paradox Community
Search:

 Welcome |  What is Paradox |  Paradox Folk |  Paradox Solutions |
 Interactive Paradox |  Paradox Programming |  Internet/Intranet Development |
 Support Options |  Classified Ads |  Wish List |  Submissions 


Paradox Programming Articles  |  Beyond Help Articles  |  Tips & Tricks Articles  


Paradox® Date, Time, and DateTime Data Types
B.C. Date Adjustments
© 2001 Rick Kelly
www.crooit.com

Download the library containing the routines used in this series.

Preface

A library of all OPAL methods presented is available here.

In the previous section of exploring Paradox Date and Time values we discovered that these values are simply stored as numbers. Later sections will show how those numbers can be manipulated arithmetically to compliment OPAL’s native methods.

There is one problem to be addressed. Paradox treats all B.C. dates (prior to January 1, 0001) as leap years. This treatment introduces errors in calculations based on the internal fixed numbers when B.C. dates are involved.
Example:
July 24, -586
Paradox stores as -214637 (longInt(date(7,24,-586)))
Correct1 (page 288) value is -214193

Handling B.C. Dates

Accurate calculation of fixed dates for the B.C. era involves the development of custom OPAL methods to:
  1. Given a Paradox Date Type, return the fixed date number
  2. Given a fixed date number, return a Paradox Date Type
Our custom OPAL methods are:

Calculating a fixed date number
emFixedFromGregorian(daAny Date) LongInt

Derive a Paradox Date Type from fixed date number
emGregorianFromFixed(liFixedDate LongInt) Date
Each method will check for B.C. dates and use arithmetical calculations when necessary.


emFixedFromGregorian

The calculation of the fixed date for the B.C. era involves counting the number of days in prior years, the number of days in all prior months of the current year, and the number of days in the current month.
method emFixedFromGregorian(daAny Date) LongInt1 (page 36)
var
nuWorkYear      Number
nuWorkMonth     Number
nuDayAdjust     Number
nuFixedYear     Number
liFixedDate     LongInt
endVar
;
; Check if Year is < 1 (B.C. era)
;
switch
case year(daAny) < 1 :
;
; Yes - Adjust Fixed Date for B.C. era
;
  nuWorkYear = number(year(daAny))
  nuWorkMonth = number(month(daAny))
;
; Add:
;
; Number of days in prior years
; Number of days in prior months of current year
; Number of days in current month
;
  nuFixedYear = 365 * (nuWorkYear - 1) +
    ; Leap Year Days
    cmFloor((nuWorkYear - 1) / 4) -
    ; Century Years Adjust
    cmFloor((nuWorkYear - 1) / 100) +
    ; Century Years Adjust
    cmFloor((nuWorkYear - 1) / 400) +
    cmFloor(((367 * nuWorkMonth) - 362) / 12)
;
; Adjust for assumption in above calculation
;   that Feb always has 30 days
;
  switch
    case nuWorkMonth < 3 :
      nuDayAdjust = 0
    case cmGregorianLeapYear(nuWorkYear) = True :
      nuDayAdjust = -1
    otherwise :
      nuDayAdjust = -2
  endSwitch
  liFixedDate = longInt(nuFixedYear + nuDayAdjust + day(daAny))
otherwise :
;
; No - Adjustment for B.C. era not necessary
;
  liFixedDate = longInt(daAny)
endSwitch
return liFixedDate

endMethod

emGregorianFromFixed

The calculation of a Paradox Date Type from a fixed date number involves sequentially determining the year, month, and day of the month. The most complicated portion is determining the year. emFixedFromGregorian above is used for calculating fixed date numbers.
method emGregorianFromFixed(liFixedDate LongInt) Date1 (page 38)
;
; Given an internal fixed date,
; return a normal pdx Date Type
;
var
daReturnDate    Date
siYear          SmallInt
siMonth         SmallInt
siDay           SmallInt
nuPriorDays     Number
endVar
;
; If liFixedDate > 0 then use normal pdx date methods
;    otherwise it is calculated
;
switch
case liFixedDate < 1 :
;
; Calculate Year
;
  siYear = cmGregorianYearFromFixed(liFixedDate)
;
; Calculate Prior Days
;
  nuPriorDays = liFixedDate - emFixedFromGregorian(date(1,1,siYear))
;
; Adjust for assumption in above calculation
;   that Feb always has 30 days
;
  switch
    case liFixedDate < emFixedFromGregorian(date(3,1,siYear)) :
    case liFixedDate >= emFixedFromGregorian(date(3,1,siYear)) and
      cmGregorianLeapYear(number(siYear)) = True :
        nuPriorDays = nuPriorDays + 1
    otherwise :
        nuPriorDays = nuPriorDays + 2
  endSwitch
;
; Calculate Month
;
  siMonth=smallInt(cmFloor((12*nuPriorDays+373)/367))
;
; Calculate Day
;
  siDay = smallInt(liFixedDate - emFixedFromGregorian(date(siMonth,1,siYear)) + 1)

  daReturnDate = date(siMonth,siDay,siYear)
otherwise :
  daReturnDate = date(liFixedDate)
endSwitch
return daReturnDate
endMethod

Conclusion

We now have methods that support converting between Paradox Date Types and fixed date numbers with a corrective provision for B.C. dates. These methods form the basis for all calculations in later sections.


Next: Ages, Days Difference between dates, Daylight Savings, Basic Holidays, ISO Dates

References
Common / Shared ObjectPAL® Routines


Discussion of this article


 Feedback |  Paradox Day |  Who Uses Paradox |  I Use Paradox |  Downloads 


 The information provided on this Web site is not in any way sponsored or endorsed by Corel Corporation.
 Paradox is a registered trademark of Corel Corporation.


 Modified: 15 May 2003
 Terms of Use / Legal Disclaimer


 Copyright © 2001- 2003 Paradox Community. All rights reserved. 
 Company and product names are trademarks or registered trademarks of their respective companies. 
 Authors hold the copyrights to their own works. Please contact the author of any article for details.