Mailing List Archive: 49091 messages

[REBOL] Re: How to...? Convert Date of Birth to Age

From: lmecir:mbox:vol:cz at: 24-Oct-2002 11:08

```
Hi,

I think, that it may be useful to summarize the results.

The first candidate:

fwd-top: func [
lo [date!] hi [date!]
/local y m d i j k
][
if hi < lo [k: lo  lo: hi  hi: k]
y: lo/year
m: lo/month
d: lo/day
i: j: k: 0
while [hi > to-date reduce [y m d]] [y: y + 1  i: i + 1]
while [hi < to-date reduce [y m d]] [y: y - 1  i: i - 1]
while [hi > to-date reduce [y m d]] [m: m + 1  j: j + 1]
while [hi < to-date reduce [y m d]] [m: m - 1  j: j - 1]
while [hi > to-date reduce [y m d]] [d: d + 1  k: k + 1]
while [hi < to-date reduce [y m d]] [d: d - 1  k: k - 1]
reduce [i j k]
]

1) Rebol compatibility

> FWD-TOP returns triplets that are consistent with the
> way REBOL converts blocks to dates.

2) Forward counting

The difference is computed counting forward in time.

3) Half-monotonicity

For two dates A and B, where A < B, we would expect the difference between A
and B
(in whatever representation) to increase as B increases.

1) "Unusual" results

>> fwd-top 31/1/2002 5/3/2002
== [0 1 2]

>> fwd-top 29/2/2004 1/3/2005
== [1 0 0]

2) Uni-directional counting

>> fwd-top 3/1/2002 2/1/2002
== [0 0 1]
>> fwd-top 3/1/2002 4/1/2002
== [0 0 1]

The second candidate:

new-age: function [birth [date!] date [date!]] [
years months days new
] [
days: date/day - birth/day
either date < birth [
if positive? days [
new: to date! reduce [birth/day date/month + 1 date/year]
if new/day <> birth/day [
new: to date! reduce [0 date/month + 2 date/year]
]
days: date - new
date: new
]
months: date/month - birth/month
years: date/year - birth/year
if positive? months [
months: months - 12
years: years  + 1
]
] [
if negative? days [
new: to date! reduce [birth/day date/month - 1 date/year]
if new/day <> birth/day [
new: to date! reduce [0 date/month date/year]
]
days: date - new
date: new
]
months: date/month - birth/month
years: date/year - birth/year
if negative? months [
months: months + 12
years: years  - 1
]
]
reduce [years months days]
]

1) "Usual" results

>> new-age 31/1/2002 5/3/2002
== [0 1 5]

>> new-age 29/2/2004 1/3/2005
== [1 0 1]

2) Birth-related counting direction

The counting starts from the BIRTH and goes towards the DATE

>> new-age 3/1/2002 2/1/2002
== [0 0 -1]
>> new-age 3/1/2002 4/1/2002
== [0 0 1]

3) Weak monotonicity

For dates A, B, C, D, for which C <= A and D >= B holds, that (new-age a b)
<= (new-age c d)

1) Non-strict monotonicity

We can obtain equal results for (new-age a b) and (new-age c b) even if (a
<> c). This means, that given a date and a new-age we aren't able to
uniquely determine the birth date.

>> new-age 30/1/2004 5/3/2004
== [0 1 5]
>> new-age 31/1/2004 5/3/2004
== [0 1 5]

The third candidate:

strict-age: function [birth [date!] date [date!]] [
years months days new direction
] [
days: date/day - birth/day
direction: either date < birth [-1] [1]
if negative? days * direction [
new: to date! reduce [birth/day date/month - direction date/year]
if new/day <> birth/day [
new: to date! reduce [birth/day date/month - direction -
direction date/year]
]
if not positive? date - new * direction  [return reduce [0 0 date -
birth]]
days: date - new
date: new
]
months: date/month - birth/month
years: date/year - birth/year
if negative? months * direction [
months: months + (12 * direction)
years: years  - direction
]
reduce [years months days]
]

1) Birth-related counting direction

The counting starts from the BIRTH and goes towards the DATE

>> strict-age 3/1/2002 2/1/2002
== [0 0 -1]
>> strict-age 3/1/2002 4/1/2002
== [0 0 1]

2) Monotonicity / uniqueness

For dates A, B, C holds, that if C < A, then (STRICT-AGE A B) < (STRICT-AGE
C B). If C > B, then (STRICT-AGE A B) < (STRICT-AGE A C). For a given
STRICT-AGE and a given DATE we can find the corresponding BIRTH date.