123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512(**************************************************************************)(* *)(* This file is part of Calendar. *)(* *)(* Copyright (C) 2003-2011 Julien Signoles *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License version 2.1 as published by the *)(* Free Software Foundation, with a special linking exception (usual *)(* for Objective Caml libraries). *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR *)(* *)(* See the GNU Lesser General Public Licence version 2.1 for more *)(* details (enclosed in the file LGPL). *)(* *)(* The special linking exception is detailled in the enclosed file *)(* LICENSE. *)(**************************************************************************)(*S Introduction.
A calendar is representing by its (exact) Julian Day -. 0.5.
This gap of 0.5 is because the Julian period begins
January first, 4713 BC at MIDDAY (and then, this Julian day is 0.0).
But, for implementation facilities, the Julian day 0.0 is coded as
January first, 4713 BC at MIDNIGHT. *)moduleMake(D:Date_sig.S)(T:Time_sig.S)=struct(*S Datatypes. *)includeUtils.FloatmoduleDate=DmoduleTime=Ttypeday=D.day=Sun|Mon|Tue|Wed|Thu|Fri|Sattypemonth=D.month=Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dectypeyear=inttypesecond=T.secondtypefield=[D.field|T.field](*S Conversions. *)letconvertxt1t2=x+.float(Time_Zone.gapt1t2)/.24.letto_gmtx=convertx(Time_Zone.current())Time_Zone.UTCletfrom_gmtx=convertxTime_Zone.UTC(Time_Zone.current())letfrom_datex=to_gmt(float(D.to_jdx))-.0.5(* Return the integral part of [x] as a date. *)letto_datex=D.from_jd(int_of_float(from_gmtx+.0.5))(* Return the fractional part of [x] as a time. *)letto_timex=lett,_=modf(from_gmtx+.0.5)inleti=t*.86400.inassert(i<86400.);T.from_seconds(T.Second.from_floati)(*S Constructors. *)letis_validx=x>=0.&&x<2914695.letcreatedt=to_gmt(float(D.to_jdd)+.T.Second.to_float(T.to_secondst)/.86400.)-.0.5letmakeymdhmns=letx=create(D.makeymd)(T.makehmns)inifis_validxthenxelseraiseD.Out_of_boundsletlmake~year?(month=1)?(day=1)?(hour=0)?(minute=0)?(second=T.Second.from_int0)()=makeyearmonthdayhourminutesecondletnow()=letnow=Unix.gettimeofday()inletgmnow=Unix.gmtimenowinletfrac,_=modfnowinfrom_gmt(make(gmnow.Unix.tm_year+1900)(gmnow.Unix.tm_mon+1)gmnow.Unix.tm_mdaygmnow.Unix.tm_hourgmnow.Unix.tm_min(T.Second.from_float(floatgmnow.Unix.tm_sec+.frac)))letfrom_jdx=to_gmtxletfrom_mjdx=to_gmtx+.2400000.5(*S Getters. *)letto_jdx=from_gmtxletto_mjdx=from_gmtx-.2400000.5letdays_in_monthx=D.days_in_month(to_datex)letday_of_weekx=D.day_of_week(to_datex)letday_of_monthx=D.day_of_month(to_datex)letday_of_yearx=D.day_of_year(to_datex)letweekx=D.week(to_datex)letmonthx=D.month(to_datex)letyearx=D.year(to_datex)lethourx=T.hour(to_timex)letminutex=T.minute(to_timex)letsecondx=T.second(to_timex)(*S Coercions. *)letfrom_unixtmx=make(x.Unix.tm_year+1900)(x.Unix.tm_mon+1)x.Unix.tm_mdayx.Unix.tm_hourx.Unix.tm_min(T.Second.from_intx.Unix.tm_sec)letto_unixtmx=lettm=D.to_unixtm(to_datex)andt=to_timexin{tmwithUnix.tm_sec=T.Second.to_int(T.secondt);Unix.tm_min=T.minutet;Unix.tm_hour=T.hourt}letjan_1_1970=2440587.5letfrom_unixfloatx=to_gmt(x/.86400.+.jan_1_1970)letto_unixfloatx=(from_gmtx-.jan_1_1970)*.86400.(*S Boolean operations on dates. *)letis_leap_dayx=D.is_leap_day(to_datex)letis_gregorianx=D.is_gregorian(to_datex)letis_julianx=D.is_julian(to_datex)letis_pmx=T.is_pm(to_timex)letis_amx=T.is_am(to_timex)(*S Period. *)modulePeriod=structtype+'ap={d:'aD.Period.period;t:'aT.Period.period}constraint'a=[<Period.date_field]type+'aperiod='aptypet=Period.date_fieldperiodletsplitx=letrecauxs=ifs<86400.then0,selseletd,s=aux(s-.86400.)ind+1,sinlets=T.Second.to_float(T.Period.lengthx.t)inletd,s=ifs>=0.thenauxselseletd,s=aux(-.s)in-(d+1),-.s+.86400.inassert(s>=0.&&s<86400.);D.Period.dayd,T.Period.second(T.Second.from_floats)letnormalizex=letdays,seconds=splitxin{d=D.Period.addx.ddays;t=seconds}letempty={d=D.Period.empty;t=T.Period.empty}letmakeymdhmns=normalize{d=D.Period.makeymd;t=T.Period.makehmns}letlmake?(year=0)?(month=0)?(day=0)?(hour=0)?(minute=0)?(second=T.Second.from_int0)()=makeyearmonthdayhourminutesecondletyearx={emptywithd=D.Period.yearx}letmonthx={emptywithd=D.Period.monthx}letweekx={emptywithd=D.Period.weekx}letdayx={emptywithd=D.Period.dayx}lethourx=normalize{emptywitht=T.Period.hourx}letminutex=normalize{emptywitht=T.Period.minutex}letsecondx=normalize{emptywitht=T.Period.secondx}letaddxy=normalize{d=D.Period.addx.dy.d;t=T.Period.addx.ty.t}letsubxy=normalize{d=D.Period.subx.dy.d;t=T.Period.subx.ty.t}letoppx=normalize{d=D.Period.oppx.d;t=T.Period.oppx.t}letcomparexy=letn=D.Period.comparex.dy.dinifn=0thenT.Period.comparex.ty.telsenletequalxy=D.Period.equalx.dy.d&&T.Period.equalx.ty.tlethash=Hashtbl.hashletto_datex=x.dletfrom_datex={emptywithd=x}letfrom_timex={emptywitht=x}exceptionNot_computable=D.Period.Not_computableletgen_to_timefx=T.Period.add(T.Period.hour(fx.d*24))x.tletto_timex=gen_to_timeD.Period.nb_daysx(* eta-expansion required *)letsafe_to_timex=gen_to_timeD.Period.safe_nb_daysxletymdsx=lety,m,d=D.Period.ymdx.diny,m,d,T.Period.to_secondsx.tend(*S Arithmetic operations on calendars and periods. *)letsplitx=lett,d=modf(from_gmt(x+.0.5))inlett,d=t*.86400.,int_of_floatdinlett,d=ift<0.thent+.86400.,d-1elset,dinassert(t>=0.&&t<86400.);D.from_jdd,T.from_seconds(T.Second.from_floatt)letunsplitdt=to_gmt(float(D.to_jdd)+.(T.Second.to_float(T.to_secondst)/.86400.))-.0.5letaddxp=letd,t=splitxinunsplit(D.addd(p.Period.d:>D.Period.t))(T.addtp.Period.t)letremxp=addx(Period.opp(p:>Period.t))letsubxy=letd1,t1=splitxinletd2,t2=splityinPeriod.normalize{Period.d=D.subd1d2;Period.t=T.subt1t2}letprecise_subxy=letd1,t1=splitxinletd2,t2=splityinPeriod.normalize{Period.d=D.precise_subd1d2;Period.t=T.subt1t2}letnextxf=letd,t=splitxinmatchfwith|#D.fieldasf->unsplit(D.nextdf)t|#T.fieldasf->unsplitd(T.nexttf)letprevxf=letd,t=splitxinmatchfwith|#D.fieldasf->unsplit(D.prevdf)t|#T.fieldasf->unsplitd(T.prevtf)end(* ************************************************************************* *)(* ************************************************************************* *)(* ************************************************************************* *)moduleMake_Precise(D:Date_sig.S)(T:Time_sig.S)=structmoduleDate=DmoduleTime=Ttypet={date:D.t;time:T.t}typeday=D.day=Sun|Mon|Tue|Wed|Thu|Fri|Sattypemonth=D.month=Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dectypeyear=inttypesecond=T.secondtypefield=[D.field|T.field](*S Comparison *)letequalxy=D.equalx.datey.date&&T.equalx.timey.timeletcomparexy=letn=D.comparex.datey.dateinifn=0thenT.comparex.timey.timeelsenlethash=Hashtbl.hash(*S Conversions. *)letnormalizedt=lett,days=T.normalizetin{date=D.addd(D.Period.daydays);time=t}letconvertxt1t2=letgap=T.Period.hour(Time_Zone.gapt1t2)innormalizex.date(T.addx.timegap)letto_gmtx=convertx(Time_Zone.current())Time_Zone.UTCletfrom_gmtx=convertxTime_Zone.UTC(Time_Zone.current())letfrom_dated=to_gmt{date=d;time=T.make00(T.Second.from_int0)}letto_datex=(from_gmtx).dateletto_timex=(from_gmtx).time(*S Constructors. *)letcreatedt=to_gmt{date=d;time=t}letlower_bound,upper_bound=letcompute()=letmidday=T.midday()inletlow,up=create(D.make(-4712)11)midday,create(D.make3268122)middayinlow,upinTime_Zone.oncomputeTime_Zone.UTC()letis_validx=comparexlower_bound>=0&&comparexupper_bound<=0letmakeymdhmns=letx=create(D.makeymd)(T.makehmns)inifis_validxthenxelseraiseD.Out_of_boundsletlmake~year?(month=1)?(day=1)?(hour=0)?(minute=0)?(second=T.Second.from_int0)()=makeyearmonthdayhourminutesecondletnow()=letnow=Unix.gettimeofday()inletgmnow=Unix.gmtimenowinletfrac,_=modfnowinfrom_gmt(make(gmnow.Unix.tm_year+1900)(gmnow.Unix.tm_mon+1)gmnow.Unix.tm_mdaygmnow.Unix.tm_hourgmnow.Unix.tm_min(T.Second.from_float(floatgmnow.Unix.tm_sec+.frac)))letfrom_jdx=letfrac,intf=modfxinto_gmt{date=D.from_jd(int_of_floatintf);time=T.from_seconds(T.Second.from_float(frac*.86400.+.43200.))}letfrom_mjdx=from_jd(x+.2400000.5)(*S Getters. *)letto_jdx=letx=from_gmtxinfloat(D.to_jdx.date)+.T.Second.to_float(T.to_secondsx.time)/.86400.-.0.5letto_mjdx=to_jdx-.2400000.5letdays_in_monthx=D.days_in_month(to_datex)letday_of_weekx=D.day_of_week(to_datex)letday_of_monthx=D.day_of_month(to_datex)letday_of_yearx=D.day_of_year(to_datex)letweekx=D.week(to_datex)letmonthx=D.month(to_datex)letyearx=D.year(to_datex)lethourx=T.hour(to_timex)letminutex=T.minute(to_timex)letsecondx=T.second(to_timex)(*S Coercions. *)letfrom_unixtmx=make(x.Unix.tm_year+1900)(x.Unix.tm_mon+1)x.Unix.tm_mdayx.Unix.tm_hourx.Unix.tm_min(T.Second.from_intx.Unix.tm_sec)letto_unixtmx=lettm=D.to_unixtm(to_datex)andt=to_timexin{tmwithUnix.tm_sec=T.Second.to_int(T.secondt);Unix.tm_min=T.minutet;Unix.tm_hour=T.hourt}letjan_1_1970=2440587.5letfrom_unixfloatx=from_jd(x/.86400.+.jan_1_1970)letto_unixfloatx=(to_jdx-.jan_1_1970)*.86400.(*S Boolean operations on dates. *)letis_leap_dayx=D.is_leap_day(to_datex)letis_gregorianx=D.is_gregorian(to_datex)letis_julianx=D.is_julian(to_datex)letis_pmx=T.is_pm(to_timex)letis_amx=T.is_am(to_timex)(*S Period. *)modulePeriod=structtype+'ap={d:'aD.Period.period;t:'aT.Period.period}constraint'a=[<Period.date_field]type+'aperiod='aptypet=Period.date_fieldperiodletsplitx=letrecauxs=ifs<86400.then0,selseletd,s=aux(s-.86400.)ind+1,sinlets=T.Second.to_float(T.Period.lengthx.t)inletd,s=ifs>=0.thenauxselseletd,s=aux(-.s)in-(d+1),-.s+.86400.inassert(s>=0.&&s<86400.);D.Period.dayd,T.Period.second(T.Second.from_floats)letnormalizex=letdays,seconds=splitxin{d=D.Period.addx.ddays;t=seconds}letempty={d=D.Period.empty;t=T.Period.empty}letmakeymdhmns=normalize{d=D.Period.makeymd;t=T.Period.makehmns}letlmake?(year=0)?(month=0)?(day=0)?(hour=0)?(minute=0)?(second=T.Second.from_int0)()=makeyearmonthdayhourminutesecondletyearx={emptywithd=D.Period.yearx}letmonthx={emptywithd=D.Period.monthx}letweekx={emptywithd=D.Period.weekx}letdayx={emptywithd=D.Period.dayx}lethourx=normalize{emptywitht=T.Period.hourx}letminutex=normalize{emptywitht=T.Period.minutex}letsecondx=normalize{emptywitht=T.Period.secondx}letaddxy=normalize{d=D.Period.addx.dy.d;t=T.Period.addx.ty.t}letsubxy=normalize{d=D.Period.subx.dy.d;t=T.Period.subx.ty.t}letoppx=normalize{d=D.Period.oppx.d;t=T.Period.oppx.t}letcomparexy=letn=D.Period.comparex.dy.dinifn=0thenT.Period.comparex.ty.telsenletequalxy=D.Period.equalx.dy.d&&T.Period.equalx.ty.tlethash=Hashtbl.hashletto_datex=x.dletfrom_datex={emptywithd=x}letfrom_timex={emptywitht=x}exceptionNot_computable=D.Period.Not_computableletgen_to_timefx=T.Period.add(T.Period.hour(fx.d*24))x.tletto_timex=gen_to_timeD.Period.nb_daysx(* eta-expansion required *)letsafe_to_timex=gen_to_timeD.Period.safe_nb_daysxletymdsx=lety,m,d=D.Period.ymdx.diny,m,d,T.Period.to_secondsx.tend(*S Arithmetic operations on calendars and periods. *)letaddxp=normalize(D.addx.date(p.Period.d:>D.Period.t))(T.addx.timep.Period.t)letremxp=addx(Period.opp(p:>Period.t))letsubxy=Period.normalize{Period.d=D.subx.datey.date;Period.t=T.subx.timey.time}letprecise_subxy=Period.normalize{Period.d=D.precise_subx.datey.date;Period.t=T.subx.timey.time}letnextx=function|#D.fieldasf->normalize(D.nextx.datef)x.time|#T.fieldasf->normalizex.date(T.nextx.timef)letprevx=function|#D.fieldasf->normalize(D.prevx.datef)x.time|#T.fieldasf->normalizex.date(T.prevx.timef)end