 : before ( duration -- -duration )
     -1 time* ;
 
+<PRIVATE
+
+: -slots ( obj1 obj2 quot -- n obj1 obj2 )
+    [ bi@ - ] curry 2keep ; inline
+
+PRIVATE>
+
 M: duration time-
-    before time+ ;
+    over timestamp? [
+        before time+
+    ] [
+        [ year>> ] -slots
+        [ month>> ] -slots
+        [ day>> ] -slots
+        [ hour>> ] -slots
+        [ minute>> ] -slots
+        [ second>> ] -slots
+        2drop <duration>
+    ] if ;
 
 : <zero> ( -- timestamp )
     0 0 0 <date-gmt> ; inline

    unix-1970 time+ ; inline

: timestamp>unix-time ( timestamp -- seconds )
    unix-1970 time- second>> ; inline

: unix-time>timestamp ( seconds -- timestamp )
    seconds since-1970 ; inline

{
    { [ os unix? ] [ "calendar.unix" ] }

    1970 <year-gmt> ; inline

: millis>timestamp ( x -- timestamp )
    [ unix-1970 ] dip 1000 / +second ;

: timestamp>millis ( timestamp -- n )
    unix-1970 (time-) 1000 * >integer ;

: micros>timestamp ( x -- timestamp )
    [ unix-1970 ] dip 1000000 / +second ;

: timestamp>micros ( timestamp -- n )
    unix-1970 (time-) 1000000 * >integer ;

: now ( -- timestamp )
    gmt gmt-offset-duration (time+) >>gmt-offset ;

: hence ( duration -- timestamp ) now swap time+ ;

: ago ( duration -- timestamp ) now swap time- ;

: zeller-congruence ( year month day -- n )
