Branch: Tag:

2000-07-12

2000-07-12 19:36:16 by Mirar (Pontus Hagland) <pike@sort.mirar.org>

first pike tree checkin

Rev: lib/modules/Calendar.pmod/Austrian.pmod:1.1
Rev: lib/modules/Calendar.pmod/CHANGES:1.1
Rev: lib/modules/Calendar.pmod/Calendar.pike:1.1
Rev: lib/modules/Calendar.pmod/Coptic.pmod:1.1
Rev: lib/modules/Calendar.pmod/Discordian.pmod:1.1
Rev: lib/modules/Calendar.pmod/Event.pmod:1.1
Rev: lib/modules/Calendar.pmod/Events.pmod:1.1
Rev: lib/modules/Calendar.pmod/FILES:1.1
Rev: lib/modules/Calendar.pmod/Gregorian.pmod:1.1
Rev: lib/modules/Calendar.pmod/ISO.pmod:1.1
Rev: lib/modules/Calendar.pmod/Islamic.pmod:1.1
Rev: lib/modules/Calendar.pmod/Julian.pmod:1.1
Rev: lib/modules/Calendar.pmod/Language.pmod:1.1
Rev: lib/modules/Calendar.pmod/Namedays.pmod:1.1
Rev: lib/modules/Calendar.pmod/Orthodox.pmod:1.1
Rev: lib/modules/Calendar.pmod/Roman.pmod:1.1
Rev: lib/modules/Calendar.pmod/Ruleset.pike:1.1
Rev: lib/modules/Calendar.pmod/Stardate.pmod:1.1
Rev: lib/modules/Calendar.pmod/Swedish.pmod:1.1
Rev: lib/modules/Calendar.pmod/TZnames.pmod:1.1
Rev: lib/modules/Calendar.pmod/TZrules.pmod:1.1
Rev: lib/modules/Calendar.pmod/TZs.h:1.1
Rev: lib/modules/Calendar.pmod/Time.pmod:1.1
Rev: lib/modules/Calendar.pmod/TimeRanges.pmod:1.1
Rev: lib/modules/Calendar.pmod/Timezone.pmod:1.1
Rev: lib/modules/Calendar.pmod/YMD.pmod:1.1
Rev: lib/modules/Calendar.pmod/localization.h:1.1
Rev: lib/modules/Calendar.pmod/mkrules.pike:1.1
Rev: lib/modules/Calendar.pmod/module.pmod:1.1
Rev: lib/modules/Calendar.pmod/namnsdagar:1.2(DEAD)
Rev: lib/modules/Calendar_I.pmod/Austrian.pmod:1.1
Rev: lib/modules/Calendar_I.pmod/Gregorian.pmod:1.23
Rev: lib/modules/Calendar_I.pmod/ISO.pmod:1.8
Rev: lib/modules/Calendar_I.pmod/Julian.pmod:1.1
Rev: lib/modules/Calendar_I.pmod/Orthodox.pmod:1.2
Rev: lib/modules/Calendar_I.pmod/Stardate.pmod:1.1
Rev: lib/modules/Calendar_I.pmod/Swedish.pmod:1.13
Rev: lib/modules/Calendar_I.pmod/module.pmod:1.5
Rev: lib/modules/Calendar_I.pmod/namnsdagar:1.2(DEAD)

1: + //! + //! module Calendar + //! submodule YMD + //! + //! base for all Roman-kind of Calendars, + //! ie, one with years, months, weeks and days + //!    -  + // #pragma strict_types +  + import "."; + inherit Time:Time; +  + #define this this_object() +  + // ---------------- + // virtual methods to tell how this calendar works + // ---------------- +  + 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); // [y,m,ndays,myd] + static int month_from_yday(int y,int yday); +  + static array(int) week_from_week(int y,int w); // [y,w,wd,ndays,wjd] + static array(int) week_from_julian_day(int jd); // [y,w,wd,ndays,wjd] +  + 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 + //! Base (virtual) time period of the Roman-kind of calendar. + //! inherits TimeRange + //------------------------------------------------------------------------ +  + class YMD + { +  inherit TimeRange; +  + // --- generic for all YMD: +  +  int y; // year +  int yjd; // julian day of the first day of the year +  +  int n; // number of this in the period +  +  int jd; // julian day of first day +  int yd; // day of year (1..) +  int m; // [*] month of year (1..12?), like +  int md; // [*] day of month (1..) +  int wy; // [*] week year +  int w; // [*] week of week year (1..) +  int wd; // [*] day of week (1..7?) +  +  int mnd=CALUNKNOWN; // days in current month +  int utco=CALUNKNOWN; // [*] distance to UTC +  string tzn=0; // timezone name +  + // // ^^^ might be uninitialized (CALUNKNOWN) +  +  Ruleset rules; +  constant is_ymd=1; +  + // ---------------------------------------- + // basic Y-M-D stuff + // ---------------------------------------- +  +  void create_now() +  { +  rules=default_rules; +  create_unixtime_default(time()); +  } +  +  void create_unixtime_default(int unixtime) +  { + // 1970-01-01 is julian day 2440588 +  create_julian_day( 2440588+unixtime/86400 ); + // we can't reuse this; it might not be start of day +  [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; // reuse, it *is* start of day +  } +  +  void make_month() // set m and md from y and yd +  { +  int myd; +  [m,md,mnd,myd]=month_from_yday(y,yd); +  } +  +  void make_week() // set w from y and yd +  { +  int wnd,wjd; +  [wy,w,wd,wnd,wjd]=week_from_julian_day(jd); +  } +  +  int __hash() { return jd; } +  + // --- query +  + //! method float fraction_no() + //! method int hour_no() + //! method int julian_day() + //! method int leap_year() + //! method int minute_no() + //! method int month_day() + //! method int month_no() + //! method int second_no() + //! method int unix_time() + //! method int utc_offset() + //! method int week_day() + //! method int week_no() + //! method int year_day() + //! method int year_no() + //! method string month_name() + //! method string month_shortname() + //! method string month_day_name() + //! method string week_day_name() + //! method string week_day_shortname() + //! method string week_name() + //! method string year_name() + //! method string tzname() + //! method string tzname_iso() +  +  int julian_day() +  { +  return jd; +  } +  +  int unix_time() +  { + // 1970-01-01 is julian day 2440588 +  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; } +  + //! function method datetime() + //! This gives back a mapping with the relevant + //! time information (representing the start of the period); + //! <pre> + //! ([ "year": int // year number (2000 AD=2000, 1 BC==0) + //! "month": int(1..) // month of year + //! "day": int(1..) // day of month + //! "yearday": int(0..) // day of year + //! "week": int(1..) // week of year + //! "week_day": int(0..) // day of week + //! "timezone": int // offset to utc, including dst + //! + //! "unix": int // unix time + //! "julian": int // julian day + //! // for compatibility: + //! "hour": 0 // hour of day, including dst + //! "minute": 0 // minute of hour + //! "second": 0 // second of minute + //! "fraction": 0.0 // fraction of second + //! ]); + //! </pre> + //! + //! note: + //! Day of week is compatible with old versions, + //! ie, 0 is sunday, 6 is saturday, so it shouldn't be + //! used to calculate the day of the week with the given + //! week number. Year day is also backwards compatible, + //! ie, one (1) less then from the year_day() function. +  +  mapping datetime(void|int skip_stuff) +  { +  if (m==CALUNKNOWN) make_month(); +  if (w==CALUNKNOWN) make_week(); +  if (skip_stuff) // called from timeofday +  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(), +  // for compatibility: +  "hour": 0, +  "minute": 0, +  "second": 0, +  "fraction": 0.0 +  ]); +  } +  } +  + // --- string format ---- +  + //! method string format_iso_ymd(); + //! method string format_ymd(); + //! method string format_ymd_short(); + //! method string format_ymd_xshort(); + //! method string format_iso_week(); + //! method string format_iso_week_short(); + //! method string format_week(); + //! method string format_week_short(); + //! method string format_month(); + //! method string format_month_short(); + //! method string format_iso_time(); + //! method string format_time(); + //! method string format_time_short(); + //! method string format_time_xshort(); + //! method string format_mtime(); + //! method string format_xtime(); + //! method string format_tod(); + //! method string format_todz(); + //! method string format_xtod(); + //! method string format_mod(); + //! Format the object into nice strings; + //! <pre> + //! iso_ymd "2000-06-02 (Jun) -W22-5 (Fri)" [2] + //! ext_ymd "Friday, 2 June 2000" [2] + //! ymd "2000-06-02" + //! ymd_short "20000602" + //! ymd_xshort "000602" [1] + //! iso_week "2000-W22" + //! iso_week_short "2000W22" + //! week "2000-w22" [2] + //! week_short "2000w22" [2] + //! month "2000-06" + //! month_short "200006" [1] + //! iso_time "2000-06-02 (Jun) -W22-5 (Fri) 00:00:00 UTC+1" [2] + //! ext_time "Friday, 2 June 2000, 00:00:00" [2] + //! ctime "Fri Jun 2 00:00:00 2000\n" [2] [3] + //! http "Fri, 02 Jun 2000 00:00:00 GMT" [4] + //! time "2000-06-02 00:00:00" + //! time_short "20000602 00:00:00" + //! time_xshort "000602 00:00:00" + //! mtime "2000-06-02 00:00" + //! xtime "2000-06-02 00:00:00.000000" + //! tod "00:00:00" + //! tod_short "000000" + //! todz "00:00:00 CET" + //! todz_iso "00:00:00 UTC+1" + //! xtod "00:00:00.000000" + //! mod "00:00" + //! </pre> + //! <tt>[1]</tt> note conflict (think 1 February 2003) + //! <br><tt>[2]</tt> language dependent + //! <br><tt>[3]</tt> as from the libc function ctime() + //! <br><tt>[4]</tt> as specified by the HTTP standard; + //! not language dependent. +  +  string format_iso_ymd() +  { +  if (m==CALUNKNOWN) make_month(); +  if (w==CALUNKNOWN) make_week(); +  return sprintf("%04d-%02d-%02d (%s) -W%02d-%d (%s)", +  y,m,md, +  month_shortname(), +  w,wd, // fixme - what weekday? +  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], +  y); +  } +  +  string format_ymd() +  { +  if (m==CALUNKNOWN) make_month(); +  return sprintf("%04d-%02d-%02d",y,m,md); +  } +  +  string format_ymd_short() +  { +  if (m==CALUNKNOWN) make_month(); +  return sprintf("%04d%02d%02d",y,m,md); +  } +  +  string format_ymd_xshort() +  { +  if (m==CALUNKNOWN) make_month(); +  return sprintf("%02d%02d%02d",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_time_xshort() +  { +  return format_ymd_xshort()+" 00:00:00"; +  } +  +  string format_mtime() +  { +  return format_ymd_short()+" 00:00"; +  } +  +  string format_xtime() +  { +  return format_ymd_short()+" 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_elapsed() +  { +  return sprintf("%dd",number_of_days()); +  } +  + // --- size and move --- +  +  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(); +  + // months are even on years +  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(); +  } +  + // weeks are not +  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); +  } +  + // fallback on days +  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) +  return second()->range(second(-1))->add(n,step); +  +  error("add: incompatible class %O\n", +  object_program(step)); +  } +  +  array(int(-1..1)) _compare(TimeRange with) +  { +  if (with->is_timeofday) +  { +  // wrap +  array(int(-1..1)) cmp=with->_compare(this_object()); +  +  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); +  } +  + // --- to other YMD +  + // years +  +  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), +  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); +  } +  +  + // days +  +  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) +  { +  if (!sizeof(mp)) +  return Day("ymd_yd",rules,y,yjd,jd,yd,1); +  +  int m=mp[0]; +  +  if (m==-1 && !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]; +  error("not in range (Day 1..%d exist)\n", +  number_of_days()); +  } +  + // --- months +  +  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_object()); +  } +  + //---- week +  +  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()); +  } +  +  + // --- functions to conform to Time.* +  +  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); }); +  + // return z; +  +  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))) +  { +  // we're in a zone shifting, and we shift a non-hour (or non-minute) +  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); +  werror("%O %O\n",z[i],z); +  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++; +  } +  werror("=> %O %O\n",z[i],z); +  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) { 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 hour(n)->minute(time[0])->second(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()}); +  } +  + // ---------------------------------------- + // virtual functions needed + // ---------------------------------------- +  +  string nice_print(); +  string _sprintf(int t); +  +  void create_julian_day(int|float jd); +  static TimeRange _move(int n,YMD step); +  TimeRange place(TimeRange what,void|int force); +  + // not needed +  +  YMD autopromote() { return this; } + } +  + //------------------------------------------------------------------------ + //! class Year + //! This is the time period of a year. + //! inherits TimeRange + //! inherits YMD + //------------------------------------------------------------------------ +  + function(mixed...:cYear) Year=cYear; + class cYear + { +  inherit YMD; +  +  constant is_year=1; +  + // --- +  + //! + //! method void create("unix",int unix_time) + //! method void create("julian",int|float julian_day) + //! method void create(int year) + //! method void create(string year) + //! It's possible to create the standard week + //! by using three different methods; either the normal + //! way - from standard unix time or the julian day, + //! and also, for more practical use, from the year number. + //! +  +  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; // unknown +  } +  } +  +  TimeRange beginning() +  { +  return Year("ymd_y",rules,y,yjd,0); +  } +  +  TimeRange end() +  { +  return Year("ymd_yn",rules,y+n,0); +  } +  + // ---------------- +  +  string _sprintf(int t) +  { +  switch (t) +  { +  case 'O': +  if (n!=1) +  return sprintf("Year(%s)",nice_print_period()); +  return sprintf("Year(%s)",nice_print()); +  default: +  return 0; +  } +  } +  +  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(); +  } +  + // --- Year _move +  +  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_object()); +  + // if (step->is_week) + // return week()->add(m,step)->set_size(this_object()); +  +  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; // not this year +  return week; +  } +  +  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(); +  + //! method Month month() + //! method Month month(int n) + //! method Month month(string name) + //! The Year type overloads the month() method, + //! so it is possible to get a specified month + //! by string: + //! + //! <tt>year-&gt;month("April")</tt> + //! + //! The integer and no argument behavior is inherited + //! from <ref to=YMD.month>YMD</ref>(). +  +  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_object()); +  +  return ::month(num); +  } +  else +  return ::month(@mp); +  } +  + //! method Week week() + //! method Week week(int n) + //! method Week week(string name) + //! The Year type overloads the week() method, + //! so it is possible to get a specified week + //! by name: + //! + //! <tt>year-&gt;week("17")</tt> + //! <tt>year-&gt;week("w17")</tt> + //! + //! The integer and no argument behavior is inherited + //! from <ref to=YMD.week>YMD</ref>(). + //! + //! This is useful, since the first week of a year + //! not always (about half the years, in the ISO calendar) + //! is numbered '1'. + //! +  +  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); +  } + } +  +  + // ---------------------------------------------------------------- + // Month + // ---------------------------------------------------------------- +  + function(mixed...:cMonth) Month=cMonth; + class cMonth + { +  inherit YMD; +  +  constant is_month=1; +  +  int nd; // number of days +  int nw; // number of weeks +  +  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; // unknown +  } +  } +  +  string _sprintf(int t) +  { + // return sprintf("month y=%d yjd=%d m=%d jd=%d yd=%d n=%d nd=%d", + // y,yjd,m,jd,yd,n,number_of_days()); +  switch (t) +  { +  case 'O': +  if (n!=1) +  return sprintf("Month(%s)",nice_print_period()); +  return sprintf("Month(%s)",nice_print()); +  default: +  return 0; +  } +  } +  +  string nice_print() +  { +  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(); +  } +  + // --- month position and distance +  +  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; // doesn't exist +  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); // just fallback +  +  if (what->is_day) +  return place_day(what->month_day(),what->n,force); +  +  error("place: Incompatible type %O\n",what); +  } +  + // --- Month to other units +  +  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); +  } +  + // --- needs to be defined +  +  static int months_to_month(int y,int m); + } +  + // ---------------------------------------------------------------- + //! class Week + //! The Calendar week represents a standard time period of + //! a week. In the Gregorian calendar, the standard week + //! starts on a sunday and ends on a saturday; in the ISO + //! calendar, it starts on a monday and ends on a sunday. + //! + //! The week are might not be aligned to the year, and thus + //! the week may cross year borders and the year of + //! the week might not be the same as the year of all the + //! days in the week. The basic rule is that the week year + //! is the year that has the most days in the week, but + //! since week number only is specified in the ISO calendar + //! - and derivates - the week number of most calendars + //! is the week number of most of the days in the ISO + //! calendar, which modifies this rule for the Gregorian calendar; + //! the week number and year is the same as for the ISO calendar, + //! except for the sundays. + //! + //! When adding, moving and subtracting months + //! to a week, it falls back to using days. + //! + //! When adding, moving or subtracting years, + //! if tries to place the moved week in the + //! resulting year. + // ---------------------------------------------------------------- +  + function(mixed...:cWeek) Week=cWeek; + class cWeek + { +  inherit YMD; +  +  constant is_week=1; +  + //! + //! method void create("unix",int unix_time) + //! method void create("julian",int|float julian_day) + //! method void create(int year,int week) + //! It's possible to create the standard week + //! by using three different methods; either the normal + //! way - from standard unix time or the julian day, + //! and also, for more practical use, from year and week + //! number. + //! +  +  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; // unknown +  } +  } +  +  string _sprintf(int t) +  { + // return sprintf("week y=%d yjd=%d w=%d jd=%d yd=%d n=%d nd=%d", + // y,yjd,w,jd,yd,n,number_of_days()); +  switch (t) +  { +  case 'O': +  if (n!=1) +  return sprintf("Week(%s)",nice_print_period()); +  return sprintf("Week(%s)",nice_print()); +  default: +  return 0; +  } +  } +  +  string nice_print() +  { +  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(); +  } +  + // --- week position and distance +  +  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_object(),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_year) +  return year()->place(what,force); // just fallback +  +  if (what->is_day) +  return place_day(what->week_day(),what->n,force); +  +  error("place: Incompatible type %O\n",what); +  } +  + // --- Week to other units +  +  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; +  + // cheat +  return Day("ymd_jd",rules,jd,number_of_days()) +  ->number_of_months(); +  } +  +  int number_of_weeks() +  { +  return n; +  } +  +  int number_of_days(); +  + //! method Day day() + //! method Day day(int n) + //! method Day day(string name) + //! The Week type overloads the day() method, + //! so it is possible to get a specified weekday + //! by string: + //! + //! <tt>week-&gt;day("sunday")</tt> + //! + //! The integer and no argument behavior is inherited + //! from <ref to=YMD.day>YMD</ref>(). + //! + //! note: + //! the weekday-from-string routine is language dependent. +  +  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_object()); +  +  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); +  } +  + // --- needs to be defined +  +  static int weeks_to_week(int y,int m); + } +  + // ---------------------------------------------------------------- + // Day + // ---------------------------------------------------------------- +  + function(mixed...:cDay) Day=cDay; + class cDay + { +  inherit YMD; +  +  constant is_day=1; +  int nw; +  + //! + //! method void create("unix",int unix_time) + //! method void create("julian",int|float julian_day) + //! method void create(int year,int month,int day) + //! method void create(int year,int year_day) + //! method void create(int julian_day) + //! It's possible to create the day + //! by using five different methods; either the normal + //! way - from standard unix time or the julian day, + //! and also, for more practical use, from year, month and day, + //! from year and day of year, and from julian day + //! without extra fuzz. +  +  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; // unknown +  +  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) +  { +  switch (t) +  { +  case 'O': +  if (n!=1) +  return sprintf("Day(%s)",nice_print_period()); +  return sprintf("Day(%s)",nice_print()); +  default: +  return 0; +  } +  } +  +  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 nice_print_period() +  { + // return nice_print()+" n="+n+""; +  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; +  } +  + // --- Day _move +  +  static TimeRange _move(int x,YMD step) +  { +  if (step->is_year) +  return year()->add(x,step)->place(this_object(),1); +  +  if (step->is_month) +  return month()->add(x,step)->place(this_object(),1); +  +  if (step->is_week) +  return week()->add(x,step)->place(this_object(),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) +  { +  if (what->is_timeofday) +  { +  int lux= +  what->ux- +  Day("unix_r",what->unix_time(),what->ruleset()) +  ->unix_time(); +  +  if (what->is_timeofday_f) +  return +  Fraction("timeofday_f",rules, +  lux+unix_time(),what->ns,what->s_len,what->ns_len) +  ->autopromote(); +  +  return Second("timeofday",rules,unix_time()+lux,what->len) +  ->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); +  } +  + // --- Day to other YMD +  +  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); +  } +  + // backwards compatible with calendar I +  string iso_name() { return format_ymd(); } +  string iso_short_name() { return format_ymd_short(); } + } +  + //------------------------------------------------------------------------ + //- class YMD_Time + //------------------------------------------------------------------------ +  + 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(); } +  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 Hour + //! inherits Time.Hour + //! inherits YMD + //------------------------------------------------------------------------ +  + 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 + } +  + //------------------------------------------------------------------------ + //! global convinience functions + //------------------------------------------------------------------------ +  + //! method TimeRange parse(string fmt,string arg) + //! parse a date, create relevant object + //! fmt is in the format "abc%xdef..." + //! where abc and def is matched, and %x is + //! one of those time units: + //! <pre> + //! %Y absolute year + //! %y dwim year (70-99 is 1970-1999, 0-69 is 2000-2069) + //! %M month (number, name or short name) (needs %y) + //! %W week (needs %y) + //! %D date (needs %y, %m) + //! %d short date (20000304, 000304) + //! %a day (needs %y) + //! %e weekday (needs %y, %w) + //! %h hour (needs %d, %D or %W) + //! %m minute (needs %h) + //! %s second (needs %m) + //! %f fraction of a second (needs %s) + //! %t short time (205314, 2053) + //! </pre> + //! + //! note: + //! Returns 0 if format doesn't match data. +  + TimeRange parse(string fmt,string arg) + { +  string nfmt; +  nfmt=replace(fmt," %","%*[ \t]%"); // whitespace -> whitespace + #define ALNU "%[^ -,./:-?[-`{-¿]" + #define NUME "%[0-9]" +  nfmt=replace(nfmt, +  ({"%Y","%y","%M","%W","%D","%a","%e","%h","%m","%s", +  "%t","%f","%d","%z"}), +  ({ALNU,ALNU,ALNU,"%d","%d","%d",ALNU,"%d","%d","%d", +  NUME,NUME,NUME,"%[-+0-9A-Za-z/]"})); +  array q=Array.map(replace(fmt,({"%*","%%"}),({"",""}))/"%", +  lambda(string s){ return s[..0];})-({""}); +  array res=array_sscanf(arg,nfmt); +  +  if (sizeof(res)<sizeof(q)) +  return 0; // parse error +  +  mapping m=mkmapping(q,res); +  +  TimeRange low; +  +  werror("%O\n",m); +  +  Calendar cal=this_object(); +  +  if (catch { +  +  if (m->z) +  cal=cal->set_timezone(m->z); +  werror("%O\n",m->z); +  +  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,m->D); +  +  if (m->d) +  { +  int y,mo,d; +  +  if (strlen(m->d)==6) +  { +  [y,mo,d]=(array(int))(m->d/2); +  if (y<70) y+=2000; else y+=1900; +  } +  else if (strlen(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 (strlen(m->y)<3) +  { +  m->y=(int)m->y; +  if (m->y<70) m->y+=2000; +  else if (m->y<100) m->y+=1900; +  } +  low=m->year=cal->Year(m->y); +  } +  else low=m->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)) +  if (stringp(m->D)) return 0; +  else m->day=low=(m->month||cal->Month())->day(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||cal->Week())->day(m->e); +  else +  low=m->day=cal->Day(); +  } +  +  if (m->t) +  { +  int h,mi,s; +  +  if (strlen(m->t)==6) +  [h,mi,s]=(array(int))(m->t/2); +  else if (strlen(m->t)==4) +  [h,mi]=(array(int))(m->t/2),s=0; +  else return 0; +  +  low=m->second=m->day->second(h,mi,s); +  } +  else if (!zero_type(m->h) && !zero_type(m->m) && !zero_type(m->s)) +  low=m->second=m->day->second(m->h,m->m,m->s); +  else +  { +  if (!zero_type(m->h)) +  low=m->hour=(m->day||cal->Day())->hour(m->h); +  if (!zero_type(m->m)) +  low=m->minute=(m->hour||cal->Hour())->minute(m->m); +  if (!zero_type(m->s)) +  low=m->second=(m->minute||cal->Minute())->second(m->s); +  } +  return low; +  +  }) +  return 0; + } +  + //! function Day dwim_day(string date) + //! Tries a number of different formats on the given date (in order): + //! <pre> + //! <ref>parse</ref> format as in + //! "%y-%M-%D (%M) -W%W-%e (%e)" "2000-03-20 (Mar) -W12-1 (Mon)" + //! "%D%*[ /]%M%*[ /-,]%y" "20/3/2000" "20 mar 2000" "20/3 -00" + //! "%e%*[ ]%D%*[ /]%M%*[ /-,]%y" "Mon 20 Mar 2000" "Mon 20/3 2000" + //! "%y-%M-%D" "2000-03-20", "00-03-20" + //! "%d" "20000320", "000320" + //! "-%y%*[ /]%D%*[ /]%M" "-00 20/3" "-00 20 mar" + //! "-%y%*[ /]%M%*[ /]%D" "-00 3/20" "-00 march 20" + //! "%y%*[ /]%D%*[ /]%M" "00 20 mar" "2000 20/3" + //! "%y%*[ /]%M%*[ /]%D" "2000 march 20" + //! "%D%*[ -/]%M" "20/3" "20 mar" "20-03" + //! "%M%*[ -/]%D" "3/20" "march 20" + //! "%e%*[ -/wv]%W%*[ -/]%y" "mon w12 -00" "1 w12 2000" + //! "%e%*[ -/wv]%W" "mon w12" + //! "%e" "monday" "1" + //! "today" "today" + //! "last %e" "last monday" + //! "next %e" "next monday" + //! </pre> + //! + //! note: + //! Casts exception if it fails to dwim out a day. + //! "dwim" means do-what-i-mean. +  + /* tests: +  + Calendar.dwim_day("2000-03-20 (Mar) -W12-1 (Mon)"); + Calendar.dwim_day("20/3/2000"); + Calendar.dwim_day("20 mar 2000"); + Calendar.dwim_day("20/3 -00"); + Calendar.dwim_day("Mon 20 Mar 2000" ); + Calendar.dwim_day("Mon 20/3 2000"); + Calendar.dwim_day("2000-03-20"); + Calendar.dwim_day("00-03-20"); + Calendar.dwim_day("20000320"); + Calendar.dwim_day("000320"); + Calendar.dwim_day("-00 20/3" ); + Calendar.dwim_day("-00 20 mar"); + Calendar.dwim_day("-00 3/20" ); + Calendar.dwim_day("-00 march 20"); + Calendar.dwim_day("00 20 mar" ); + Calendar.dwim_day("2000 20/3"); + Calendar.dwim_day("2000 march 20"); + Calendar.dwim_day("20/3" ); + Calendar.dwim_day("20 mar" ); + Calendar.dwim_day("20-03"); + Calendar.dwim_day("3/20" ); + Calendar.dwim_day("march 20"); + Calendar.dwim_day("mon w12 -00" ); + Calendar.dwim_day("1 w12 2000"); + Calendar.dwim_day("mon w12"); + Calendar.dwim_day("monday" ); + Calendar.dwim_day("1"); + Calendar.dwim_day("today"); + Calendar.dwim_day("last monday"); + Calendar.dwim_day("next monday"); +  + */ +  + cDay dwim_day(string day) + { +  cDay d; +  +  foreach ( ({ "%y-%M-%D (%*s) -W%W-%e (%e)", +  "%D%*[ /]%M%*[- /,]%y", +  "%M %D%*[- /,]%y", +  "%e%*[ ]%D%*[ /]%M%*[-/ ,]%y", +  "%y-%M-%D", +  "-%y%*[ /]%D%*[ /]%M", +  "-%y%*[ /]%M%*[ /]%D", +  "%y%*[ /]%D%*[ /]%M", +  "%y%*[ /]%M%*[ /]%D", +  "%D%*[- /]%M", +  "%M%*[- /]%D", +  "%e%*[- /wv]%W%*[ -/]%y", +  "%e%*[- /wv]%W", +  "%d"}), +  string dayformat) +  if ( (d=parse(dayformat,day)) ) return d; +  +  cDay t=Day(); +  if ( (d=parse("%e",day)) ) +  { +  if (d>=t) return d; +  else return (d->week()+1)->place(d); +  } +  +  if (strlen(day)==4) catch { return parse("%M/%D",day/2*"/"); }; +  +  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) + { +  string a,h,m,s; +  TimeofDay t; +  +  foreach ( ({ " %z","%z",""}), +  string zone ) +  foreach ( ({ "%t", +  "%h:%*[ :]%m%*[ :]:%s", +  "%h:%*[ :]%m" }), +  string todformat ) +  foreach ( ({ "%y-%M-%D (%*s) -W%W-%e (%e)", +  "%D%*[ /]%M%*[- /,]%y", +  "%M %D%*[- /,]%y", +  "%e%*[ ]%D%*[ /]%M%*[-/ ,]%y", +  "%y-%M-%D", +  "%d", +  "-%y%*[ /]%D%*[ /]%M", +  "-%y%*[ /]%M%*[ /]%D", +  "%y%*[ /]%D%*[ /]%M", +  "%y%*[ /]%M%*[ /]%D", +  "%D%*[- /]%M", +  "%M%*[- /]%D", +  "%e%*[- /wv]%W%*[ -/]%y", +  "%e%*[- /wv]%W" }), +  string dayformat ) +  { +  if ( (t=parse(dayformat+" "+todformat+zone,what)) ) return t; +  if ( (t=parse(todformat+zone+" "+dayformat,what)) ) return t; +  } +  +  error("Failed to dwim time from %O\n",what); + } +  + //-- auxillary functions------------------------------------------------ +  + //! + //! function datetime(int|void unix_time) + //! Replacement for localtime; gives back a mapping: + //! <pre> + //! ([ "year": int // year number (2000 AD=2000, 1 BC==0) + //! "month": int(1..) // month of year + //! "day": int(1..) // day of month + //! "yearday": int(1..) // day of year + //! "week": int(1..) // week of year + //! "week_day": int(1..) // day of week (depending on calendar) + //! "unix": int // unix time + //! "julian": float // julian day + //! "hour": int(0..) // hour of day, including dst + //! "minute": int(0..59) // minute of hour + //! "second": int(0..59) // second of minute + //! "fraction": float // fraction of second + //! "timezone": int // offset to utc, including dst + //! ]); + //! </pre> + //! This is the same as calling <ref>Second</ref>()-><ref to=Second.datetime>datetime</ref>(). + //! + //! function datetime_name(int|void unix_time) + //! function datetime_short_name(int|void unix_time) + //! Compat functions; same as <ref>format_iso</ref> + //! and <ref>format_iso_short</ref>. + //! + //! function string format_iso(void|int unix_time) + //! function string format_iso_short(void|int unix_time) + //! function string format_iso_tod(void|int unix_time) + //! function string format_day_iso(void|int unix_time) + //! function string format_day_iso_short(void|int unix_time) + //! Format the object into nice strings; + //! <pre> + //! iso "2000-06-02 (Jun) -W22-5 (Fri) 11:57:18 CEST" + //! iso_short "2000-06-02 11:57:18" + //! iso_tod "11:57:18" + //! </pre> +  + // Sane replacement for localtime(). + 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(); + } +    Newline at end of file added.