123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155open!ImportopenStd_internalopen!Int.Replace_polymorphic_comparemoduleSpan=Span_floatmoduleOfday=Ofday_floatmoduleAbsolute=structtypeunderlying=Float.tinclude(Float:sigtypet=float[@@derivingbin_io,hash,typerep]includeComparable.S_commonwithtypet:=tincludemoduletypeofstructincludeFloat.Oendend)(* due to precision limitations in float we can't expect better than microsecond
precision *)includeFloat.Robust_compare.Make(structletrobust_comparison_tolerance=1E-6end)letdifft1t2=Span.of_sec(t1-t2)letaddtspan=t+.Span.to_secspanletsubtspan=t-.Span.to_secspanletprevt=Float.one_ulp`Downtletnextt=Float.one_ulp`Uptletto_span_since_epoch=Span.of_secletof_span_since_epoch=Span.to_secendincludeAbsolutemoduleDate_and_ofday=structtypet=floatletof_synthetic_span_since_epochspan=Span.to_secspanletto_synthetic_span_since_epocht=Span.of_sectletof_date_ofdaydateofday=letdays=Float.of_int(Date0.Days.diff(Date0.Days.of_datedate)Date0.Days.unix_epoch)in(days*.86400.)+.Span.to_sec(Ofday.to_span_since_start_of_dayofday);;letto_absoluterelative~offset_from_utc=subrelativeoffset_from_utcletof_absoluteabsolute~offset_from_utc=addabsoluteoffset_from_utc(* Years out of range for [Date.create_exn]. *)let[@cold]assert_in_bounds~sec_since_epoch=(* $ TZ=UTC date --date=@-62167219200
Sat Jan 1 00:00:00 UTC 0000 *)letgmtime_lower_bound=-62_167_219_200.in(* $ TZ=UTC date --date=@253402300799
Fri Dec 31 23:59:59 UTC 9999 *)letgmtime_upper_bound=253_402_300_799.inifFloat.(>=)sec_since_epoch(gmtime_upper_bound+.1.)||Float.(<)sec_since_epochgmtime_lower_boundthenfailwithf"Time.gmtime: out of range (%f)"sec_since_epoch();;letsec_per_day=Int63.of_int86_400letto_days_from_epocht=assert_in_bounds~sec_since_epoch:t;letopenInt63.Oinletdays_from_epoch_approx=Int63.of_floatt/sec_per_dayin(* when [t] is negative the integer division that calculated days_from_epoch_approx
will leave us one day short because it truncates (e.g. -100 / 86_400 = 0 and we
want -1) -- adjust for that here. *)ifFloat.(<)t(Int63.to_float(days_from_epoch_approx*sec_per_day))thenInt63.preddays_from_epoch_approxelsedays_from_epoch_approx;;letofday_of_days_from_epocht~days_from_epoch=letopenInt63.Oinletdays_from_epoch_in_sec=Int63.to_float(days_from_epoch*sec_per_day)inletremainder=t-.days_from_epoch_in_secinSpan.of_secremainder|>Ofday.of_span_since_start_of_day_exn;;letdate_of_days_from_epoch~days_from_epoch=Int63.to_int_exndays_from_epoch|>Date0.Days.add_daysDate0.Days.unix_epoch|>Date0.Days.to_date;;letto_datet=letdays_from_epoch=to_days_from_epochtindate_of_days_from_epoch~days_from_epoch;;letto_ofdayt=letdays_from_epoch=to_days_from_epochtinofday_of_days_from_epocht~days_from_epoch;;letto_date_ofdayt=letdays_from_epoch=to_days_from_epochtinletdate=date_of_days_from_epoch~days_from_epochinletofday=ofday_of_days_from_epocht~days_from_epochindate,ofday;;endletnext_multiple_internal~can_equal_after~base~after~interval=ifSpan.(<=)intervalSpan.zerothenfailwiths~here:[%here]"Time.next_multiple got nonpositive interval"interval[%sexp_of:Span.t];letbase_to_after=diffafterbaseinifSpan.(<)base_to_afterSpan.zerothenbase(* [after < base], choose [k = 0]. *)else(letnext=addbase(Span.scaleinterval(Float.round~dir:`Down(Span.(//)base_to_afterinterval)))inifnext>after||(can_equal_after&&next=after)thennextelseaddnextinterval);;letnext_multiple?(can_equal_after=false)~base~after~interval()=next_multiple_internal~can_equal_after~base~after~interval;;letprev_multiple?(can_equal_before=false)~base~before~interval()=next_multiple_internal~can_equal_after:(notcan_equal_before)~base~after:(subbeforeinterval)~interval;;letnow()=letfloat_ns=Time_now.nanoseconds_since_unix_epoch()|>Int63.to_floatinof_span_since_epoch(Span.of_sec(float_ns*.1E-9));;moduleStable=structmoduleSpan=Span.StablemoduleOfday=Ofday.Stableend