pike.git / lib / modules / Calendar.pmod / YMD.pike

version» Context lines:

pike.git/lib/modules/Calendar.pmod/YMD.pike:18:   // 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 array(int) month_from_yday(int y,int yday); // [m,day-of-month,ndays,myd]    - 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 array(int) week_from_week(int y,int w); // [wy,w,wd,ndays,wjd] + static array(int) week_from_julian_day(int jd); // [wy,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;
pike.git/lib/modules/Calendar.pmod/YMD.pike:49:   //! Base (virtual) time period of the Roman-kind of calendar.   //! inherits TimeRange   //------------------------------------------------------------------------      class YMD   {    inherit TimeRange;      // --- generic for all YMD:    +  // The correct year to use in context with yjd, yd, m and md is y. +  // The correct year to use in context with w is wy. +  // The correct year to use without context is year_no() (= either y or wy). +     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
pike.git/lib/modules/Calendar.pmod/YMD.pike:219:    return wd;    }       int year_day()    {    return yd;    }       string year_name()    { -  return rules->language[f_year_name_from_number](y); +  return rules->language[f_year_name_from_number](year_no());    }       string week_name()    {    if (w==CALUNKNOWN) make_week();    return rules->language[f_week_name_from_number](w);    }       string month_name()    {
pike.git/lib/modules/Calendar.pmod/YMD.pike:258:    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 leap_year() { return year_leap_year(year_no()); }       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>
pike.git/lib/modules/Calendar.pmod/YMD.pike:293:   //! "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. + //! + //! note: + //! If this function is called in a Week object that begins with + //! the first week of a year, it returns the previous year if that + //! is where the week starts. To keep the representation + //! unambiguous, the returned week number is then one more than + //! the number of weeks in that year. + //! + //! E.g. Week(2008,1)->datetime() will return year 2007 and week + //! 53 since the first week of 2008 starts in 2007.       mapping datetime(void|int skip_stuff)    {    if (m==CALUNKNOWN) make_month();    if (w==CALUNKNOWN) make_week(); -  +  +  int week; +  if (y == wy) +  week = w; +  else +  // w is the first week of the year and it begins in the +  // previous year, so we know y == wy - 1 and w == 1. +  week = week_from_week (y, 0)[1] + 1; +     if (skip_stuff) // called from timeofday    return ([ "year": y,    "month": m,    "day": md,    "yearday": yd-1, -  "week": w, +  "week": week,    "week_day": compat_week_day(wd)    ]);    else    {    return ([ "year": y,    "month": m,    "day": md,    "yearday": yd-1, -  "week": w, +  "week": week,    "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    ]);
pike.git/lib/modules/Calendar.pmod/YMD.pike:389:   //! <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)", -  ((yd < 1)?y-1:y),m,md, +  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(),
pike.git/lib/modules/Calendar.pmod/YMD.pike:422:    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)); +  y);    }       string format_ext_time_short()    {    if (wd==CALUNKNOWN) make_week();    if (md==CALUNKNOWN) make_month();       return    sprintf("%s, %d %s %d 00:00:00 GMT",    week_day_shortname(), -  month_day(),month_shortname(),year_no()); +  month_day(),month_shortname(),y);    }       string format_ymd()    {    if (m==CALUNKNOWN) make_month(); -  return sprintf("%04d-%02d-%02d",((yd < 1)?y-1:y),m,md); +  return sprintf("%04d-%02d-%02d",y,m,md);    }       string format_ymd_short()    {    if (m==CALUNKNOWN) make_month(); -  return sprintf("%04d%02d%02d",((yd < 1)?y-1:y),m,md); +  return sprintf("%04d%02d%02d",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); +  return sprintf("%02d%02d%02d",y%100,m,md);    }       string format_iso_week()    {    if (w==CALUNKNOWN) make_week();    return sprintf("%04d-W%02d",wy,w);    }       string format_iso_week_short()    {    if (w==CALUNKNOWN) make_week();    return sprintf("%04d%02d",wy,w);    }       string format_week()    { -  return sprintf("%04d-%s",y,week_name()); +  if (w==CALUNKNOWN) make_week(); +  return sprintf("%04d-%s",wy,week_name());    }       string format_week_short()    { -  return sprintf("%04d%s",y,week_name()); +  if (w==CALUNKNOWN) make_week(); +  return sprintf("%04d%s",wy,week_name());    }       string format_month()    {    if (m==CALUNKNOWN) make_month();    return sprintf("%04d-%02d",y,m);    }       string format_month_short()    {
pike.git/lib/modules/Calendar.pmod/YMD.pike:617:    if (md==1)    return Month("ymd_yjmw",rules,y,yjd,jd,m,    t->number_of_months()*n,wd,w,wy)    ->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); +  if (wd==1) return Week("ymd_yjwm",rules,y,yjd,jd,wy,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,wy,w,wd,mnd);       error("set_size: incompatible class %O\n",    object_program(t));    }
pike.git/lib/modules/Calendar.pmod/YMD.pike:682:      // 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) +  array(cYear) years(void|int from, void|int to)    { -  int from=1,n=number_of_years(),to=n; +  int n=number_of_years();    -  if (sizeof(range)) -  if (sizeof(range)<2) -  error("Illegal numbers of arguments to days()\n"); +  if (zero_type (from)) { +  from = 1; +  to = n; +  }    else -  +  if (zero_type (to)) +  error("Illegal numbers of arguments to years()\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 ({}); +  if (from>n) return ({}); else if (from<1) from=1; +  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)) +  if (zero_type (m)) m=1; +  +  if (!n&&m==-1)    return Year("ymd_y",rules,y,yjd,1);    -  if (m<0) m=number_of_years()+m; +  if (m<0) m += 1 + number_of_years();       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); +  error("Not in range (Year 1..%d exist)\n", +  number_of_years());    }         // days       int number_of_days();    -  array(cDay) days(int ...range) +  array(cDay) days(void|int from, void|int to)    { -  int from=1,n=number_of_days(),to=n; +  int n=number_of_days();    -  if (sizeof(range)) -  if (sizeof(range)<2) -  error("Illegal numbers of arguments to days()\n"); +  if (zero_type (from)) { +  from = 1; +  to = n; +  }    else -  +  if (zero_type (to)) +  error("Illegal number 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); });
pike.git/lib/modules/Calendar.pmod/YMD.pike:768:    zjd+=rd;    to-=rd;    }       [zy,zyjd]=year_from_julian_day(zjd);    zyd=zjd-zyjd+1;    }    return res;    }    -  cDay day(int ... mp) +  cDay day(void|int m, mixed... ignored)    { -  int m; -  if (sizeof(mp)) m=mp[0]; -  else m=1; +  if (zero_type (m)) 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",
pike.git/lib/modules/Calendar.pmod/YMD.pike:1250:    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)    { -  if (other->y) -  create(other->y); -  else + #if 0 +  // The following is disabled since it leads to inconsistent +  // behavior with other time ranges when they are converted to +  // partly overlapping time ranges. If the user wants to convert +  // a week to the year it "unambiguously" belongs to, (s)he can +  // do Calendar.ISO.Year(week->year_no()). +  if (other->is_week) { +  // Weeks aren't even on years but they still unambiguously +  // belong to years. We therefore convert using the week year +  // instead of the default method that uses the julian day. +  create ("ymd_yn", other->rules, other->wy, +  other->n > 1 ? +  other->week(-1)->wy - other->wy + 1 : +  other->n); +  return; +  } + #endif +     ::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 +  if (!force && week->wy!=y) return 0; // not this year    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)
pike.git/lib/modules/Calendar.pmod/YMD.pike:1520:       string nice_print_period()    {    if (!n) return day()->nice_print()+" "+minute()->nice_print()+" 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(); +  return nice_print()+" .. "+mo->nice_print();    }    -  cDay beginning() +  TimeRange beginning()    {    return Month("ymd_yjmw",rules,y,yjd,jd,m,0,wd,w,wy)    ->autopromote();    }    -  cDay end() +  TimeRange end()    {    return Month("ymd_ym",rules,y,m+n,0)    ->autopromote();    }      // --- month position and distance       TimeRange distance(TimeRange to)    {    if (to->is_timeofday)
pike.git/lib/modules/Calendar.pmod/YMD.pike:1690:   //! 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;    +  // Note: wy, w and wd are never CALUNKNOWN in this class. +     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
pike.git/lib/modules/Calendar.pmod/YMD.pike:1716:    {    rules=default_rules;    create_unixtime_default(time());    return;    }    else    switch (args[0])    {    case "ymd_yw":    rules=args[1]; -  y=args[2]; +  wy=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); +  [wy,w,wd,int nd,jd]=week_from_week(wy,w); +  int wyjd=julian_day_from_year(wy); +  if (wyjd > jd) +  y = wy - 1, yjd = julian_day_from_year (y); +  else +  y = wy, yjd = wyjd;    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]; +  wy=args[5]; +  w=args[6]; +  n=args[7]; +  md=args[8]; +  m=args[9]; +  mnd=args[10];    wd=1; -  wy=y; -  // Adjust according to julian day (typically to -  // correct the year). -  create_julian_day(jd); +     nd=CALUNKNOWN;    return;    case "ymd_jd":    rules=args[1];    create_julian_day(args[2]);    n=args[3];    return;    case "unix": case "unix_r": case "julian": case "julian_r":    // Handled by ::create.    break;    default:    if (intp(args[0]) && sizeof(args)==2)    {    create("ymd_yw",default_rules,args[0],args[1],1); -  if (y!=args[0]) +  if (wy!=args[0]) +  // FIXME: Allow weeks 0 and 53/54 if they contain +  // at least one day in this year.    error("Week %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); +  [wy,w,zwd,int nd,jd]=week_from_julian_day(_jd); +  [y,yjd]=year_from_julian_day(_jd);    yd=1+jd-yjd;       n=1;    wd=1; -  wy=y; +     md=m=CALUNKNOWN; // unknown    }    }       string _sprintf(int t,mapping m)    {   // 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)    {
pike.git/lib/modules/Calendar.pmod/YMD.pike:1802:    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);    }    }    +  int year_no() +  { +  return wy>0?wy:-1+wy; +  } +  +  int year_day() +  //! Can be less than 1 for the first week of the year if it begins +  //! in the previous year. +  { +  return y != wy ? 1 + jd - julian_day_from_year (wy) : yd; +  } +     string nice_print()    {    return    sprintf("%s %s",    week_name(),    year_name());    }       string format_nice()    {
pike.git/lib/modules/Calendar.pmod/YMD.pike:1823:    sprintf("%s %s",    week_name(),    year_name());    }          string nice_print_period()    {    if (!n) return day()->nice_print()+" "+minute()->nice_print()+" sharp";    cWeek wo=week(-1); -  if (wo->y==y) +  if (wo->wy==wy)    return sprintf("%s..%s %s",    week_name(),    wo->week_name(),    year_name()); -  return nice_print()+" .. "+week(-1)->nice_print(); +  return nice_print()+" .. "+wo->nice_print();    }    -  cDay beginning() +  TimeRange beginning()    { -  return Week("ymd_yjwm",rules,y,yjd,jd,w,0,md,m,mnd) +  return Week("ymd_yjwm",rules,y,yjd,jd,wy,w,0,md,m,mnd)    ->autopromote();    }    -  cDay end() +  TimeRange end()    { -  return Week("ymd_yw",rules,y,w+n,0) +  return Week("ymd_yw",rules,wy,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); +  int n1=weeks_to_week(to->wy,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) +  return Week("ymd_yjwm",rules,y,yjd,jd,wy,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,wy,w,1,mnd)
pike.git/lib/modules/Calendar.pmod/YMD.pike:1884:    ::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) +  return Week("ymd_yw",rules,wy,w+x*step->n,n)    ->autopromote();    -  if (step->is_year) -  return year()->add(x,step)->place(this,1); +  if (step->is_year) { +  TimeRange stepped = year()->add(x,step); +  if (TimeRange placed = stepped->place(this,0)) +  return placed; +  // If we couldn't place our week in the target year it means +  // we're in week 53 and the target year got only 52 weeks. We +  // return the closest week of the target year, i.e. week 52. +  return Week ("ymd_yw", rules, stepped->y, 52, n); +  }       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)
pike.git/lib/modules/Calendar.pmod/YMD.pike:1920:    if (what->is_supertimerange)    return what->mend_overlap(map(what->parts,place,force));   // return `|(@map(what->parts,place,force));       if (what->is_year)    return year()->place(what,force); // just fallback    if (what->is_month)    return month()->place(what,force); // just fallback       if (what->is_week) -  return Week("ymd_yw",rules,y,w,what->number_of_weeks()); +  return Week("ymd_yw",rules,wy,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);    }      // --- Week to other units       int number_of_years()    { -  if (n<=1) return 1; +  if (n<=1 && y == wy) return 1;    -  [int y2,int w2,int wd2,int nd2,int jd2]=week_from_week(y,w+n); +  [int y2,int w2,int wd2,int nd2,int jd2]=week_from_week(wy,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();
pike.git/lib/modules/Calendar.pmod/YMD.pike:1990:    error("no such day %O in %O\n",mp[0],this);       return ::day(num);    }    else    return ::day(@mp);    }       cWeek set_ruleset(Calendar.Ruleset r)    { -  return Week("ymd_yjwm",r,y,yjd,jd,w,n,md,m,mnd); +  return Week("ymd_yjwm",r,y,yjd,jd,wy,w,n,md,m,mnd);    }      // --- needs to be defined       static int weeks_to_week(int y,int m);   }      // ----------------------------------------------------------------   // Day   // ----------------------------------------------------------------
pike.git/lib/modules/Calendar.pmod/YMD.pike:2046:    yjd=args[3];    jd=args[4];    yd=args[5];    n=args[6];    m=args[7];    md=args[8];    wy=args[9];    w=args[10];    wd=args[11];    mnd=args[12]; -  // Adjust according to julian day (typically to -  // correct the year in case weeks are involved). -  create_julian_day(jd); +     nw=CALUNKNOWN;    return;    case "ymd_yd":    rules=args[1];    y=args[2];    yjd=args[3];    jd=args[4];    yd=args[5];    n=args[6];    wy=wd=nw=md=m=w=CALUNKNOWN;
pike.git/lib/modules/Calendar.pmod/YMD.pike:2195:    month_day_name(),month_shortname());    }       string nice_print_period()    {   // return nice_print()+" n="+n+"";    if (!n) return nice_print()+" "+minute()->nice_print()+" sharp";    return nice_print()+" .. "+day(-1)->nice_print();    }    -  cDay beginning() +  TimeRange beginning()    {    return Day("ymd_ydmw",rules,y,yjd,jd,yd,0,m,md,wy,w,wd,mnd);    }    -  cDay end() +  TimeRange 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();