Thats some intense regex code dude!
[qoute]Here's what I use as testing between your code and mine
//var %d1 = 1/1/2007 14:00:00, %d2 = 2/2/2006 13:01:01 | echo -s dftf____ $Duration.From.To.Format(%d1, %d2) | echo -s datediff $datediff(%d1,%d2,nws)
Yes, it gives different output, I think it's not my problem but yours :tongue: (change both a year to the future too)
Also, 2000 is a leap year, you didn't consider that. I did steal your $gettok concept tho

[/quote]
On the 2000 being a leap year. I dont really get you. Mine does have it as a leap year. I didnt worry about the every 100 not a leap but every 400 is, since 2000 is and mine was limited to dates definable under $ctime, its actually only limited to that becuase i was to lazy to errorcheck the inputs.
However it appears its yours and mine that are incorrect, while either of those results can be deemed correct, they are only so by chance.
dftf____ 10mths 3wks 6days 58mins 59secs
mine advances 3wks & 6 days (27 days) from 2/2/2006 to 1/3/2006 then advances 10 months to 1/1/2007 datediff 10mths 4wks 2days 58mins 59secs
yours advances 10 months from 2/2/2006 to 2/12/2006 then 4wks & 2 days (30 days) to 1/1/2007Yours begins to fail on closer values
//var %d1 = 1/3/2006 00:00:00, %d2 = 2/2/2006 00:00:00 | echo -s dftf____ $Duration.From.To.Format(%d1, %d2) | echo -s datediff $datediff(%d1,%d2,nws)
dftf____ 3wks 6days
datediff
4wks 2daysFew to many for FEB

While mine appeared to maintain a valid number of days, on closer inspection, the flow was not correct, such as results like this.
4mths
3mths 3wks 6days,
this was a valid value but used a system that did not flow with surounding dates 3mths 4wks,
3mths 3wks 6days
Anyway
heres mine corrected
[code]
;Duration.From.To.Format
; * Pass it any two dates that $ctime can return values for (1970-01-01 00:00:00 +-12 hours onward to sometime)
; * and it returns back the yrs,mths,wks,days,hrs,mins,secs from one to the other. A few output format options also see below.
;
;usage $Duration.From.To.Format($1,$2,$3)
; $1 = $date $time
; $2 = $date $time
; $3 = formating (as follows)
; e=short extentions yrs,mths,wks,days,hrs,mins,secs (default)
; E=long extentions years,months,weeks,days,hours,minutes,seconds (overrides e)
; a=all fields
; A=all fields no extentions (overrides e & E & a)
; z=zeropad fields years(4) Months(2) Weeks(1) Days(1) Hours(2) Minutes(2) Seconds(2)
;
alias Duration.From.To.Format {
var %c1 = $ctime($1), %c2 = $ctime($2)
if ((%c1 == $null) || (%c2 == $null)) { RETURN }
if (%c1 < %c2) { var %temp = %c1, %c1 = %c2, %c2 = %temp }
var %y1 = $date(%c1,yyyy), %m1 = $date(%c1,mm), %d1 = $date(%c1,dd), %t1 = $calc($time(%c1,HH) * 3600 + $time(%c1,nn) * 60 + $time(%c1,ss))
var %y2 = $date(%c2,yyyy), %m2 = $date(%c2,mm), %d2 = $date(%c2,dd), %t2 = $calc($time(%c2,HH) * 3600 + $time(%c2,nn) * 60 + $time(%c2,ss))
if (%t1 < %t2) { inc %t1 86400 | dec %d1 }
if (%d1 < %d2) { inc %d1 $gettok(31 31 $iif(!$calc(%y1 % 4),29,28) 31 30 31 30 31 31 30 31 30,%m1,32) | dec %m1 }
if (%m1 < %m2) { inc %m1 12 | dec %y1 }
var %y0 = $calc(%y1 - %y2), %m0 = $calc(%m1 - %m2), %d0 = $calc(%d1 - %d2), %t0 = $calc(%t1 - %t2), %w0 = $int($calc(%d0 / 7))
var %d0 = $calc(%d0 % 7), %h0 = $int($calc(%t0 / 3600)), %n0 = $int($calc((%t0 % 3600) / 60)), %s0 = $calc(%t0 % 60)
;
if ((A isincs $3) && (z isin $3)) { RETURN $right($+(0000,%y0),4) $right($+(00,%m0),2) %w0 %d0 $right($+(00,%h0),2) $right($+(00,%n0),2) $right($+(00,%s0),2) }
if ((A isincs $3)) { RETURN %y0 %m0 %m0 %w0 %d0 %h0 %n0 %s0 }
if ((a isincs $3) && (E isincs $3) && (z isin $3)) { RETURN $+($right($+(0000,%y0),4),$iif(%y0 == 1,year,years)) $+($right($+(00,%m0),2),$iif(%m0 == 1,month,months)) $+(%w0,$iif(%w0 == 1,week,weeks)) $+(%d0,$iif(%d0 == 1,day,days)) $+($right($+(00,%h0),2),$iif(%h0 == 1,hour,hours)) $+($right($+(00,%n0),2),$iif(%n0 == 1,minute,minutes)) $+($right($+(00,%s0),2),$iif(%s0 == 1,second,seconds)) }
if ((a isincs $3) && (E isincs $3)) { RETURN $+(%y0,$iif(%y0 == 1,year,years)) $+(%m0,$iif(%m0 == 1,month,months)) $+(%w0,$iif(%w0 == 1,week,weeks)) $+(%d0,$iif(%d0 == 1,day,days)) $+(%h0,$iif(%h0 == 1,hour,hours)) $+(%n0,$iif(%n0 == 1,minute,minutes)) $+(%s0,$iif(%s0 == 1,second,seconds)) }
if ((a isincs $3) && (z isin $3)) { RETURN $+($right($+(0000,%y0),4),$iif(%y0 == 1,yr,yrs)) $+($right($+(00,%m0),2),$iif(%m0 == 1,mth,mths)) $+(%w0,$iif(%w0 == 1,wk,wks)) $+(%d0,$iif(%d0 == 1,day,days)) $+($right($+(00,%h0),2),$iif(%h0 == 1,hr,hrs)) $+($right($+(00,%n0),2),$iif(%n0 == 1,min,mins)) $+($right($+(00,%s0),2),$iif(%s0 == 1,sec,secs)) }
if ((a isincs $3)) { RETURN $+(%y0,$iif(%y0 == 1,yr,yrs)) $+(%m0,$iif(%m0 == 1,mth,mths)) $+(%w0,$iif(%w0 == 1,wk,wks)) $+(%d0,$iif(%d0 == 1,day,days)) $+(%h0,$iif(%h0 == 1,hr,hrs)) $+(%n0,$iif(%n0 == 1,min,mins)) $+(%s0,$iif(%s0 == 1,sec,secs)) }
if ((E isincs $3) && (z isin $3)) { RETURN $iif(%y0,$+($right($+(0000,%y0),4),$iif(%y0 == 1,year,years))) $iif(%m0,$+($right($+(00,%m0),2),$iif(%m0 == 1,month,months))) $iif(%w0,$+(%w0,$iif(%w0 == 1,week,weeks))) $iif(%d0,$+(%d0,$iif(%d0 == 1,day,days))) $iif(%h0,$+($right($+(00,%h0),2),$iif(%h0 == 1,hour,hours))) $iif(%n0,$+($right($+(00,%n0),2),$iif(%n0 == 1,minute,minutes))) $iif(%s0,$+($right($+(00,%s0),2),$iif(%s0 == 1,second,seconds))) }
if ((E isincs $3)) { RETURN $iif(%y0,$+(%y0,$iif(%y0 == 1,year,years))) $iif(%m0,$+(%m0,$iif(%m0 == 1,month,months))) $iif(%w0,$+(%w0,$iif(%w0 == 1,week,weeks))) $iif(%d0,$+(%d0,$iif(%d0 == 1,day,days))) $iif(%h0,$+(%h0,$iif(%h0 == 1,hour,hours))) $iif(%n0,$+(%n0,$iif(%n0 == 1,minute,minutes))) $iif(%s0,$+(%s0,$iif(%s0 == 1,second,seconds))) }
if ((z isin $3)) { RETURN $iif(%y0,$+($right($+(0000,%y0),4),$iif(%y0 == 1,yr,yrs))) $iif(%m0,$+($right($+(00,%m0),2),$iif(%m0 == 1,mth,mths))) $iif(%w0,$+(%w0,$iif(%w0 == 1,wk,wks))) $iif(%d0,$+(%d0,$iif(%d0 == 1,day,days))) $iif(%h0,$+($right($+(00,%h0),2),$iif(%h0 == 1,hr,hrs))) $iif(%n0,$+($right($+(00,%n0),2),$iif(%n0 == 1,min,mins))) $iif(%s0,$+($right($+(00,%s0),2),$iif(%s0 == 1,sec,secs))) }
if (($true)) { RETURN $iif(%y0,$+(%y0,$iif(%y0 == 1,yr,yrs))) $iif(%m0,$+(%m0,$iif(%m0 == 1,mth,mths))) $iif(%w0,$+(%w0,$iif(%w0 == 1,wk,wks))) $iif(%d0,$+(%d0,$iif(%d0 == 1,day,days))) $iif(%h0,$+(%h0,$iif(%h0 == 1,hr,hrs))) $iif(%n0,$+(%n0,$iif(%n0 == 1,min,mins))) $iif(%s0,$+(%s0,$iif(%s0 == 1,sec,secs))) }
}
[code]
* yours needs the same patch applied
if (%d < 0) var %d = %d + $gettok(31 $iif((!$calc(%y1 % 400)) || (($calc(%y1 % 100)) && (!$calc(%y1 % 4))),29,28) 31 30 31 30 31 31 30 31 30 31,%m1,32), %m1 = %m1 - 1
must be replaced with
if (%d < 0) var %d = %d + $gettok(31 31 $iif((!$calc(%y1 % 400)) || (($calc(%y1 % 100)) && (!$calc(%y1 % 4))),29,28) 31 30 31 30 31 31 30 31 30,%m1,32), %m1 = %m1 - 1
The reasoning for this, i really had to sit down and work out on a bit of paper.
Say you have 2/1/2005 and the 1/4/2005 (d/m/y), you cant be taking 2 from 1 you get -1 so you must add a months days however its not the 4th month you add but the month before becuase your going to take that month off the date. Making you now doing the dates 2/1/2005 and 32/3/2005, which breaks to 30days one month.
I have run both yours and mine, and they follow the flow perfectly with this adjustment.
4mths
3mths 4wks 1day
3mths 4wks,
3mths 3wks 6days
etc