;+ ; NAME: ; TimeOp ; PURPOSE: ; Simple operations on times ; CATEGORY: ; gen/idl/toolbox/time ; CALLING SEQUENCE: FUNCTION TimeOp, t, u, unit , $ add = add , $ subtract = subtract , $ meant = meant , $ times = times , $ divide = divide , $ wt = wt , $ wu = wu , $ units = units , $ old_units = old_units , $ new_units = new_units , $ signdiff = signdiff ; v = TimeOp(t,u, /add) ; v = TimeOp(t,u, /subtract) ; v = TimeOp(t,u, /meant, wt=wt, wu=wu) ; u = TimeOp(t, /units, old_units=old_units, new_units=new_units) ; INPUTS: ; t array; type: time structure ; u array; type: time structure ; OPTIONAL INPUT PARAMETERS: ; /add if set, add t and u (not that u in this case is interpreted ; as a time difference ; /subtract if set, get the time difference t-u ; /meant return a weighted mean of t and u (with weights wt and wu) ; /times ; /divide ; /units if set convert from 'old_units' to 'new_units' ; ; If none of the above keywords is set then /subtract is assumed. ; ; wt=wt scalar or array; type: double; default: 1.0d0-wu or 0.5d0 ; weight for first time array (t) ; wu=wu scalar or array; type: double; default: 1.0d0-wt or 0.5d0 ; weight for second time array (u) ; Input is converted to double if necessary ; ; old_units=old_units ; scalar; type: integer; default: !TimeUnits.in_day ; # times per day currently stored in t ; new_units=new_units ; scalar; type: integer; default: !TimeUnits.tiny ; new units ; OUTPUTS: ; u array; type: time structure ; added times ; INCLUDE: @compile_opt.pro ; On error, return to caller ; CALLS: ; InitVar, IsType, TimePieces, TimeStandardize, TimeGet, TimeUnit, TimeSet ; PROCEDURE: ; /meant set: ; ; If neither wu nor wt are specified then the unweighted mean time ; (t+u)/2 is returned. ; ; If only one weight is defined then the other weight is set to ; 1-(specified) weight, i.e. a weighted mean is calculated: ; wt*t+(1-wt(u)) or (1-wu)*t+wu*t ; ; If both weights are specified the wt*t+wu*u is returned. ; ; Uses !TimeUnits ; Note that the units in the returned time are not necessarily consistent ; anymore with !TimeUnits.in_day. It is the users responsibility to make ; sure that this does not lead to mayhem. ; MODIFICATION HISTORY: ; JAN-2004, Paul Hick (UCSD/CASS) ; APR-2004, Paul Hick (UCSD/CASS; pphick@ucsd.edu) ; Fixed bug in calculation of signdiff ; Added keyword /scalar to TimeGet call used to get signdiff. ; Signdiff is now a returned as a scalar if both t and u are ; 1-element time structure arrays. ;- InitVar, add , /key InitVar, subtract, /key InitVar, times , /key InitVar, divide , /key InitVar, meant , /key InitVar, units , /key CASE 1 OF ; The 'subtract' clause is repeated at the end as the 'else' clause subtract: BEGIN IF n_elements(t) EQ 1 THEN v = u ELSE v = t v = TimePieces(/days, v, TimePieces(/days,t)-TimePieces(/days,u)) v = TimePieces(/unit, v, TimePieces(/unit,t)-TimePieces(/unit,u)) v = TimeStandardize(v) IF arg_present(signdiff) THEN signdiff = 1-2*(TimeGet(v,/diff,/full,TimeUnit(/msec),/scalar) LT 0) IF IsType(unit,/defined) THEN v = TimeGet(v,/diff,/full,unit,/scalar) END add: BEGIN IF n_elements(t) EQ 1 THEN v = u ELSE v = t v = TimePieces(/days, v, TimePieces(/days,t)+TimePieces(/days,u)) v = TimePieces(/unit, v, TimePieces(/unit,t)+TimePieces(/unit,u)) v = TimeStandardize(v) IF IsType(unit,/defined) THEN v = TimeGet(v,/diff,/full,unit,/scalar) END meant: BEGIN CASE IsType(wu,/defined) OF 0: InitVar, wt, 0.5d0 1: InitVar, wt, 1.0d0-wu ENDCASE CASE IsType(wt,/defined) OF 0: InitVar, wu, 0.5d0 1: InitVar, wu, 1.0d0-wt ENDCASE ; Make sure wt and wu are of type double (this is especially important ; if the input is wu or wt are integer: the multiplication in runit ; might cause integer overflow without the conversion. wt = double(wt) wu = double(wu) rday = wt*TimePieces(/days,t)+wu*TimePieces(/days,u) runit = wt*TimePieces(/unit,t)+wu*TimePieces(/unit,u) ; runit will need to be rounded to the nearest integer. ; First reduce the value by splitting of integer days to avoid ; integer overflow when the round is applied. n = floor(runit/!TimeUnits.in_day) rday += n runit -= double(n)*!TimeUnits.in_day v = TimePieces(/unit, TimeSet(day=rday,/diff), round(runit), /add) v = TimeStandardize(v) END times: BEGIN InitVar, wt, 0.5d0 v = TimeSet(day=wt*TimePieces(/days,t), /diff) v = TimePieces(/unit, v, round(wt*TimePieces(/unit,t)), /add) v = TimeStandardize(v) END divide: $ v = TimeGet(t, /day, /diff, /full)/TimeGet(u, /day, /diff, /full) units: BEGIN InitVar, old_units, !TimeUnits.in_day InitVar, new_units, !TimeUnits.tiny v = t IF new_units NE old_units THEN BEGIN CASE 1 OF new_units/old_units*old_units EQ new_units: v = TimePieces(/unit,v, TimePieces(/unit,v) * (new_units/old_units)) old_units/new_units*new_units EQ old_units: v = TimePieces(/unit,v,round(double(TimePieces(/unit,v))/double(old_units/new_units))) ELSE : v = TimePieces(/unit,v,round(double(TimePieces(/unit,v))/double(old_units)*double(new_units))) ENDCASE ENDIF END ELSE: BEGIN ; Same as subtract IF n_elements(t) EQ 1 THEN v = u ELSE v = t v = TimePieces(/days, v, TimePieces(/days,t)-TimePieces(/days,u)) v = TimePieces(/unit, v, TimePieces(/unit,t)-TimePieces(/unit,u)) v = TimeStandardize(v) IF arg_present(signdiff) THEN signdiff = 1-2*(TimeGet(v,/diff,/full,TimeUnit(/msec),/scalar) LT 0) IF IsType(unit,/defined) THEN v = TimeGet(v,/diff,/full,unit,/scalar) END ENDCASE RETURN, v & END