local a=require'pl.class'local b,c=os.time,os.date;local d=require'pl.stringx'local e=require'pl.utils'local f,g=e.assert_arg,e.assert_string;e.raise_deprecation{source="Penlight "..e._VERSION,message="the 'Date' module is deprecated, see https://github.com/lunarmodules/Penlight/issues/285",version_removed="2.0.0",version_deprecated="1.9.2"}local h=a()h.Format=a()function h:_init(i,...)local j;local k=select('#',...)if k>2 then local l={...}local m=i;i={year=m,month=l[1],day=l[2],hour=l[3],min=l[4],sec=l[5]}end;if k==1 then self.utc=select(1,...)==true end;if i==nil or i=='utc'then j=b()self.utc=i=='utc'elseif type(i)=='number'then j=i;if self.utc==nil then self.utc=true end elseif type(i)=='table'then if getmetatable(i)==h then j=i.time;self.utc=i.utc else if not(i.year and i.month)then local n=c('*t')if not i.year and not i.month and not i.day then i.year=n.year;i.month=n.month;i.day=n.day else i.year=i.year or n.year;i.month=i.month or(i.day and n.month or 1)i.day=i.day or 1 end end;i.day=i.day or 1;j=b(i)end else error("bad type for Date constructor: "..type(i),2)end;self:set(j)end;function h:set(i)self.time=i;if self.utc then self.tab=c('!*t',i)else self.tab=c('*t',i)end end;function h.tzone(o)if o==nil then o=b()elseif type(o)=="table"then if getmetatable(o)==h then o=o.time else o=h(o).time end end;local p=c('!*t',o)local q=c('*t',o)q.isdst=false;return os.difftime(b(q),b(p))end;function h:toUTC()local r=h(self)if not self.utc then r.utc=true;r:set(r.time)end;return r end;function h:toLocal()local r=h(self)if self.utc then r.utc=false;r:set(r.time)end;return r end;for s,t in ipairs{'year','month','day','hour','min','sec','yday'}do h[t]=function(self,u)if u then f(1,u,"number")self.tab[t]=u;self:set(b(self.tab))return self else return self.tab[t]end end end;function h:weekday_name(v)return c(v and'%A'or'%a',self.time)end;function h:month_name(v)return c(v and'%B'or'%b',self.time)end;function h:is_weekend()return self.tab.wday==1 or self.tab.wday==7 end;function h:add(i)local w=self.tab.isdst;local x,u=next(i)self.tab[x]=self.tab[x]+u;self:set(b(self.tab))if w~=self.tab.isdst then self.tab.hour=self.tab.hour-(w and 1 or-1)self:set(b(self.tab))end;return self end;function h:last_day()local y=28;local z=self.tab.month;while self.tab.month==z do y=y+1;self:add{day=1}end;self:add{day=-1}return self end;function h:diff(A)local B=self.time-A.time;if B<0 then error("date difference is negative!",2)end;return h.Interval(B)end;function h:__tostring()local C='%Y-%m-%dT%H:%M:%S'if self.utc then C="!"..C end;local i=c(C,self.time)if self.utc then return i..'Z'else local D=self:tzone()if D==0 then return i..'Z'end;local E=D>0 and'+'or'-'local F=math.ceil(D/3600)local z=D%3600/60;if z==0 then return i..('%s%02d'):format(E,F)else return i..('%s%02d:%02d'):format(E,F,z)end end end;function h:__eq(A)return self.time==A.time end;function h:__lt(A)return self.time<A.time end;h.__sub=h.diff;function h:__add(A)local G=h(self)if h.Interval:class_of(A)then A={sec=A.time}end;G:add(A)return G end;h.Interval=a(h)function h.Interval:_init(i)self:set(i)end;function h.Interval:set(i)self.time=i;self.tab=c('!*t',self.time)end;local function H(I)if I>1 then return's 'else return' 'end end;function h.Interval:__tostring()local i,J=self.tab,''local K,z,y=i.year-1970,i.month-1,i.day-1;if K>0 then J=J..K..' year'..H(K)end;if z>0 then J=J..z..' month'..H(z)end;if y>0 then J=J..y..' day'..H(y)end;if K==0 and z==0 then local F=i.hour;if F>0 then J=J..F..' hour'..H(F)end;if i.min>0 then J=J..i.min..' min 'end;if i.sec>0 then J=J..i.sec..' sec 'end end;if J==''then J='zero'end;return J end;local L={d={'day',{true,true}},y={'year',{false,true,false,true}},m={'month',{true,true}},H={'hour',{true,true}},M={'min',{true,true}},S={'sec',{true,true}}}function h.Format:_init(C)if not C then self.fmt='%Y-%m-%d %H:%M:%S'self.outf=self.fmt;self.plain=true;return end;local M=table.insert;local N,O,P,Q='\001','\002','\003','\004'local R,S={},{}local T,U={},{}local V=1;while V<#C do local W=C:sub(V,V)local X=L[W]if X then if S[W]then error("field appeared twice: "..W,4)end;S[W]=true;local s,Y=C:find(W..'+',V+1)local Z=not s and 1 or Y-V+1;if not X[2][Z]then error("wrong number of fields: "..W,4)end;local _=Z==1 and N..O or N:rep(Z)M(T,P.._..Q)M(R,W)if W=='y'then M(U,Z==2 and'%y'or'%Y')else M(U,'%'..W)end;V=V+Z else M(T,W)M(U,W)V=V+1 end end;C=e.escape(table.concat(T))C=C:gsub(N,'%%d'):gsub(O,'+'):gsub(P,'('):gsub(Q,')')self.fmt=C;self.outf=table.concat(U)self.vars=R end;local a0;function h.Format:parse(a1)g(1,a1)if self.plain then return a0(a1,self.us)end;local J={a1:match(self.fmt)}if#J==0 then return nil,'cannot parse '..a1 end;local a2={}for V,a3 in ipairs(self.vars)do local a4=L[a3][1]a2[a4]=tonumber(J[V])end;if not(a2.year and a2.month and a2.day)then local a5=h()a2.year=a2.year or a5:year()a2.month=a2.month or a5:month()a2.day=a2.day or a5:day()end;local a6=a2.year;if a6<100 then a2.year=a6+(a6<35 and 2000 or 1999)elseif not a6 then a2.year=1970 end;return h(a2)end;function h.Format:tostring(y)local a7;local C=self.outf;if type(y)=='number'then a7=y else a7=y.time;if y.utc then C='!'..C end end;return c(C,a7)end;function h.Format:US_order(a8)self.us=a8 end;local a9;local aa;local function ab()local ac,ad=aa'2000-12-31',{day=1}a9={}for V=1,12 do ac=ac:last_day()ac:add(ad)local ae=ac:month_name():lower()a9[ae]=V end end;local function af(ag)return ag:match'^%a+,*$'~=nil end;local ah=d.isdigit;local function ai(aj,ak,al,am)am=am or''local I=tonumber(aj)if not I then error(("%snot a number: '%s'"):format(am,aj))end;if I<ak or I>al then error(("%s out of range: %s is not between %d and %d"):format(am,aj,ak,al))end;return I end;local function an(_,ao,ap)local s,aq,ar=_:find('^%.%d+',ao+1)if ar then ap=ap..ar;_=_:sub(aq+1)else _=_:sub(ao+1)end;if _:match'z$'then return ap,{h=0,m=0}end;_=_:gsub(':','')local s,s,E,D=_:find('^([%+%-])(%d+)')if not E then return ap,nil end;if#D==2 then D=D..'00'end;local as={h=tonumber(D:sub(1,2)),m=tonumber(D:sub(3,4))}if E=='-'then as.h=-as.h;as.m=-as.m end;return ap,as end;function aa(aj,at)aj=aj:gsub('T',' ')local au=d.split(aj:lower())local V,_=1,au[1]local function av()V=V+1;_=au[V]end;local m,aw,ax,ap,ay;local as;local s,az,aA,aB=_:find'^(%d+)/(%d+)'if aA then if at then aA,aB=aB,aA end;s,s,m=_:find('^/(%d+)',az+1)av()else m,aB,aA=_:match('^(%d+)%-(%d+)%-(%d+)')if m then av()end end;if _ and not m and ah(_)then if#_<4 then aA=_;av()else m=true end end;if _ and af(_)then _=_:sub(1,3)if not a9 then ab()end;local ae=a9[_]if ae then aB=ae else error("not a month: ".._)end;av()end;if _ and not m and ah(_)then m=_;av()end;if _ then s,az,ax,aw=_:find'^(%d+):(%d+)'local ao;if az then s,ao,ap=_:find('^:(%d+)',az+1)ap,as=an(_,ao or az,ap)else s,ao,ax,aw=_:find'^(%d+)%.(%d+)'if ao then ay=_:match'[ap]m$'else local aC;s,az,aC=_:find('^(%d+)')if az then ax=aC:sub(1,2)aw=aC:sub(3,4)ap=aC:sub(5,6)if#ap==0 then ap=nil end;ap,as=an(_,az,ap)end end end end;local a5;if m==true then m=nil end;if not(m and aB and aA)then a5=h()end;aA=aA and ai(aA,1,31,'day')or(aB and 1 or a5:day())aB=aB and ai(aB,1,12,'month')or a5:month()m=m and tonumber(m)or a5:year()if m<100 then m=m+(m<35 and 2000 or 1900)end;ax=ax and ai(ax,0,ay and 12 or 24,'hour')or 12;if ay=='pm'then ax=ax+12 end;aw=aw and ai(aw,0,59)or 0;ap=ap and ai(ap,0,60)or 0;local J=h{year=m,month=aB,day=aA,hour=ax,min=aw,sec=ap}if as then local aD=false;if as.h~=0 then J:add{hour=-as.h}aD=true end;if as.m~=0 then J:add{min=-as.m}aD=true end;J.utc=true;if aD then J=J:toLocal()end end;return J end;function a0(aj)local aE,y=pcall(aa,aj)if not aE then y=y:gsub('.-:%d+: ','')return nil,y else return y end end;return h