It was a reply to DaveC, so those comments (about leap years etc) weren't directed at you smile

But I was bored (no, I didn't like what I should be doing) so I wrote something more appropriate to your problem:

You'll need the $datediff function above too...
(Sorry about the whole lot of code)
Code:
; Return duration in years/months/days starting from a specific date and a duration in
; (one, more or all of) years/months/weeks/days/hours/minutes/seconds
; usage: $datediff3(25/12/2002 10:35:00,1yr 252wks 15mths 60days 25hrs 61secs,past,nsw)
; use past for having a duration to something that's in the past and future for something in the future
; use now as date for using the current date.
; nsw -> see switches of $datediff
alias datediff3 return $datediff($1,$datediff2($1,$2,$3,$4),$4)

; Return the date something happened or will happen based on start date and duration

; usage: $datediff3(25/12/2002 10:35:00,1yr 252wks 15mths 60days 25hrs 61secs,past)
; use past for having a duration to something that's in the past and future for something in the future
; use now as date for using the current date.
; use u as 4th parameter only for mm/dd/yyy hh:nn:ss style dates
alias datediff2 {
  var %1 = $iif($1 == now,$date(dd/mm/yyyy hh:nn:ss),$1) , %2 = $$2
  if ($regex(%1,/^0*(\d+)\D0*(\d+)\D(\d+)\D0*(\d+)\D0*(\d+)\D0*(\d+)(?:\D?([ap]\.?m\.?|noon|midday|midnight))?$/i)) {
    var %d1 = $regml($iif(u isin $4,2,1)), %m1 = $regml($iif(u isin $4,1,2))
    var %h1 = $regml(4), %n1 = $regml(5), %s1 = $regml(6), %y1 = $regml(3)
    if ((%h1 == 12) && (($regml(7) == am) || ($v1 == midnight))) var %h1 = 0
    elseif ((%h1 isnum 1-11) && ($regml(7) == pm)) inc %h1 12
  }
  if ((%m1 !isnum 1-12) || (%d1 !isnum 1-31) || (%h1 !isnum 0-23) || (%m1 !isnum 0-59) || (%s1 !isnum 0-59)) return Date invalid


  if ($regex(%2,/^(?:(\d+) *y\w* |())(?:(\d+) *mo?n?ths? |())(?:(\d+) *w\w* |())(?:(\d+) *d\w* |()) $+ $&
    (?:(\d+) *h\w* |())(?:(\d+) *mi\w* |())(?:(\d+) *s\w*|()) *$/i)) {
    var %y = $calc($regml(1)), %m = $calc($regml(2)), %d = $calc(7 * $calc($regml(3)) + $calc($regml(4)))
    var %h = $calc($regml(5)), %n = $calc($regml(6)), %s = $calc($regml(7))
  }
  else return invalid duration given...

  if ($3 == future) {
    var %s2 = %s1 + %s
    while (%s2 > 60) var %s2 = %s2 - 60, %n = %n + 1
    var %n2 = %n1 + %n
    while (%n2 > 60) var %n2 = %n2 - 60, %h = %h + 1
    var %h2 = %h1 + %h
    while (%h2 > 24) var %h2 = %h2 - 24, %d = %d + 1
    var %m2 = %m1 + %m
    while (%m2 > 12) var %m2 = %m2 - 12, %y = %y + 1
    var %y2 = %y1 + %y, %d2 = %d1 + %d
    while (%d2 > $gettok(31 $iif((!$calc(%y2 % 400)) || (($calc(%y2 % 100)) && (!$calc(%y2 % 4))),29,28) 31 30 31 30 31 31 30 31 30 31,%m2,32)) {
      var %d2 = %d2 - $v2, %m2 = %m2 + 1
      if (%m2 > 12) var %m2 = %m2 - 12, %y2 = %y2 + 1
    }
  }
  elseif ($3 == past) {
    var %s2 = %s1 - %s
    while (%s2 < 0) var %s2 = %s2 + 60, %n = %n - 1
    var %n2 = %n1 - %n
    while (%n2 < 0) var %n2 = %n2 + 60, %h = %h - 1
    var %h2 = %h1 - %h
    while (%h2 < 0) var %h2 = %h2 + 24, %d = %d - 1
    var %m2 = %m1 - %m
    while (%m2 < 1) var %m2 = %m2 + 12, %y = %y - 1
    var %y2 = %y1 - %y, %d2 = %d1 - %d
    while (%d2 < 1) {
      var %d2 = %d2 + $gettok(31 $iif((!$calc(%y2 % 400)) || (($calc(%y2 % 100)) && (!$calc(%y2 % 4))),29,28) 31 30 31 30 31 31 30 31 30 31,%m2,32)
      var %m2 = %m2 - 1 | if (%m2 < 1) var %m2 = %m2 + 12, %y2 = %y2 - 1
    }
  }
  else return uhm, you want the third parameter to be future or past...
  if (u isin $4) return $+($base(%m2,10,10,2),/,$base(%d2,10,10,2),/,$base(%y2,10,10,4) $base(%h2,10,10,2),:,$base(%n2,10,10,2),:,$base(%s2,10,10,2))
  return $+($base(%d2,10,10,2),/,$base(%m2,10,10,2),/,$base(%y2,10,10,4) $base(%h2,10,10,2),:,$base(%n2,10,10,2),:,$base(%s2,10,10,2))
}


This should give what you want, probably in a more elaborate (read: slower) way than yours. It should never be off, unless you just slam in the wrong start date smile
//echo -s $datediff3(1/1/2005 12:5:5,252wks 700days 80mins 59secs, past,snw)