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

### From: joel:neely:fedex at: 25-Oct-2002 15:17

Hi, Ladislav, Nice summary! Let me add a few remarks and another alternative. Ladislav Mecir wrote:> I think, that it may be useful to summarize the results. > > The first candidate: > > fwd-top: func [...> ] > > Advantages: > > 1) Rebol compatibility > > > FWD-TOP returns triplets that are consistent with the > > way REBOL converts blocks to dates. >In retrospect, I could have specified this option by saying: For two dates A, B such that A <= B, return the "smallest" triplet of (non-negative) values Y, M, D such that b = to-date reduce [a/year + y a/month + m a/day + d]> 2) Forward counting > 3) Half-monotonicity > > Disadvantages: > > 1) "Unusual" results >This is unavoidable, if the REBOL compatibility criterion is to be satisfied. For all solutions, "Usuality" and compatibility with REBOL date arithmetic are mutually exclusive. Pick one.> 2) Uni-directional counting >I was addressing the expanded problem of "difference between two arbitrary dates" to avoid the semantic complications of birthdays (see below). To be fair, we could add: 3) Slow. (However, I have another version that is equivalent but much faster; benchmarks to follow later.)> The second candidate: > > new-age: function [birth [date!] date [date!]] [...> ] > > Advantages: > > 1) "Usual" results > 2) Birth-related counting direction >For a person born on 24-Aug-1977, what was that person's age on 12-Aug-1974? Some would say that the question is meaningless, in the same sense that find [1 3 5 7 9 11] 2 evaluates to NONE.> 3) Weak monotonicity > > Disadvantages: > > 1) Non-strict monotonicity > > The third candidate: > > strict-age: function [birth [date!] date [date!]] [...> Advantages: > > 1) Birth-related counting direction > 2) Monotonicity / uniqueness > > Disadvantages: > > 1) "Unusual" results >By way of philosophy, let me offer another Grand Universal Principle of software development: When there are multiple arguably correct solutions to a problem, push the decision up the food chain. We can do this at requirements time by insisting on more rigorous specification in advance, or we can do this at run time by making the selection among alternatives available to the caller/user. Therefore... A fourth candidate: ymd-sub: func [ left [date!] right [date!] /local y m d not-yet? too-far? one i j k ][ either left <= right [ not-yet?: :greater? too-far?: :lesser? one: +1 ][ not-yet?: :lesser? too-far?: :greater? one: -1 ] y: left/year m: left/month d: left/day i: j: k: 0 while [not-yet? right to-date reduce [y m d]] [y: y + one i: i + one] while [too-far? right to-date reduce [y m d]] [y: y - one i: i - one] while [not-yet? right to-date reduce [y m d]] [m: m + one j: j + one] while [too-far? right to-date reduce [y m d]] [m: m - one j: j - one] while [not-yet? right to-date reduce [y m d]] [d: d + one k: k + one] while [too-far? right to-date reduce [y m d]] [d: d - one k: k - one] reduce [i j k] ] which behaves as follows:>> ymd-sub 28-jan-2000 3-mar-2000 == [0 1 4] >> ymd-sub 3-mar-2000 28-jan-2000 == [0 -1 -6]i.e., if the arguments are increasing, calculate the difference with time running forward, but if the arguments are decreasing, calculate the result with time moving backward. The results will be unambiguous in the sense that forward differences are all non-negative (>= 0), while backward differences are all non-positive (<= 0). -jn- -- ---------------------------------------------------------------------- Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446