78fd532000-07-12Mirar (Pontus Hagland) // this is a script to generate rules // from timezone data files; // ftp://elsie.nci.nih.gov/pub/ // (timezone mailing list: tz@elsie.nci.nih.gov) // // source datafile are usually found somewhere around zic(8), // if they exist in the system. // // Most systems only have compiled files, just like pike, // and zic(8) is the usual compiler. // pike mkrules.pike ../data/{africa,antarctica,asia,australasia,backward,etcetera,europe,northamerica,pacificnew,southamerica,systemv}
fd37f52011-04-25Martin Stjernholm // $Id$
78fd532000-07-12Mirar (Pontus Hagland) 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
78fd532000-07-12Mirar (Pontus Hagland)  object cal=Calendar.ISO->set_timezone("UTC"); function Year=cal->Year; object nleapy=Year(1999); object tzrules; // needed to make timezones, compiled below mapping rules=([]); mapping zones=([]); mapping links=([]); array arules=({}); array azones=({});
b4b26c2012-05-17Henrik Grubbström (Grubba) mapping(string:mapping(int:array(string))) abbr2zones = ([ "DFT":([ 0x7fffffff:({ "Europe/Oslo", "Europe/Paris" }), ]), "NFT":([ 0x7fffffff:({ "Europe/Oslo", "Europe/Paris" }), ]),
630c4b2012-05-17Henrik Grubbström (Grubba) ]);
78fd532000-07-12Mirar (Pontus Hagland) #define FIXED(D) (yjd+((D)-1)) #define FIX_L(D) (yjd+leap+((D)-1)) #define LDAY(D,W) (yjd+((D)-1)-( (yjd+((D)+(8-W)-1)) % 7)) #define LDAYL(D,W) (yjd+((D)-1)+leap-( (yjd+leap+((D)+(8-W)-1)) % 7)) #define FIXID(id) replace(id,"/-+"/1,"__p"/1)
b4b26c2012-05-17Henrik Grubbström (Grubba) void add_abbr(string abbr, string zone, int until) { mapping(int:array(string)) zones = abbr2zones[abbr]; if (!zones) abbr2zones[abbr] = zones = ([]); zones[until] += ({ zone }); }
78fd532000-07-12Mirar (Pontus Hagland) int parse_offset(string t) { int h,m,s; string res; if (t=="0") return 0; res=""; if (sscanf(t,"-%d:%d:%d%s",h,m,s,res)&&res=="") return -(h*3600+m*60+s); res=""; if (sscanf(t,"-%d:%d%s",h,m,res)&&res=="") return -(h*3600+m*60); res=""; if (sscanf(t,"%d:%d:%d%s",h,m,s,res)&&res=="") return h*3600+m*60+s; res=""; if (sscanf(t,"-%d:%d%s",h,m,res)&&res=="") return h*3600+m*60; complain("failed to parse offset %O\n",t); } array parse_tod(string t) { int h,m,s; string res; if (t=="0") return 0; if (sscanf(t,"%d:%d:%d%s",h,m,s,res)==4) return ({h*3600+m*60+s,res}); res=""; if (sscanf(t,"%d:%d%s",h,m,res)==3) return ({h*3600+m*60,res}); if (sscanf(t,"%d%s",h,res)==2) return ({h*3600,res}); complain("failed to parse time of day %O\n",t); } class Shift { string dayrule; int time; string timetype; int offset; string s; string comment; void create(array a) { switch (sizeof(a)) { case 5: dayrule=think_day(a[0],a[1]); comment=a[0]+" "+a[1];
5fd96d2011-09-20Henrik Grubbström (Grubba)  // NB: The Morocco rule for 2011-07-31 has 0 as AT, // while all others have 0:00. [time,timetype] = parse_tod(a[2]) || ({ 0, "" });
78fd532000-07-12Mirar (Pontus Hagland)  switch (timetype) { case "": timetype="w"; break; case "s": case "u": case "w": break; default: complain("unknown time of day type %O\n",timetype); } offset=parse_offset(a[3]); s=(a[4]=="-")?"":a[4]; break; case 6: [dayrule,comment,time,timetype,offset,s]=a; break; default: error("illegal size of a\n"); } } string _sprintf(int t) { return (t=='O')? sprintf("Shift(%s,%d%s,%+d,%O)", dayrule,time,timetype,offset,s): 0; } int `==(Shift other) { return ( dayrule==other->dayrule && time==other->time && timetype==other->timetype && offset==other->offset && s==other->s ); } function(Shift:int) __equal=`==; constant wday=(["Mon":1,"Tue":2,"Wed":3,"Thu":4,"Fri":5,"Sat":6,"Sun":7]); constant vmonth=(<"Jan","Feb","Mar","Apr","May","Jun", "Jul","Aug","Sep","Nov","Dec">); string think_day(string mon,string rule) { int d; string ds; if (mon=="") return "0"; if (rule==(string)(d=(int)rule)) { if (mon=="Feb") return "FIXED("+(31+d)+")"; if (mon=="Jan") return "FIXED("+(d)+")"; return "FIX_L("+nleapy->month(mon)->day(d)->year_day()+")"; } else if (sscanf(rule,"last%s",ds)) { int wd=wday[ds]; if (!wd) complain("unknown weekday %O (last%s)\n",ds,ds); if (mon=="Jan") return "LDAY ("+31+","+wd+")"; return "LDAYL("+nleapy->month(mon)->day(-1)->year_day()+ ","+wd+")"; } else if (sscanf(rule,"%s>=%d",ds,d)) { int wd=wday[ds]; if (!wd) complain("unknown weekday %O (last%s)\n",ds,ds); if (d>24 && mon=="Feb") complain("can't handle Feb %d in a >= rule\n",d); if (mon=="Jan") return "LDAY ("+(nleapy->month(mon)->day(d)->year_day()+6)+ ","+wd+")"; return "LDAYL("+(nleapy->month(mon)->day(d)->year_day()+6)+ ","+wd+")"; } else if (sscanf(rule,"%s<=%d",ds,d)) { int wd=wday[ds]; if (!wd) complain("unknown weekday %O (last%s)\n",ds,ds); if (d>24 && mon=="Feb") complain("can't handle Feb %d in a <= rule\n",d); if (mon=="Jan" || mon=="Feb") return "LDAY ("+(nleapy->month(mon)->day(d)->year_day())+ ","+wd+")"; return "LDAYL("+(nleapy->month(mon)->day(d)->year_day())+ ","+wd+")"; } else complain("unknown rule method %O\n",rule); } Shift|array ``+(array|Shift s) {
563bd72004-01-11Martin Nilsson  if (!s) return this;
78fd532000-07-12Mirar (Pontus Hagland)  if (!arrayp(s)) s=({s});
563bd72004-01-11Martin Nilsson  return s+({this});
78fd532000-07-12Mirar (Pontus Hagland)  } int ldayl_is_fix_l(int d1,int wd,int d2,int yn1,int yn2) { object y1=Year(yn1); object y2=Year(yn2); int yjd,leap; yjd=y1->julian_day(); leap=y1->leap_year();
884d542000-11-08Fredrik Hübinette (Hubbe)  d1=LDAYL(d1,wd);
78fd532000-07-12Mirar (Pontus Hagland)  yjd=y2->julian_day(); leap=y2->leap_year();
884d542000-11-08Fredrik Hübinette (Hubbe)  d2=FIX_L(d2);
78fd532000-07-12Mirar (Pontus Hagland)  return d1==d2; } Shift try_promote(Shift t,int y0,int y1) { // this is year y0 // t is year y1
563bd72004-01-11Martin Nilsson  if (t==this) return t; // same!
78fd532000-07-12Mirar (Pontus Hagland)  if (t->time!=time || t->timetype!=timetype || t->offset!=offset || t->s!=s) return 0; // no chance int a,b,c; if (sscanf(dayrule,"LDAYL(%d,%d)",a,b)==2 && sscanf(t->dayrule,"FIX_L(%d)",c)==1) if (ldayl_is_fix_l(a,b,c,y0,y1))
563bd72004-01-11Martin Nilsson  return this; // ldayl
78fd532000-07-12Mirar (Pontus Hagland)  else return 0; // no if (sscanf(t->dayrule,"LDAYL(%d,%d)",a,b)==2 && sscanf(dayrule,"FIX_L(%d)",c)==1) if (ldayl_is_fix_l(a,b,c,y1,y0)) return t; // ldayl else return 0; // no return 0; } string dump(int lastoffset,multiset ys) { string t; array z=(array)ys; int l=Year(z[0])->leap_year(); foreach (z[1..],int y) if (Year(y)->leap_year()!=l) { l=2; break; } switch (timetype) { case "s": t=sprintf("UO%+d",time); break; case "u": t=""+time; break; case "w": t=sprintf("UO%+d",(time-lastoffset)); break; default: error("illegal state\n"); } string r=dayrule; if (l!=2) { int d,w; if (sscanf(r,"FIX_L(%d)",d)) r=sprintf("FIXED(%d)",d+l); else if (sscanf(r,"LDAYL(%d,%d)",d,w)==2) r=sprintf("LDAY (%d,%d)",d+l,w); } return sprintf("({%-12s,%-10s,%-5d,%-6O}), %s", r,t,offset,s,comment!=""?"// "+comment:""); } }
9b26302003-03-12Martin Nilsson class MyRule
78fd532000-07-12Mirar (Pontus Hagland) { string id; mapping rules=([]);
630c4b2012-05-17Henrik Grubbström (Grubba)  multiset(string) symbols = (<>);
78fd532000-07-12Mirar (Pontus Hagland)  int amt=0; void create(string _id) { id=_id; } void add(string line) { array a= array_sscanf(line, replace("%s %s %s %s %s %s %s %[^\t ]", " ","%*[ \t]")); if (sizeof(a)<8) complain("illegal rule line format\n");
630c4b2012-05-17Henrik Grubbström (Grubba)  a[7] = (a[7]/" #")[0]; if (a[7] == "-") a[7] = ""; symbols[a[7]] = 1;
78fd532000-07-12Mirar (Pontus Hagland)  if (!(int)a[0] && a[0]!="min") complain("unknown year %O\n",a[0]); // --- #define INF_YEAR 2050 #define NUL_YEAR 1850 int y1=(int)a[0] || NUL_YEAR; int y2; if (a[1]=="max") y2=INF_YEAR; else if (a[1]=="only") y2=y1; else if (!(y2=(int)a[1])) complain("unknown year %O\n",a[1]); else if (y2>=INF_YEAR) complain("big year\n"); Shift sh=Shift(a[3..]); switch (a[2]) { case "-": for (;y1<=y2;y1++) rules[y1]+=sh; break; case "odd": if (!(y1&1)) y1++; for (;y1<=y2;y1+=2) rules[y1]+=sh; break; case "even": if ((y1&1)) y1++; for (;y1<=y2;y1+=2) rules[y1]+=sh; break; default: complain("unknown year type %O\n",a[2]); } } string dump() { mapping r2=([]); Shift last=Shift(({"0","?",0,"u",0,"?"})); Shift first=last; string res=""; if (!r2[NUL_YEAR]) r2[NUL_YEAR]=({last});
5de3c42000-10-21Martin Nilsson  for (int y=min(@indices(rules));y<=INF_YEAR; y++)
78fd532000-07-12Mirar (Pontus Hagland)  [r2[y],last]=mkperiods(rules[y],last,first); res+=("class "+ FIXID(id)+"\n" "{\n" " inherit TZRules;\n"
beb21d2008-06-28Martin Nilsson  " protected array(array(string|int)) jd_year_periods(int jd)\n"
78fd532000-07-12Mirar (Pontus Hagland)  " {\n" " [int y,int yjd,int leap]=gregorian_yjd(jd);\n" " switch (y)\n" " {\n"); string s="",t;
5de3c42000-10-21Martin Nilsson  int mn=min(@indices(rules-(<NUL_YEAR>)));
78fd532000-07-12Mirar (Pontus Hagland) 
5de3c42000-10-21Martin Nilsson  for (int y=INF_YEAR;sizeof(r2);y--)
78fd532000-07-12Mirar (Pontus Hagland)  if (r2[y]) { array z=r2[y]; multiset my=(<y>); foreach (indices(r2),int y2) if (join_periods(z,r2[y2],y,y2)) my[y2]=1; foreach ((array)my,int y2) m_delete(r2,y2); string t=""; int y0=min(@(array)my); int y2=max(@(array)my); for (; y0<=y2; y0++) if (my[y0]) { int y1=y0; while (my[++y1]); y1--; if (y0==NUL_YEAR) { if (my[INF_YEAR]) t+=" default: // .."+max(y1,mn-1)+ " and ½½½..\n"; else t+=" default: // .."+max(y1,mn-1)+":\n"; } else if (y0==y1) t+=" case "+y0+":\n"; else if (y1==2050) { if (!my[NUL_YEAR]) t+=" case "+y0+"..:\n"; else t=replace(t,"½½½",(string)y0); } else t+=" case "+y0+".."+y1+":\n"; y0=y1; } int lastoffset=0; string res=" "*12+"return ({"; foreach (z,Shift s) { res+=s->dump(lastoffset,my)+("\n"+" "*21); lastoffset=s->offset; } array resa=res/"\n"; resa[-2]=replace(resa[-2],", ","});");
8a531a2006-11-04Martin Nilsson  t+=resa[..<1]*"\n"+"\n";
78fd532000-07-12Mirar (Pontus Hagland)  s=t+s; } res+=(s+ " }\n" " }\n" "}\n\n"); return res; } int join_periods(array s,array t,int y0,int y1) { if (equal(s,t)) return 1; if (sizeof(s)!=sizeof(t)) return 0; if (s[0]!=t[0]) return 0; // try promote array q=s[..0]; int i; for (i=1; i<sizeof(s); i++) { Shift u=s[i]->try_promote(t[i],y0,y1); if (!u) return 0; q+=({u}); } for (i=1; i<sizeof(s); i++) s[i]=q[i]; // destructive return 1; } array(array(Shift)|Shift) mkperiods(array|Shift s,Shift last,Shift first) { if (!s) s=({}); if (!arrayp(s)) s=({s}); sort(map(s,lambda(Shift s) { return array_sscanf(s->dayrule,"%*[^(](%d")[0]; }),s); if (first->s=="?") foreach (s,Shift d) if (!d->offset) first->s=d->s; s=({last,@s}); last=Shift( ({"0","",0,"u", s[-1]->offset,s[-1]->s}) ); return ({s, last}); } } class Zone { string id; array rules=({}); void create(string _id) { id=_id; } void add(string line) { array a= array_sscanf(line, replace("%s %s %s %s", " ","%*[ \t]")); if (sizeof(a)<4) complain("parse error\n");
5de3c42000-10-21Martin Nilsson  a=({parse_offset(a[0]), // offset a[1], // rule or added offset a[2], // string a[3], 0, 0, "tz", 0}); // until
78fd532000-07-12Mirar (Pontus Hagland)  a[5]=rule_shift(a); a[4]=clone_rule(a);
630c4b2012-05-17Henrik Grubbström (Grubba)  if (sizeof(a[2])) {
b4b26c2012-05-17Henrik Grubbström (Grubba)  int until = (a[5] == "forever")?0x7fffffff:(int)a[5];
630c4b2012-05-17Henrik Grubbström (Grubba)  foreach(a[2]/"/", string fmt) { MyRule rule = global::rules[a[1]]; if (rule) { foreach(indices(rule->symbols), string sym) { if ((sizeof(sym) > 2) && (fmt != "%s")) continue;
b4b26c2012-05-17Henrik Grubbström (Grubba)  add_abbr(sprintf(fmt, sym), id, until);
630c4b2012-05-17Henrik Grubbström (Grubba)  } } else if (a[1] == "Romania") { // Kludge for forward reference in tzdata2012c/europe // for Europe/Chisinau to the Romania rule. foreach(({ "", "S" }), string sym) {
b4b26c2012-05-17Henrik Grubbström (Grubba)  add_abbr(sprintf(fmt, sym), id, until);
630c4b2012-05-17Henrik Grubbström (Grubba)  } } else {
b4b26c2012-05-17Henrik Grubbström (Grubba)  add_abbr(fmt, id, until);
630c4b2012-05-17Henrik Grubbström (Grubba)  } } }
78fd532000-07-12Mirar (Pontus Hagland)  rules+=({a}); } string clone_rule(array a) { int h,m,s,roff=-17; if (a[1]=="-") roff=0; else if (sscanf(a[1],"-%d:%d:%d",h,m,s)==3) roff=h*3600+m*60+s; else if (sscanf(a[1],"%d:%d:%d",h,m,s)==3) roff=h*3600+m*60+s; else if (sscanf(a[1],"-%d:%d",h,m)==2) roff=h*3600+m*60; else if (sscanf(a[1],"%d:%d",h,m)==2) roff=h*3600+m*60; if (roff==-17) // based on DST rule return sprintf( "TZrules.%s(%d,%O)", FIXID(a[1]),-a[0],a[2]); else // simple timezone return sprintf(
9b26302003-03-12Martin Nilsson  "Rule.Timezone(%d,%O)",
78fd532000-07-12Mirar (Pontus Hagland)  -(roff+a[0]),a[2]); } string rule_shift(array a) { if (a[3]=="" || a[3][0]=='#') return "forever"; string in=a[3]; sscanf(in,"until %s",in); sscanf(in,"%s#",in); // werror("%O\n",in); int y,d=1,t=0; string mn="Jan",ty="w"; if (sscanf(in,"%d%*[ \t]%s%*[ \t]%d%*[ \t]%[^# \t]", y,mn,d,string tod)==7 && tod!="") [t,ty]=parse_tod(tod); else if (!(sscanf(in,"%d%*[ \t]%[A-Za-z]%*[ \t]%d",y,mn,d)==5 || (sscanf(in,"%d%*[ \t]%[A-Za-z]",y,mn)==3 && mn!="") || (mn="Jan",sscanf(in,"%d",y)))) { // werror("%O\n",array_sscanf(in,"%d%*[ \t]%[A-Za-z]")); complain("failed to understand UNTIL %O\n",in); y=2000; } int utc0=Year(y)->month(mn)->day(d)->unix_time(); switch (ty) { case "u": // utc time // a[3]=sprintf("[%d+%d=%d] %s\n",utc0,t,utc0+t,a[3]); return (string)(utc0+t); break; case "s": // local standard time // a[3]=sprintf("[%d+%d-%d=%d] %s\n",utc0,t,a[0],utc0+t-a[0],a[3]); return (string)(utc0+t-a[0]); break; case "w": case "": // with rule; check rule int h,m,s,roff=-17; if (a[1]=="-") roff=0; else if (sscanf(a[1],"-%d:%d:%d",h,m,s)==3) roff=h*3600+m*60+s; else if (sscanf(a[1],"%d:%d:%d",h,m,s)==3) roff=h*3600+m*60+s; else if (sscanf(a[1],"-%d:%d",h,m)==2) roff=h*3600+m*60; else if (sscanf(a[1],"%d:%d",h,m)==2) roff=h*3600+m*60; if (roff==-17) // based on DST rule { if (!tzrules) return 0; // can't do that now object|program rules=tzrules[FIXID(a[1])]; if (!rules) { werror("ERROR: Missing rule %O (used in Zone %O)\n",a[1],id); return "[err]"; } rules=rules(-a[0],"-"); roff=rules->tz_jd(Year(y)->month(mn)->day(d)->julian_day())[0]; // werror("Using %O:%O\n",rules,roff); return (string)(utc0+t-roff); } return (string)(utc0+t-a[0]-roff); default: complain("unknown time of day modifier %O\n",ty); } } string dump() { string cid=FIXID(id); string res=""; if (!sizeof(rules)) { res+=("// skipped %O due to errors\n",id); return res; } if (sizeof(rules)==1) // simple zone {
9b26302003-03-12Martin Nilsson  res+=("Rule.Timezone "+cid+"="+
78fd532000-07-12Mirar (Pontus Hagland)  rules[0][4]+";\n"); return res; } mapping rname=([]); int n=1; foreach (rules,array a) if (rname[a[4]]) a[6]=rname[a[4]]; else a[6]=rname[a[4]]="tz"+n++; res+=("class "+cid+"\n" "{\n" " inherit TZHistory;\n"
9b26302003-03-12Martin Nilsson  " Rule.Timezone "+
78fd532000-07-12Mirar (Pontus Hagland)  sort(values(rname))*","+";\n"
9b26302003-03-12Martin Nilsson  " Rule.Timezone whatrule(int ux)\n"
78fd532000-07-12Mirar (Pontus Hagland)  " {\n" ); foreach (rules,array a) { if (!a[5]) a[5]=rule_shift(a); string s=""; sscanf(a[3],"%s#%*[ \t]%s",a[3],s); a[3]="from "+reverse(array_sscanf(reverse(a[3]),"%*[ \t]%s")[0]); a[7]=s; } array last=rules[-1];
5de3c42000-10-21Martin Nilsson  n=sizeof(rules);
78fd532000-07-12Mirar (Pontus Hagland)  foreach (reverse(rules)[1..],array a) { res+=sprintf(" if (ux>=%s) // %s %s\n" " return %s || (%s=%s);\n", a[5],a[3],last[7],last[6],last[6],last[4]); n--; last=a; } if (last[7]!="") res+=sprintf(" // %s\n",last[7]); res+=sprintf(" return %s || (%s=%s);\n", last[6],last[6],last[4]); res+=(" }\n" "}\n"); return res; } } void complain(string fmt,mixed ... args) { throw( sprintf(fmt,@args) ); } void collect_rules(string file) { int n=0; werror("reading %O...\n",file); string s=Stdio.read_bytes(file),t; if (!s) { werror("%s:-: Failed to open file: %s\n",file,strerror(errno())); return; } Zone lastz;
9b26302003-03-12Martin Nilsson  MyRule lastr;
78fd532000-07-12Mirar (Pontus Hagland)  foreach (s/"\n",string line) { n++; mixed err=catch { if (line[..0]!="#") if (sscanf(line,"Zone%*[ \t]%[^ \t]%*[ \t]%s",s,t)==4) { if (zones[s]) lastz=zones[s]->add(t); else (lastz=zones[s]=Zone(s))->add(t),azones+=({lastz}); } else if (sscanf(line,"Rule%*[ \t]%[^ \t]%*[ \t]%s",s,t)==4) { if (rules[s]) rules[s]->add(t);
9b26302003-03-12Martin Nilsson  else (lastr=rules[s]=MyRule(s))->add(t),arules+=({lastr});
78fd532000-07-12Mirar (Pontus Hagland)  lastz=0; } else if (sscanf(line,"Link%*[ \t]%[^ \t]%*[ \t]%[^ \t]",s,t)==4) { // link t to s if (links[s]) links[s]+=({t}); else links[s]=({t}); }
ead9722003-01-20Martin Nilsson  else if (sscanf(line,"%*[ \t]%[-0-9]%s",s,t)==3 && sizeof(s))
78fd532000-07-12Mirar (Pontus Hagland)  { if (!lastz) complain("implicit zone line w/o zone\n"); lastz->add(s+t); } else if ((t="",sscanf(line,"%[ \t]",t),t==line)) ;
6537062008-05-18Henrik Grubbström (Grubba)  else if (sscanf(line,"%*[ \t]#%s",t)==2)
78fd532000-07-12Mirar (Pontus Hagland)  ; else complain("unknown keyword %O...\n",line[..10]); }; if (err) if (stringp(err)) werror("%s:%d: %s",file,n,err); else throw(err); } } int main(int ac,array(string) am) {
1b76902009-05-12Henrik Grubbström (Grubba)  array(string) files = am[1..]; if (!sizeof(files))
78fd532000-07-12Mirar (Pontus Hagland)  {
1b76902009-05-12Henrik Grubbström (Grubba)  werror("defaulting to reading zonefiles from %s...", combine_path(__FILE__, "../tzdata")); files = get_dir(combine_path(__FILE__, "../tzdata")); files = map(sort(files), lambda(string fname) {
00bbec2014-10-16Henrik Grubbström (Grubba)  if ((< ".gitignore", "Makefile", "Theory", "factory", "leapseconds", >)[fname] || (upper_case(fname) == fname) ||
1b76902009-05-12Henrik Grubbström (Grubba)  has_prefix(fname, "solar") ||
00bbec2014-10-16Henrik Grubbström (Grubba)  has_suffix(fname, ".awk") || has_suffix(fname, ".list") || has_suffix(fname, ".pl") ||
1b76902009-05-12Henrik Grubbström (Grubba)  has_suffix(fname, ".sh") || has_suffix(fname, ".tab")) return 0; return combine_path(__FILE__, "../tzdata", fname); }) - ({ 0 });
78fd532000-07-12Mirar (Pontus Hagland)  }
1b76902009-05-12Henrik Grubbström (Grubba)  map(files, collect_rules);
78fd532000-07-12Mirar (Pontus Hagland)  write("thinking...\n"); string t=TZrules_base;
9b26302003-03-12Martin Nilsson  foreach (arules,MyRule r)
78fd532000-07-12Mirar (Pontus Hagland)  t+=r->dump(); tzrules=compile_string(t)(); mv("TZrules.pmod","TZrules.pmod~");
ead9722003-01-20Martin Nilsson  werror("writing TZrules.pmod (%d bytes)...",sizeof(t));
78fd532000-07-12Mirar (Pontus Hagland)  Stdio.File("TZrules.pmod","wtc")->write(t); werror("\n"); t="// ----------------------------------------------------------------\n" "// Timezones\n" "//\n" "// NOTE: this file is generated by mkrules.pike;\n" "// please do not edit manually /Mirar\n" "// ----------------------------------------------------------------\n" "\n" "import \".\";\n\n"; t+=("// "+"-"*70+"\n" "// Timezones\n" "// "+"-"*70+"\n\n"); mixed err=catch { foreach (azones,Zone z) if (sizeof(z->rules)==1) { t+=z->dump(); if (links[z->id]) foreach(links[z->id],string s)
9b26302003-03-12Martin Nilsson  t+="Rule.Timezone "+FIXID(s)+"="+
78fd532000-07-12Mirar (Pontus Hagland)  FIXID(z->id)+";\n"; } }; if (err) if (stringp(err)) error(err); else throw(err); t+=("\n" "// "+"-"*70+"\n" "// Timezones with an attitude\n" "// "+"-"*70+"\n" "\n");
5de3c42000-10-21Martin Nilsson  err=catch {
78fd532000-07-12Mirar (Pontus Hagland)  foreach (azones,Zone z) if (sizeof(z->rules)!=1) { t+=z->dump(); if (links[z->id]) foreach(links[z->id],string s) t+="constant "+FIXID(s)+"="+ FIXID(z->id)+";\n"; t+="\n"; } }; if (err) if (stringp(err)) error(err); else throw(err); t+=("\n" "// "+"-"*70+"\n");
630c4b2012-05-17Henrik Grubbström (Grubba)  mv("TZs.h","TZs.h~");
ead9722003-01-20Martin Nilsson  werror("writing TZs.h (%d bytes)...",sizeof(t));
78fd532000-07-12Mirar (Pontus Hagland)  Stdio.File("TZs.h","wtc")->write(t); werror("\n"); mapping zs=([]); foreach (azones,Zone z) if (sscanf(z->id,"%s/%s",string s,string t)==2) zs[s]=(zs[s]||({}))+({t});
54add72009-05-12Henrik Grubbström (Grubba)  // Read and parse the original TZnames.pmod file. string orig_names = Stdio.read_bytes("TZnames.pmod"); array(string) fragments = orig_names/" zones="; if (sizeof(fragments) == 1) fragments = orig_names/" zones ="; if (sizeof(fragments) > 2) fragments = ({ fragments[0], fragments[1..] * " zones =" }); fragments[1] = (fragments[1]/"]);\n\n")[1..]*"]);\n\n"; t = fragments[0] + " zones =\n" "([\n"; multiset(string) zone_names = (multiset)indices(zs); zone_names->SystemV = 0; zone_names->Etc = 0; // Historical ordering... foreach (({"America", "Pacific", "Antarctica", "Atlantic", "Indian", "Europe", "Africa", "Asia", "Australia" }), string co) {
27a57e2012-04-28Henrik Grubbström (Grubba)  t += sprintf(" %-13s({%-=60s\n",
54add72009-05-12Henrik Grubbström (Grubba)  sprintf("%O:",co), map(zs[co],lambda(string s) { return sprintf("%O",s); })
27a57e2012-04-28Henrik Grubbström (Grubba)  *", "+"}),");
54add72009-05-12Henrik Grubbström (Grubba)  zone_names[co] = 0; } // Take care of any remaining zones (probably none).
27a57e2012-04-28Henrik Grubbström (Grubba)  foreach (sort(indices(zone_names)),string co) { t += sprintf(" %-13s({%-=60s\n",
78fd532000-07-12Mirar (Pontus Hagland)  sprintf("%O:",co), map(zs[co],lambda(string s) { return sprintf("%O",s); })
27a57e2012-04-28Henrik Grubbström (Grubba)  *", "+"}),"); }
54add72009-05-12Henrik Grubbström (Grubba)  t += "]);\n\n" +
630c4b2012-05-17Henrik Grubbström (Grubba)  fragments[1]; // Update the abbreviation table as well. fragments = t/" abbr2zones="; if (sizeof(fragments) == 1) fragments = t/" abbr2zones ="; if (sizeof(fragments) > 2) fragments = ({ fragments[0], fragments[1..] * " abbr2zones =" }); fragments[1] = (fragments[1]/"]);\n\n")[1..]*"]);\n\n"; t = fragments[0] + " abbr2zones =\n" "([\n"; foreach(sort(indices(abbr2zones)), string abbr) { string line = sprintf(" %q: ({", abbr);
b4b26c2012-05-17Henrik Grubbström (Grubba)  mapping(int:array(string)) info = abbr2zones[abbr]; array(string) zones = ({}); array(int) until = ({}); foreach(info; int us; array(string) zs) { zones += zs; until += allocate(sizeof(zs), -us); } // Sort so that the most recent use comes first, // and secondarily on the zone name. sort(zones, until); sort(until, zones); foreach(Array.uniq(zones); int i; string zone) {
630c4b2012-05-17Henrik Grubbström (Grubba)  string seg = sprintf("%s%q", i?", ":"", zone); if (sizeof(line) + sizeof(seg) < 77) { line += seg; continue; } t += line + ",\n"; line = sprintf(" %q", zone); } t += line + "}),\n"; } t += "]);\n\n" + fragments[1];
27a57e2012-04-28Henrik Grubbström (Grubba)  // Cleanup white-space at end of line. string t2 = t; while ((t = replace(t2, ({ " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", }), ({ "\n" })*8)) != t2) { t2 = t; }
78fd532000-07-12Mirar (Pontus Hagland) 
54add72009-05-12Henrik Grubbström (Grubba)  mv("TZnames.pmod","TZnames.pmod~");
ead9722003-01-20Martin Nilsson  werror("writing TZnames.pmod (%d bytes)...",sizeof(t));
78fd532000-07-12Mirar (Pontus Hagland)  Stdio.File("TZnames.pmod","wtc")->write(t); werror("\n"); return 0; } string TZrules_base= #"// ---------------------------------------------------------------- // Daylight savings and war time rules // // NOTE: this file is generated by mkrules.pike; // please do not edit manually /Mirar // ---------------------------------------------------------------- // ---------------------------------------------------------------- // all rules are based on the gregorian calendar, so // this is the gregorian rule: // ----------------------------------------------------------------
beb21d2008-06-28Martin Nilsson protected array gregorian_yjd(int jd)
78fd532000-07-12Mirar (Pontus Hagland) { int d=jd-1721426; int century=(4*d+3)/146097; int century_jd=(century*146097)/4; int century_day=d-century_jd; int century_year=(100*century_day+75)/36525; int y=century*100+century_year+1; return ({ y, 1721426+century_year*365+century_year/4+century_jd, (!(((y)%4) || (!((y)%100) && ((y)%400)))) }); } // ---------------------------------------------------------------- // Base \"Timezone with rules\" class // ---------------------------------------------------------------- class TZRules { constant is_timezone=1; constant is_dst_timezone=1;
beb21d2008-06-28Martin Nilsson  protected int offset_to_utc;
78fd532000-07-12Mirar (Pontus Hagland)  string name;
beb21d2008-06-28Martin Nilsson  protected function(string:string) tzformat; protected array names;
78fd532000-07-12Mirar (Pontus Hagland) 
beb21d2008-06-28Martin Nilsson  protected void create(int offset,string _name)
78fd532000-07-12Mirar (Pontus Hagland)  { offset_to_utc=offset; name=_name;
3b6a322003-08-07Martin Nilsson  if (has_value(name, \"/\"))
78fd532000-07-12Mirar (Pontus Hagland)  { names=name/\"/\"; tzformat=lambda(string s) { if (s==\"\") return names[0]; else return names[1]; }; } else tzformat=lambda(string s) { return sprintf(name,s); }; } // the Rule: // which julian day does dst start and end this year?
beb21d2008-06-28Martin Nilsson  protected array(array(string|int)) jd_year_periods(int jd);
78fd532000-07-12Mirar (Pontus Hagland)  // is (midnight) this julian day dst? array tz_jd(int jd) { array(array(string|int)) a=jd_year_periods(jd); int i=0,n=sizeof(a)-1; while (i<n) { array b=a[i+1]; if (jd<b[0]) break; if (jd==b[0] && -offset_to_utc+b[1]>=0) break; i++; } return ({offset_to_utc-a[i][2],tzformat(a[i][3])}); } // is this unixtime (utc) dst? array tz_ux(int ux) { int jd=2440588+ux/86400; array(array(string|int)) a=jd_year_periods(jd); int i=0,n=sizeof(a)-1; while (i<n) { array b=a[i+1]; if (jd<b[0]-1) break; if (jd<b[0]+1 && ux<(b[0]-2440588)*86400+b[1]) break; i++; } return ({offset_to_utc-a[i][2],tzformat(a[i][3])}); } string _sprintf(int t) { return (t=='O')?\"Timezone(\"+name+\")\":0; } int raw_utc_offset() { return offset_to_utc; } } // ---------------------------------------------------------------------- // DST Rules // ---------------------------------------------------------------------- // useful macros #define FIXED(D) (yjd+((D)-1)) #define FIX_L(D) (yjd+leap+((D)-1)) #define LDAY(D,W) (yjd+((D)-1)-( (yjd+((D)+(8-W)-1)) % 7)) #define LDAYL(D,W) (yjd+((D)-1)+leap-( (yjd+leap+((D)+(8-W)-1)) % 7)) #define UO offset_to_utc // ---------------------------------------------------------------------- ";