Changeset 2792
 Timestamp:
 Dec 31, 2011, 8:01:59 PM (4 years ago)
 File:

 1 edited
Legend:
 Unmodified
 Added
 Removed

ofw/fs/unixtime.fth
r752 r2792 3 3 4 4 decimal 5 \ date&time is number of seconds since 1970 5 \ February is given 29 days so the loop in >d/m will exit at the "unloop". 6 \ The array begins at March so that the leap day falls at the end. 6 7 create days/month 7 \ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec8 31 c, 28 c, 31 c, 30 c, 31 c, 30 c, 31 c, 31 c, 30 c, 31 c, 30 c, 31c,8 \ Mar Apr May Jun Jul Aug Sep Oct Nov Dec Jan Feb 9 31 c, 30 c, 31 c, 30 c, 31 c, 31 c, 30 c, 31 c, 30 c, 31 c, 31 c, 29 c, 9 10 10 : >d/m ( dayinyear  day month ) 11 12 0 do 12 days/month i ca+ c@ 2dup < if 13 drop 1+ i 1+ leave 14 then 15  16 loop 11 \ In >d/m and d/m>, the yearly period starts on March 1. dayinyear is 12 \ relative to March 1, and monthindex 0 is March, 9 is December, 10 is January, 13 \ 11 is February. This representation simplifies the calculations by 14 \ putting the optional leap day at the end, i.e. dayofyear=365. 15 16 \ Convert dayinyear to dayofmonth and monthindex. 17 18 : >d/m ( dayinyear0..365  day1..31 monthindex0..11 ) 19 d# 12 0 do ( daysleft ) 20 days/month i ca+ c@ 2dup < if ( daysleft ) 21 drop 1+ i unloop exit (  day1..31 monthindex0..11 ) 22 then ( daysleft ) 23  ( daysleft' ) 24 loop ( daysleft ) 25 \ This is reached only if the argument is >365 26 1+ d# 12 ( day1..31 monthindex0..11 ) 17 27 ; 18 : unixseconds> ( seconds  s m h d m y ) 19 60 u/mod 60 u/mod 24 u/mod ( s m h days ) 20 [ 365 4 * 1+ ] literal /mod >r ( s m h dayincycle ) ( r: cycles ) 21 dup [ 365 365 + 31 + 29 + ] literal 22 2dup = if \ exactly leap year Feb 29 23 3drop 2 29 2 ( s m h yearincycle d m ) 24 else 25 > if 1 then \ after leap year 26 365 u/mod ( s m h dayinyear yearincycle ) 27 swap >d/m ( s m h yearincycle d m ) 28 then 29 rot r> 4 * + 1970 + ( s m h d m y ) 28 29 \ Convert dayofmonth and monthindex to dayinyear. 30 31 : d/m> ( day1..31 monthindex0..11  dayinyear0..365 ) 32 swap 1 swap 0 ?do i days/month + c@ + loop ( dayinyear ) 30 33 ; 31 : >unixseconds ( s m h d m y  seconds ) \ since 1970 32 d# 1970  4 /mod [ d# 365 4 * 1+ ] literal * ( s m h d m yrs days ) 33 swap d# 365 * + ( s m h d m days ) 34 swap 1 max d# 12 min ( s m h d days m' ) 35 1 0 ?do i days/month + c@ + loop ( s m h d days ) 36 + 1 ( s m h days ) 37 d# 24 * + d# 60 * + d# 60 * + 34 35 \ 36 d# 365 constant d/y 37 d/y d# 30 * \ Years from 1970 to 2000 38 d# 7 + \ Leap days from 1970 to 2000 39 d# 31 + \ Days in January 2000 40 d# 28 + \ Days in February 2000 (not a leap year) 41 constant daystobreak 42 43 : unixseconds> ( seconds  s m h d m y ) 44 \ Changing the 3 /mod's below to u/mod's would "fix" the year 2038 problem 45 \ at the expense of breaking dates before 1970. 46 d# 60 /mod d# 60 /mod d# 24 /mod ( s m h days ) 47 48 \ Rotate the number space so that day 0 is March 1, 2000 49 \ That's convenient because it begins a 4 year + 1 day leap cycle 50 daystobreak  51 52 \ Adjust days before day 0 for the fact that 2000, unlike other 53 \ 0mod4 years, is not a leap year 54 dup 0< if 1 then ( s m h days' ) 55 56 \ Reduce modulo the number of days in a 4year leap cycle 57 \ This depends on floored division 58 [ d/y 4 * 1+ ] literal /mod >r ( s m h dayincycle r: cycles ) 59 60 \ Reduce by the number of days in a normal year 61 d/y /mod ( s m h dayinyear yearincycle r: cycles ) 62 63 \ If yearincycle is 4, it's Feb 29 64 dup 4 = if ( s m h dayinyear yearincycle r: cycles ) 65 \ Leap day Feb 29 at end of cycle 66 swap d/y + swap 1 ( s m h dayinyear' yearincycle' r: cycles ) 67 then ( s m h dayinyear yearincycle r: cycles ) 68 r> 4 * + >r ( s m h dayinyear r: year ) 69 70 >d/m ( s m h dayinmonth monthindex r: year ) 71 72 \ Adjust the month number  at this point March is 0 and we want it to be 3 73 3 + ( s m h d month' r: year ) 74 75 \ Months 13 and 14 are January and February of the following year 76 dup d# 13 >= if ( s m h d month r: year ) 77 d# 12  r> 1+ >r ( s m h d month' r: year' ) 78 then ( s m h d month r: year ) 79 80 r> d# 2000 + ( s m h d m y ) 81 ; 82 83 : >unixseconds ( s m h d m y  seconds ) \ since 1970 84 d# 2000  >r ( s m h d m r: y' ) 85 86 \ Move January and February to the end so the leap day is day number 365 87 dup 3 < if ( s m h d month' r: y ) 88 d# 12 + r> 1 >r ( s m h d month' r: y' ) 89 then ( s m h d month r: y ) 90 91 \ Convert month numbers 3..14 to 0..11 92 3  ( s m h d monthindex r: y ) 93 94 \ Convert day and month to day in year 95 d/m> ( s m h dayinyear r: y ) 96 97 r@ 4 / ( s m h dayinyear leapyears r: y ) 98 r> d/y * + ( s m h dayinyear yeardays ) 99 + ( s m h days ) 100 101 \ Adjust for the missing leap day in 2000 102 dup 0< if 1+ then ( s m h days' ) 103 104 \ Adjust to 1970 105 daystobreak + ( s m h days' ) 106 107 108 \ Changing the 3 *'s below to u*'s would "fix" the year 2038 problem 109 \ at the expense of breaking dates before 1970. 110 d# 24 * + d# 60 * + d# 60 * + ( seconds ) 38 111 ; 39 112
Note: See TracChangeset
for help on using the changeset viewer.