diff --git a/lib/modules/Calendar.pmod/Stardate.pmod b/lib/modules/Calendar.pmod/Stardate.pmod index 47b4abb797024ad1451ef64dd9e1fb6451616f5d..d81099120599e7354bbef06cc11204f2e0629662 100644 --- a/lib/modules/Calendar.pmod/Stardate.pmod +++ b/lib/modules/Calendar.pmod/Stardate.pmod @@ -1,108 +1,305 @@ +//! module Calendar //! submodule Stardate -//! time unit: TNGDate +//! This implements TNG stardates. -//! class TNGDate -//! implements ST:TNG stardates -//! can be used as create argument to Day +import "."; -#pike __VERSION__ +inherit TimeRanges; -class TNGDate -{ - inherit Calendar._TimeUnit; +static constant TNGSTARPERJULIAN=1000.0/365.2425; +static constant TNGSTARPERSECOND=TNGSTARPERJULIAN/86400; +static constant TNG0JULIAN=2569518.5; +static constant TNG0UNIX=11139552000; + +string calendar_name() { return "Stardate"; } - // 40759.5 2363-10-05 2584405 - // 47391.2 2370-05-23 2586827 +function(mixed...:cTick) Tick=cTick; +class cTick +{ + inherit TimeRange; - // 50893.5 2373-11-23 2588107 + constant is_stardate=1; - // 6631.7 ---------- 2422 - // 10134.0 ---------- 3702 - // 1000.0 ---------- 365.2425 - // 0.0 - - 2569519 -#define TNGSTARPERJULIAN (1000.0/365.2425) + float tick; + float len; -//-- variables ------------------------------------------------------ +//! method void create(mixed ...) +//! method void create(int|float date) +//! method void create() +//! Apart from the standard creation methods +//! (julian day, etc), you can create a stardate +//! from the stardate number. The length +//! of the period will then be zero. +//! +//! You can also omit any arguments to create now. +//! +//! known bugs: +//! Since the precision is limited to the float type +//! of pike you can get non-precise results: +//! +//! <pre> +//! > Calendar.Second(Calendar.Stardate.Day(Calendar.Year())); +//! Result: Second(Fri 31 Dec 1999 23:59:18 CET - Sun 31 Dec 2000 23:59:18 CET) +//! </pre> - float jd; - float tics; - -//-- standard methods ----------------------------------------------- - void create(int|float|object ... day) + void create(mixed ...args) { - float jd; - if (!sizeof(day)) - day=({Calendar.Gregorian.Second()}); - else if (floatp(day[0])) + switch (sizeof(args)) { - from_stardate(day[0]); - return; - } - if (!intp(day[0])) - { - object o=day[0]; - - if (o->julian_day || o->julian_day_f) - jd=(float)(o->julian_day_f||o->julian_day)(); - else // dig - if (o->day) // larger + case 4: + // internal + if (args[0]=="stardate") { - o=o->day(0); - if (o->julian_day_f) - jd=o->julian_day_f(); - else if (o->julian_day) - jd=(float)o->julian_day(); - else - ; // error, like + rules=args[1]; + tick=args[2]; + len=args[3]; + return; } - else // smaller + break; + case 1: + if (intp(args[0]) || floatp(args[0])) { - float z=1.0; - while (sizeof(o->greater())) - { - string name=o->is(); - o=o[o->greater()[0]](); - z*=o["number_of_"+name+"s"](); - if (o->julian_day_f || o->julian_day) - { - jd=(o->julian_day||o->julian_day_f)()/z; - break; - } - } + rules=default_rules; + tick=(float)args[0]; + len=0.0; + return; } + break; + case 0: + rules=default_rules; + create_unixtime_default(time()); + return; + } + rules=default_rules; + ::create(@args); + } + + static void create_unixtime(int unixtime,int seconds) + { + tick=(unixtime-TNG0UNIX)*TNGSTARPERSECOND; + len=seconds*TNGSTARPERSECOND; + } + + static void create_unixtime_default(int unixtime) + { + tick=(unixtime-TNG0UNIX)*TNGSTARPERSECOND; + len=0.0; + } + + static void create_julian_day(int|float jd) + { + tick=(jd-TNG0JULIAN)*TNGSTARPERJULIAN; + len=0.0; + } + +//! method float tics() +//! This gives back the number of stardate tics +//! in the period. + + float tics() + { + return len; + } + +//! method int number_of_seconds() +//! method int number_of_days() +//! This gives back the Gregorian/Earth/ISO number of seconds +//! and number of days, for convinience and conversion to +//! other calendars. + + int number_of_seconds() + { + return (int)(len/TNGSTARPERSECOND); + } + + int number_of_days() + { + return (int)(len/TNGSTARPERJULIAN); + } + + int unix_time() + { + return ((int)(tick/TNGSTARPERSECOND))+TNG0UNIX; + } + + float julian_day() + { + return ((int)(tick/TNGSTARPERJULIAN))+TNG0JULIAN; + } + + TimeRange add(int n,void|this_program step) + { + float x; + if (!step) + x=len; + else + { + if (!step->is_stardate) + error("add: Incompatible type %O\n",step); + x=step->len; + } + + + if (n&&x) + return Tick("stardate",rules,tick+x,len); + return this_object(); + } + + static void convert_from(TimeRange other) + { + if (other->unix_time) + create_unixtime_default(other->unix_time()); + else + ::convert_from(other); + if (other->is_stardate) + { + tick=other->tick; + len=other->len; } + else if (other->number_of_seconds) + len=TNGSTARPERSECOND*other->number_of_seconds(); + else if (other->number_of_days) + len=TNGSTARPERJULIAN*other->number_of_days(); + else + len=0.0; + } + + static TimeRange _set_size(int n,TimeRange x) + { + if (!x->is_stardate) + error("distance: Incompatible type %O\n",x); + return Tick("stardate",rules,tick,x->len); + } + + TimeRange place(TimeRange what,void|int force) + { +// can't do this + return this_object(); + } + + array(TimeRange) split(int n) + { + if (!n) return ({this_object()}); // foo + + float z=tick; + float l=len/n; + array(TimeRange) res=({}); + + while (n--) + res+=({Tick("stardate",rules,z,l)}),z+=l; + + return res; + } + + TimeRange beginning() + { + if (!len) return this_object(); + return Tick("stardate",rules,tick,0.0); + } + + TimeRange end() + { + if (!len) return this_object(); + return Tick("stardate",rules,tick+len,0.0); + } + + TimeRange distance(TimeRange to) + { + if (!to->is_stardate) + error("distance: Incompatible type %O\n",to); + if (to->tick<tick) + error("negative distance\n"); + return Tick("stardate",rules,tick,to->tick-tick); + } + + array _compare(TimeRange with) + { + float b1=tick; + float e1=tick+len; + float b2,e2; + if (with->is_stardate) + b2=with->tick,e2=b2+with->len; else - jd=(float)day[0]; - from_julian_day(jd); + ::_compare(with); +#define CMP(A,B) ( ((A)<(B))?-1:((A)>(B))?1:0 ) + return ({ CMP(b1,b2),CMP(b1,e2),CMP(e1,b2),CMP(e1,e2) }); } - static void from_stardate(float f) + int __hash() { return (int)tick; } + + cTick set_ruleset(Ruleset r) { - tics=f; - jd=f/TNGSTARPERJULIAN+2569518.5; + return Tick("stardate",r,tick,len); } - static void from_julian_day(float f) + string _sprintf(int t) { - jd=f; - tics=(f-2569518.5)*TNGSTARPERJULIAN; + switch (t) + { + case 'O': + if (len!=0.0) + return sprintf("Tick(%s)",nice_print_period()); + return sprintf("Tick(%s)",nice_print()); + default: + return 0; + } } -//-- nonstandard methods -------------------------------------------- + string nice_print_period() + { + if (len>0.010) + return sprintf("%s..%s",nice_print(),end()->nice_print()); + else + return sprintf("%s..%+g",nice_print(),len); + } - float number() + string nice_print() { - return tics; + return sprintf("%.3f",tick); } - - int julian_day() + +//! string format_long() +//! string format_short() +//! string format_vshort() +//! Format the stardate tick nicely. +//! <pre> +//! long "-322537.312" +//! short "77463.312" (w/o >100000-component) +//! short "7463.312" (w/o >10000-component) +//! </pre> + + string format_long() { - return (int)jd; + return sprintf("%.3f",tick); } - float julian_day_f() + string format_short() { - return jd; + return sprintf("%.3f",tick-((int)tick/100000)*100000); } + + string format_vshort() + { + return sprintf("%.3f",tick-((int)tick/10000)*10000); + } +} + +// compat +function(mixed...:cTick) TNGDate=cTick; + +// for events +function(mixed...:cTick) Day=cTick; + +//------------------------------------------------------------------------ +// global convinience functions +//------------------------------------------------------------------------ + +//! method TimeofDay now() +//! Give the zero-length time period of the +//! current time. + +TimeofDay now() +{ + return Tick(); }