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 ]
-- 
To unsubscribe from this list, please send an email to
[EMAIL PROTECTED] with "unsubscribe" in the 
subject, without the quotes.

Reply via email to