|
|
|
|
|
|
|
|
#pike __REAL_VERSION__ |
|
|
|
inherit .Time:Time; |
|
#include "constants.h" |
|
|
|
|
|
static array(int) year_from_julian_day(int jd); |
static int julian_day_from_year(int year); |
static int year_remaining_days(int y,int yday); |
|
static array(int) year_month_from_month(int y,int m); |
static array(int) month_from_yday(int y,int yday); |
|
static array(int) week_from_week(int y,int w); |
static array(int) week_from_julian_day(int jd); |
|
static string f_month_name_from_number; |
static string f_month_shortname_from_number; |
static string f_month_number_from_name; |
static string f_month_day_name_from_number; |
static string f_week_name_from_number; |
static string f_week_day_number_from_name; |
static string f_week_day_shortname_from_number; |
static string f_week_day_name_from_number; |
static string f_year_name_from_number; |
static string f_year_number_from_name; |
|
|
static int(0..1) year_leap_year(int y); |
|
static int compat_week_day(int n); |
|
|
|
|
|
|
|
class YMD |
{ |
inherit TimeRange; |
|
|
|
int y; |
int yjd; |
|
int n; |
|
int jd; |
int yd; |
int m; |
int md; |
int wy; |
int w; |
int wd; |
|
int mnd=CALUNKNOWN; |
int utco=CALUNKNOWN; |
string tzn=0; |
|
|
|
.Ruleset rules; |
constant is_ymd=1; |
|
|
|
|
|
void create_now() |
{ |
rules=default_rules; |
create_unixtime_default(time()); |
} |
|
void create_unixtime_default(int unixtime) |
{ |
|
create_julian_day( 2440588+unixtime/86400 ); |
|
[int mutco,string mtzn]=rules->timezone->tz_ux(unixtime); |
int uxo=unixtime%86400-mutco; |
if (uxo<0) |
create_julian_day( 2440588+unixtime/86400-1 ); |
else if (uxo>=86400) |
create_julian_day( 2440588+unixtime/86400+1 ); |
else if (uxo==0) |
utco=mutco,tzn=mtzn; |
} |
|
void make_month() |
{ |
int myd; |
[m,md,mnd,myd]=month_from_yday(y,yd); |
} |
|
void make_week() |
{ |
int wnd,wjd; |
[wy,w,wd,wnd,wjd]=week_from_julian_day(jd); |
} |
|
int __hash() { return jd; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int julian_day() |
{ |
return jd; |
} |
|
|
|
|
|
int unix_time() |
{ |
|
int ux=(jd-2440588)*86400; |
if (utco==CALUNKNOWN) |
[utco,tzn]=rules->timezone->tz_jd(jd); |
return ux+utco; |
} |
|
int utc_offset() |
{ |
if (utco==CALUNKNOWN) |
[utco,tzn]=rules->timezone->tz_jd(jd); |
return utco; |
} |
|
string tzname() |
{ |
if (!tzn) |
[utco,tzn]=rules->timezone->tz_jd(jd); |
return tzn; |
} |
|
string tzname_iso() |
{ |
int u=utc_offset(); |
if (!(u%3600)) |
return sprintf("UTC%+d",-u/3600); |
if (!(u%60)) |
return |
(u<0) |
?sprintf("UTC+%d:%02d",-u/3600,(-u/60)%60) |
:sprintf("UTC-%d:%02d",u/3600,(u/60)%60); |
return |
(u<0) |
?sprintf("UTC+%d:%02d:%02d",-u/3600,(-u/60)%60,(-u)%60) |
:sprintf("UTC-%d:%02d:%02d",u/3600,(u/60)%60,u%60); |
} |
|
int year_no() |
{ |
return y>0?y:-1+y; |
} |
|
int month_no() |
{ |
if (m==CALUNKNOWN) make_month(); |
return m; |
} |
|
int week_no() |
{ |
if (w==CALUNKNOWN) make_week(); |
return w; |
} |
|
int month_day() |
{ |
if (md==CALUNKNOWN) make_month(); |
return md; |
} |
|
int week_day() |
{ |
if (wd==CALUNKNOWN) make_week(); |
return wd; |
} |
|
int year_day() |
{ |
return yd; |
} |
|
string year_name() |
{ |
return rules->language[f_year_name_from_number](y); |
} |
|
string week_name() |
{ |
if (w==CALUNKNOWN) make_week(); |
return rules->language[f_week_name_from_number](w); |
} |
|
string month_name() |
{ |
if (m==CALUNKNOWN) make_month(); |
return rules->language[f_month_name_from_number](m); |
} |
|
string month_shortname() |
{ |
if (m==CALUNKNOWN) make_month(); |
return rules->language[f_month_shortname_from_number](m); |
} |
|
string month_day_name() |
{ |
if (mnd==CALUNKNOWN) make_month(); |
return rules->language[f_month_day_name_from_number](md,mnd); |
} |
|
string week_day_name() |
{ |
if (wd==CALUNKNOWN) make_week(); |
return rules->language[f_week_day_name_from_number](wd); |
} |
|
string week_day_shortname() |
{ |
if (wd==CALUNKNOWN) make_week(); |
return rules->language[f_week_day_shortname_from_number](wd); |
} |
|
int leap_year() { return year_leap_year(y); } |
|
int hour_no() { return 0; } |
int minute_no() { return 0; } |
int second_no() { return 0; } |
float fraction_no() { return 0.0; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping datetime(void|int skip_stuff) |
{ |
if (m==CALUNKNOWN) make_month(); |
if (w==CALUNKNOWN) make_week(); |
if (skip_stuff) |
return ([ "year": y, |
"month": m, |
"day": md, |
"yearday": yd-1, |
"week": w, |
"week_day": compat_week_day(wd) |
]); |
else |
{ |
return ([ "year": y, |
"month": m, |
"day": md, |
"yearday": yd-1, |
"week": w, |
"week_day": compat_week_day(wd), |
"timezone": utc_offset(), |
"julian": jd, |
"unix": unix_time(), |
|
"hour": 0, |
"minute": 0, |
"second": 0, |
"fraction": 0.0 |
]); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string format_iso_ymd() |
{ |
if (m==CALUNKNOWN) make_month(); |
if (w==CALUNKNOWN) make_week(); |
return sprintf("%04d-%02d-%02d (%s) -W%02d-%d (%s)", |
((yd < 1)?y-1:y),m,md, |
month_shortname(), |
w,wd, |
week_day_shortname()); |
} |
|
string format_ext_ymd() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%s, %s %s %s", |
week_day_name(), |
month_day_name(),month_name(),year_name()); |
} |
|
string format_ctime() |
{ |
return sprintf("%s %s %2d 00:00:00 %s\n", |
week_day_shortname(), |
month_shortname(), |
md, |
year_name()); |
} |
|
string format_http() |
{ |
if (wd==CALUNKNOWN) make_week(); |
if (md==CALUNKNOWN) make_month(); |
|
return |
sprintf("%s, %02d %s %04d 00:00:00 GMT", |
("SunMonTueWedThuFriSat"/3)[compat_week_day(wd)], |
md, |
("zzzJanFebMarAprMayJunJulAugSepOctNovDec"/3)[m], |
((yd < 1)?y-1:y)); |
} |
|
string format_ymd() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%04d-%02d-%02d",((yd < 1)?y-1:y),m,md); |
} |
|
string format_ymd_short() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%04d%02d%02d",((yd < 1)?y-1:y),m,md); |
} |
|
string format_ymd_xshort() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%02d%02d%02d",((yd < 1)?y-1:y)%100,m,md); |
} |
|
string format_iso_week() |
{ |
if (w==CALUNKNOWN) make_week(); |
return sprintf("%04d-W%02d",y,w); |
} |
|
string format_iso_week_short() |
{ |
if (w==CALUNKNOWN) make_week(); |
return sprintf("%04d%02d",y,w); |
} |
|
string format_week() |
{ |
return sprintf("%04d-%s",y,week_name()); |
} |
|
string format_week_short() |
{ |
return sprintf("%04d%s",y,week_name()); |
} |
|
string format_month() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%04d-%02d",y,m); |
} |
|
string format_month_short() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%04d%02d",y,m); |
} |
|
string format_iso_time() |
{ |
return format_iso_ymd()+" 00:00:00"; |
} |
|
string format_ext_time() |
{ |
return format_ext_ymd()+" 00:00:00"; |
} |
|
string format_time() |
{ |
return format_ymd()+" 00:00:00"; |
} |
|
string format_time_short() |
{ |
return format_ymd_short()+" 00:00:00"; |
} |
|
string format_iso_short() |
{ |
return format_ymd_short()+"T00:00:00"; |
} |
|
string format_time_xshort() |
{ |
return format_ymd_xshort()+" 00:00:00"; |
} |
|
string format_mtime() |
{ |
return format_ymd()+" 00:00"; |
} |
|
string format_xtime() |
{ |
return format_ymd()+" 00:00:00.000000"; |
} |
|
string format_tod() |
{ |
return "00:00:00"; |
} |
|
string format_tod_short() |
{ |
return "000000"; |
} |
|
string format_todz() |
{ |
return "00:00:00 "+tzname(); |
} |
|
string format_todz_iso() |
{ |
return "00:00:00 "+tzname_iso(); |
} |
|
string format_mod() |
{ |
return "00:00"; |
} |
|
string format_xtod() |
{ |
return "00:00:00.000000"; |
} |
|
string format_nice(); |
string format_nicez() |
{ |
return format_nice()+" "+tzname(); |
} |
|
string tzname_utc_offset() |
{ |
int u=utc_offset(); |
return sprintf("%+03d%02d", -u/3600, abs(u)/60%60); |
} |
|
string format_smtp() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%s, %s %s %s 00:00:00 %s", |
week_day_shortname(), |
month_day_name(),month_shortname(),year_name(), |
tzname_utc_offset()); |
} |
|
string format_commonlog() |
{ |
if (m==CALUNKNOWN) make_month(); |
return sprintf("%02d/%s/%d:%s %s", |
month_day(), month_shortname(), year_no(), format_tod(), |
tzname_utc_offset()); |
} |
|
string format_elapsed() |
{ |
return sprintf("%dd",number_of_days()); |
} |
|
|
|
static TimeRange _set_size(int n,TimeRange t) |
{ |
if (t->is_timeofday) |
return second()->set_size(n,t); |
|
if (yd==1 && t->is_year) |
return Year("ymd_y",rules,y,yjd,t->n*n) |
->autopromote(); |
|
|
if (t->is_year || t->is_month) |
{ |
if (md==CALUNKNOWN) make_month(); |
if (md==1) |
return Month("ymd_yjmw",rules,y,yjd,jd,m, |
t->number_of_months()*n,wd,w) |
->autopromote(); |
} |
|
|
if (t->is_week) |
{ |
if (wd==CALUNKNOWN) make_week(); |
if (wd==1) return Week("ymd_yjwm",rules,y,yjd,jd,w,t->n*n,md,m,mnd); |
} |
|
|
if (t->is_ymd) |
return Day("ymd_ydmw",rules,y,yjd,jd,yd, |
n*t->number_of_days(),m,md,w,wd,mnd); |
|
error("set_size: incompatible class %O\n", |
object_program(t)); |
} |
|
static TimeRange _add(int _n,TimeRange step) |
{ |
if (step->is_ymd) |
return _move(_n,step); |
if (step->is_timeofday) |
if (n) |
return second()->range(second(-1))->add(_n,step); |
else |
return second()->beginning()->add(_n,step); |
|
error("add: incompatible class %O\n", |
object_program(step)); |
} |
|
array(int(-1..1)) _compare(TimeRange with) |
{ |
if (objectp(with)) |
if (with->is_timeofday) |
{ |
|
array(int(-1..1)) cmp=with->_compare(this); |
|
return ({-cmp[0], |
-cmp[2], |
-cmp[1], |
-cmp[3]}); |
} |
else if (with->is_ymd || with->julian_day) |
{ |
#define CMP(A,B) ( ((A)<(B))?-1:((A)>(B))?1:0 ) |
|
int b1=julian_day(); |
int e1=b1+number_of_days(); |
|
int b2=with->julian_day(); |
int e2=b2+with->number_of_days(); |
|
return ({ CMP(b1,b2),CMP(b1,e2),CMP(e1,b2),CMP(e1,e2) }); |
} |
return ::_compare(with); |
} |
|
|
|
|
|
int number_of_years() |
{ |
int m=number_of_days(); |
if (m<=1 || m+yd-1<year()->number_of_days()) return 1; |
return 1+y-year_from_julian_day(jd+m-1)[0]; |
} |
|
array(cYear) years(int ...range) |
{ |
int from=1,n=number_of_years(),to=n; |
|
if (sizeof(range)) |
if (sizeof(range)<2) |
error("Illegal numbers of arguments to days()\n"); |
else |
{ |
[from,to]=range; |
if (from>=n) return ({}); else if (from<0) from=0; |
if (to>=n) to=n; else if (to<from) return ({}); |
} |
|
return map(enumerate(1+to-from,1,y+from-1), |
lambda(int x) |
{ return Year("ymd_yn",rules,x,1); }); |
} |
|
cYear year(void|int m) |
{ |
if (!m || (!n&&m==-1)) |
return Year("ymd_y",rules,y,yjd,1); |
|
if (m<0) m=number_of_years()+m; |
|
array(TimeRange) res=years(m,m); |
if (sizeof(res)==1) return res[0]; |
error("not in range (Year 0..%d exist)\n", |
number_of_years()-1); |
} |
|
|
|
|
int number_of_days(); |
|
array(cDay) days(int ...range) |
{ |
int from=1,n=number_of_days(),to=n; |
|
if (sizeof(range)) |
if (sizeof(range)<2) |
error("Illegal numbers of arguments to days()\n"); |
else |
{ |
[from,to]=range; |
if (from>n) return ({}); else if (from<1) from=1; |
if (to>n) to=n; else if (to<from) return ({}); |
} |
|
int zy=y; |
int zyd=yd+from-1; |
int zjd=jd+from-1; |
int zyjd=yjd; |
array(cDay) res=({}); |
|
to-=from-1; |
|
if (zyd<1) |
{ |
[zy,zyjd]=year_from_julian_day(zjd); |
zyd=zjd-zyjd+1; |
} |
|
for (;;) |
{ |
int rd=year_remaining_days(zy,zyd)+1; |
|
if (rd>0) |
{ |
if (rd>to) rd=to; |
res+=map(enumerate(rd,1,zyd), |
lambda(int x) |
{ return Day("ymd_yd",rules,zy,zyjd,zyjd+x-1,x,1); }); |
if (rd==to) break; |
zjd+=rd; |
to-=rd; |
} |
|
[zy,zyjd]=year_from_julian_day(zjd); |
zyd=zjd-zyjd+1; |
} |
return res; |
} |
|
cDay day(int ... mp) |
{ |
int m; |
if (sizeof(mp)) m=mp[0]; |
else m=1; |
|
if (!n) |
return Day("ymd_yd",rules,y,yjd,jd,yd,1); |
|
if (m<0) m+=1+number_of_days(); |
|
array(TimeRange) res=days(m,m); |
if (sizeof(res)==1) return res[0]; |
if(number_of_days()) |
error("Not in range (Day 1..%d exist).\n", |
number_of_days()); |
else |
error("No days in object.\n"); |
} |
|
|
|
int number_of_months(); |
|
array(cMonth) months(int ...range) |
{ |
int from=1,n=number_of_months(),to=n; |
|
if (sizeof(range)) |
if (sizeof(range)<2) |
error("Illegal numbers of arguments to months()\n"); |
else |
{ |
[from,to]=range; |
if (from>n) return ({}); else if (from<1) from=1; |
if (to>n) to=n; else if (to<from) return ({}); |
} |
|
if (md==CALUNKNOWN) make_month(); |
|
return map(enumerate(1+to-from,1,from+m-1), |
lambda(int x) |
{ return Month("ymd_ym",rules,y,x,1); }); |
} |
|
cMonth month(int ... mp) |
{ |
if (md==CALUNKNOWN) make_month(); |
|
if (!sizeof(mp)) |
return Month("ymd_ym",rules,y,m,1); |
|
int num=mp[0]; |
|
if (num==-1 && !n) |
return Month("ymd_ym",rules,y,m,1); |
|
if (num<0) num+=1+number_of_months(); |
|
array(TimeRange) res=months(num,num); |
if (sizeof(res)==1) return res[0]; |
error("not in range; Month 1..%d exist in %O\n", |
number_of_months(),this); |
} |
|
|
|
int number_of_weeks(); |
|
array(cWeek) weeks(int ...range) |
{ |
int from=1,n=number_of_weeks(),to=n; |
|
if (sizeof(range)) |
if (sizeof(range)<2) |
error("Illegal numbers of arguments to weeks()\n"); |
else |
{ |
[from,to]=range; |
if (from>n) return ({}); else if (from<1) from=1; |
if (to>n) to=n; else if (to<from) return ({}); |
} |
|
if (wd==CALUNKNOWN) make_week(); |
|
return map(enumerate(1+to-from,1,from+w-1), |
lambda(int x) |
{ return Week("ymd_yw",rules,wy,x,1); }); |
} |
|
cWeek week(int ... mp) |
{ |
if (wd==CALUNKNOWN) make_week(); |
|
if (!sizeof(mp)) |
return Week("ymd_yw",rules,wy,w,1); |
|
int num=mp[0]; |
|
if (num==-1 && !n) |
return Week("ymd_yw",rules,wy,w,1); |
|
if (num<0) num+=1+number_of_weeks(); |
|
array(TimeRange) res=weeks(num,num); |
if (sizeof(res)==1) return res[0]; |
error("not in range (Week 1..%d exist)\n", |
number_of_weeks()); |
} |
|
|
|
|
static TimeRange get_unit(string unit,int m) |
{ |
if (!n) return day()[unit](); |
if (m<0) m+=::`[]("number_of_"+unit+"s")(); |
array(TimeRange) res=::`[](unit+"s")(m,m); |
if (sizeof(res)==1) return res[0]; |
error("not in range ("+unit+" 0..%d exist)\n", |
::`[]("number_of_"+unit+"s")()-1); |
} |
|
static array(TimeRange) get_timeofday(string unit, |
int start,int step,program p, |
int ... range) |
{ |
int from=0,n=::`[]("number_of_"+unit)(),to=n-1; |
|
if (sizeof(range)) |
if (sizeof(range)<2) |
error("Illegal numbers of arguments to "+unit+"()\n"); |
else |
{ |
[from,to]=range; |
if (from>=n) return ({}); else if (from<0) from=0; |
if (to>=n) to=n-1; else if (to<from) return ({}); |
} |
|
from*=step; |
to*=step; |
|
to-=from-step; |
|
from+=unix_time(); |
|
array z= |
map(enumerate(to/step,step,from), |
lambda(int x) |
{ return p("timeofday",rules,x,step); }); |
|
|
|
if (sizeof(z)>1 && |
((p==cHour && z[0]->utc_offset()%3600 != z[-1]->utc_offset()%3600) || |
(p==cMinute && z[0]->utc_offset()%60 != z[-1]->utc_offset()%60))) |
{ |
|
cSecond sec=Second(); |
int i,uo=z[0]->utc_offset(); |
for (i=1; i<sizeof(z); i++) |
if (z[i]->utc_offset()!=uo) |
{ |
int uq=(z[i]->utc_offset()-uo); |
if (uq<0) |
{ |
if (uq<=-step) uq=-(-uq%step); |
z= z[..i-1]+ |
({z[i]->set_size(step+uq,sec)})+ |
map(z[i+1..],"add",uq,sec); |
} |
else |
{ |
if (uq>=step) uq%=step; |
z= z[..i-1]+ |
({z[i]->set_size(uq,sec)})+ |
map(z[i..sizeof(z)-2],"add",uq,sec); |
i++; |
} |
uo=z[i]->utc_offset(); |
} |
} |
return z; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int number_of_hours() { return (number_of_seconds()+3599)/3600; } |
cHour hour(void|int n) { return get_unit("hour",n); } |
array(cHour) hours(int ...range) |
{ return get_timeofday("hours",0,3600,Hour,@range); } |
|
int number_of_minutes() { return (number_of_seconds()+59)/60; } |
cMinute minute(void|int n,int ... time) |
{ |
if (sizeof(time)) |
return minute(n*60+time[0]); |
return get_unit("minute",n); |
} |
array(cMinute) minutes(int ...range) |
{ return get_timeofday("minutes",0,60,Minute,@range); } |
|
int number_of_seconds() { return end()->unix_time()-unix_time(); } |
cSecond second(void|int n,int ...time) |
{ |
if (sizeof(time)==2) |
{ |
return second(n*3600+time[0]*60+time[1]); |
|
} |
return get_unit("second",n); |
} |
array(cSecond) seconds(int ...range) |
{ return get_timeofday("seconds",0,1,Second,@range); } |
|
float number_of_fractions() { return (float)number_of_seconds(); } |
cSecond fraction(void|float|int n) |
{ |
return fractions()[0]; |
} |
array(cSecond) fractions(int|float ...range) |
{ |
float from,to,n=number_of_fractions(); |
if (sizeof(range)==2) |
from=(float)range[0],to=(float)range[1]; |
else if (sizeof(range)==0) |
from=0.0,to=n; |
else |
error("Illegal arguments\n"); |
if (from<0.0) from=0.0; |
if (to>n) to=n; |
return ({Fraction("timeofday_f",rules,unix_time(),0, |
(int)to,(int)(inano*(to-(int)to))) |
->autopromote()}); |
} |
|
TimeRange `*(int|float n) |
{ |
if(intp(n)) |
return set_size(n,this); |
else |
return second()*(int)(how_many(Second)*n); |
} |
|
array(TimeRange) split(int|float n, void|function|TimeRange with) |
{ |
if(!with) |
with=Second(); |
else if (functionp(with)) |
with=promote_program(with); |
|
int length=(int)(how_many(with)/n); |
|
TimeRange start=beginning(); |
TimeRange end=end(); |
array result=({}); |
while(start+with*length < end) |
{ |
result += ({ start->distance(start+with*length) }); |
start=start+with*length; |
} |
result += ({ start->distance(end) }); |
return result; |
} |
|
|
|
|
|
string nice_print(); |
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 't': |
return "Calendar."+calendar_name()+".YMD"; |
default: |
return ::_sprintf(t,m); |
} |
} |
|
void create_julian_day(int|float jd); |
static TimeRange _move(int n,YMD step); |
TimeRange place(TimeRange what,void|int force); |
|
|
|
YMD autopromote() { return this; } |
} |
|
|
|
|
|
|
|
|
function(mixed...:cYear) Year=cYear; |
class cYear |
{ |
inherit YMD; |
|
constant is_year=1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void create(mixed ...args) |
{ |
if (!sizeof(args)) |
{ |
create_now(); |
return; |
} |
else switch (args[0]) |
{ |
case "ymd_y": |
rules=args[1]; |
y=args[2]; |
jd=yjd=args[3]; |
n=args[4]; |
m=md=w=wd=CALUNKNOWN; |
yd=1; |
return; |
case "ymd_yn": |
rules=args[1]; |
y=args[2]; |
jd=yjd=julian_day_from_year(y); |
n=args[3]; |
m=md=w=wd=CALUNKNOWN; |
yd=1; |
return; |
default: |
if (intp(args[0]) && sizeof(args)==1) |
{ |
rules=default_rules; |
y=args[0]; |
jd=yjd=julian_day_from_year(y); |
n=1; |
m=md=w=wd=CALUNKNOWN; |
yd=1; |
return; |
} |
else if (stringp(args[0])) |
{ |
y=default_rules->language[f_year_number_from_name](args[0]); |
rules=default_rules; |
jd=yjd=julian_day_from_year(y); |
n=1; |
m=md=w=wd=CALUNKNOWN; |
yd=1; |
return; |
} |
break; |
|
} |
rules=default_rules; |
::create(@args); |
} |
|
void create_julian_day(int|float _jd) |
{ |
if (floatp(_jd)) |
create_unixtime_default((int)((jd-2440588)*86400)); |
else |
{ |
[y,yjd]=year_from_julian_day(_jd); |
jd=yjd; |
n=1; |
md=yd=m=1; |
wd=w=CALUNKNOWN; |
} |
} |
|
TimeRange beginning() |
{ |
return Year("ymd_y",rules,y,yjd,0); |
} |
|
TimeRange end() |
{ |
return Year("ymd_yn",rules,y+n,0); |
} |
|
|
|
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 'O': |
if (n!=1) |
return sprintf("Year(%s)",nice_print_period()); |
return sprintf("Year(%s)",nice_print()); |
case 't': |
return "Calendar."+calendar_name()+".Year"; |
default: |
return ::_sprintf(t,m); |
} |
} |
|
string nice_print_period() |
{ |
if (!n) return nice_print()+" sharp"; |
return sprintf("%s..%s",nice_print(),year(-1)->nice_print()); |
} |
|
string nice_print() |
{ |
return year_name(); |
} |
|
string format_nice() |
{ |
return year_name(); |
} |
|
|
|
TimeRange _move(int m,YMD step) |
{ |
if (!step->n || !m) |
return this; |
|
if (step->is_year) |
return Year("ymd_yn",rules,y+m*step->n,n) |
->autopromote(); |
|
if (step->is_month) |
return month()->add(m,step)->set_size(this); |
|
|
|
|
if (step->is_ymd) |
return Day("ymd_jd",rules, |
yjd+m*step->number_of_days(),number_of_days()) |
->autopromote(); |
|
error("_move: Incompatible type %O\n",step); |
} |
|
static void convert_from(TimeRange other) |
{ |
::convert_from(other); |
if (other->number_of_years) |
n=other->number_of_years(); |
else |
n=0; |
} |
|
TimeRange place(TimeRange what,void|int force) |
{ |
if (what->is_day) |
{ |
int yd=what->yd; |
return Day("ymd_yd",rules,y,yjd,yjd+yd-1,yd,what->n); |
} |
|
if (what->is_week) |
{ |
cWeek week=Week("ymd_yw",rules,y,what->w,what->n); |
if (!force && week->y!=y) return 0; |
return week; |
} |
|
if (what->is_year) |
return Year("ymd_yn",rules,y,what->number_of_years()); |
|
if (what->is_month) |
return month(what->month_name()); |
|
if (what->is_timeofday) |
return place(what->day(),force)->place(what,force); |
|
error("place: Incompatible type %O\n",what); |
} |
|
TimeRange distance(TimeRange to) |
{ |
if (to->is_timeofday) |
{ |
return hour()->distance(to); |
} |
if (to->is_ymd) |
{ |
if (to->is_year) |
{ |
int y1=y; |
int y2=to->y; |
if (y2<y1) |
error("distance: negative distance\n"); |
return Year("ymd_yn",rules,y,y2-y1) |
->autopromote(); |
} |
if (to->is_month) |
return month()->distance(to); |
return day()->distance(to); |
} |
|
error("distance: Incompatible type %O\n",to); |
} |
|
|
|
int number_of_years() |
{ |
return n; |
} |
|
int number_of_weeks(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
cMonth month(int|string ... mp) |
{ |
if (sizeof(mp) && |
stringp(mp[0])) |
{ |
int num=((int)mp[0]) || |
rules->language[f_month_number_from_name](mp[0]); |
if (!num) |
error("no such month %O in %O\n",mp[0],this); |
|
return ::month(num); |
} |
else |
return ::month(@mp); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cWeek week(int|string ... mp) |
{ |
if (sizeof(mp) && |
stringp(mp[0])) |
{ |
int num; |
sscanf(mp[0],"%d",num); |
sscanf(mp[0],"w%d",num); |
|
cWeek w=::week(num); |
if (w->week_no()==num) return w; |
return ::week(num-(w->week_no()-num)); |
} |
else |
return ::week(@mp); |
} |
|
cYear set_ruleset(.Ruleset r) |
{ |
return Year("ymd_y",r,y,yjd,n); |
} |
} |
|
|
|
|
|
|
function(mixed...:cMonth) Month=cMonth; |
class cMonth |
{ |
inherit YMD; |
|
constant is_month=1; |
|
int nd; |
int nw; |
|
void create(mixed ...args) |
{ |
if (!sizeof(args)) |
{ |
rules=default_rules; |
create_unixtime_default(time()); |
return; |
} |
else |
switch (args[0]) |
{ |
case "ymd_ym": |
rules=args[1]; |
y=args[2]; |
m=args[3]; |
n=args[4]; |
md=1; |
w=wd=CALUNKNOWN; |
[y,m,nd,yd]=year_month_from_month(y,m); |
yjd=julian_day_from_year(y); |
jd=yjd+yd-1; |
if (n!=1) nd=CALUNKNOWN; |
nw=CALUNKNOWN; |
return; |
case "ymd_yjmw": |
rules=args[1]; |
y=args[2]; |
yjd=args[3]; |
jd=args[4]; |
yd=1+jd-yjd; |
m=args[5]; |
n=args[6]; |
wd=args[7]; |
w=args[8]; |
md=1; |
nw=nd=CALUNKNOWN; |
return; |
case "ymd_jd": |
rules=args[1]; |
create_julian_day(args[2]); |
n=args[3]; |
return; |
default: |
if (intp(args[0]) && sizeof(args)==2) |
{ |
create("ymd_ym",default_rules,args[0],args[1],1); |
if (y!=args[0]) |
error("month %d doesn't exist in %d\n",args[1],args[0]); |
return; |
} |
break; |
} |
|
rules=default_rules; |
::create(@args); |
} |
|
void create_julian_day(int|float _jd) |
{ |
if (floatp(_jd)) |
create_unixtime_default((int)((jd-2440588)*86400)); |
else |
{ |
int zmd; |
[y,yjd]=year_from_julian_day(jd=_jd); |
[m,zmd,nd,yd]=month_from_yday(y,1+jd-yjd); |
jd=yd+yjd-1; |
|
n=1; |
md=1; |
nw=wd=w=CALUNKNOWN; |
} |
} |
|
string _sprintf(int t,mapping m) |
{ |
|
|
switch (t) |
{ |
case 'O': |
if (n!=1) |
return sprintf("Month(%s)",nice_print_period()); |
return sprintf("Month(%s)",nice_print()); |
case 't': |
return "Calendar."+calendar_name()+".Month"; |
default: |
return ::_sprintf(t,m); |
} |
} |
|
string nice_print() |
{ |
return sprintf("%s %s", month_name(), year_name()); |
} |
|
string format_nice() |
{ |
return sprintf("%s %s", month_name(), year_name()); |
} |
|
|
string nice_print_period() |
{ |
if (!n) return day()->nice_print()+" 0:00 sharp"; |
cMonth mo=month(-1); |
if (mo->y==y) |
return sprintf("%s..%s %s", |
month_shortname(), |
mo->month_shortname(), |
year_name()); |
return nice_print()+" .. "+month(-1)->nice_print(); |
} |
|
cDay beginning() |
{ |
return Month("ymd_yjmw",rules,y,yjd,jd,m,0,wd,w) |
->autopromote(); |
} |
|
cDay end() |
{ |
return Month("ymd_ym",rules,y,m+n,0) |
->autopromote(); |
} |
|
|
|
TimeRange distance(TimeRange to) |
{ |
if (to->is_timeofday) |
return hour()->distance(to); |
|
if (to->is_ymd) |
{ |
if (to->is_month || to->is_year) |
{ |
int n1=months_to_month(to->y,to->is_year?1:to->m); |
if (n1<0) |
error("distance: negative distance (%d months)\n",n1); |
return Month("ymd_yjmw",rules,y,yjd,jd,m,n1,wd,w) |
->autopromote(); |
} |
|
int d1=jd; |
int d2=to->jd; |
if (d2<d1) |
error("distance: negative distance (%d days)\n",d2-d1); |
return Day("ymd_ydmw",rules,y,yjd,jd,yd,d2-d1,m,1,w,wd,mnd) |
->autopromote(); |
} |
|
error("distance: Incompatible type %O\n",to); |
} |
|
static void convert_from(TimeRange other) |
{ |
::convert_from(other); |
if (other->number_of_months) |
n=other->number_of_months(); |
else |
n=0; |
} |
|
TimeRange _move(int x,YMD step) |
{ |
if (step->is_year) |
return Month("ymd_ym",rules,y+x*step->n,m,n) |
->autopromote(); |
if (step->is_month) |
return Month("ymd_ym",rules,y,m+x*step->n,n) |
->autopromote(); |
|
return Day("ymd_jd",rules,jd+x*step->number_of_days(),number_of_days()) |
->autopromote(); |
} |
|
TimeRange place_day(int day,int day_n,void|int force) |
{ |
if (day>number_of_days()) return 0; |
return Day("ymd_jd",rules,jd+day-1,day_n)->autopromote(); |
} |
|
TimeRange place(TimeRange what,void|int force) |
{ |
if (what->is_year) |
return year()->place(what,force); |
|
if (what->is_day) |
return place_day(what->month_day(),what->n,force); |
|
if (what->is_month) |
return Month("ymd_ym",rules,y,m,what->number_of_months()) |
->autopromote(); |
|
if (what->is_week) |
return place(what->day(),force)->week(); |
|
if (what->is_timeofday) |
return place(what->day(),force)->place(what,force); |
|
error("place: Incompatible type %O\n",what); |
} |
|
|
|
int number_of_years() |
{ |
if (n<=1) return 1; |
|
[int y2,int m2,int nd2,int yd2]=year_month_from_month(y,m+n); |
return 1+y2-y; |
} |
|
int number_of_days() |
{ |
if (nd!=CALUNKNOWN) return nd; |
|
[int y2,int m2,int nd2,int yd2]=year_month_from_month(y,m+n); |
return nd=julian_day_from_year(y2)+yd2-jd-1; |
} |
|
int number_of_weeks() |
{ |
if (nw!=CALUNKNOWN) return nw; |
|
[int y2,int m2,int nd2,int yd2]=year_month_from_month(y,m+n); |
|
return nw= |
Week("julian_r",jd,rules) |
->range(Week("julian_r",julian_day_from_year(y2)+yd2-2,rules)) |
->number_of_weeks(); |
} |
|
int number_of_months() |
{ |
return n; |
} |
|
cMonth set_ruleset(.Ruleset r) |
{ |
return Month("ymd_yjmw",r,y,yjd,jd,m,n,wd,w); |
} |
|
|
|
static int months_to_month(int y,int m); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function(mixed...:cWeek) Week=cWeek; |
class cWeek |
{ |
inherit YMD; |
|
constant is_week=1; |
|
|
|
|
|
|
|
|
|
|
|
|
void create(mixed ...args) |
{ |
if (!sizeof(args)) |
{ |
rules=default_rules; |
create_unixtime_default(time()); |
return; |
} |
else |
switch (args[0]) |
{ |
case "ymd_yw": |
rules=args[1]; |
y=args[2]; |
w=args[3]; |
n=args[4]; |
m=md=CALUNKNOWN; |
[y,w,wd,int nd,jd]=week_from_week(y,w); |
yjd=julian_day_from_year(y); |
yd=1+jd-yjd; |
wy=y; |
if (n!=1) nd=CALUNKNOWN; |
return; |
case "ymd_yjwm": |
rules=args[1]; |
y=args[2]; |
yjd=args[3]; |
jd=args[4]; |
yd=1+jd-yjd; |
w=args[5]; |
n=args[6]; |
md=args[7]; |
m=args[8]; |
mnd=args[9]; |
wd=1; |
wy=y; |
nd=CALUNKNOWN; |
return; |
case "ymd_jd": |
rules=args[1]; |
create_julian_day(args[2]); |
n=args[3]; |
return; |
default: |
if (intp(args[0]) && sizeof(args)==2) |
{ |
create("ymd_yw",default_rules,args[0],args[1],1); |
if (y!=args[0]) |
error("month %d doesn't exist in %d\n",args[1],args[0]); |
return; |
} |
break; |
} |
|
rules=default_rules; |
::create(@args); |
} |
|
void create_julian_day(int|float _jd) |
{ |
if (floatp(_jd)) |
create_unixtime_default((int)((jd-2440588)*86400)); |
else |
{ |
int zwd; |
[y,w,zwd,int nd,jd]=week_from_julian_day(_jd); |
yjd=julian_day_from_year(y); |
yd=1+jd-yjd; |
|
n=1; |
wd=1; |
wy=y; |
md=m=CALUNKNOWN; |
} |
} |
|
string _sprintf(int t,mapping m) |
{ |
|
|
switch (t) |
{ |
case 'O': |
if (n!=1) |
return sprintf("Week(%s)",nice_print_period()); |
return sprintf("Week(%s)",nice_print()); |
case 't': |
return "Calendar."+calendar_name()+".Week"; |
default: |
return ::_sprintf(t,m); |
} |
} |
|
string nice_print() |
{ |
return |
sprintf("%s %s", |
week_name(), |
year_name()); |
} |
|
string format_nice() |
{ |
return |
sprintf("%s %s", |
week_name(), |
year_name()); |
} |
|
|
string nice_print_period() |
{ |
if (!n) return day()->nice_print()+" 0:00 sharp"; |
cWeek wo=week(-1); |
if (wo->y==y) |
return sprintf("%s..%s %s", |
week_name(), |
wo->week_name(), |
year_name()); |
return nice_print()+" .. "+week(-1)->nice_print(); |
} |
|
cDay beginning() |
{ |
return Week("ymd_yjwm",rules,y,yjd,jd,w,0,md,m,mnd) |
->autopromote(); |
} |
|
cDay end() |
{ |
return Week("ymd_yw",rules,y,w+n,0) |
->autopromote(); |
} |
|
|
|
TimeRange distance(TimeRange to) |
{ |
if (to->is_timeofday) |
return hour()->distance(to); |
|
if (to->is_week) |
{ |
int n1=weeks_to_week(to->y,to->w); |
if (n1<0) |
error("distance: negative distance (%d weeks)\n",n1); |
return Week("ymd_yjwm",rules,y,yjd,jd,w,n1,md,m,mnd) |
->autopromote(); |
} |
|
if (to->julian_day) |
{ |
int d1=jd; |
int d2=to->julian_day(); |
if (d2<d1) |
error("distance: negative distance (%d days)\n",d2-d1); |
return Day("ymd_ydmw",rules,y,yjd,jd,yd,d2-d1,m,md,w,1,mnd) |
->autopromote(); |
} |
|
error("distance: Incompatible type %O\n",to); |
} |
|
static void convert_from(TimeRange other) |
{ |
::convert_from(other); |
if (other->number_of_weeks) |
n=other->number_of_weeks(); |
else |
n=0; |
} |
|
TimeRange _move(int x,YMD step) |
{ |
if (step->is_week) |
return Week("ymd_yw",rules,y,w+x*step->n,n) |
->autopromote(); |
|
if (step->is_year) |
return year()->add(x,step)->place(this,1); |
|
if (step->number_of_days) |
return Day("ymd_jd",rules, |
jd+x*step->number_of_days(),number_of_days()) |
->autopromote(); |
|
error("add: Incompatible type %O\n",step); |
} |
|
TimeRange place_day(int day,int day_n,int force) |
{ |
if (day>number_of_days()) |
if (!force) |
return 0; |
else |
return Day("ymd_jd",rules,jd+day-1,max(0,day_n-1))->autopromote(); |
return Day("ymd_jd",rules,jd+day-1,day_n)->autopromote(); |
} |
|
TimeRange place(TimeRange what,void|int force) |
{ |
if (what->is_supertimerange) |
return what->mend_overlap(map(what->parts,place,force)); |
|
|
if (what->is_year) |
return year()->place(what,force); |
if (what->is_month) |
return month()->place(what,force); |
|
if (what->is_week) |
return Week("ymd_yw",rules,y,w,what->number_of_weeks()); |
|
if (what->is_day) |
return place_day(what->week_day(),what->n,force); |
|
if (what->is_timeofday) |
return place(what->day(),force)->place(what,force); |
|
error("place: Incompatible type %O\n",what); |
} |
|
|
|
int number_of_years() |
{ |
if (n<=1) return 1; |
|
[int y2,int w2,int wd2,int nd2,int jd2]=week_from_week(y,w+n); |
return 1+y2-y; |
} |
|
int number_of_months() |
{ |
if (!n) return 1; |
|
|
return Day("ymd_jd",rules,jd,number_of_days()) |
->number_of_months(); |
} |
|
int number_of_weeks() |
{ |
return n; |
} |
|
int number_of_days(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cDay day(int|string ... mp) |
{ |
if (sizeof(mp) && |
stringp(mp[0])) |
{ |
int num=((int)mp[0]) || |
rules->language[f_week_day_number_from_name](mp[0]); |
if (!num) |
error("no such day %O in %O\n",mp[0],this); |
|
return ::day(num); |
} |
else |
return ::day(@mp); |
} |
|
cWeek set_ruleset(.Ruleset r) |
{ |
return Week("ymd_yjwm",r,y,yjd,jd,w,n,md,m,mnd); |
} |
|
|
|
static int weeks_to_week(int y,int m); |
} |
|
|
|
|
|
class cDay |
{ |
inherit YMD; |
|
constant is_day=1; |
int nw; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void create(mixed ...args) |
{ |
if (!sizeof(args)) |
{ |
rules=default_rules; |
create_unixtime_default(time()); |
return; |
} |
else |
switch (args[0]) |
{ |
case "ymd_ydmw": |
rules=args[1]; |
y=args[2]; |
yjd=args[3]; |
jd=args[4]; |
yd=args[5]; |
n=args[6]; |
m=args[7]; |
md=args[8]; |
w=args[9]; |
wd=args[10]; |
mnd=args[11]; |
nw=CALUNKNOWN; |
return; |
case "ymd_yd": |
rules=args[1]; |
y=args[2]; |
yjd=args[3]; |
jd=args[4]; |
yd=args[5]; |
n=args[6]; |
wd=nw=md=m=w=CALUNKNOWN; |
return; |
case "ymd_jd": |
rules=args[1]; |
create_julian_day(args[2]); |
n=args[3]; |
wd=nw=md=m=w=CALUNKNOWN; |
return; |
case "unix_r": |
case "julian_r": |
case "unix": |
case "julian": |
break; |
default: |
rules=default_rules; |
wd=nw=md=m=w=CALUNKNOWN; |
n=1; |
switch (sizeof(args)) |
{ |
case 1: |
if (intp(args[0])) |
{ |
create_julian_day(args[0]); |
return; |
} |
break; |
case 2: |
if (stringp(args[0])) |
y=default_rules->language[f_year_number_from_name] |
(args[0]); |
else if (intp(args[0])) |
y=args[0]; |
else |
break; |
if (!intp(args[1])) |
break; |
yd=args[1]; |
yjd=julian_day_from_year(y); |
jd=yjd+yd-1; |
return; |
case 3: |
if (stringp(args[0])) |
y=default_rules->language[f_year_number_from_name] |
(args[0]); |
else if (intp(args[0])) |
y=args[0]; |
else |
break; |
if (!intp(args[1]) || |
!intp(args[2])) break; |
md=args[2]; |
[y,m,int nmd,int myd]= |
year_month_from_month(y,args[1]); |
if (m!=args[1] || y!=args[0]) |
error("No such month (%d-%02d)\n",args[0],args[1]); |
yjd=julian_day_from_year(y); |
md=args[2]; |
jd=yjd+myd+md-2; |
yd=jd-yjd+1; |
if (md>nmd || md<1) |
error("No such day of month (%d-%02d-%02d)\n", |
@args); |
return; |
} |
} |
|
rules=default_rules; |
::create(@args); |
} |
|
void create_julian_day(int|float _jd) |
{ |
n=1; |
nw=md=m=wd=w=CALUNKNOWN; |
|
if (floatp(_jd)) |
{ |
create_unixtime_default((int)((jd-2440588)*86400)); |
} |
else |
{ |
[y,yjd]=year_from_julian_day(jd=_jd); |
yd=1+jd-yjd; |
} |
} |
|
string _sprintf(int t,mapping m) |
{ |
switch (t) |
{ |
case 'O': |
catch { |
if (n!=1) |
return sprintf("Day(%s)",nice_print_period()); |
return sprintf("Day(%s)",nice_print()); |
}; |
return sprintf("Day(%d)", unix_time()); |
case 't': |
return "Calendar."+calendar_name()+".Day"; |
default: |
return ::_sprintf(t,m); |
} |
} |
|
string nice_print() |
{ |
if (m==CALUNKNOWN) make_month(); |
if (wd==CALUNKNOWN) make_week(); |
return |
sprintf("%s %s %s %s", |
week_day_shortname(), |
month_day_name(),month_shortname(), |
year_name()); |
} |
|
string format_nice() |
{ |
if (m==CALUNKNOWN) make_month(); |
if (calendar()->Year()!=year()) |
return |
sprintf("%s %s %s", |
month_day_name(),month_shortname(), |
year_name()); |
else |
return |
sprintf("%s %s", |
month_day_name(),month_shortname()); |
} |
|
string nice_print_period() |
{ |
|
if (!n) return nice_print()+" 0:00 sharp"; |
return nice_print()+" .. "+day(-1)->nice_print(); |
} |
|
cDay beginning() |
{ |
return Day("ymd_ydmw",rules,y,yjd,jd,yd,0,m,md,w,wd,mnd); |
} |
|
cDay end() |
{ |
return Day("ymd_jd",rules,jd+n,0) |
->autopromote(); |
} |
|
static void convert_from(TimeRange other) |
{ |
::convert_from(other); |
if (other->number_of_days) |
n=other->number_of_days(); |
else |
n=0; |
} |
|
|
|
static TimeRange _move(int x,YMD step) |
{ |
if (step->is_year) |
return year()->add(x,step)->place(this,1); |
|
if (step->is_month) |
return month()->add(x,step)->place(this,1); |
|
if (step->is_week) |
return week()->add(x,step)->place(this,1); |
|
if (step->is_day) |
return Day("ymd_jd",rules,jd+x*step->n,n) |
->autopromote(); |
|
error("_move: Incompatible type %O\n",step); |
} |
|
TimeRange place(TimeRange what,int|void force) |
{ |
if (what->is_timeofday) |
{ |
int lux= |
what->ux- |
Day("unix_r",what->unix_time(),what->ruleset()) |
->unix_time(); |
TimeRange res; |
|
if (what->is_timeofday_f) |
res= |
Fraction("timeofday_f",rules, |
lux+unix_time(),what->ns,what->s_len,what->ns_len); |
else |
res=Second("timeofday",rules,unix_time()+lux,what->len); |
|
if (what->rules->timezone->is_dst_timezone || |
rules->timezone->is_dst_timezone) |
{ |
int u0=what->utc_offset()-what->day()->utc_offset(); |
int u1=res->utc_offset()-utc_offset(); |
|
if (u1-u0) |
res=res->add(u1-u0,Second); |
else |
res=res->autopromote(); |
|
if (!force) |
{ |
if (res->hour_no()!=what->hour_no()) |
error("place: no such time of " |
"day (DST shift)\n",what,this); |
} |
} |
else |
res=res->autopromote(); |
|
return res; |
} |
|
if (what->is_year) |
return year()->place(what,force); |
if (what->is_month) |
return month()->place(what,force); |
if (what->is_week) |
return week()->place(what,force); |
|
if (what->is_day) |
return Day("ymd_jd",rules,jd,what->number_of_days()) |
->autopromote(); |
|
error("place: Incompatible type %O\n",what); |
} |
|
TimeRange distance(TimeRange to) |
{ |
if (to->is_timeofday) |
return hour()->distance(to); |
if (to->is_ymd) |
{ |
int d1=jd; |
int d2=to->jd; |
if (d2<d1) |
error("distance: negative distance (%d days)\n",d2-d1); |
return Day("ymd_ydmw",rules,y,yjd,jd,yd,d2-d1,m,md,w,wd,mnd) |
->autopromote(); |
} |
|
error("distance: Incompatible type %O\n",to); |
} |
|
|
|
int number_of_days() |
{ |
return n; |
} |
|
int number_of_years() |
{ |
if (n<=1) return 1; |
return 1+year_from_julian_day(jd+n-1)[0]-y; |
} |
|
int number_of_weeks() |
{ |
if (nw!=CALUNKNOWN) return nw; |
|
if (n<=1) return nw=1; |
|
return nw= |
Week("julian_r",jd,rules) |
->range(Week("julian_r",jd+n-1,rules)) |
->number_of_weeks(); |
} |
|
cDay set_ruleset(.Ruleset r) |
{ |
return Day("ymd_ydmw",r,y,yjd,jd,yd,n,m,md,w,wd,mnd); |
} |
|
|
string iso_name() { return format_ymd(); } |
string iso_short_name() { return format_ymd_short(); } |
} |
|
function(mixed...:cDay) Day=cDay; |
|
|
|
|
|
class YMD_Time |
{ |
#define MKRBASE \ |
do \ |
{ \ |
int n; \ |
if (!rbase) \ |
rbase=Day("unix_r",this->ux,this->rules)->range(Day("unix_r",this->ux+this->len,this->rules)); \ |
} while (0) |
|
#define RBASE (this->base || this->make_base()) |
|
cDay day(int ...n) { return RBASE->day(@n); } |
cDay number_of_days() { return RBASE->number_of_days(); } |
array(cDay) days(int ...r) { return RBASE->days(@r); } |
|
cMonth month(int ...n) { return RBASE->month(@n); } |
cMonth number_of_months() { return RBASE->number_of_months(); } |
array(cMonth) months(int ...r) { return RBASE->months(@r); } |
|
cWeek week(int ...n) { return RBASE->week(@n); } |
cWeek number_of_weeks() { return RBASE->number_of_weeks(); } |
array(cWeek) weeks(int ...r) { return RBASE->weeks(@r); } |
|
cYear year(int ...n) { return RBASE->year(@n); } |
cYear number_of_years() { return RBASE->number_of_years(); } |
array(cYear) years(int ...r) { return RBASE->years(@r); } |
|
int year_no() { return RBASE->year_no(); } |
int month_no() { return RBASE->month_no(); } |
int week_no() { return RBASE->week_no(); } |
int month_name() { return RBASE->month_name(); } |
int month_shortname() { return RBASE->month_shortname(); } |
int month_day() { return RBASE->month_day(); } |
int month_day_name() { return RBASE->month_day_name(); } |
int week_day() { return RBASE->week_day(); } |
int year_day() { return RBASE->year_day(); } |
int year_name() { return RBASE->year_name(); } |
string week_name() { return RBASE->week_name(); } |
string week_day_name() { return RBASE->week_day_name(); } |
string week_day_shortname() { return RBASE->week_day_shortname(); } |
int leap_year() { return RBASE->leap_year(); } |
|
string format_iso_ymd() { return RBASE->format_iso_ymd(); } |
string format_ext_ymd() { return RBASE->format_ext_ymd(); } |
string format_ymd() { return RBASE->format_ymd(); } |
string format_ymd_short() { return RBASE->format_ymd_short(); } |
string format_ymd_xshort() { return RBASE->format_ymd_xshort(); } |
string format_iso_week() { return RBASE->format_iso_week(); } |
string format_iso_week_short() |
{ return RBASE->format_iso_week_short(); } |
string format_week() { return RBASE->format_week(); } |
string format_week_short() { return RBASE->format_week_short(); } |
string format_month() { return RBASE->format_month(); } |
string format_month_short() { return RBASE->format_month_short(); } |
|
#undef RBASE |
} |
|
#define OVERLOAD_TIMEOFDAY \ |
\ |
static int(0..1) create_backtry(mixed ... args) \ |
{ \ |
if (sizeof(args)>=5 && \ |
(intp(args[0])||stringp(args[0])) && \ |
intp(args[1]) && \ |
intp(args[2])) \ |
{ \ |
base=Day(@args[..2]); \ |
return ::create_backtry(@args[3..]); \ |
} \ |
return ::create_backtry(@args); \ |
} |
|
|
|
|
|
|
|
|
class cHour |
{ |
inherit Time::cHour; |
inherit YMD_Time; |
OVERLOAD_TIMEOFDAY; |
} |
|
class cMinute |
{ |
inherit Time::cMinute; |
inherit YMD_Time; |
OVERLOAD_TIMEOFDAY; |
} |
|
class cSecond |
{ |
inherit Time::cSecond; |
inherit YMD_Time; |
OVERLOAD_TIMEOFDAY; |
} |
|
class cFraction |
{ |
inherit Time::cFraction; |
inherit YMD_Time; |
OVERLOAD_TIMEOFDAY; |
} |
|
class cSuperTimeRange |
{ |
inherit Time::cSuperTimeRange; |
|
array(cYear) years(int ...range) { return get_units("years",@range); } |
cYear year(void|int n) { return get_unit("years",n); } |
int number_of_years() { return num_units("years"); } |
|
array(cMonth) months(int ...range) { return get_units("months",@range); } |
cMonth month(void|int n) { return get_unit("months",n); } |
int number_of_months() { return num_units("months"); } |
|
array(cWeek) weeks(int ...range) { return get_units("weeks",@range); } |
cWeek week(void|int n) { return get_unit("weeks",n); } |
int number_of_weeks() { return num_units("weeks"); } |
|
array(cDay) days(int ...range) { return get_units("days",@range); } |
cDay day(void|int n) { return get_unit("days",n); } |
int number_of_days() { return num_units("days"); } |
|
#define RBASE parts[0] |
|
int year_no() { return RBASE->year_no(); } |
int month_no() { return RBASE->month_no(); } |
int week_no() { return RBASE->week_no(); } |
int month_name() { return RBASE->month_name(); } |
int month_shortname() { return RBASE->month_shortname(); } |
int month_day() { return RBASE->month_day(); } |
int month_day_name() { return RBASE->month_day_name(); } |
int week_day() { return RBASE->week_day(); } |
int year_day() { return RBASE->year_day(); } |
string week_name() { return RBASE->week_name(); } |
string week_day_name() { return RBASE->week_day_name(); } |
string week_day_shortname() { return RBASE->week_day_shortname(); } |
int leap_year() { return RBASE->leap_year(); } |
|
string format_iso_ymd() { return RBASE->format_iso_ymd(); } |
string format_ext_ymd() { return RBASE->format_ext_ymd(); } |
string format_ymd() { return RBASE->format_ymd(); } |
string format_ymd_short() { return RBASE->format_ymd_short(); } |
string format_ymd_xshort() { return RBASE->format_ymd_xshort(); } |
string format_iso_week() { return RBASE->format_iso_week(); } |
string format_iso_week_short() { return RBASE->format_iso_week_short(); } |
string format_week() { return RBASE->format_week(); } |
string format_week_short() { return RBASE->format_week_short(); } |
string format_month() { return RBASE->format_month(); } |
string format_month_short() { return RBASE->format_month_short(); } |
|
#undef RBASE |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static TimeRange dwim_tod(TimeRange origin,string whut,int h,int m,int s) |
{ |
TimeRange tr; |
if (catch { |
tr=origin[whut](h,m,s); |
}) { |
if (h==24 && m==0 && s==0) |
return origin->end()->second(); |
else { |
object d=origin->day(); |
array(cHour) ha=origin->hours(); |
int n=search(ha->hour_no(),h); |
if (n!=-1) tr=ha[n]->minute(m)->second(s); |
else return 0; |
} |
} |
|
if (tr->hour_no()!=h || tr->minute_no()!=m) |
{ |
|
|
|
if (tr->hour_no()!=h) |
tr=tr->add(h-tr->hour_no(),Hour); |
if (tr->minute_no()!=m) |
tr=tr->add(m-tr->minute_no(),Minute); |
if (tr->second_no()!=s) |
tr=tr->add(s-tr->second_no(),Second); |
if (tr->hour_no()!=h || tr->minute_no()!=m || |
tr->second_no()!=s) return 0; |
} |
return tr; |
} |
|
static mapping abbr2zones; |
|
|
|
static TimeRange dwim_zone(TimeRange origin,string zonename, |
string whut,int ...args) |
{ |
if (zonename=="") return 0; |
|
if (zonename[0]=='"') sscanf(zonename,"\"%s\"",zonename); |
sscanf(zonename,"%*[ \t]%s",zonename); |
|
if(sizeof(zonename)==4 && zonename[2]=='S') |
zonename = zonename[0..1] + zonename[3..3]; |
else if(sizeof(zonename)>4 && has_suffix(zonename, "DST")) |
zonename = zonename[..sizeof(zonename)-1-3]; |
|
if (origin->rules->abbr2zone[zonename]) |
zonename=origin->rules->abbr2zone[zonename]; |
|
.Rule.Timezone zone=.Timezone[zonename]; |
if (!zone) |
{ |
if (sscanf(zonename,"%[^-+]%s",string a,string b)==2 && a!="" && b!="") |
{ |
TimeRange tr=dwim_zone(origin,a,whut,@args); |
if (!tr) return 0; |
|
return |
dwim_tod(origin->set_timezone( |
.Timezone.make_new_timezone( |
tr->timezone(), |
.Timezone.decode_timeskew(b))), |
whut,@args); |
} |
if(!abbr2zones) |
abbr2zones = master()->resolv("Calendar")["TZnames"]["abbr2zones"]; |
array pz=abbr2zones[zonename]; |
if (!pz) return 0; |
foreach (pz,string zn) |
{ |
TimeRange try=dwim_zone(origin,zn,whut,@args); |
if (try && try->tzname()==zonename) return try; |
} |
return 0; |
} |
else |
return dwim_tod(origin->set_timezone(zone),whut,@args); |
} |
|
static mapping(string:array) parse_format_cache=([]); |
|
static mapping dwim_year=([ "past_lower":70, "past_upper":100, |
"current_century":2000, "past_century":1900 ]); |
|
TimeRange parse(string fmt,string arg,void|TimeRange context) |
{ |
[string nfmt,array q]=(parse_format_cache[fmt]||({0,0})); |
|
if (!nfmt) |
{ |
|
#define ALNU "%[^- -,./:-?[-`{-¿]" |
#define AMPM "%[ampAMP.]" |
#define NUME "%[0-9]" |
#define ZONE "%[-+0-9A-Za-z/]" |
nfmt=replace(fmt, |
({"%Y","%y","%M","%W","%D","%a","%e","%h","%m","%s","%p", |
"%t","%f","%d","%z","%n","%S"}), |
({ALNU,ALNU,ALNU,"%d",NUME,"%d",ALNU,"%d","%d","%d",AMPM, |
NUME,NUME,NUME,ZONE,"%s","%d"})); |
|
#if 1 |
q=array_sscanf(fmt,"%{%*[^%]%%%1s%}")*({})*({})-({"*","%"}); |
#else |
|
array q=Array.map(replace(fmt,({"%*","%%"}),({"",""}))/"%", |
lambda(string s){ return s[..0];})-({""}); |
|
array q=({}); |
array pr=(array)fmt; |
int i=-1; |
while ((i=search(pr,'%',i+1))!=-1) q+=({sprintf("%c",pr[i+1])}); |
#endif |
if (sizeof(q)==0) error("format doesn't contain anything to parse\n"); |
if (q[-1]=="z") nfmt=replace(nfmt,ZONE,"%s"); |
parse_format_cache[fmt]=({nfmt,q}); |
} |
|
array res=array_sscanf(arg,nfmt); |
|
int i=search(res,""); |
if (i!=-1 && i<sizeof(res)-1) return 0; |
|
if (sizeof(res)<sizeof(q)) |
return 0; |
|
mapping m=mkmapping(q,res); |
if (i!=-1 && m->n!="") return 0; |
|
|
|
|
|
|
TimeRange low; |
|
.Calendar cal=this; |
|
|
|
#ifndef NOCATCH |
if (catch { |
#else |
werror("%O\n",m); |
#endif |
if (m->n && m->n!="") return 0; |
|
string x; |
if (m->Y) |
m->Y=default_rules->language[f_year_number_from_name](m->Y); |
|
if (!zero_type(m->Y) && m->D && (int)m->M) |
low=m->day=cal->Day(m->Y,(int)m->M,(int)m->D); |
|
|
if (m->d) |
{ |
int y,mo,d; |
|
if (sizeof(m->d)==6) |
{ |
[y,mo,d]=(array(int))(m->d/2); |
if (y<dwim_year->past_lower) |
y+=dwim_year->current_century; |
else |
y+=dwim_year->past_century; |
} |
else if (sizeof(m->d)==8) |
[y,mo,d]=(array(int))array_sscanf(m->d,"%4s%2s%2s"); |
else return 0; |
|
low=m->day=cal->Day(y,mo,d); |
} |
else |
{ |
if (!zero_type(m->Y)) m->year=cal->Year(m->Y); |
else if (m->y) |
{ |
if (sizeof(m->y)<3) |
{ |
m->y=(int)m->y; |
|
if (m->y<dwim_year->past_lower) |
m->y+=dwim_year->current_century; |
else if (m->y<dwim_year->past_upper) |
m->y+=dwim_year->past_century; |
} |
low=m->year=cal->Year(m->y); |
} |
else low=m->year=context?context->year():cal->Year(); |
|
if (m->M) |
{ |
m->month=low=m->year->month(m->M); |
} |
if (m->W) |
m->week=low=m->year->week("w"+m->W); |
|
if (!zero_type(m->D)) |
m->day=low=(m->month||(context?context->month():cal->Month())) |
->day((int)m->D); |
else if (!zero_type(m->a)) |
m->day=low=m->year->day(m->a); |
else if (!zero_type(m->e)) |
m->day=low=(m->week||(context?context->week():cal->Week())) |
->day(m->e); |
else |
low=m->day=context?context->day():cal->Day(); |
|
if (m->day && zero_type(m->Y) && zero_type(m->y) && m->e) |
if (m->month) |
{ |
|
cYear y2=m->day->year(); |
object d2; |
int i; |
for (i=0; i<20; i++) |
{ |
d2=(y2+i)->place(m->day); |
if (d2 && d2->week()->day(m->e)==d2) break; |
d2=(y2-i)->place(m->day); |
if (d2 && d2->week()->day(m->e)==d2) break; |
} |
if (i==20) return 0; |
low=m->day=d2; |
} |
else |
{ |
|
cYear m2=m->day->month(); |
object d2; |
int i; |
for (i=0; i<20; i++) |
{ |
d2=(m2+i)->place(m->day); |
if (d2 && d2->week()->day(m->e)==d2) break; |
d2=(m2-i)->place(m->day); |
if (d2 && d2->week()->day(m->e)==d2) break; |
} |
if (i==20) return 0; |
low=m->day=d2; |
} |
} |
|
int h=0,mi=0,s=0; |
float sub_second; |
string g=0; |
|
if (m->t) |
{ |
if (sizeof(m->t)==6) |
[h,mi,s]=(array(int))(m->t/2),g="second"; |
else if (sizeof(m->t)==4) |
[h,mi]=(array(int))(m->t/2),g="minute"; |
else return 0; |
} |
else |
{ |
if (!zero_type(m->h)) h=m->h,g="hour"; |
if (!zero_type(m->m)) mi=m->m,g="minute"; |
if (!zero_type(m->s)) s=m->s,g="second"; |
if (!zero_type(m->f)) sub_second=(float)("0."+m->f+"0"*9)[..10]; |
} |
|
if (!zero_type(m->p)) |
{ |
switch (lower_case(m->p)-".") |
{ |
case "am": |
if (h==12) h=0; |
break; |
case "pm": |
if (h!=12) h+=12; |
break; |
default: |
return 0; |
} |
} |
|
if (m->z) |
low = dwim_zone(low,m->z,g,h,mi,s); |
else if (g) |
low = dwim_tod(low,g,h,mi,s); |
else if (!zero_type(m->S)) |
low = Second(m->S); |
if (sub_second) |
low = low->fraction(sub_second); |
return low; |
|
#ifndef NOCATCH |
}) |
#endif |
return 0; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static constant dwim_day_strings= |
({ |
"%y-%M-%D (%*s) -W%W-%e (%e)", |
"%y-%M-%D", |
"%M/%D/%y", |
"%D%*[ /]%M%*[- /,]%y", |
"%M %D%*[- /,]%y", |
"%e%*[, ]%D%*[a-z:]%*[ /]%M%*[-/ ,]%y", |
"%e%*[, ]%M%*[ ,]%D%*[ ,]%y", |
"-%y%*[ /]%D%*[ /]%M", |
"-%y%*[ /]%M%*[ /]%D", |
"%y%*[ /]%M%*[ /]%D", |
"%y%*[ /]%D%*[ /]%M", |
"%D.%M.%y", |
"%D%*[- /]%M", |
"%M%*[- /]%D", |
"%M-%D-%y", |
"%D-%M-%y", |
"%e%*[- /]%D%*[- /]%M", |
"%e%*[- /]%M%*[- /]%D", |
"%e%*[- /wv]%W%*[ -/]%y", |
"%e%*[- /wv]%W", |
"%d" |
}); |
|
cDay dwim_day(string day,void|TimeRange context) |
{ |
cDay d; |
|
foreach ( dwim_day_strings, |
string dayformat) |
if ( (d=parse(dayformat+"%n",day,context)) ) |
return d; |
|
cDay t=context?context->day():Day(); |
if ( (d=parse("%e",day,context)) ) |
{ |
if (d>=t) return d; |
else return (d->week()+1)->place(d); |
} |
|
if (sizeof(day)==4) |
catch { |
d = parse("%M/%D",day/2*"/",context); |
if(d) return d; |
}; |
|
if (day=="today") return t; |
if (day=="tomorrow") return t+1; |
if (day=="yesterday") return t-1; |
if (sscanf(day,"last %s",day)) |
{ |
cDay d=dwim_day(day); |
return (d->week()-1)->place(d); |
} |
if (sscanf(day,"next %s",day)) |
{ |
cDay d=dwim_day(day); |
return (d->week()+1)->place(d); |
} |
|
error("Failed to dwim day from %O\n",day); |
} |
|
TimeofDay dwim_time(string what,void|TimeRange cx) |
{ |
string a,h,m,s; |
TimeofDay t; |
|
|
#define COLON ":" |
#define SPACED(X) replace(X," ","%*[ ]") |
|
what = String.trim_all_whites(what); |
|
if (sizeof(what)>12 && |
(t=parse(SPACED("%e %M %D %h:%m:%s %Y"),what,cx))) return t; |
if (sizeof(what)>15 && |
(t=parse(SPACED("%e %M %D %h:%m:%s %z %Y"),what,cx))) return t; |
if (sizeof(what)>19 && |
(t=parse(SPACED("%e %M %D %h:%m:%s %z DST %Y"),what,cx))) return t; |
|
foreach ( dwim_day_strings + |
({""}), |
string dayformat ) |
foreach ( ({ "%t %z", |
"T%t %z", |
"T%t", |
"%h"COLON"%m"COLON"%s %p %z", |
"%h"COLON"%m"COLON"%s %p", |
"%h"COLON"%m"COLON"%s %z", |
"%h"COLON"%m"COLON"%s%z", |
"%h"COLON"%m"COLON"%s", |
"%h"COLON"%m %p %z", |
"%h"COLON"%m %p", |
"%h"COLON"%m %z", |
"%h"COLON"%m%z", |
"%h"COLON"%m", |
"%h%*[ ]%p", |
"%*[a-zA-Z.] %h"COLON"%m"COLON"%s %p %z", |
"%*[a-zA-Z.] %h"COLON"%m"COLON"%s %p", |
"%*[a-zA-Z.] %h"COLON"%m"COLON"%s %z", |
"%*[a-zA-Z.] %h"COLON"%m"COLON"%s%z", |
"%*[a-zA-Z.] %h"COLON"%m"COLON"%s", |
"%*[a-zA-Z.] %h"COLON"%m %p %z", |
"%*[a-zA-Z.] %h"COLON"%m %p", |
"%*[a-zA-Z.] %h"COLON"%m %z", |
"%*[a-zA-Z.] %h"COLON"%m%z", |
"%*[a-zA-Z.] %h"COLON"%m", |
"%*[a-zA-Z.] %h%*[ ]%p", }), |
string todformat ) |
{ |
|
|
|
if (dayformat=="") |
{ |
if ( (t=parse(todformat+"%*[ ]%n",what,cx)) ) return t; |
} |
else |
{ |
if ( (t=parse(dayformat+"%*[ ,:]"+todformat,what,cx)) ) return t; |
if ( (t=parse(todformat+"%*[ ,:]"+dayformat,what,cx)) ) return t; |
} |
} |
|
error("Failed to dwim time from %O\n",what); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping(string:int) datetime(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->datetime(); |
} |
|
string datetime_name(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->format_iso(); |
} |
|
string datetime_short_name(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->format_iso_short(); |
} |
|
string format_iso(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->format_iso(); |
} |
|
string format_iso_short(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->format_iso_short(); |
} |
|
string format_iso_tod(int|void unix_time) |
{ |
return Second("unix",unix_time||time())->format_iso_tod(); |
} |
|
string format_day_iso(int|void unix_time) |
{ |
return Day("unix",unix_time||time())->format_iso(); |
} |
|
string format_day_iso_short(int|void unix_time) |
{ |
return Day("unix",unix_time||time())->format_iso_short(); |
} |
|
|
|