[REBOL] Re: How to...? Convert Date of Birth to Age
From: joel:neely:fedex at: 3-Jul-2002 8:21
Hi, Andrew,
Andrew Martin wrote:
> Using Rebol (of course!), how would I convert a date of birth to
> an age in years, months and days?
>
First a couple of observations:
- Date arithmetic is non-trivial; tricks with 365.25 (or 365.2425,
to be more precise ;-) days are fragile in the presence of leap
years.
- Keeping up with lots of boilerplate (e.g. days per month) offers
many opportunities for typos with subtle bugs.
- As with sorting, one can do things simply (trading away speed)
or highly tuned (trading away simplicity and clarity).
All of that said, here's a "bubble-sort-style" solution. It's not
a speed winner (and isn't suitable for large problems), but should
be obvious and clear enough that you can type it from memory any
time you need such a calculation. First, a version with comments
explaining the strategy:
8<----------------------------------------------------------------
datedelta: func [
bdate [date!] edate [date!]
/local result temp adjust
][
;
; ensure proper order
;
if bdate > edate [temp: bdate bdate: edate edate: temp]
;
; result = difference between bdate and temp (initially zero)
;
temp: reduce [bdate/year bdate/month bdate/day]
result: copy [0 0 0]
;
; function to modify a date component [y=1 m=2 d=3]
; in both result and temp by the same adjustment amount
;
adjust: func [pos [integer!] delta [integer!]] [
poke result pos result/:pos + delta
poke temp pos temp/:pos + delta
]
;
; tally difference in years, then months, then days
;
foreach datepart [1 2 3] [
;
; adjust up until overshoot
;
while [edate > to-date temp] [ adjust datepart 1 ]
;
; correct any overshoot
;
while [edate < to-date temp] [ adjust datepart -1 ]
]
;
; result = difference between bdate and temp
; temp = edate
; ergo result is final answer
;
result
]
8<----------------------------------------------------------------
... then a version without comments to help remember just the code:
8<----------------------------------------------------------------
datedelta: func [
bdate [date!] edate [date!]
/local result temp adjust
][
if bdate > edate [temp: bdate bdate: edate edate: temp]
temp: reduce [bdate/year bdate/month bdate/day]
result: copy [0 0 0]
adjust: func [pos [integer!] delta [integer!]] [
poke result pos result/:pos + delta
poke temp pos temp/:pos + delta
]
foreach datepart [1 2 3] [
while [edate > to-date temp] [adjust datepart 1]
while [edate < to-date temp] [adjust datepart -1]
]
result
]
8<----------------------------------------------------------------
HTH!
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]