PNG  IHDRQgAMA a cHRMz&u0`:pQ<bKGDgmIDATxwUﹻ& ^CX(J I@ "% (** BX +*i"]j(IH{~R)[~>h{}gy)I$Ij .I$I$ʊy@}x.: $I$Ii}VZPC)I$IF ^0ʐJ$I$Q^}{"r=OzI$gRZeC.IOvH eKX $IMpxsk.쒷/&r[޳<v| .I~)@$updYRa$I |M.e JaֶpSYR6j>h%IRز if&uJ)M$I vLi=H;7UJ,],X$I1AҒJ$ XY XzI@GNҥRT)E@;]K*Mw;#5_wOn~\ DC&$(A5 RRFkvIR}l!RytRl;~^ǷJj اy뷦BZJr&ӥ8Pjw~vnv X^(I;4R=P[3]J,]ȏ~:3?[ a&e)`e*P[4]T=Cq6R[ ~ޤrXR Հg(t_HZ-Hg M$ãmL5R uk*`%C-E6/%[t X.{8P9Z.vkXŐKjgKZHg(aK9ڦmKjѺm_ \#$5,)-  61eJ,5m| r'= &ڡd%-]J on Xm|{ RҞe $eڧY XYrԮ-a7RK6h>n$5AVڴi*ֆK)mѦtmr1p| q:흺,)Oi*ֺK)ܬ֦K-5r3>0ԔHjJئEZj,%re~/z%jVMڸmrt)3]J,T K֦OvԒgii*bKiNO~%PW0=dii2tJ9Jݕ{7"I P9JKTbu,%r"6RKU}Ij2HKZXJ,妝 XYrP ެ24c%i^IK|.H,%rb:XRl1X4Pe/`x&P8Pj28Mzsx2r\zRPz4J}yP[g=L) .Q[6RjWgp FIH*-`IMRaK9TXcq*I y[jE>cw%gLRԕiFCj-ďa`#e~I j,%r,)?[gp FI˨mnWX#>mʔ XA DZf9,nKҲzIZXJ,L#kiPz4JZF,I,`61%2s $,VOϚ2/UFJfy7K> X+6 STXIeJILzMfKm LRaK9%|4p9LwJI!`NsiazĔ)%- XMq>pk$-$Q2x#N ؎-QR}ᶦHZډ)J,l#i@yn3LN`;nڔ XuX5pF)m|^0(>BHF9(cզEerJI rg7 4I@z0\JIi䵙RR0s;$s6eJ,`n 䂦0a)S)A 1eJ,堌#635RIgpNHuTH_SԕqVe ` &S)>p;S$魁eKIuX`I4춒o}`m$1":PI<[v9^\pTJjriRŭ P{#{R2,`)e-`mgj~1ϣLKam7&U\j/3mJ,`F;M'䱀 .KR#)yhTq;pcK9(q!w?uRR,n.yw*UXj#\]ɱ(qv2=RqfB#iJmmL<]Y͙#$5 uTU7ӦXR+q,`I}qL'`6Kͷ6r,]0S$- [RKR3oiRE|nӦXR.(i:LDLTJjY%o:)6rxzҒqTJjh㞦I.$YR.ʼnGZ\ֿf:%55 I˼!6dKxm4E"mG_ s? .e*?LRfK9%q#uh$)i3ULRfK9yxm܌bj84$i1U^@Wbm4uJ,ҪA>_Ij?1v32[gLRD96oTaR׿N7%L2 NT,`)7&ƝL*꽙yp_$M2#AS,`)7$rkTA29_Iye"|/0t)$n XT2`YJ;6Jx".e<`$) PI$5V4]29SRI>~=@j]lp2`K9Jaai^" Ԋ29ORI%:XV5]JmN9]H;1UC39NI%Xe78t)a;Oi Ҙ>Xt"~G>_mn:%|~ޅ_+]$o)@ǀ{hgN;IK6G&rp)T2i୦KJuv*T=TOSV>(~D>dm,I*Ɛ:R#ۙNI%D>G.n$o;+#RR!.eU˽TRI28t)1LWϚ>IJa3oFbu&:tJ*(F7y0ZR ^p'Ii L24x| XRI%ۄ>S1]Jy[zL$adB7.eh4%%누>WETf+3IR:I3Xה)3אOۦSRO'ٺ)S}"qOr[B7ϙ.edG)^ETR"RtRݜh0}LFVӦDB^k_JDj\=LS(Iv─aTeZ%eUAM-0;~˃@i|l @S4y72>sX-vA}ϛBI!ݎߨWl*)3{'Y|iSlEڻ(5KtSI$Uv02,~ԩ~x;P4ցCrO%tyn425:KMlD ^4JRxSهF_}شJTS6uj+ﷸk$eZO%G*^V2u3EMj3k%)okI]dT)URKDS 7~m@TJR~荪fT"֛L \sM -0T KfJz+nإKr L&j()[E&I ߴ>e FW_kJR|!O:5/2跌3T-'|zX ryp0JS ~^F>-2< `*%ZFP)bSn"L :)+pʷf(pO3TMW$~>@~ū:TAIsV1}S2<%ޟM?@iT ,Eūoz%i~g|`wS(]oȤ8)$ ntu`өe`6yPl IzMI{ʣzʨ )IZ2= ld:5+請M$-ї;U>_gsY$ÁN5WzWfIZ)-yuXIfp~S*IZdt;t>KūKR|$#LcԀ+2\;kJ`]YǔM1B)UbG"IRߊ<xܾӔJ0Z='Y嵤 Leveg)$znV-º^3Ւof#0Tfk^Zs[*I꯳3{)ˬW4Ւ4 OdpbZRS|*I 55#"&-IvT&/윚Ye:i$ 9{LkuRe[I~_\ؠ%>GL$iY8 9ܕ"S`kS.IlC;Ҏ4x&>u_0JLr<J2(^$5L s=MgV ~,Iju> 7r2)^=G$1:3G< `J3~&IR% 6Tx/rIj3O< ʔ&#f_yXJiގNSz; Tx(i8%#4 ~AS+IjerIUrIj362v885+IjAhK__5X%nV%Iͳ-y|7XV2v4fzo_68"S/I-qbf; LkF)KSM$ Ms>K WNV}^`-큧32ŒVؙGdu,^^m%6~Nn&͓3ŒVZMsRpfEW%IwdǀLm[7W&bIRL@Q|)* i ImsIMmKmyV`i$G+R 0tV'!V)֏28vU7͒vHꦼtxꗞT ;S}7Mf+fIRHNZUkUx5SAJㄌ9MqμAIRi|j5)o*^'<$TwI1hEU^c_j?Е$%d`z cyf,XO IJnTgA UXRD }{H}^S,P5V2\Xx`pZ|Yk:$e ~ @nWL.j+ϝYb퇪bZ BVu)u/IJ_ 1[p.p60bC >|X91P:N\!5qUB}5a5ja `ubcVxYt1N0Zzl4]7­gKj]?4ϻ *[bg$)+À*x쳀ogO$~,5 زUS9 lq3+5mgw@np1sso Ӻ=|N6 /g(Wv7U;zωM=wk,0uTg_`_P`uz?2yI!b`kĸSo+Qx%!\οe|އԁKS-s6pu_(ֿ$i++T8=eY; צP+phxWQv*|p1. ά. XRkIQYP,drZ | B%wP|S5`~́@i޾ E;Չaw{o'Q?%iL{u D?N1BD!owPHReFZ* k_-~{E9b-~P`fE{AܶBJAFO wx6Rox5 K5=WwehS8 (JClJ~ p+Fi;ŗo+:bD#g(C"wA^ r.F8L;dzdIHUX݆ϞXg )IFqem%I4dj&ppT{'{HOx( Rk6^C٫O.)3:s(۳(Z?~ٻ89zmT"PLtw䥈5&b<8GZ-Y&K?e8,`I6e(֍xb83 `rzXj)F=l($Ij 2*(F?h(/9ik:I`m#p3MgLaKjc/U#n5S# m(^)=y=đx8ŬI[U]~SцA4p$-F i(R,7Cx;X=cI>{Km\ o(Tv2vx2qiiDJN,Ҏ!1f 5quBj1!8 rDFd(!WQl,gSkL1Bxg''՞^ǘ;pQ P(c_ IRujg(Wz bs#P­rz> k c&nB=q+ؔXn#r5)co*Ũ+G?7< |PQӣ'G`uOd>%Mctz# Ԫڞ&7CaQ~N'-P.W`Oedp03C!IZcIAMPUۀ5J<\u~+{9(FbbyAeBhOSܳ1 bÈT#ŠyDžs,`5}DC-`̞%r&ڙa87QWWp6e7 Rϫ/oY ꇅ Nܶըtc!LA T7V4Jsū I-0Pxz7QNF_iZgúWkG83 0eWr9 X]㾮݁#Jˢ C}0=3ݱtBi]_ &{{[/o[~ \q鯜00٩|cD3=4B_b RYb$óBRsf&lLX#M*C_L܄:gx)WΘsGSbuL rF$9';\4Ɍq'n[%p.Q`u hNb`eCQyQ|l_C>Lb꟟3hSb #xNxSs^ 88|Mz)}:](vbۢamŖ࿥ 0)Q7@0=?^k(*J}3ibkFn HjB׻NO z x}7p 0tfDX.lwgȔhԾŲ }6g E |LkLZteu+=q\Iv0쮑)QٵpH8/2?Σo>Jvppho~f>%bMM}\//":PTc(v9v!gոQ )UfVG+! 35{=x\2+ki,y$~A1iC6#)vC5^>+gǵ@1Hy٪7u;p psϰu/S <aʸGu'tD1ԝI<pg|6j'p:tպhX{o(7v],*}6a_ wXRk,O]Lܳ~Vo45rp"N5k;m{rZbΦ${#)`(Ŵg,;j%6j.pyYT?}-kBDc3qA`NWQū20/^AZW%NQ MI.X#P#,^Ebc&?XR tAV|Y.1!؅⨉ccww>ivl(JT~ u`ٵDm q)+Ri x/x8cyFO!/*!/&,7<.N,YDŽ&ܑQF1Bz)FPʛ?5d 6`kQձ λc؎%582Y&nD_$Je4>a?! ͨ|ȎWZSsv8 j(I&yj Jb5m?HWp=g}G3#|I,5v珿] H~R3@B[☉9Ox~oMy=J;xUVoj bUsl_35t-(ՃɼRB7U!qc+x4H_Qo֮$[GO<4`&č\GOc[.[*Af%mG/ ňM/r W/Nw~B1U3J?P&Y )`ѓZ1p]^l“W#)lWZilUQu`-m|xĐ,_ƪ|9i:_{*(3Gѧ}UoD+>m_?VPۅ15&}2|/pIOʵ> GZ9cmíتmnz)yߐbD >e}:) r|@R5qVSA10C%E_'^8cR7O;6[eKePGϦX7jb}OTGO^jn*媓7nGMC t,k31Rb (vyܴʭ!iTh8~ZYZp(qsRL ?b}cŨʊGO^!rPJO15MJ[c&~Z`"ѓޔH1C&^|Ш|rʼ,AwĴ?b5)tLU)F| &g٣O]oqSUjy(x<Ϳ3 .FSkoYg2 \_#wj{u'rQ>o;%n|F*O_L"e9umDds?.fuuQbIWz |4\0 sb;OvxOSs; G%T4gFRurj(֍ڑb uԖKDu1MK{1^ q; C=6\8FR艇!%\YÔU| 88m)֓NcLve C6z;o&X x59:q61Z(T7>C?gcļxѐ Z oo-08jہ x,`' ҔOcRlf~`jj".Nv+sM_]Zk g( UOPyεx%pUh2(@il0ݽQXxppx-NS( WO+轾 nFߢ3M<;z)FBZjciu/QoF 7R¥ ZFLF~#ȣߨ^<쩡ݛкvџ))ME>ώx4m#!-m!L;vv#~Y[đKmx9.[,UFS CVkZ +ߟrY٧IZd/ioi$%͝ب_ֶX3ܫhNU ZZgk=]=bbJS[wjU()*I =ώ:}-蹞lUj:1}MWm=̛ _ ¾,8{__m{_PVK^n3esw5ӫh#$-q=A̟> ,^I}P^J$qY~Q[ Xq9{#&T.^GVj__RKpn,b=`żY@^՝;z{paVKkQXj/)y TIc&F;FBG7wg ZZDG!x r_tƢ!}i/V=M/#nB8 XxЫ ^@CR<{䤭YCN)eKOSƟa $&g[i3.C6xrOc8TI;o hH6P&L{@q6[ Gzp^71j(l`J}]e6X☉#͕ ׈$AB1Vjh㭦IRsqFBjwQ_7Xk>y"N=MB0 ,C #o6MRc0|$)ف"1!ixY<B9mx `,tA>)5ػQ?jQ?cn>YZe Tisvh# GMމȇp:ԴVuږ8ɼH]C.5C!UV;F`mbBk LTMvPʍϤj?ԯ/Qr1NB`9s"s TYsz &9S%U԰> {<ؿSMxB|H\3@!U| k']$U+> |HHMLޢ?V9iD!-@x TIî%6Z*9X@HMW#?nN ,oe6?tQwڱ.]-y':mW0#!J82qFjH -`ѓ&M0u Uγmxϵ^-_\])@0Rt.8/?ٰCY]x}=sD3ojަЫNuS%U}ԤwHH>ڗjܷ_3gN q7[q2la*ArǓԖ+p8/RGM ]jacd(JhWko6ڎbj]i5Bj3+3!\j1UZLsLTv8HHmup<>gKMJj0@H%,W΃7R) ">c, xixј^ aܖ>H[i.UIHc U1=yW\=S*GR~)AF=`&2h`DzT󑓶J+?W+}C%P:|0H܆}-<;OC[~o.$~i}~HQ TvXΈr=b}$vizL4:ȰT|4~*!oXQR6Lk+#t/g lԁߖ[Jڶ_N$k*". xsxX7jRVbAAʯKҎU3)zSNN _'s?f)6X!%ssAkʱ>qƷb hg %n ~p1REGMHH=BJiy[<5 ǁJҖgKR*倳e~HUy)Ag,K)`Vw6bRR:qL#\rclK/$sh*$ 6덤 KԖc 3Z9=Ɣ=o>X Ώ"1 )a`SJJ6k(<c e{%kϊP+SL'TcMJWRm ŏ"w)qc ef꒵i?b7b('"2r%~HUS1\<(`1Wx9=8HY9m:X18bgD1u ~|H;K-Uep,, C1 RV.MR5άh,tWO8WC$ XRVsQS]3GJ|12 [vM :k#~tH30Rf-HYݺ-`I9%lIDTm\ S{]9gOڒMNCV\G*2JRŨ;Rҏ^ڽ̱mq1Eu?To3I)y^#jJw^Ńj^vvlB_⋌P4x>0$c>K†Aļ9s_VjTt0l#m>E-,,x,-W)سo&96RE XR.6bXw+)GAEvL)͞K4$p=Ũi_ѱOjb HY/+@θH9޼]Nԥ%n{ &zjT? Ty) s^ULlb,PiTf^<À] 62R^V7)S!nllS6~͝V}-=%* ʻ>G DnK<y&>LPy7'r=Hj 9V`[c"*^8HpcO8bnU`4JȪAƋ#1_\ XϘHPRgik(~G~0DAA_2p|J묭a2\NCr]M_0 ^T%e#vD^%xy-n}-E\3aS%yN!r_{ )sAw ڼp1pEAk~v<:`'ӭ^5 ArXOI驻T (dk)_\ PuA*BY]yB"l\ey hH*tbK)3 IKZ򹞋XjN n *n>k]X_d!ryBH ]*R 0(#'7 %es9??ښFC,ՁQPjARJ\Ρw K#jahgw;2$l*) %Xq5!U᢯6Re] |0[__64ch&_}iL8KEgҎ7 M/\`|.p,~`a=BR?xܐrQ8K XR2M8f ?`sgWS%" Ԉ 7R%$ N}?QL1|-эټwIZ%pvL3Hk>,ImgW7{E xPHx73RA @RS CC !\ȟ5IXR^ZxHл$Q[ŝ40 (>+ _C >BRt<,TrT {O/H+˟Pl6 I B)/VC<6a2~(XwV4gnXR ϱ5ǀHٻ?tw똤Eyxp{#WK qG%5],(0ӈH HZ])ג=K1j&G(FbM@)%I` XRg ʔ KZG(vP,<`[ Kn^ SJRsAʠ5xՅF`0&RbV tx:EaUE/{fi2;.IAwW8/tTxAGOoN?G}l L(n`Zv?pB8K_gI+ܗ #i?ޙ.) p$utc ~DžfՈEo3l/)I-U?aԅ^jxArA ΧX}DmZ@QLےbTXGd.^|xKHR{|ΕW_h] IJ`[G9{).y) 0X YA1]qp?p_k+J*Y@HI>^?gt.06Rn ,` ?);p pSF9ZXLBJPWjgQ|&)7! HjQt<| ؅W5 x W HIzYoVMGP Hjn`+\(dNW)F+IrS[|/a`K|ͻ0Hj{R,Q=\ (F}\WR)AgSG`IsnAR=|8$}G(vC$)s FBJ?]_u XRvύ6z ŨG[36-T9HzpW̞ú Xg큽=7CufzI$)ki^qk-) 0H*N` QZkk]/tnnsI^Gu't=7$ Z;{8^jB% IItRQS7[ϭ3 $_OQJ`7!]W"W,)Iy W AJA;KWG`IY{8k$I$^%9.^(`N|LJ%@$I}ֽp=FB*xN=gI?Q{٥4B)mw $Igc~dZ@G9K X?7)aK%݅K$IZ-`IpC U6$I\0>!9k} Xa IIS0H$I H ?1R.Чj:4~Rw@p$IrA*u}WjWFPJ$I➓/6#! LӾ+ X36x8J |+L;v$Io4301R20M I$-E}@,pS^ޟR[/s¹'0H$IKyfŸfVOπFT*a$I>He~VY/3R/)>d$I>28`Cjw,n@FU*9ttf$I~<;=/4RD~@ X-ѕzἱI$: ԍR a@b X{+Qxuq$IЛzo /~3\8ڒ4BN7$IҀj V]n18H$IYFBj3̵̚ja pp $Is/3R Ӻ-Yj+L;.0ŔI$Av? #!5"aʄj}UKmɽH$IjCYs?h$IDl843.v}m7UiI=&=0Lg0$I4: embe` eQbm0u? $IT!Sƍ'-sv)s#C0:XB2a w I$zbww{."pPzO =Ɔ\[ o($Iaw]`E).Kvi:L*#gР7[$IyGPI=@R 4yR~̮´cg I$I/<tPͽ hDgo 94Z^k盇΄8I56^W$I^0̜N?4*H`237}g+hxoq)SJ@p|` $I%>-hO0eO>\ԣNߌZD6R=K ~n($I$y3D>o4b#px2$yڪtzW~a $I~?x'BwwpH$IZݑnC㧄Pc_9sO gwJ=l1:mKB>Ab<4Lp$Ib o1ZQ@85b̍ S'F,Fe,^I$IjEdù{l4 8Ys_s Z8.x m"+{~?q,Z D!I$ϻ'|XhB)=…']M>5 rgotԎ 獽PH$IjIPhh)n#cÔqA'ug5qwU&rF|1E%I$%]!'3AFD/;Ck_`9 v!ٴtPV;x`'*bQa w I$Ix5 FC3D_~A_#O݆DvV?<qw+I$I{=Z8".#RIYyjǪ=fDl9%M,a8$I$Ywi[7ݍFe$s1ՋBVA?`]#!oz4zjLJo8$I$%@3jAa4(o ;p,,dya=F9ً[LSPH$IJYЉ+3> 5"39aZ<ñh!{TpBGkj}Sp $IlvF.F$I z< '\K*qq.f<2Y!S"-\I$IYwčjF$ w9 \ߪB.1v!Ʊ?+r:^!I$BϹB H"B;L'G[ 4U#5>੐)|#o0aڱ$I>}k&1`U#V?YsV x>{t1[I~D&(I$I/{H0fw"q"y%4 IXyE~M3 8XψL}qE$I[> nD?~sf ]o΁ cT6"?'_Ἣ $I>~.f|'!N?⟩0G KkXZE]ޡ;/&?k OۘH$IRۀwXӨ<7@PnS04aӶp.:@\IWQJ6sS%I$e5ڑv`3:x';wq_vpgHyXZ 3gЂ7{{EuԹn±}$I$8t;b|591nءQ"P6O5i }iR̈́%Q̄p!I䮢]O{H$IRϻ9s֧ a=`- aB\X0"+5"C1Hb?߮3x3&gşggl_hZ^,`5?ߎvĸ%̀M!OZC2#0x LJ0 Gw$I$I}<{Eb+y;iI,`ܚF:5ܛA8-O-|8K7s|#Z8a&><a&/VtbtLʌI$I$I$I$I$I$IRjDD%tEXtdate:create2022-05-31T04:40:26+00:00!Î%tEXtdate:modify2022-05-31T04:40:26+00:00|{2IENDB`Mini Shell

HOME


Mini Shell 1.0
DIR:/usr/share/zsh/5.5.1/functions/
Upload File :
Current File : //usr/share/zsh/5.5.1/functions/calendar_scandate
# Scan a line for various common date and time formats.
# Set REPLY to the number of seconds since the epoch at which that
# time occurs.  The time does not need to be matched; this will
# produce midnight at the start of the date.
#
# Absolute times
#
# The rules below are fairly complicated, to allow any natural (and
# some highly unnatural but nonetheless common) combination of
# time and date used by English speakers.  It is recommended that,
# rather than exploring the intricacies of the system, users find
# a date format that is natural to them and stick to it.  This
# will avoid unexpected effects.  Various key facts should be noted,
# explained in more detail below:
#
# - In particular, note the confusion between month/day/year and
#   day/month/year when the month is numeric; this format should be
#   avoided if at all possible.  Many alternatives are available.
# - However, there is currently no localization support, so month
#   names must be English (though only the first three letters are required).
#   The same applies to days of the week if they occur (they are not useful).
# - The year must be given in full to avoid confusion, and only years
#   from 1900 to 2099 inclusive are matched.
# - Although timezones are parsed (complicated formats may not be recognized),
#   they are then ignored; no time adjustment is made.
# - Embedding of times within dates (e.g. "Wed Jun 16 09:30:00 BST 2010")
#   causes horrific problems because of the combination of the many
#   possible date and time formats to match.  The approach taken
#   here is to match the time, remove it, and see if the nearby text
#   looks like a date.  The problem is that the time matched may not
#   be that associated with the date, in which case the time will be
#   ignored.  To minimise this, when the argument "-a" is given to
#   anchor the date/time to the start of the line, we never look
#   beyond a newline.  So if any date/time strings in the text
#   are on separate lines the problem is avoided.
# - If you feel sophisticated enough and wish to avoid any ambiguity,
#   you can use RFC 2445 date/time strings, for example 20100601T170000.
#   These are parsed in one go.
#
# The following give some obvious examples; users finding here
# a format they like and not subject to vagaries of style may skip
# the full description.  As dates and times are matched separately
# (even though the time may be embedded in the date), any date format
# may be mixed with any format for the time of day provide the
# separators are clear (whitespace, colons, commas).
#   2007/04/03 13:13
#   2007/04/03:13:13
#   2007/04/03 1:13 pm
#   3rd April 2007, 13:13
#   April 3rd 2007 1:13 p.m.
#   Apr 3, 2007 13:13
#   Tue Apr 03 13:13:00 2007
#   13:13 2007/apr/3
#
# Times are parsed and extracted before dates.  They must use colons
# to separate hours and minutes, though a dot is allowed before seconds
# if they are present.  This limits time formats to
#   HH:MM[:SS[.FFFFF]] [am|pm|a.m.|p.m.]
#   HH:MM.SS[.FFFFF] [am|pm|a.m.|p.m.]
# in which square brackets indicate optional elements, possibly with
# alternatives.  Fractions of a second are recognised but ignored.
# Unless -r or -R are given (see below), a date is mandatory but a time of day is
# not; the time returned is at the start of the date.
#
# Time zones are not handled, though if one is matched following a time
# specification it will be removed to allow a surrounding date to be
# parsed.  This only happens if the format of the timezone is not too
# wacky:
#   +0100
#   GMT
#   GMT-7
#   CET+1CDT
# etc. are all understood, but any part of the timezone that is not numeric
# must have exactly three capital letters in the name.
#
# Dates suffer from the ambiguity between DD/MM/YYYY and MM/DD/YYYY.  It is
# recommended this form is avoided with purely numeric dates, but use of
# ordinals, eg. 3rd/04/2007, will resolve the ambiguity as the ordinal is
# always parsed as the day of the month.  Years must be four digits (and
# the first two must be 19 or 20); 03/04/08 is not recognised.  Other
# numbers may have leading zeroes, but they are not required.  The
# following are handled:
#   YYYY/MM/DD
#   YYYY-MM-DD
#   YYYY/MNM/DD
#   YYYY-MNM-DD
#   DD[th|st|rd] MNM[,] YYYY
#   DD[th|st|rd] MNM[,]            current year assumed
#   MNM DD[th|st|rd][,] YYYY
#   MNM DD[th|st|rd][,]            current year assumed
#   DD[th|st|rd]/MM[,] YYYY
#   DD[th|st|rd]/MM/YYYY
#   MM/DD[th|st|rd][,] YYYY
#   MM/DD[th|st|rd]/YYYY
# Here, MNM is at least the first three letters of a month name,
# matched case-insensitively.  The remainder of the month name may appear but
# its contents are irrelevant, so janissary, febrile, martial, apricot,
# etc. are happily handled.
#
# Note there are only two cases that assume the current year, the
# form "Jun 20" or "14 September" (the only two commonly occurring
# forms, apart from a "the" in some forms of English, which isn't
# currently supported).  Such dates will of course become ambiguous
# in the future, so should ideally be avoided.
#
# Times may follow dates with a colon, e.g. 1965/07/12:09:45; this
# is in order to provide a format with no whitespace.  A comma
# and whitespace are allowed, e.g. "1965/07/12, 09:45".
# Currently the order of these separators is not checked, so
# illogical formats such as "1965/07/12, : ,09:45" will also
# be matched.  Otherwise, a time is only recognised as being associated
# with a date if there is only whitespace in between, or if the time
# was embedded in the date.
#
# Days of the week are not scanned, but will be ignored if they occur
# at the start of the date pattern only.
#
# For example, the standard date format:
#   Fri Aug 18 17:00:48 BST 2006
# is handled by matching HH:MM:SS and removing it together with the
# matched (but unused) time zone.  This leaves the following:
#   Fri Aug 18 2006
# "Fri" is ignored and the rest is matched according to the sixth of
# the standard rules.
#
# Relative times
# ==============
#
# The option -r allows a relative time.  Years (or ys, yrs, or without s),
# months (or mths, mons, mnths, months, or without s --- "m", "ms" and
# "mns" are ambiguous and are not handled), weeks (or ws, wks, or without
# s) and days (or ds, dys, days, or without s), hours (or hs, hrs, with or
# without s), minutes (or mins, with or without s) and seconds (or ss,
# secs, with or without s) are understood.  Spaces between the numbers
# are optional, but are required between items, although a comma
# may be used (with or without spaces).
#
# Note that a year here is 365.25 days and a month is 30 days.
#
# With -R start_time, a relative time is parsed and start_time is treated
# as the start of the period.  This allows months and years to be calculated
# accurately.  If the option -m (minus) is also given the relative time is
# taken backwards from the start time.
#
# This allows forms like:
#   30 years 3 months 4 days 3:42:41
#   14 days 5 hours
#   4d,10hr
# In this case absolute dates are ignored.

emulate -L zsh
setopt extendedglob # xtrace

zmodload -i zsh/datetime || return 1

# separator characters before time or between time and date
# allow , - or : before the time: this allows spaceless but still
# relatively logical dates like 2006/09/19:14:27
# don't allow / before time !  the above
# is not 19 hours 14 mins and 27 seconds after anything.
local tschars="[-,:[:blank:]]"
# start pattern for time when anchored
local tspat_anchor="(${tschars}#)"
# ... when not anchored
local tspat_noanchor="(|*${tschars})"
# separator characters between elements.  comma is fairly
# natural punctuation; otherwise only allow whitespace.
local schars="[.,[:space:]]"
local -a dayarr
dayarr=(sun mon tue wed thu fri sat)
local daypat="${schars}#((#B)(${(j.|.)dayarr})[a-z]#~month*)"
# Start pattern for date: treat , as space for simplicity.  This
# is illogical at the start but saves lots of minor fiddling later.
# Date start pattern when anchored at the start.
# We need to be able to ignore the day here, although (for consistency
# with the unanchored case) we don't remove it until later.
# (The problem in the other case is that matching anything before
# the day of the week is greedy, so the day of the week gets ignored
# if it's optional.)
local dspat_anchor="(|(#B)(${daypat}|)(#b)${schars}#)"
local dspat_anchor_noday="(|${schars}#)"
# Date start pattern when not anchored at the start.
local dspat_noanchor="(|*${schars})"
# end pattern for relative times: similar remark about use of $schars.
local repat="(|s)(|${schars}*)"
# not locale-dependent!  I don't know how to get the months out
# of the system for the purpose of finding out where they occur.
# We may need some completely different heuristic.
local monthpat="(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]#"
integer daysecs=$(( 24 * 60 * 60 ))
local d="[[:digit:]]"

integer year year2 month month2 day day2 hour minute second then nth wday wday2
local opt line orig_line mname MATCH MBEGIN MEND tz test rest_line
local -a match mbegin mend
# Flags that we found a date or a time (maybe a relative time)
integer date_found time_found
# Flag that it's OK to have a time only
integer time_ok
# Indices of positions of start and end of time and dates found.
# These are actual character indices as zsh would normally use, i.e.
# line[time_start,time_end] is the string for the time.
integer time_start time_end date_start date_end
integer anchor anchor_end debug setvar
integer relative relative_start reladd reldate relsign=1 newadd h1 h2 hd

while getopts "aAdmrR:st" opt; do
  case $opt in
    (a)
    # anchor
    (( anchor = 1 ))
    ;;

    (A)
    # anchor at end, too
    (( anchor = 1, anchor_end = 1 ))
    ;;

    (d)
    # enable debug output
    (( debug = 1 ))
    ;;

    (m)
    # relative with negative offsets
    (( relsign = -1 ))
    ;;

    (r)
    # relative with no fixed start
    (( relative = 1 ))
    ;;

    (R)
    # relative with fixed start supplied
    (( relative_start = OPTARG, relative = 2 ))
    ;;

    (s)
    (( setvar = 1 ))
    ;;

    (t)
    (( time_ok = 1 ))
    ;;

    (*)
    return 1
    ;;
  esac
done
shift $(( OPTIND - 1 ))

line=$1

local dspat dspat_noday tspat
if (( anchor )); then
  # Anchored at the start.
  dspat=$dspat_anchor
  dspat_noday=$dspat_anchor_noday
  if (( relative )); then
    tspat=$tspat_anchor
  else
    # We'll test later if the time is associated with the date.
    tspat=$tspat_noanchor
  fi
  # We can save a huge amount of grief (I've discovered) if when
  # we're anchored to the start we ignore anything after a newline.
  # However, don't do this if we're anchored to the end.  The
  # match should fail if there are extra lines in that case.
  if [[ anchor_end -eq 0 && $line = (#b)([^$'\n']##)($'\n'*) ]]; then
    line=$match[1]
    rest_line=$match[2]
  fi
else
  dspat=$dspat_noanchor
  dspat_noday=$dspat_noanchor
  tspat=$tspat_noanchor
fi
orig_line=$line

# Look for a time separately; we need colons for this.
# We want to look for the first time to ensure it's associated
# with a date at the start of the line.  Of course there may be
# a time followed by some other text followed by a date, but
# in that case the whole thing is too ambiguous to worry about
# (and we don't need to worry about this for a calendar entry where
# the date must be at the start).
#
# We do this by minimal matching at the head, i.e. ${...#...}.
# To use a case statement we'd need to be able to request non-greedy
# matching for a pattern.
local rest
# HH:MM:SECONDS am/pm with optional decimal seconds
rest=${line#(#ibm)${~tspat}(<0-12>):(<0-59>)[.:]((<0-59>)(.<->|))[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))}
if [[ $rest != $line ]]; then
  hour=$match[2]
  minute=$match[3]
  second=$match[5]
  [[ $match[7] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
  time_found=1
fi
if (( time_found == 0 )); then
  # no seconds, am/pm
  rest=${line#(#ibm)${~tspat}(<0-12>):(<0-59>)[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))}
  if [[ $rest != $line ]]; then
    hour=$match[2]
    minute=$match[3]
    [[ $match[4] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
    time_found=1
  fi
fi
if (( time_found == 0 )); then
  # no colon, even, but a.m./p.m. indicator
  rest=${line#(#ibm)${~tspat}(<0-12>)[[:space:]]#([ap])(|.)[[:space:]]#m(.|[[:space:]]|(#e))}
  if [[ $rest != $line ]]; then
    hour=$match[2]
    minute=0
    [[ $match[3] = (#i)p ]] && (( hour <= 12 )) && (( hour += 12 ))
    time_found=1
  fi
fi
if (( time_found == 0 )); then
  # 24 hour clock, with seconds
  rest=${line#(#ibm)${~tspat}(<0-24>):(<0-59>)[.:]((<0-59>)(.<->|))(.|[[:space:]]|(#e))}
  if [[ $rest != $line ]]; then
    hour=$match[2]
    minute=$match[3]
    second=$match[5]
    time_found=1
  fi
fi
if (( time_found == 0 )); then
  rest=${line#(#ibm)${~tspat}(<0-24>):(<0-59>)(.|[[:space:]]|(#e))}
  if [[ $rest != $line ]]; then
    hour=$match[2]
    minute=$match[3]
    time_found=1
  fi
fi
if (( time_found == 0 )); then
  # Combined date and time formats:  here we can use an anchor because
  # we know the complete format.
  (( anchor )) && tspat=$tspat_anchor
  # RFC 2445
  rest=${line#(#ibm)${~tspat}(|\"[^\"]##\":)($~d$~d$~d$~d)($~d$~d)($~d$~d)T($~d$~d)($~d$~d)($~d$~d)([[:space:]]#|(#e))}
  if [[ $rest != $line ]]; then
    year=$match[3]
    month=$match[4]
    day=$match[5]
    hour=$match[6]
    minute=$match[7]
    second=$match[8]
    # signal don't need to take account of time in date...
    time_found=2
    date_found=1
    date_start=$mbegin[3]
    date_end=$mend[-1]
  fi
fi
(( hour == 24 )) && hour=0

if (( time_found && ! date_found )); then
  # time was found; if data also found already, process below.
  time_start=$mbegin[2]
  time_end=$mend[-1]
  # Remove the timespec because it may be in the middle of
  # the date (as in the output of "date".
  # There may be a time zone, too, which we don't yet handle.
  # (It's not in POSIX strptime() and libraries don't support it well.)
  # This attempts to remove some of the weirder forms.
  if [[ $line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z]|[-+][0-9][0-9][0-9][0-9])([[:space:]]|(#e))* || \
        $line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z](|[-+])<0-12>)([[:space:]]|(#e))*  || \
        $line[$time_end+1,-1] = (#b)[[:space:]]#([A-Z][A-Z][A-Z](|[-+])<0-12>[A-Z][A-Z][A-Z])([[:space:]]|(#e))* ]]; then
     (( time_end += ${mend[-1]} ))
     tz=$match[1]
  fi
  line=$line[1,time_start-1]$line[time_end+1,-1]
  (( debug )) && print "line after time: $line"
fi

if (( relative == 0 && date_found == 0 )); then
  # Date.
  case $line in
  # Look for YEAR[-/.]MONTH[-/.]DAY
  ((#bi)${~dspat}((19|20)[0-9][0-9])[-/](<1-12>)[-/](<1-31>)*)
  year=$match[2]
  month=$match[4]
  day=$match[5]
  date_start=$mbegin[2] date_end=$mend[5]
  date_found=1
  ;;

  # Same with month name
  ((#bi)${~dspat}((19|20)[0-9][0-9])[-/]${~monthpat}[-/](<1-31>)*)
  year=$match[2]
  mname=$match[4]
  day=$match[5]
  date_start=$mbegin[2] date_end=$mend[5]
  date_found=1
  ;;

  # Look for DAY[th/st/nd/rd] MNAME[,] YEAR
  ((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)[[:space:]]##${~monthpat}(|,)[[:space:]]##((19|20)[0-9][0-9])*)
  day=$match[2]
  mname=$match[4]
  year=$match[6]
  date_start=$mbegin[2] date_end=$mend[6]
  date_found=1
  ;;

  # Look for MNAME DAY[th/st/nd/rd][,] YEAR
  ((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|nd|rd)(|,)[[:space:]]##((19|20)[0-9][0-9])*)
  mname=$match[2]
  day=$match[3]
  year=$match[6]
  date_start=$mbegin[2] date_end=$mend[6]
  date_found=1
  ;;

  # Look for DAY[th/st/nd/rd] MNAME; assume current year
  ((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)[[:space:]]##${~monthpat}(|,)([[:space:]]##*|))
  day=$match[2]
  mname=$match[4]
  strftime -s year "%Y" $EPOCHSECONDS
  date_start=$mbegin[2] date_end=$mend[5]
  date_found=1
  ;;

  # Look for MNAME DAY[th/st/nd/rd]; assume current year
  ((#bi)${~dspat}${~monthpat}[[:space:]]##(<1-31>)(|th|st|nd|rd)(|,)([[:space:]]##*|))
  mname=$match[2]
  day=$match[3]
  strftime -s year "%Y" $EPOCHSECONDS
  date_start=$mbegin[2] date_end=$mend[5]
  date_found=1
  ;;

  # Now it gets a bit ambiguous.
  # Look for DAY[th/st/nd/rd][/]MONTH[/ ,]YEAR
  ((#bi)${~dspat}(<1-31>)(|th|st|nd|rd)/(<1-12>)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
  day=$match[2]
  month=$match[4]
  year=$match[7]
  date_start=$mbegin[2] date_end=$mend[7]
  date_found=1
  ;;

  # Look for MONTH[/]DAY[th/st/nd/rd][/ ,]YEAR
  ((#bi)${~dspat}(<1-12>)/(<1-31>)(|th|st|nd|rd)((|,)[[:space:]]##|/)((19|20)[0-9][0-9])*)
  month=$match[2]
  day=$match[3]
  year=$match[7]
  date_start=$mbegin[2] date_end=$mend[7]
  date_found=1
  ;;

  # Look for WEEKDAY
  ((#bi)${~dspat_noday}(${~daypat})(|${~schars})*)
  integer wday_now wday
  local wdaystr=${(L)match[3]}
  date_start=$mbegin[2] date_end=$mend[2]

  # Find the day number.
  local -a wdays
  # This is the ordering of %w in strtfime (zero-offset).
  wdays=(sun mon tue wed thu fri sat sun)
  (( wday = ${wdays[(i)$wdaystr]} - 1 ))

  # Find the date for that day.
  (( then = EPOCHSECONDS ))
  strftime -s wday_now "%w" $then
  # Day is either today or in the past.
  (( wday_now < wday )) && (( wday_now += 7 ))
  (( then -= (wday_now - wday) * 24 * 60 * 60 ))
  strftime -s year "%Y" $then
  strftime -s month "%m" $then
  strftime -s day "%d" $then
  date_found=1
  ;;

  # Look for "today", "yesterday", "tomorrow"
  ((#bi)${~dspat_noday}(yesterday|today|tomorrow|now)(|${~schars})*)
  (( then = EPOCHSECONDS ))
  case ${(L)match[2]} in
    (yesterday)
    (( then -= daysecs ))
    ;;

    (tomorrow)
    (( then += daysecs ))
    ;;

    (now)
    time_found=1 time_end=0 time_start=1
    strftime -s hour "%H" $then
    strftime -s minute "%M" $then
    strftime -s second "%S" $then
    ;;
  esac
  strftime -s year "%Y" $then
  strftime -s month "%m" $then
  strftime -s day "%d" $then
  date_start=$mbegin[2] date_end=$mend[2]
  date_found=1
  ;;
  esac
fi

if (( date_found || (time_ok && time_found) )); then
  # date found
  # see if there's a day at the start
  if (( date_found )); then
    if [[ ${line[1,$date_start-1]} = (#bi)${~daypat}${~schars}# ]]; then
	    date_start=$mbegin[1]
    fi
    line=${line[1,$date_start-1]}${line[$date_end+1,-1]}
  fi
  if (( time_found == 1 )); then
    if (( date_found )); then
      # If we found a time, it must be associated with the date,
      # or we can't use it.  Since we removed the time from the
      # string to find the date, however, it's complicated to
      # know where both were found.  Reconstruct the date indices of
      # the original string.
      if (( time_start <= date_start )); then
	# Time came before start of date; add length in.
	(( date_start += time_end - time_start + 1 ))
      fi
      if (( time_start <= date_end )); then
	(( date_end += time_end - time_start + 1 ))
      fi

      if (( time_end + 1 < date_start )); then
	# If time wholly before date, OK if only separator characters
	# in between.  (This allows some illogical stuff with commas
	# but that's probably not important.)
	if [[ ${orig_line[time_end+1,date_start-1]} != ${~schars}# ]]; then
	  # Clearly this can't work if anchor is set.  In principle,
	  # we could match the date and ignore the time if it wasn't.
	  # However, that seems dodgy.
	  return 1
	else
	  # Form massaged line by removing the entire date/time chunk.
	  line="${orig_line[1,time_start-1]}${orig_line[date_end+1,-1]}"
	fi
      elif (( date_end + 1 < time_start )); then
	# If date wholly before time, OK if only time separator characters
	# in between.  This allows 2006/10/12:13:43 etc.
	if [[ ${orig_line[date_end+1,time_start-1]} != ${~tschars}# ]]; then
	  # Here, we assume the time is associated with something later
	  # in the line.  This is pretty much inevitable for the sort
	  # of use we are expecting.  For example,
	  #   2006/10/24  Meeting from early, may go on till 12:00.
	  # or with some uses of the calendar system,
	  #   2006/10/24 MR 1 Another pointless meeting WARN 01:00
	  # The 01:00 says warn an hour before, not that the meeting starts
	  # at 1 am.  About the only safe way round would be to force
	  # a time to be present, but that's not how the traditional
	  # calendar programme works.
	  #
	  # Hence we need to reconstruct.
	  (( time_found = 0, hour = 0, minute = 0, second = 0 ))
	  line="${orig_line[1,date_start-1]}${orig_line[date_end+1,-1]}"
	else
	  # As above.
	  line="${orig_line[1,date_start-1]}${orig_line[time_end+1,-1]}"
	fi
      fi
    else
      # Time only.
      # We didn't test anchors for time originally, since it
      # might have been embedded in the date.  If there's no date,
      # we need to test specially.
      if (( anchor )) &&
	[[ ${orig_line[1,time_start-1]} != ${~tschars}# ]]; then
	# Anchor at start failed.
	return 1
      fi
      strftime -s year "%Y" $EPOCHSECONDS
      strftime -s month "%m" $EPOCHSECONDS
      strftime -s day "%d" $EPOCHSECONDS
      # Date now handled.
      (( date_found = 1 ))
    fi
    if (( debug )); then
      print "Time string: $time_start,$time_end:" \
	"'$orig_line[time_start,time_end]'"
      (( date_ok )) && print "Date string: $date_start,$date_end:" \
	"'$orig_line[date_start,date_end]'"
      print "Remaining line: '$line$rest_line'"
    fi
  fi
fi

if (( relative )); then
  if (( relative == 2 )); then
    # Relative years and months are variable, and we may need to
    # be careful about days.
    strftime -s year "%Y" $relative_start
    strftime -s month "%m" $relative_start
    strftime -s day "%d" $relative_start
    strftime -rs then "%Y:%m:%d" "${year}:${month}:${day}"
  fi
  if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(y|yr|year|yearly)${~repat} ]]; then
    [[ -z $match[2] ]] && match[2]=1
    if (( relative == 2 )); then
      # We need the difference between relative_start & the
      # time ${match[2]} years later.  This means keeping the month and
      # day the same and changing the year.
      (( year2 = year + relsign * ${match[2]} ))
      strftime -rs reldate "%Y:%m:%d" "${year2}:${month}:${day}"

      # If we've gone from a leap year to a non-leap year, go back a day.
      strftime -s month2 "%m" $reldate
      (( month2 != month )) && (( reldate -= daysecs ))

      # Keep this as a difference for now since we may need to add in other stuff.
      (( reladd += reldate - then ))
    else
      (( reladd += relsign * ((365*4+1) * daysecs * ${match[2]} + 1) / 4 ))
    fi
    line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
    time_found=1
  fi
  if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(mth|mon|mnth|month|monthly)${~repat} ]]; then
     [[ -z $match[2] ]] && match[2]=1
     if (( relative == 2 )); then
       # Need to add on ${match[2]} months as above.
       (( month2 = month + relsign * ${match[2]} ))
       if (( month2 <= 0 )); then
	 # going backwards beyond start of given year
	 (( year2 = year + month2 / 12 - 1, month2 = month2 + (year-year2)*12 ))
       else
	 (( year2 = year + (month2 - 1)/ 12, month2 = (month2 - 1) % 12 + 1 ))
       fi
       strftime -rs reldate "%Y:%m:%d" "${year2}:${month2}:${day}"

       # If we've gone past the end of the month because it was too short,
       # we have two options (i) get the damn calendar fixed (ii) wind
       # back to the end of the previous month.  (ii) is easier for now.
       if (( day > 28 )); then
	 while true; do
	   strftime -s day2 "%d" $reldate
	   # There are only up to 3 days in it, so just wind back one at a
           # time.  Saves counting.
	   (( day2 >= 28 )) && break
	   (( reldate -= daysecs ))
	 done
       fi

       (( reladd += reldate - then ))
     else
       (( reladd += relsign * 30 * daysecs * ${match[2]} ))
     fi
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
  # For the next three items we accumulate adjustments in "newadd".
  # See note below for why they are special.
  if [[ $relative = 2 && $line = (#bi)${~dspat_noday}(<->)(th|rd|nd|st)(${~daypat})(|${~schars}*) ]]; then
     nth=$match[2]
     test=${(L)${${match[4]##${~schars}#}%%${~schars}#}[1,3]}
     wday=${dayarr[(I)$test]}
     if (( wday )); then
       line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
       time_found=1
       # We want weekday 0 to 6
       (( wday-- ))
       (( reldate = relative_start + reladd ))
       strftime -s year2 "%Y" $reldate
       strftime -s month2 "%m" $reldate
       # Find day of week of the first of the month we've landed on.
       strftime -rs then "%Y:%m:%d" "${year2}:${month2}:1"
       strftime -s wday2 "%w" $then
       # Calculate day of month
       (( day = 1 + (wday - wday2) + (nth - 1) * 7 ))
       (( wday < wday2 )) && (( day += 7 ))
       # whereas the day of the month calculated so far is...
       strftime -s day2 "%d" $reldate
       # so we need to compensate by...
       (( newadd += (day - day2) * daysecs ))
     fi
  fi
  if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(w|wk|week|weekly)${~repat} ]]; then
     [[ -z $match[2] ]] && match[2]=1
     (( newadd += relsign * 7 * daysecs * ${match[2]} ))
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
  if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(d|dy|day|daily)${~repat} ]]; then
     [[ -z $match[2] ]] && match[2]=1
     (( newadd += relsign * daysecs * ${match[2]} ))
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
  if (( relative == 2 && newadd )); then
    # You thought a day was always the same time?  Ho, ho, ho.
    # If the clocks go forward or back, we can gain or lose
    # an hour.  Check this by seeing what the hour is before
    # and after adding the number of days.  If it changes,
    # remove the difference.
    #
    # We need this correction for days (including days of a given
    # month) and weeks.
    # We don't need it for years and months because we calculated
    # those by actually looking at the calendar for a given
    # time of day, so the adjustment came out in the wash.
    # We don't need it for hours or smaller periods because
    # presumably if a user asks for something in 3 hours time
    # they don't mean 4 hours if the clocks went back and
    # 2 hours if they went forward.  At least, I think so.
    # Consider:
    #   % calendar_showdate +2d,1hr
    #   Sun Mar 25 00:37:00 GMT 2007
    #   % calendar_showdate +2d,2hr
    #   Sun Mar 25 02:37:09 BST 2007
    # At first sight that looks wrong because the clock appears
    # to jump two hours.  (Yes, it took me all of 9 seconds to
    # edit the line.)  But actually it's only jumped the hour
    # you asked for, because one is in GMT and the other in BST.
    # In principle you could say the same thing about days:
    # Sun Mar 25 00:00:00 GMT 2007  and  Mon Mar 26 01:00:00 BST 2007
    # are a day apart.  But usually if you say "same time next Tuesday"
    # you mean "when the clock says the same time, even if someone
    # has nipped in and adjusted it in the mean time", although
    # for some reason you don't usually bother saying that.
    #
    # Hope that's clear.
    strftime -s h1 "%H" $(( relative_start + reladd ))
    strftime -s h2 "%H" $(( relative_start + reladd + newadd ))
    (( hd = h2 - h1 ))
    # and of course we might go past midnight...
    if (( hd > 12 )); then
      (( hd -= 24 ))
    elif (( hd < -12 )); then
      (( hd += 24 ))
    fi
    (( newadd -= hd * 3600 ))
  fi
  (( reladd += newadd ))
  if [[ $line = (#bi)${~dspat}(<->|)[[:space:]]#(h|hr|hour|hourly)${~repat} ]]; then
     [[ -z $match[2] ]] && match[2]=1
     (( reladd += relsign * 60 * 60 * ${match[2]} ))
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
  if [[ $line = (#bi)${~dspat}(<->)[[:space:]]#(min|minute)${~repat} ]]; then
     (( reladd += relsign * 60 * ${match[2]} ))
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
  if [[ $line = (#bi)${~dspat}(<->)[[:space:]]#(s|sec|second)${~repat} ]]; then
     (( reladd += relsign * ${match[2]} ))
     line=${line[1,$mbegin[2]-1]}${line[$mend[4]+1,-1]}
     time_found=1
  fi
fi

if (( relative )); then
  # If no date was found, we're in trouble unless we found a time.
  if (( time_found )); then
    if (( anchor_end )); then
      # must be left with only separator characters
      if [[ $line != ${~schars}# ]]; then
	return 1
      fi
    fi
    # relative_start is zero if we're not using it
    (( reladd += (hour * 60 + minute) * 60 + second ))
    typeset -g REPLY
    (( REPLY = relative_start + reladd  ))
    [[ -n $setvar ]] && typeset -g REPLY2="$line$rest_line"
    return 0
  fi
  return 1
elif (( date_found == 0 )); then
  return 1
fi

if (( anchor_end )); then
  # must be left with only separator characters
  if [[ $line != ${~schars}# ]]; then
    return 1
  fi
fi

local fmt nums
if [[ -n $mname ]]; then
  fmt="%Y %b %d %H %M %S"
  nums="$year $mname $day $hour $minute $second"
else
  fmt="%Y %m %d %H %M %S"
  nums="$year $month $day $hour $minute $second"
fi

strftime -s REPLY -r $fmt $nums

[[ -n $setvar ]] && typeset -g REPLY2="$line$rest_line"

return 0