123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104typewday=Sun|Mon|Tue|Wed|Thu|Fri|Satletstring_of_wday=function|Sun->"Sun"|Mon->"Mon"|Tue->"Tue"|Wed->"Wed"|Thu->"Thu"|Fri->"Fri"|Sat->"Sat"typemonth=Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Decletindex_of_month=function|Jan->0|Feb->1|Mar->2|Apr->3|May->4|Jun->5|Jul->6|Aug->7|Sep->8|Oct->9|Nov->10|Dec->11letstring_of_month=function|Jan->"Jan"|Feb->"Feb"|Mar->"Mar"|Apr->"Apr"|May->"May"|Jun->"Jun"|Jul->"Jul"|Aug->"Aug"|Sep->"Sep"|Oct->"Oct"|Nov->"Nov"|Dec->"Dec"(* of_m.(m) = ⌊13(m+1)/5⌋ mod 7 *)letof_m=[|1;4;3;6;1;4;6;2;5;0;3;5|](* of_y.(y) = y + ⌊y/4⌋ mod 7, for y = 0,...,27 *)letof_y=[|0;1;2;3;5;6;0;1;3;4;5;6;1;2;3;4;6;0;1;2;4;5;6;0;2;3;4;5|](* of_c.(c) = ⌊c/4⌋ - 2c mod 7, for c = 0,...,3 *)letof_c=[|0;5;3;1|](* Zeller's algorithm *)letcompute_wdayday(* ∈ {1,...,31} *)monthyear=letyear=ifmonth=Jan||month=Febthenyear-1elseyearinlety=(yearmod100)mod28inlety=of_y.(ify<0then28+yelsey)inletc=(year/100)mod4inletc=of_c.(ifc<0thenc+4elsec)inmatch(day+of_m.(index_of_monthmonth)+y+c)mod7with|1->Sun|2->Mon|3->Tue|4->Wed|5->Thu|6->Fri|0->Sat|_->assertfalsetypet={day:int;month:month;year:int;hour:int;min:int;sec:int;tz:int;wday:wdayLazy.t;}letdayd=d.dayletmonthd=d.monthletyeard=d.yearlethourd=d.hourletmind=d.minletsecd=d.secletwdayd=Lazy.forced.wdayletmonth_of_stringsofs=matchs.[ofs]with|'J'->ifs.[ofs+1]='a'thenJanelseifs.[ofs+2]='n'thenJunelseJul|'F'->Feb|'M'->ifs.[ofs+2]='r'thenMarelseMay|'A'->ifs.[ofs+1]='p'thenAprelseAug|'S'->Sep|'O'->Oct|'N'->Nov|'D'->Dec|_->assertfalse(* When the parsing fails, return the Epoch *)letepoch={day=1;month=Jan;year=1970;wday=lazyThu;hour=0;min=0;sec=0;tz=0}(* Parse date of the form [s]. Never fail. Simple minded. *)(* FIXME: return an option instead?? *)(* FIXME: one should validate the date *)letof_strings=tryletday=int_of_string(String.subs52)inletmonth=month_of_strings8inletyear=int_of_string(String.subs124)inlethour=int_of_string(String.subs172)inletmin=int_of_string(String.subs202)inletsec=int_of_string(String.subs232)inlettz=ifs.[26]='+'thenint_of_string(String.subs274)elseint_of_string(String.subs265)in{day;month;year;hour;min;sec;tz;wday=lazy(compute_wdaydaymonthyear)}with_->epochletto_stringd=letwday=string_of_wday(wdayd)inletmonth=string_of_monthd.monthinPrintf.sprintf"%s, %d %s %d %d:%d:%d %+05d"wdayd.daymonthd.yeard.hourd.mind.secd.tz