diff options
author | tadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-02-26 08:10:03 +0000 |
---|---|---|
committer | tadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2011-02-26 08:10:03 +0000 |
commit | fdf361189c2f0f695cd1f91177281725e6753c7b (patch) | |
tree | e3b813889a79ac3d7eca4efcacc600aec7acde47 | |
parent | b08efdee966ca5daf7d71cf183e6e653c64e7954 (diff) | |
download | ruby-fdf361189c2f0f695cd1f91177281725e6753c7b.tar.gz |
* lib/date.rb: [Feature #4257]
* ext/date/extconf.rb: new
* ext/date/date_core.c: new
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30961 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | ext/date/date_core.c | 3629 | ||||
-rw-r--r-- | ext/date/extconf.rb | 4 | ||||
-rw-r--r-- | lib/date.rb | 363 |
4 files changed, 3837 insertions, 167 deletions
@@ -1,3 +1,11 @@ +Sat Feb 26 17:07:53 2011 Tadayoshi Funaba <tadf@dotrb.org> + + * lib/date.rb: [Feature #4257] + + * ext/date/extconf.rb: new + + * ext/date/date_core.c: new + Sat Feb 26 16:10:23 2011 Shota Fukumori <sorah@tubusu.net> * lib/test/unit.rb: --jobs-status won't puts over 2 lines. diff --git a/ext/date/date_core.c b/ext/date/date_core.c new file mode 100644 index 0000000000..f6d1f74b71 --- /dev/null +++ b/ext/date/date_core.c @@ -0,0 +1,3629 @@ +/* + date_core.c: Coded by Tadayoshi Funaba 2010, 2011 +*/ + +#include "ruby.h" +#include "ruby/encoding.h" +#include <math.h> +#include <time.h> + +#define NDEBUG +#include <assert.h> + +#ifdef RUBY_EXTCONF_H +#include RUBY_EXTCONF_H +#endif + +#ifndef HAVE_FLOORL +#define floorl(x) ((long double)floor((double)(x))) +#endif +#ifndef HAVE_ROUNDL +#define roundl(x) ((long double)round((double)(x))) +#endif + +#define LIGHT_MODE (1 << 0) +#define HAVE_JD (1 << 1) +#define HAVE_DF (1 << 2) +#define HAVE_CIVIL (1 << 3) +#define HAVE_TIME (1 << 4) + +#define light_mode_p(x) ((x)->flags & LIGHT_MODE) +#define have_jd_p(x) ((x)->flags & HAVE_JD) +#define have_df_p(x) ((x)->flags & HAVE_DF) +#define have_civil_p(x) ((x)->flags & HAVE_CIVIL) +#define have_time_p(x) ((x)->flags & HAVE_TIME) + +#define MIN_YEAR -4713 +#define MAX_YEAR 1000000 +#define MIN_JD -327 +#define MAX_JD 366963925 + +#define LIGHTABLE_JD(j) (j >= MIN_JD && j <= MAX_JD) +#define LIGHTABLE_YEAR(y) (y >= MIN_YEAR && y <= MAX_YEAR) +#define LIGHTABLE_CWYEAR(y) LIGHTABLE_YEAR(y) + +#define ITALY 2299161 + +#define DAY_IN_SECONDS 86400 +#define SECOND_IN_NANOSECONDS 1000000000 +#define DAY_IN_NANOSECONDS 86400000000000LL + +/* copied from time.c */ +#define NDIV(x,y) (-(-((x)+1)/(y))-1) +#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) +#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) +#define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d)) + +union DateData +{ + unsigned flags; + struct { + unsigned flags; + VALUE ajd; + VALUE of; + VALUE sg; + VALUE cache; + } r; + struct { + unsigned flags; + long jd; /* as utc */ + double sg; + /* decoded as utc=local */ + int year; + int mon; + int mday; + } l; +}; + +union DateTimeData +{ + unsigned flags; + struct { + unsigned flags; + VALUE ajd; + VALUE of; + VALUE sg; + VALUE cache; + } r; + struct { + unsigned flags; + long jd; /* as utc */ + int df; /* as utc, in secs */ + long long sf; /* in nano secs */ + int of; /* in secs */ + double sg; + /* decoded as local */ + int year; + int mon; + int mday; + int hour; + int min; + int sec; + } l; +}; + +#define get_d1(x)\ + union DateData *dat;\ + Data_Get_Struct(x, union DateData, dat) + +#define get_d2(x,y)\ + union DateData *adat, *bdat;\ + Data_Get_Struct(x, union DateData, adat);\ + Data_Get_Struct(y, union DateData, bdat) + +#define get_d1_dt1(x,y)\ + union DateData *adat;\ + union DateTimeData *bdat;\ + Data_Get_Struct(x, union DateData, adat);\ + Data_Get_Struct(y, union DateTimeData, bdat) + +#define get_dt1(x)\ + union DateTimeData *dat;\ + Data_Get_Struct(x, union DateTimeData, dat) + +#define get_dt2(x,y)\ + union DateTimeData *adat, *bdat;\ + Data_Get_Struct(x, union DateTimeData, adat);\ + Data_Get_Struct(y, union DateTimeData, bdat) + +#define get_dt1_d1(x,y)\ + union DateTimeData *adat;\ + union DateData *bdat;\ + Data_Get_Struct(x, union DateTimeData, adat);\ + Data_Get_Struct(y, union DateData, bdat) + +#define get_dt2_cast(x,y)\ + union DateData *atmp, *btmp;\ + union DateTimeData abuf, bbuf, *adat, *bdat;\ + if (k_datetime_p(x))\ + Data_Get_Struct(x, union DateTimeData, adat);\ + else {\ + Data_Get_Struct(x, union DateData, atmp);\ + abuf.l.jd = atmp->l.jd;\ + abuf.l.df = 0;\ + abuf.l.sf = 0;\ + abuf.l.of = 0;\ + abuf.l.sg = atmp->l.sg;\ + abuf.l.year = atmp->l.year;\ + abuf.l.mon = atmp->l.mon;\ + abuf.l.mday = atmp->l.mday;\ + abuf.l.hour = 0;\ + abuf.l.min = 0;\ + abuf.l.sec = 0;\ + abuf.flags = HAVE_DF | HAVE_TIME | atmp->l.flags;\ + adat = &abuf;\ + }\ + if (k_datetime_p(y))\ + Data_Get_Struct(y, union DateTimeData, bdat);\ + else {\ + Data_Get_Struct(y, union DateData, btmp);\ + bbuf.l.jd = btmp->l.jd;\ + bbuf.l.df = 0;\ + bbuf.l.sf = 0;\ + bbuf.l.of = 0;\ + bbuf.l.sg = btmp->l.sg;\ + bbuf.l.year = btmp->l.year;\ + bbuf.l.mon = btmp->l.mon;\ + bbuf.l.mday = btmp->l.mday;\ + bbuf.l.hour = 0;\ + bbuf.l.min = 0;\ + bbuf.l.sec = 0;\ + bbuf.flags = HAVE_DF | HAVE_TIME | btmp->l.flags;\ + bdat = &bbuf;\ + } + +#define f_add(x,y) rb_funcall(x, '+', 1, y) +#define f_sub(x,y) rb_funcall(x, '-', 1, y) +#define f_mul(x,y) rb_funcall(x, '*', 1, y) +#define f_div(x,y) rb_funcall(x, '/', 1, y) + +#define forward0(k,m) rb_funcall(k, rb_intern(m), 0) +#define cforward0(m) forward0(klass, m) +#define iforward0(m) forward0(self, m) +#define forward1(k,m,a) rb_funcall(k, rb_intern(m), 1, a) +#define iforward1(m,a) forward1(self, m, a) +#define forwardv(k,m) rb_funcall2(k, rb_intern(m), argc, argv) +#define cforwardv(m) forwardv(klass, m) +#define iforwardv(m) forwardv(self, m) +#define forwardop(k,m) rb_funcall(k, rb_intern(m), 1, other) +#define iforwardop(m) forwardop(self, m) + +static VALUE cDate, cDateTime; +static VALUE rzero, rhalf, day_in_nanoseconds; + +static int valid_civil_p(int y, int m, int d, double sg, + int *rm, int *rd, long *rjd, int *ns); + +static int +find_fdoy(int y, double sg, long *rjd, int *ns) +{ + int d, rm, rd; + + for (d = 1; d < 31; d++) + if (valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns)) + return 1; + return 0; +} + +static int +find_ldoy(int y, double sg, long *rjd, int *ns) +{ + int i, rm, rd; + + for (i = 0; i < 30; i++) + if (valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns)) + return 1; + return 0; +} + +#if 0 +static int +find_fdom(int y, int m, double sg, long *rjd, int *ns) +{ + int d, rm, rd; + + for (d = 1; d < 31; d++) + if (valid_civil_p(y, m, d, sg, &rm, &rd, rjd, ns)) + return 1; + return 0; +} +#endif + +static int +find_ldom(int y, int m, double sg, long *rjd, int *ns) +{ + int i, rm, rd; + + for (i = 0; i < 30; i++) + if (valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns)) + return 1; + return 0; +} + +static void +civil_to_jd(int y, int m, int d, double sg, long *rjd, int *ns) +{ + double a, b, jd; + + if (m <= 2) { + y -= 1; + m += 12; + } + a = floor(y / 100.0); + b = 2 - a + floor(a / 4.0); + jd = floor(365.25 * (y + 4716)) + + floor(30.6001 * (m + 1)) + + d + b - 1524; + if (jd < sg) { + jd -= b; + *ns = 0; + } + else + *ns = 1; + + *rjd = jd; +} + +static void +jd_to_civil(long jd, double sg, int *ry, int *rm, int *rdom) +{ + double x, a, b, c, d, e, y, m, dom; + + if (jd < sg) + a = jd; + else { + x = floor((jd - 1867216.25) / 36524.25); + a = jd + 1 + x - floor(x / 4.0); + } + b = a + 1524; + c = floor((b - 122.1) / 365.25); + d = floor(365.25 * c); + e = floor((b - d) / 30.6001); + dom = b - d - floor(30.6001 * e); + if (e <= 13) { + m = e - 1; + y = c - 4716; + } + else { + m = e - 13; + y = c - 4715; + } + + *ry = y; + *rm = m; + *rdom = dom; +} + +static void +ordinal_to_jd(int y, int d, double sg, long *rjd, int *ns) +{ + int ns2; + + find_fdoy(y, sg, rjd, &ns2); + *rjd += d - 1; + *ns = (*rjd < sg) ? 0 : 1; +} + +static void +jd_to_ordinal(long jd, double sg, int *ry, int *rd) +{ + int rm2, rd2, ns; + long rjd; + + jd_to_civil(jd, sg, ry, &rm2, &rd2); + find_fdoy(*ry, sg, &rjd, &ns); + *rd = jd - rjd + 1; +} + +static void +commercial_to_jd(int y, int w, int d, double sg, long *rjd, int *ns) +{ + long rjd2; + int ns2; + + find_fdoy(y, sg, &rjd2, &ns2); + rjd2 += 3; + *rjd = + (rjd2 - MOD((rjd2 - 1) + 1, 7)) + + 7 * (w - 1) + + (d - 1); + *ns = (*rjd < sg) ? 0 : 1; +} + +static void +jd_to_commercial(long jd, double sg, int *ry, int *rw, int *rd) +{ + int ry2, rm2, rd2, a, ns2; + long rjd2; + + jd_to_civil(jd - 3, sg, &ry2, &rm2, &rd2); + a = ry2; + commercial_to_jd(a + 1, 1, 1, sg, &rjd2, &ns2); + if (jd >= rjd2) + *ry = a + 1; + else { + commercial_to_jd(a, 1, 1, sg, &rjd2, &ns2); + *ry = a; + } + *rw = 1 + DIV(jd - rjd2, 7); + *rd = MOD(jd + 1, 7); + if (*rd == 0) + *rd = 7; +} + +#if 0 +static void +weeknum_to_jd(int y, int w, int d, int f, double sg, long *rjd, int *ns) +{ + long rjd2; + int ns2; + + find_fdoy(y, sg, &rjd2, &ns2); + rjd2 += 6; + *rjd = (rjd2 - MOD(((rjd2 - f) + 1), 7) - 7) + 7 * w + d; + *ns = (*rjd < sg) ? 0 : 1; +} +#endif + +static void +jd_to_weeknum(long jd, int f, double sg, int *ry, int *rw, int *rd) +{ + int rm, rd2, ns; + long rjd, j; + + jd_to_civil(jd, sg, ry, &rm, &rd2); + find_fdoy(*ry, sg, &rjd, &ns); + rjd += 6; + j = jd - (rjd - MOD((rjd - f) + 1, 7)) + 7; + *rw = DIV(j, 7); + *rd = MOD(j, 7); +} + +#if 0 +static void +nth_kday_to_jd(int y, int m, int n, int k, double sg, long *rjd, int *ns) +{ + long rjd2; + int ns2; + + if (n > 0) { + find_fdom(y, m, sg, &rjd2, &ns2); + rjd2 -= 1; + } + else { + find_ldom(y, m, sg, &rjd2, &ns2); + rjd2 += 7; + } + *rjd = (rjd2 - MOD((rjd2 - k) + 1, 7)) + 7 * n; + *ns = (*rjd < sg) ? 0 : 1; +} +#endif + +#if 0 +inline static int jd_to_wday(long jd); + +static void +jd_to_nth_kday(long jd, double sg, int *ry, int *rm, int *rn, int *rk) +{ + int rd, ns2; + long rjd; + + jd_to_civil(jd, sg, ry, rm, &rd); + find_fdom(*ry, *rm, sg, &rjd, &ns2); + *rn = DIV(jd - rjd, 7) + 1; + *rk = jd_to_wday(jd); +} +#endif + +static int +valid_ordinal_p(int y, int d, double sg, + int *rd, long *rjd, int *ns) +{ + int ry2, rd2; + + if (d < 0) { + long rjd2; + int ns2; + + if (!find_ldoy(y, sg, &rjd2, &ns2)) + return 0; + jd_to_ordinal(rjd2 + d + 1, sg, &ry2, &rd2); + if (ry2 != y) + return 0; + d = rd2; + } + ordinal_to_jd(y, d, sg, rjd, ns); + jd_to_ordinal(*rjd, sg, &ry2, &rd2); + if (ry2 != y || rd2 != d) + return 0; + return 1; +} + +static const int monthtab[2][13] = { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } +}; + +inline static int +leap_p(int y) +{ + return MOD(y, 4) == 0 && y % 100 != 0 || MOD(y, 400) == 0; +} + +static int +last_day_of_month(int y, int m) +{ + return monthtab[leap_p(y) ? 1 : 0][m]; +} + +static int +valid_gregorian_p(int y, int m, int d, int *rm, int *rd) +{ + int last; + + if (m < 0) + m += 13; + last = last_day_of_month(y, m); + if (d < 0) + d = last + d + 1; + + *rm = m; + *rd = d; + + return !(m < 0 || m > 12 || + d < 1 || d > last); +} + +static int +valid_civil_p(int y, int m, int d, double sg, + int *rm, int *rd, long *rjd, int *ns) +{ + int ry; + + if (m < 0) + m += 13; + if (d < 0) { + if (!find_ldom(y, m, sg, rjd, ns)) + return 0; + jd_to_civil(*rjd + d + 1, sg, &ry, rm, rd); + if (ry != y || *rm != m) + return 0; + d = *rd; + } + civil_to_jd(y, m, d, sg, rjd, ns); + jd_to_civil(*rjd, sg, &ry, rm, rd); + if (ry != y || *rm != m || *rd != d) + return 0; + return 1; +} + +static int +valid_commercial_p(int y, int w, int d, double sg, + int *rw, int *rd, long *rjd, int *ns) +{ + int ns2, ry2, rw2, rd2; + + if (d < 0) + d += 8; + if (w < 0) { + long rjd2; + + commercial_to_jd(y + 1, 1, 1, sg, &rjd2, &ns2); + jd_to_commercial(rjd2 + w * 7, sg, &ry2, &rw2, &rd2); + if (ry2 != y) + return 0; + w = rw2; + } + commercial_to_jd(y, w, d, sg, rjd, ns); + jd_to_commercial(*rjd, sg, &ry2, rw, rd); + if (y != ry2 || w != *rw || d != *rd) + return 0; + return 1; +} + +static int +valid_time_p(int h, int min, int s, int *rh, int *rmin, int *rs) +{ + if (h < 0) + h += 24; + if (min < 0) + min += 60; + if (s < 0) + s += 60; + *rh = h; + *rmin = min; + *rs = s; + return !(h < 0 || h > 24 || + min < 0 || min > 59 || + s < 0 || s > 59 || + (h == 24 && (min > 0 || s > 0))); +} + +inline static int +df_local_to_utc(int df, int of) +{ + df -= of; + if (df < 0) + df += DAY_IN_SECONDS; + else if (df >= DAY_IN_SECONDS) + df -= DAY_IN_SECONDS; + return df; +} + +inline static int +df_utc_to_local(int df, int of) +{ + df += of; + if (df < 0) + df += DAY_IN_SECONDS; + else if (df >= DAY_IN_SECONDS) + df -= DAY_IN_SECONDS; + return df; +} + +inline static long +jd_local_to_utc(long jd, int df, int of) +{ + df -= of; + if (df < 0) + jd -= 1; + else if (df >= DAY_IN_SECONDS) + jd += 1; + return jd; +} + +inline static long +jd_utc_to_local(long jd, int df, int of) +{ + df += of; + if (df < 0) + jd -= 1; + else if (df >= DAY_IN_SECONDS) + jd += 1; + return jd; +} + +inline static int +time_to_df(int h, int min, int s) +{ + return h * 3600 + min * 60 + s; +} + +inline static int +jd_to_wday(long jd) +{ + return MOD(jd + 1, 7); +} + +static int +daydiff_to_sec(VALUE vof, int *rof) +{ + switch (TYPE(vof)) { + case T_FIXNUM: + { + int n; + + n = FIX2INT(vof); + if (n != -1 && n != 0 && n != 1) + return 0; + *rof = n * DAY_IN_SECONDS; + return 1; + } + case T_FLOAT: + { + double n; + + n = NUM2DBL(vof); + if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) + return 0; + *rof = round(n * DAY_IN_SECONDS); + return 1; + } + case T_RATIONAL: + { + VALUE vs = f_mul(vof, INT2FIX(DAY_IN_SECONDS)); + VALUE vn = RRATIONAL(vs)->num; + VALUE vd = RRATIONAL(vs)->den; + int n, d; + + if (!FIXNUM_P(vn) || !FIXNUM_P(vd)) + return 0; + n = FIX2INT(vn); + d = FIX2INT(vd); + if (d != 1) + return 0; + if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) + return 0; + *rof = n; + return 1; + } + case T_STRING: + { + VALUE vs = rb_funcall(cDate, rb_intern("zone_to_diff"), 1, vof); + int n; + + if (!FIXNUM_P(vs)) + return 0; + n = FIX2INT(vs); + if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) + return 0; + *rof = n; + return 1; + } + } + return 0; +} + +inline static void +get_d_jd(union DateData *x) +{ + if (!have_jd_p(x)) { + long jd; + int ns; + + assert(have_civil_p(x)); + + civil_to_jd(x->l.year, x->l.mon, x->l.mday, x->l.sg, &jd, &ns); + x->l.jd = jd; + x->l.flags |= HAVE_JD; + } +} + +inline static void +get_d_civil(union DateData *x) +{ + if (!have_civil_p(x)) { + int y, m, d; + + assert(have_jd_p(x)); + + jd_to_civil(x->l.jd, x->l.sg, &y, &m, &d); + x->l.year = y; + x->l.mon = m; + x->l.mday = d; + x->l.flags |= HAVE_CIVIL; + } +} + +inline static void +get_dt_df(union DateTimeData *x) +{ + if (!have_df_p(x)) { + assert(have_time_p(x)); + + x->l.df = df_local_to_utc(time_to_df(x->l.hour, x->l.min, x->l.sec), + x->l.of); + x->l.flags |= HAVE_DF; + } +} + +inline static void +get_dt_time(union DateTimeData *x) +{ + int r; + + if (!have_time_p(x)) { + assert(have_df_p(x)); + + r = df_utc_to_local(x->l.df, x->l.of); + x->l.hour = r / 3600; + r %= 3600; + x->l.min = r / 60; + x->l.sec = r % 60; + x->l.flags |= HAVE_TIME; + } +} + +inline static void +get_dt_jd(union DateTimeData *x) +{ + if (!have_jd_p(x)) { + long jd; + int ns; + + assert(have_civil_p(x)); + + civil_to_jd(x->l.year, x->l.mon, x->l.mday, x->l.sg, &jd, &ns); + + get_dt_time(x); + x->l.jd = jd_local_to_utc(jd, + time_to_df(x->l.hour, x->l.min, x->l.sec), + x->l.of); + x->l.flags |= HAVE_JD; + } +} + +inline static void +get_dt_civil(union DateTimeData *x) +{ + if (!have_civil_p(x)) { + long jd; + int y, m, d; + + assert(have_jd_p(x)); + + get_dt_df(x); + jd = jd_utc_to_local(x->l.jd, x->l.df, x->l.of); + jd_to_civil(jd, x->l.sg, &y, &m, &d); + x->l.year = y; + x->l.mon = m; + x->l.mday = d; + x->l.flags |= HAVE_CIVIL; + } +} + +inline static long +local_jd(union DateTimeData *x) +{ + assert(have_jd_p(x)); + assert(have_df_p(x)); + return jd_utc_to_local(x->l.jd, x->l.df, x->l.of); +} + +inline static int +local_df(union DateTimeData *x) +{ + assert(have_df_p(x)); + return df_utc_to_local(x->l.df, x->l.of); +} + +inline static VALUE +f_kind_of_p(VALUE x, VALUE c) +{ + return rb_obj_is_kind_of(x, c); +} + +inline static VALUE +k_date_p(VALUE x) +{ + return f_kind_of_p(x, cDate); +} + +inline static VALUE +k_datetime_p(VALUE x) +{ + return f_kind_of_p(x, cDateTime); +} + +inline static VALUE +k_numeric_p(VALUE x) +{ + return f_kind_of_p(x, rb_cNumeric); +} + +static VALUE +date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass) +{ + VALUE vjd, vsg; + + rb_scan_args(argc, argv, "11", &vjd, &vsg); + + return Qtrue; +} + +static VALUE +date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vm, vd, vsg; + int y, m, d, rm, rd; + double sg; + + rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg); + + if (!(FIXNUM_P(vy) && + FIXNUM_P(vm) && + FIXNUM_P(vd))) + return cforwardv("valid_civil_r?"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + m = 1; + d = 1; + + switch (argc) { + case 4: + case 3: + d = NUM2LONG(vd); + case 2: + m = NUM2LONG(vm); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("valid_civil_r?"); + } + + if (isinf(sg) && sg < 0) { + if (!valid_gregorian_p(y, m, d, &rm, &rd)) + return Qfalse; + return Qtrue; + } + else { + long jd; + int ns; + + if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns)) + return Qfalse; + return Qtrue; + } +} + +static VALUE +date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vd, vsg; + int y, d, rd; + double sg; + + rb_scan_args(argc, argv, "21", &vy, &vd, &vsg); + + if (!(FIXNUM_P(vy) && + FIXNUM_P(vd))) + return cforwardv("valid_ordinal_r?"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + d = 1; + + switch (argc) { + case 3: + case 2: + d = NUM2LONG(vd); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("valid_ordinal_r?"); + } + + { + long jd; + int ns; + + if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns)) + return Qfalse; + return Qtrue; + } +} + +static VALUE +date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vw, vd, vsg; + int y, w, d, rw, rd; + double sg; + + rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg); + + if (!(FIXNUM_P(vy) && + FIXNUM_P(vw) && + FIXNUM_P(vd))) + return cforwardv("valid_commercial_r?"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + w = 1; + d = 1; + + switch (argc) { + case 4: + case 3: + d = NUM2LONG(vd); + case 2: + w = NUM2LONG(vw); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_CWYEAR(y)) + return cforwardv("valid_commercial_r?"); + } + + { + long jd; + int ns; + + if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns)) + return Qfalse; + return Qtrue; + } +} + +static void +d_right_gc_mark(union DateData *dat) +{ + if (!light_mode_p(dat)) { + rb_gc_mark(dat->r.ajd); + rb_gc_mark(dat->r.of); + rb_gc_mark(dat->r.sg); + rb_gc_mark(dat->r.cache); + } +} + +inline static VALUE +d_right_s_new_internal(VALUE klass, VALUE ajd, VALUE of, VALUE sg, + unsigned flags) +{ + union DateData *dat; + VALUE obj; + + obj = Data_Make_Struct(klass, union DateData, d_right_gc_mark, -1, dat); + + dat->r.ajd = ajd; + dat->r.of = of; + dat->r.sg = sg; + dat->r.cache = rb_hash_new(); + dat->r.flags = flags; + + return obj; +} + +inline static VALUE +d_lite_s_new_internal(VALUE klass, long jd, double sg, + int y, int m, int d, unsigned flags) +{ + union DateData *dat; + VALUE obj; + + obj = Data_Make_Struct(klass, union DateData, d_right_gc_mark, -1, dat); + + dat->l.jd = jd; + dat->l.sg = sg; + dat->l.year = y; + dat->l.mon = m; + dat->l.mday = d; + dat->l.flags = flags; + + return obj; +} + +static VALUE +d_lite_s_new_internal_wo_civil(VALUE klass, long jd, double sg, + unsigned flags) +{ + return d_lite_s_new_internal(klass, jd, sg, 0, 0, 0, flags); +} + +static VALUE +d_lite_s_alloc(VALUE klass) +{ + return d_lite_s_new_internal_wo_civil(klass, 0, 0, 0); +} + +static VALUE +d_right_s_new_r_bang(int argc, VALUE *argv, VALUE klass) +{ + VALUE vajd, vof, vsg; + + rb_scan_args(argc, argv, "03", &vajd, &vof, &vsg); + + if (argc < 1) + vajd = INT2FIX(0); + if (argc < 2) + vof = INT2FIX(0); + if (argc < 3) + vsg = DBL2NUM(ITALY); + + return d_right_s_new_internal(klass, vajd, vof, vsg, 0); +} + +static VALUE +d_lite_s_new_l_bang(int argc, VALUE *argv, VALUE klass) +{ + VALUE vjd, vsg; + long jd; + double sg; + + rb_scan_args(argc, argv, "02", &vjd, &vsg); + + if (argc < 1) + jd = 0; + else { + if (!FIXNUM_P(vjd)) + rb_raise(rb_eArgError, "cannot create"); + jd = NUM2LONG(vjd); + if (!LIGHTABLE_JD(jd)) + rb_raise(rb_eArgError, "cannot create"); + } + if (argc < 2) + sg = 0; + else + sg = NUM2DBL(vsg); + + return d_lite_s_new_internal_wo_civil(klass, + jd, + sg, + LIGHT_MODE | HAVE_JD); +} + +static VALUE +date_s_new_r_bang(int argc, VALUE *argv, VALUE klass) +{ + return d_right_s_new_r_bang(argc, argv, klass); +} + +static VALUE +date_s_new_l_bang(int argc, VALUE *argv, VALUE klass) +{ + return d_lite_s_new_l_bang(argc, argv, klass); +} + +static VALUE +date_s_jd(int argc, VALUE *argv, VALUE klass) +{ + VALUE vjd, vsg; + long jd; + double sg; + + rb_scan_args(argc, argv, "02", &vjd, &vsg); + + if (!FIXNUM_P(vjd)) + return cforwardv("jd_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + if (argc >= 1) { + jd = NUM2LONG(vjd); + if (!LIGHTABLE_JD(jd)) + return cforwardv("jd_r"); + } + else + jd = 0; + + if (jd < sg) + return cforwardv("jd_r"); + + return d_lite_s_new_internal_wo_civil(klass, jd, sg, LIGHT_MODE | HAVE_JD); +} + +static VALUE +date_s_ordinal(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vd, vsg; + int y, d, rd; + double sg; + + rb_scan_args(argc, argv, "03", &vy, &vd, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vd) || FIXNUM_P(vd)))) + return cforwardv("ordinal_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + d = 1; + + switch (argc) { + case 3: + case 2: + d = NUM2LONG(vd); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("ordinal_r"); + } + + { + long jd; + int ns; + + if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("ordinal_r"); + + return d_lite_s_new_internal_wo_civil(klass, jd, sg, + LIGHT_MODE | HAVE_JD); + } +} + +static VALUE +date_s_civil(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vm, vd, vsg; + int y, m, d, rm, rd; + double sg; + + rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vm) || FIXNUM_P(vm)) && + (NIL_P(vd) || FIXNUM_P(vd)))) + return cforwardv("civil_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + m = 1; + d = 1; + + switch (argc) { + case 4: + case 3: + d = NUM2LONG(vd); + case 2: + m = NUM2LONG(vm); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("civil_r"); + } + + if (isinf(sg) && sg < 0) { + if (!valid_gregorian_p(y, m, d, &rm, &rd)) + rb_raise(rb_eArgError, "invalid date"); + + return d_lite_s_new_internal(klass, 0, sg, y, rm, rd, + LIGHT_MODE | HAVE_CIVIL); + } + else { + long jd; + int ns; + + if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("civil_r"); + + return d_lite_s_new_internal(klass, jd, sg, y, rm, rd, + LIGHT_MODE | HAVE_JD | HAVE_CIVIL); + } +} + +static VALUE +date_s_commercial(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vw, vd, vsg; + int y, w, d, rw, rd; + double sg; + + rb_scan_args(argc, argv, "04", &vy, &vw, &vd, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vw) || FIXNUM_P(vw)) && + (NIL_P(vd) || FIXNUM_P(vd)))) + return cforwardv("commercial_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + w = 1; + d = 1; + + switch (argc) { + case 4: + case 3: + d = NUM2LONG(vd); + case 2: + w = NUM2LONG(vw); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_CWYEAR(y)) + return cforwardv("commercial_r"); + } + + { + long jd; + int ns; + + if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("commercial_r"); + + return d_lite_s_new_internal_wo_civil(klass, jd, sg, + LIGHT_MODE | HAVE_JD); + } +} + +#if !defined(HAVE_GMTIME_R) +static struct tm* +localtime_r(const time_t *t, struct tm *tm) +{ + auto struct tm *tmp = localtime(t); + if (tmp) + *tm = *tmp; + return tmp; +} +#endif + +static VALUE +date_s_today(int argc, VALUE *argv, VALUE klass) +{ + VALUE vsg; + double sg; + time_t t; + struct tm tm; + long y; + int m, d; + + rb_scan_args(argc, argv, "01", &vsg); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + if (time(&t) == -1) + rb_sys_fail("time"); + localtime_r(&t, &tm); + + y = tm.tm_year + 1900; + m = tm.tm_mon + 1; + d = tm.tm_mday; + + if (!LIGHTABLE_YEAR(y)) + rb_raise(rb_eArgError, "cannot create"); + + if (isinf(sg) && sg < 0) + return d_lite_s_new_internal(klass, 0, sg, (int)y, m, d, + LIGHT_MODE | HAVE_CIVIL); + else { + long jd; + int ns; + + civil_to_jd((int)y, m, d, sg, &jd, &ns); + + return d_lite_s_new_internal(klass, jd, sg, (int)y, m, d, + LIGHT_MODE | HAVE_JD | HAVE_CIVIL); + } +} + +static VALUE +d_lite_ajd(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return dat->r.ajd; + { + get_d_jd(dat); + return f_sub(INT2FIX(dat->l.jd), rhalf); + } +} + +static VALUE +d_lite_amjd(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("amjd_r"); + { + get_d_jd(dat); + return rb_rational_new1(LONG2NUM(dat->l.jd - 2400001L)); + } +} + +static VALUE +d_lite_jd(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("jd_r"); + { + get_d_jd(dat); + return INT2FIX(dat->l.jd); + } +} + +static VALUE +d_lite_mjd(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("mjd_r"); + { + get_d_jd(dat); + return LONG2NUM(dat->l.jd - 2400001L); + } +} + +static VALUE +d_lite_ld(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("ld_r"); + { + get_d_jd(dat); + return LONG2NUM(dat->l.jd - 2299160L); + } +} + +static VALUE +d_lite_year(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("year_r"); + { + get_d_civil(dat); + return INT2FIX(dat->l.year); + } +} + +static VALUE +d_lite_yday(VALUE self) +{ + int ry, rd; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("yday_r"); + { + get_d_jd(dat); + jd_to_ordinal(dat->l.jd, dat->l.sg, &ry, &rd); + return INT2FIX(rd); + } +} + +static VALUE +d_lite_mon(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("mon_r"); + { + get_d_civil(dat); + return INT2FIX(dat->l.mon); + } +} + +static VALUE +d_lite_mday(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("mday_r"); + { + get_d_civil(dat); + return INT2FIX(dat->l.mday); + } +} + +static VALUE +d_lite_day_fraction(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("day_fraction_r"); + return INT2FIX(0); +} + +static VALUE +d_lite_wnum0(VALUE self) +{ + int ry, rw, rd; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("wnum0_r"); + { + get_d_jd(dat); + jd_to_weeknum(dat->l.jd, 0, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +d_lite_wnum1(VALUE self) +{ + int ry, rw, rd; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("wnum1_r"); + { + get_d_jd(dat); + jd_to_weeknum(dat->l.jd, 1, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +d_lite_hour(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("hour_r"); + return INT2FIX(0); +} + +static VALUE +d_lite_min(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("min_r"); + return INT2FIX(0); +} + +static VALUE +d_lite_sec(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("sec_r"); + return INT2FIX(0); +} + +static VALUE +d_lite_sec_fraction(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("sec_fraction_r"); + return INT2FIX(0); +} + +static VALUE +d_lite_offset(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return dat->r.of; + return INT2FIX(0); +} + +static VALUE +d_lite_zone(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("zone_r"); + return rb_usascii_str_new2("+00:00"); +} + +static VALUE +d_lite_cwyear(VALUE self) +{ + int ry, rw, rd; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("cwyear_r"); + { + get_d_jd(dat); + jd_to_commercial(dat->l.jd, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(ry); + } +} + +static VALUE +d_lite_cweek(VALUE self) +{ + int ry, rw, rd; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("cweek_r"); + { + get_d_jd(dat); + jd_to_commercial(dat->l.jd, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +d_lite_cwday(VALUE self) +{ + int w; + + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("cwday_r"); + { + get_d_jd(dat); + w = jd_to_wday(dat->l.jd); + if (w == 0) + w = 7; + return INT2FIX(w); + } +} + +static VALUE +d_lite_wday(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("wday_r"); + { + get_d_jd(dat); + return INT2FIX(jd_to_wday(dat->l.jd)); + } +} + +static VALUE +d_lite_julian_p(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("julian_r?"); + return Qfalse; +} + +static VALUE +d_lite_gregorian_p(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("gregorian_r?"); + return Qtrue; +} + +static VALUE +d_lite_leap_p(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("leap_r?"); + { + get_d_civil(dat); + return leap_p(dat->l.year) ? Qtrue : Qfalse; + } +} + +static VALUE +d_lite_start(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return dat->r.sg; + return DBL2NUM(dat->l.sg); +} + +static VALUE +d_lite_new_start(int argc, VALUE *argv, VALUE self) +{ + VALUE vsg; + double sg; + + get_d1(self); + + if (!light_mode_p(dat)) + return iforwardv("new_start_r"); + + rb_scan_args(argc, argv, "01", &vsg); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + { + get_d_jd(dat); + + if (dat->l.jd < sg) + return iforwardv("new_start_r"); + + return d_lite_s_new_internal_wo_civil(CLASS_OF(self), + dat->l.jd, + sg, + LIGHT_MODE | HAVE_JD); + } +} + +static VALUE +d_lite_new_offset(int argc, VALUE *argv, VALUE self) +{ + VALUE vof; + int rof; + + get_d1(self); + + if (!light_mode_p(dat)) + return iforwardv("new_offset_r"); + + rb_scan_args(argc, argv, "01", &vof); + + if (NIL_P(vof)) + rof = 0; + else { + if (!daydiff_to_sec(vof, &rof) || rof != 0) + return iforwardv("new_offset_r"); + } + + { + get_d_jd(dat); + + return d_lite_s_new_internal_wo_civil(CLASS_OF(self), + dat->l.jd, + dat->l.sg, + LIGHT_MODE | HAVE_JD); + } +} + +static VALUE +d_lite_plus(VALUE self, VALUE other) +{ + get_d1(self); + + if (!light_mode_p(dat)) + return iforwardop("plus_r"); + + switch (TYPE(other)) { + case T_FIXNUM: + { + long jd; + + get_d_jd(dat); + + jd = dat->l.jd + FIX2LONG(other); + + if (LIGHTABLE_JD(jd) && jd >= dat->l.sg) + return d_lite_s_new_internal(CLASS_OF(self), + jd, dat->l.sg, + 0, 0, 0, + dat->l.flags & ~HAVE_CIVIL); + } + break; + case T_FLOAT: + { + double d = NUM2DBL(other); + long l = round(d); + if (l == d && LIGHTABLE_JD(l)) + return d_lite_plus(self, INT2FIX(l)); + } + break; + } + return iforwardop("plus_r"); +} + +static VALUE +minus_dd(VALUE self, VALUE other) +{ + get_dt2_cast(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + long d; + int df, sf; + VALUE r; + + get_dt_jd(adat); + get_dt_jd(bdat); + get_dt_df(adat); + get_dt_df(bdat); + + d = adat->l.jd - bdat->l.jd; + df = adat->l.df - bdat->l.df; + sf = adat->l.sf - bdat->l.sf; + if (df < 0) { + d -= 1; + df += DAY_IN_SECONDS; + } + else if (df >= DAY_IN_SECONDS) { + d += 1; + df -= DAY_IN_SECONDS; + } + if (sf < 0) { + df -= 1; + sf += SECOND_IN_NANOSECONDS; + } + else if (sf >= SECOND_IN_NANOSECONDS) { + df += 1; + sf -= SECOND_IN_NANOSECONDS; + } + r = rb_rational_new1(LONG2NUM(d)); + if (df) + r = f_add(r, rb_rational_new2(INT2FIX(df), + INT2FIX(DAY_IN_SECONDS))); + if (sf) + r = f_add(r, rb_rational_new2(INT2FIX(sf), day_in_nanoseconds)); + return r; + } + return iforwardop("minus_r"); +} + +static VALUE +d_lite_minus(VALUE self, VALUE other) +{ + if (k_datetime_p(other)) + return minus_dd(self, other); + + assert(!k_datetime_p(other)); + if (k_date_p(other)) { + get_d2(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + long d; + + get_d_jd(adat); + get_d_jd(bdat); + + d = adat->l.jd - bdat->l.jd; + return rb_rational_new1(LONG2NUM(d)); + } + } + + switch (TYPE(other)) { + case T_FIXNUM: + return d_lite_plus(self, LONG2NUM(-FIX2LONG(other))); + case T_FLOAT: + return d_lite_plus(self, DBL2NUM(-NUM2DBL(other))); + } + return iforwardop("minus_r"); +} + +static VALUE +cmp_dd(VALUE self, VALUE other) +{ + get_dt2_cast(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + get_dt_jd(adat); + get_dt_jd(bdat); + get_dt_df(adat); + get_dt_df(bdat); + + if (adat->l.jd == bdat->l.jd) { + if (adat->l.df == bdat->l.df) { + if (adat->l.sf == bdat->l.sf) { + return INT2FIX(0); + } + else if (adat->l.sf < bdat->l.sf) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + else if (adat->l.df < bdat->l.df) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + else if (adat->l.jd < bdat->l.jd) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + return iforwardop("cmp_r"); +} + +static VALUE +d_lite_cmp(VALUE self, VALUE other) +{ + if (k_datetime_p(other)) + return cmp_dd(self, other); + + assert(!k_datetime_p(other)); + if (k_date_p(other)) { + get_d2(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + if (have_jd_p(adat) && + have_jd_p(bdat)) { + if (adat->l.jd == bdat->l.jd) + return INT2FIX(0); + if (adat->l.jd < bdat->l.jd) + return INT2FIX(-1); + return INT2FIX(1); + } + else { + get_d_civil(adat); + get_d_civil(bdat); + + if (adat->l.year == bdat->l.year) { + if (adat->l.mon == bdat->l.mon) { + if (adat->l.mday == bdat->l.mday) { + return INT2FIX(0); + } + else if (adat->l.mday < bdat->l.mday) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + else if (adat->l.mon < bdat->l.mon) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + else if (adat->l.year < bdat->l.year) { + return INT2FIX(-1); + } + else { + return INT2FIX(1); + } + } + } + } + return iforwardop("cmp_r"); +} + +static VALUE +equal_dd(VALUE self, VALUE other) +{ + get_dt2_cast(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + get_dt_jd(adat); + get_dt_jd(bdat); + get_dt_df(adat); + get_dt_df(bdat); + + if (local_jd(adat) == local_jd(bdat)) + return Qtrue; + return Qfalse; + } + return iforwardop("equal_r"); +} + +static VALUE +d_lite_equal(VALUE self, VALUE other) +{ + if (k_datetime_p(other)) + return equal_dd(self, other); + + assert(!k_datetime_p(other)); + if (k_date_p(other)) { + get_d2(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + if (have_jd_p(adat) && + have_jd_p(bdat)) { + if (adat->l.jd == bdat->l.jd) + return Qtrue; + return Qfalse; + } + else { + get_d_civil(adat); + get_d_civil(bdat); + + if (adat->l.year == bdat->l.year) + if (adat->l.mon == bdat->l.mon) + if (adat->l.mday == bdat->l.mday) + return Qtrue; + return Qfalse; + } + } + } + return iforwardop("equal_r"); +} + +static VALUE +eql_p_dd(VALUE self, VALUE other) +{ + get_dt2_cast(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + get_dt_jd(adat); + get_dt_jd(bdat); + get_dt_df(adat); + get_dt_df(bdat); + + if (adat->l.jd == bdat->l.jd) + if (adat->l.df == bdat->l.df) + if (adat->l.sf == bdat->l.sf) + return Qtrue; + return Qfalse; + } + return iforwardop("eql_r?"); +} + +static VALUE +d_lite_eql_p(VALUE self, VALUE other) +{ + if (k_datetime_p(other)) + return eql_p_dd(self, other); + + assert(!k_datetime_p(other)); + if (k_date_p(other)) { + get_d2(self, other); + + if (light_mode_p(adat) && + light_mode_p(bdat)) { + if (have_jd_p(adat) && + have_jd_p(bdat)) { + if (adat->l.jd == bdat->l.jd) + return Qtrue; + return Qfalse; + } + else { + get_d_civil(adat); + get_d_civil(bdat); + + if (adat->l.year == bdat->l.year) + if (adat->l.mon == bdat->l.mon) + if (adat->l.mday == bdat->l.mday) + return Qtrue; + return Qfalse; + } + } + } + return iforwardop("eql_r?"); +} + +static VALUE +d_lite_hash(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("hash_r"); + return rb_hash(d_lite_ajd(self)); +} + +static VALUE +d_lite_to_s(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("to_s_r"); + { + get_d_civil(dat); + return rb_enc_sprintf(rb_usascii_encoding(), + "%.4d-%02d-%02d", + dat->l.year, dat->l.mon, dat->l.mday); + } +} + +static VALUE +d_lite_inspect(VALUE self) +{ + get_d1(self); + if (!light_mode_p(dat)) + return iforward0("inspect_r"); + { + get_d_civil(dat); + get_d_jd(dat); + return rb_enc_sprintf(rb_usascii_encoding(), + "#<%s[L]: %.4d-%02d-%02d (%ldj,0,%.0f)>", + rb_obj_classname(self), + dat->l.year, dat->l.mon, dat->l.mday, + dat->l.jd, dat->l.sg); + } +} + +static VALUE +d_lite_marshal_dump(VALUE self) +{ + VALUE a; + + get_d1(self); + + if (!light_mode_p(dat)) + a = rb_ary_new3(3, dat->r.ajd, dat->r.of, dat->r.sg); + else { + get_d_jd(dat); + a = rb_assoc_new(LONG2NUM(dat->l.jd), DBL2NUM(dat->l.sg)); + } + + if (FL_TEST(self, FL_EXIVAR)) { + rb_copy_generic_ivar(a, self); + FL_SET(a, FL_EXIVAR); + } + + return a; +} + +static VALUE +d_lite_marshal_load(VALUE self, VALUE a) +{ + get_d1(self); + + if (!FIXNUM_P(RARRAY_PTR(a)[0])) { + dat->r.ajd = RARRAY_PTR(a)[0]; + dat->r.of = RARRAY_PTR(a)[1]; + dat->r.sg = RARRAY_PTR(a)[2]; + dat->r.cache = rb_hash_new(); + dat->r.flags = 0; + } + else { + dat->l.jd = NUM2LONG(RARRAY_PTR(a)[0]); + dat->l.sg = NUM2DBL(RARRAY_PTR(a)[1]); + dat->l.year = 0; + dat->l.mon = 0; + dat->l.mday = 0; + dat->l.flags = LIGHT_MODE | HAVE_JD; + } + + if (FL_TEST(a, FL_EXIVAR)) { + rb_copy_generic_ivar(self, a); + FL_SET(self, FL_EXIVAR); + } + + return self; +} + +static VALUE +d_right_cache(VALUE self) +{ + get_d1(self); + if (light_mode_p(dat)) + return Qnil; + return dat->r.cache; +} + +/* datetime light */ + +inline static VALUE +dt_lite_s_new_internal(VALUE klass, long jd, int df, + long long sf, int of, double sg, + int y, int m, int d, + int h, int min, int s, + unsigned flags) +{ + union DateTimeData *dat; + VALUE obj; + + obj = Data_Make_Struct(klass, union DateTimeData, 0, -1, dat); + + dat->l.jd = jd; + dat->l.df = df; + dat->l.sf = sf; + dat->l.of = of; + dat->l.sg = sg; + dat->l.year = y; + dat->l.mon = m; + dat->l.mday = d; + dat->l.hour = h; + dat->l.min = min; + dat->l.sec = s; + dat->l.flags = flags; + + return obj; +} + +static VALUE +dt_lite_s_new_internal_wo_civil(VALUE klass, long jd, int df, + long long sf, int of, double sg, + unsigned flags) +{ + return dt_lite_s_new_internal(klass, jd, df, sf, of, sg, + 0, 0, 0, 0, 0, 0, flags); +} + +static VALUE +dt_lite_s_alloc(VALUE klass) +{ + return dt_lite_s_new_internal_wo_civil(klass, 0, 0, 0, 0, 0, 0); +} + +static VALUE +dt_lite_s_new_l_bang(int argc, VALUE *argv, VALUE klass) +{ + VALUE vjd, vdf, vsf, vof, vsg; + long jd; + + rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg); + + if (argc < 1) + vjd = INT2FIX(0); + if (argc < 2) + vdf = INT2FIX(0); + if (argc < 3) + vsf = INT2FIX(0); + if (argc < 4) + vof = INT2FIX(0); + if (argc < 5) + vsg = INT2FIX(0); + + if (!FIXNUM_P(vjd) || + !FIXNUM_P(vdf) || + !FIXNUM_P(vsf) || + !FIXNUM_P(vof)) + rb_raise(rb_eArgError, "cannot create"); + jd = NUM2LONG(vjd); + if (!LIGHTABLE_JD(jd)) + rb_raise(rb_eArgError, "cannot create"); + + return dt_lite_s_new_internal_wo_civil(klass, + jd, + FIX2INT(vdf), + FIX2INT(vsf), + FIX2INT(vof), + NUM2DBL(vsg), + LIGHT_MODE | HAVE_JD | HAVE_DF); +} + +static VALUE +datetime_s_new_l_bang(int argc, VALUE *argv, VALUE klass) +{ + return dt_lite_s_new_l_bang(argc, argv, klass); +} + +static VALUE +datetime_s_jd(int argc, VALUE *argv, VALUE klass) +{ + VALUE vjd, vh, vmin, vs, vof, vsg; + long jd; + int h, min, s, rh, rmin, rs, rof; + double sg; + + rb_scan_args(argc, argv, "06", &vjd, &vh, &vmin, &vs, &vof, &vsg); + + if (!FIXNUM_P(vjd)) + return cforwardv("jd_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + jd = h = min = s = 0; + rof = 0; + + switch (argc) { + case 6: + case 5: + if (!daydiff_to_sec(vof, &rof)) + return cforwardv("jd_r"); + case 4: + s = NUM2LONG(vs); + case 3: + min = NUM2LONG(vmin); + case 2: + h = NUM2LONG(vh); + case 1: + jd = NUM2LONG(vjd); + if (!LIGHTABLE_JD(jd)) + return cforwardv("jd_r"); + } + + if (jd < sg) + return cforwardv("jd_r"); + + if (!valid_time_p(h, min, s, &rh, &rmin, &rs)) + rb_raise(rb_eArgError, "invalid date"); + + return dt_lite_s_new_internal(klass, + jd_local_to_utc(jd, + time_to_df(rh, rmin, rs), + rof), + 0, 0, rof, sg, 0, 0, 0, rh, rmin, rs, + LIGHT_MODE | HAVE_JD | HAVE_TIME); +} + +static VALUE +datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vd, vh, vmin, vs, vof, vsg; + int y, d, rd, h, min, s, rh, rmin, rs, rof; + double sg; + + rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vd) || FIXNUM_P(vd)) && + (NIL_P(vh) || FIXNUM_P(vh)) && + (NIL_P(vmin) || FIXNUM_P(vmin)) && + (NIL_P(vs) || FIXNUM_P(vs)))) + return cforwardv("ordinal_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + d = 1; + + h = min = s = 0; + rof = 0; + + switch (argc) { + case 7: + case 6: + if (!daydiff_to_sec(vof, &rof)) + return cforwardv("ordinal_r"); + case 5: + s = NUM2LONG(vs); + case 4: + min = NUM2LONG(vmin); + case 3: + h = NUM2LONG(vh); + case 2: + d = NUM2LONG(vd); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("ordinal_r"); + } + + { + long jd; + int ns; + + if (!valid_ordinal_p(y, d, sg, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + if (!valid_time_p(h, min, s, &rh, &rmin, &rs)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("ordinal_r"); + + return dt_lite_s_new_internal(klass, + jd_local_to_utc(jd, + time_to_df(rh, rmin, rs), + rof), + 0, 0, rof, sg, + 0, 0, 0, rh, rmin, rs, + LIGHT_MODE | HAVE_JD | HAVE_TIME); + } +} + +static VALUE +datetime_s_civil(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vm, vd, vh, vmin, vs, vof, vsg; + int y, m, d, rm, rd, h, min, s, rh, rmin, rs, rof; + double sg; + + rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vm) || FIXNUM_P(vm)) && + (NIL_P(vd) || FIXNUM_P(vd)) && + (NIL_P(vh) || FIXNUM_P(vh)) && + (NIL_P(vmin) || FIXNUM_P(vmin)) && + (NIL_P(vs) || FIXNUM_P(vs)))) + return cforwardv("civil_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + m = 1; + d = 1; + + h = min = s = 0; + rof = 0; + + switch (argc) { + case 8: + case 7: + if (!daydiff_to_sec(vof, &rof)) + return cforwardv("civil_r"); + case 6: + s = NUM2LONG(vs); + case 5: + min = NUM2LONG(vmin); + case 4: + h = NUM2LONG(vh); + case 3: + d = NUM2LONG(vd); + case 2: + m = NUM2LONG(vm); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_YEAR(y)) + return cforwardv("civil_r"); + } + + if (isinf(sg) && sg < 0) { + if (!valid_gregorian_p(y, m, d, &rm, &rd)) + rb_raise(rb_eArgError, "invalid date"); + if (!valid_time_p(h, min, s, &rh, &rmin, &rs)) + rb_raise(rb_eArgError, "invalid date"); + + return dt_lite_s_new_internal(klass, 0, 0, 0, rof, sg, + y, rm, rd, rh, rmin, rs, + LIGHT_MODE | HAVE_CIVIL | HAVE_TIME); + } + else { + long jd; + int ns; + + if (!valid_civil_p(y, m, d, sg, &rm, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + if (!valid_time_p(h, min, s, &rh, &rmin, &rs)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("civil_r"); + + return dt_lite_s_new_internal(klass, + jd_local_to_utc(jd, + time_to_df(rh, rmin, rs), + rof), + 0, 0, rof, sg, + y, rm, rd, rh, rmin, rs, + LIGHT_MODE | HAVE_JD | + HAVE_CIVIL | HAVE_TIME); + } +} + +static VALUE +datetime_s_commercial(int argc, VALUE *argv, VALUE klass) +{ + VALUE vy, vw, vd, vh, vmin, vs, vof, vsg; + int y, w, d, rw, rd, h, min, s, rh, rmin, rs, rof; + double sg; + + rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg); + + if (!((NIL_P(vy) || FIXNUM_P(vy)) && + (NIL_P(vw) || FIXNUM_P(vw)) && + (NIL_P(vd) || FIXNUM_P(vd)) && + (NIL_P(vh) || FIXNUM_P(vh)) && + (NIL_P(vmin) || FIXNUM_P(vmin)) && + (NIL_P(vs) || FIXNUM_P(vs)))) + return cforwardv("commercial_r"); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + y = -4712; + w = 1; + d = 1; + + h = min = s = 0; + rof = 0; + + switch (argc) { + case 8: + case 7: + if (!daydiff_to_sec(vof, &rof)) + return cforwardv("commercial_r"); + case 6: + s = NUM2LONG(vs); + case 5: + min = NUM2LONG(vmin); + case 4: + h = NUM2LONG(vh); + case 3: + d = NUM2LONG(vd); + case 2: + w = NUM2LONG(vw); + case 1: + y = NUM2LONG(vy); + if (!LIGHTABLE_CWYEAR(y)) + return cforwardv("commercial_r"); + } + + { + long jd; + int ns; + + if (!valid_commercial_p(y, w, d, sg, &rw, &rd, &jd, &ns)) + rb_raise(rb_eArgError, "invalid date"); + if (!valid_time_p(h, min, s, &rh, &rmin, &rs)) + rb_raise(rb_eArgError, "invalid date"); + + if (!LIGHTABLE_JD(jd) || !ns) + return cforwardv("commercial_r"); + + return dt_lite_s_new_internal(klass, + jd_local_to_utc(jd, + time_to_df(rh, rmin, rs), + rof), + 0, 0, rof, sg, + 0, 0, 0, rh, rmin, rs, + LIGHT_MODE | HAVE_JD | HAVE_TIME); + } +} + +static VALUE +datetime_s_now(int argc, VALUE *argv, VALUE klass) +{ + VALUE vsg; + double sg; +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; +#else + struct timeval tv; +#endif + struct tm tm; + long y; + int m, d, h, min, s, of; + long long sf; + + rb_scan_args(argc, argv, "01", &vsg); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + +#ifdef HAVE_CLOCK_GETTIME + if (clock_gettime(CLOCK_REALTIME, &ts) == -1) + rb_sys_fail("clock_gettime"); + localtime_r(&ts.tv_sec, &tm); +#else + if (gettimeofday(&tv, NULL) == -1) + rb_sys_fail("gettimeofday"); + localtime_r(&tv.tv_sec, &tm); +#endif + + y = tm.tm_year + 1900; + m = tm.tm_mon + 1; + d = tm.tm_mday; + h = tm.tm_hour; + min = tm.tm_min; + s = tm.tm_sec; + if (s == 60) + s = 59; +#ifdef HAVE_STRUCT_TM_TM_GMTOFF + of = tm.tm_gmtoff; +#else + of = (int)-timezone; +#endif +#ifdef HAVE_CLOCK_GETTIME + sf = ts.tv_nsec; +#else + sf = tv.tv_usec * 1000; +#endif + + if (!LIGHTABLE_YEAR(y)) + rb_raise(rb_eArgError, "cannot create"); + + if (isinf(sg) && sg < 0) + return dt_lite_s_new_internal(klass, 0, 0, sf, of, sg, + (int)y, m, d, h, min, s, + LIGHT_MODE | HAVE_CIVIL | HAVE_TIME); + else { + long jd; + int ns; + + civil_to_jd((int)y, m, d, sg, &jd, &ns); + + return dt_lite_s_new_internal(klass, + jd_local_to_utc(jd, + time_to_df(h, min, s), + of), + 0, sf, of, sg, + (int)y, m, d, h, min, s, + LIGHT_MODE | HAVE_JD | + HAVE_CIVIL | HAVE_TIME); + } +} + +static VALUE +dt_lite_ajd(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return dat->r.ajd; + { + VALUE r; + + get_dt_jd(dat); + get_dt_df(dat); + r = f_sub(INT2FIX(dat->l.jd), rhalf); + if (dat->l.df) + r = f_add(r, rb_rational_new2(INT2FIX(dat->l.df), + INT2FIX(DAY_IN_SECONDS))); + if (dat->l.sf) + r = f_add(r, rb_rational_new2(INT2FIX(dat->l.sf), + day_in_nanoseconds)); + return r; + } +} + +static VALUE +dt_lite_amjd(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("amjd_r"); + { + VALUE r; + + get_dt_jd(dat); + get_dt_df(dat); + r = rb_rational_new1(LONG2NUM(dat->l.jd - 2400001L)); + if (dat->l.df) + r = f_add(r, rb_rational_new2(INT2FIX(dat->l.df), + INT2FIX(DAY_IN_SECONDS))); + if (dat->l.sf) + r = f_add(r, rb_rational_new2(INT2FIX(dat->l.sf), + day_in_nanoseconds)); + return r; + } +} + +static VALUE +dt_lite_jd(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("jd_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + return INT2FIX(local_jd(dat)); + } +} + +static VALUE +dt_lite_mjd(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("mjd_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + return LONG2NUM(local_jd(dat) - 2400001L); + } +} + +static VALUE +dt_lite_ld(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("ld_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + return LONG2NUM(local_jd(dat) - 2299160L); + } +} + +static VALUE +dt_lite_year(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("year_r"); + { + get_dt_civil(dat); + return INT2FIX(dat->l.year); + } +} + +static VALUE +dt_lite_yday(VALUE self) +{ + int ry, rd; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("yday_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + jd_to_ordinal(local_jd(dat), dat->l.sg, &ry, &rd); + return INT2FIX(rd); + } +} + +static VALUE +dt_lite_mon(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("mon_r"); + { + get_dt_civil(dat); + return INT2FIX(dat->l.mon); + } +} + +static VALUE +dt_lite_mday(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("mday_r"); + { + get_dt_civil(dat); + return INT2FIX(dat->l.mday); + } +} + +static VALUE +dt_lite_day_fraction(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("day_fraction_r"); + { + get_dt_df(dat); + return rb_rational_new2(INT2FIX(local_df(dat)), + INT2FIX(DAY_IN_SECONDS)); + } +} + +static VALUE +dt_lite_wnum0(VALUE self) +{ + int ry, rw, rd; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("wnum0_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + jd_to_weeknum(local_jd(dat), 0, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +dt_lite_wnum1(VALUE self) +{ + int ry, rw, rd; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("wnum1_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + jd_to_weeknum(local_jd(dat), 1, dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +dt_lite_hour(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("hour_r"); + { + get_dt_time(dat); + return INT2FIX(dat->l.hour); + } +} + +static VALUE +dt_lite_min(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("min_r"); + { + get_dt_time(dat); + return INT2FIX(dat->l.min); + } +} + +static VALUE +dt_lite_sec(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("sec_r"); + { + get_dt_time(dat); + return INT2FIX(dat->l.sec); + } +} + +static VALUE +dt_lite_sec_fraction(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("sec_fraction_r"); + return rb_rational_new2(INT2FIX(dat->l.sf), INT2FIX(SECOND_IN_NANOSECONDS)); +} + +static VALUE +dt_lite_offset(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return dat->r.of; + return rb_rational_new2(INT2FIX(dat->l.of), INT2FIX(DAY_IN_SECONDS)); +} + +#define decode_offset(of,s,h,m)\ +{\ + int a;\ + s = (of < 0) ? '-' : '+';\ + a = (of < 0) ? -of : of;\ + h = a / 3600;\ + m = a % 3600 / 60;\ +} + +static VALUE +dt_lite_zone(VALUE self) +{ + int s, h, m; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("zone_r"); + decode_offset(dat->l.of, s, h, m); + return rb_enc_sprintf(rb_usascii_encoding(), "%c%02d:%02d", s, h, m); +} + +static VALUE +dt_lite_cwyear(VALUE self) +{ + int ry, rw, rd; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("cwyear_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + jd_to_commercial(local_jd(dat), dat->l.sg, &ry, &rw, &rd); + return INT2FIX(ry); + } +} + +static VALUE +dt_lite_cweek(VALUE self) +{ + int ry, rw, rd; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("cweek_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + jd_to_commercial(local_jd(dat), dat->l.sg, &ry, &rw, &rd); + return INT2FIX(rw); + } +} + +static VALUE +dt_lite_cwday(VALUE self) +{ + int w; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("cwday_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + w = jd_to_wday(local_jd(dat)); + if (w == 0) + w = 7; + return INT2FIX(w); + } +} + +static VALUE +dt_lite_wday(VALUE self) +{ + int w; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("wday_r"); + { + get_dt_jd(dat); + get_dt_df(dat); + w = jd_to_wday(local_jd(dat)); + return INT2FIX(w); + } +} + +static VALUE +dt_lite_julian_p(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("julian_r?"); + return Qfalse; +} + +static VALUE +dt_lite_gregorian_p(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("gregorian_r?"); + return Qtrue; +} + +static VALUE +dt_lite_leap_p(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("leap_r?"); + { + get_dt_civil(dat); + return leap_p(dat->l.year) ? Qtrue : Qfalse; + } +} + +static VALUE +dt_lite_start(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return dat->r.sg; + return DBL2NUM(dat->l.sg); +} + +static VALUE +dt_lite_new_start(int argc, VALUE *argv, VALUE self) +{ + VALUE vsg; + double sg; + + get_dt1(self); + + if (!light_mode_p(dat)) + return iforwardv("new_start_r"); + + rb_scan_args(argc, argv, "01", &vsg); + + if (!NIL_P(vsg)) + sg = NUM2DBL(vsg); + else + sg = ITALY; + + { + get_dt_jd(dat); + get_dt_df(dat); + + if (dat->l.jd < sg) + return iforwardv("new_start_r"); + + return dt_lite_s_new_internal_wo_civil(CLASS_OF(self), + dat->l.jd, + dat->l.df, + dat->l.sf, + dat->l.of, + sg, + LIGHT_MODE | HAVE_JD | HAVE_DF); + } +} + +static VALUE +dt_lite_new_offset(int argc, VALUE *argv, VALUE self) +{ + VALUE vof; + int rof; + + get_dt1(self); + + if (!light_mode_p(dat)) + return iforwardv("new_offset_r"); + + rb_scan_args(argc, argv, "01", &vof); + + if (NIL_P(vof)) + rof = 0; + else { + if (!daydiff_to_sec(vof, &rof)) + return iforwardv("new_offset_r"); + } + + { + get_dt_jd(dat); + get_dt_df(dat); + + return dt_lite_s_new_internal_wo_civil(CLASS_OF(self), + dat->l.jd, + dat->l.df, + dat->l.sf, + rof, + dat->l.sg, + LIGHT_MODE | HAVE_JD | HAVE_DF); + } +} + +static VALUE +dt_lite_plus(VALUE self, VALUE other) +{ + get_dt1(self); + + if (!light_mode_p(dat)) + return iforwardop("plus_r"); + + switch (TYPE(other)) { + case T_FIXNUM: + { + long jd; + + get_dt1(self); + get_dt_jd(dat); + get_dt_df(dat); + + jd = dat->l.jd + FIX2LONG(other); + + if (LIGHTABLE_JD(jd) && jd >= dat->l.sg) + return dt_lite_s_new_internal(CLASS_OF(self), + jd, + dat->l.df, + dat->l.sf, + dat->l.of, + dat->l.sg, + 0, 0, 0, + dat->l.hour, + dat->l.min, + dat->l.sec, + dat->l.flags & ~HAVE_CIVIL); + } + break; + case T_FLOAT: + { + long jd, df; + long long sf; + long double o; + int s; + + get_dt1(self); + get_dt_jd(dat); + get_dt_df(dat); + + jd = dat->l.jd; + o = NUM2DBL(other); + + if (o < 0) { + s = -1; + o = -o; + } + else + s = +1; + + jd = (long)floorl(o); + o = o - jd; + o *= DAY_IN_SECONDS; + df = (long)floorl(o); + o = o - df; + o *= SECOND_IN_NANOSECONDS; + sf = (long)roundl(o); + + if (s < 0) { + jd = -jd; + df = -df; + sf = -sf; + } + + sf = dat->l.sf + sf; + if (sf < 0) { + df -= 1; + sf += SECOND_IN_NANOSECONDS; + } + else if (sf >= SECOND_IN_NANOSECONDS) { + df += 1; + sf -= SECOND_IN_NANOSECONDS; + } + + df = dat->l.df + df; + if (df < 0) { + jd -= 1; + df += DAY_IN_SECONDS; + } + else if (df >= DAY_IN_SECONDS) { + jd += 1; + df -= DAY_IN_SECONDS; + } + + jd = dat->l.jd + jd; + + if (LIGHTABLE_JD(jd) && jd >= dat->l.sg) + return dt_lite_s_new_internal(CLASS_OF(self), + jd, + df, + sf, + dat->l.of, + dat->l.sg, + 0, 0, 0, + dat->l.hour, + dat->l.min, + dat->l.sec, + dat->l.flags & + ~HAVE_CIVIL & + ~HAVE_TIME); + } + break; + } + return iforwardop("plus_r"); +} + +static VALUE +dt_lite_minus(VALUE self, VALUE other) +{ + if (k_date_p(other)) + return minus_dd(self, other); + + switch (TYPE(other)) { + case T_FIXNUM: + return dt_lite_plus(self, LONG2NUM(-FIX2LONG(other))); + case T_FLOAT: + return dt_lite_plus(self, DBL2NUM(-NUM2DBL(other))); + } + return iforwardop("minus_r"); +} + +static VALUE +dt_lite_cmp(VALUE self, VALUE other) +{ + if (k_date_p(other)) + return cmp_dd(self, other); + return iforwardop("cmp_r"); +} + +static VALUE +dt_lite_equal(VALUE self, VALUE other) +{ + if (k_date_p(other)) + return equal_dd(self, other); + return iforwardop("equal_r"); +} + +static VALUE +dt_lite_eql_p(VALUE self, VALUE other) +{ + if (k_date_p(other)) + return eql_p_dd(self, other); + return iforwardop("eql_r?"); +} + +static VALUE +dt_lite_hash(VALUE self) +{ + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("hash_r"); + return rb_hash(dt_lite_ajd(self)); +} + +static VALUE +dt_lite_to_s(VALUE self) +{ + int s, h, m; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("to_s_r"); + { + get_dt_civil(dat); + get_dt_time(dat); + decode_offset(dat->l.of, s, h, m); + return rb_enc_sprintf(rb_usascii_encoding(), + "%.4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + dat->l.year, dat->l.mon, dat->l.mday, + dat->l.hour, dat->l.min, dat->l.sec, + s, h, m); + } +} + +static VALUE +dt_lite_inspect(VALUE self) +{ + int s, h, m; + + get_dt1(self); + if (!light_mode_p(dat)) + return iforward0("inspect_r"); + { + get_dt_civil(dat); + get_dt_time(dat); + get_dt_jd(dat); + get_dt_df(dat); + decode_offset(dat->l.of, s, h, m); + return rb_enc_sprintf(rb_usascii_encoding(), + "#<%s[L]: " + "%.4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d " + "((%ldj,%ds,%.0fn),%d/86400,%.0f)>", + rb_obj_classname(self), + dat->l.year, dat->l.mon, dat->l.mday, + dat->l.hour, dat->l.min, dat->l.sec, + s, h, m, + dat->l.jd, dat->l.df, (double)dat->l.sf, + dat->l.of, dat->l.sg); + } +} + +static VALUE +dt_lite_marshal_dump(VALUE self) +{ + VALUE a; + + get_dt1(self); + + if (!light_mode_p(dat)) + a = rb_ary_new3(3, dat->r.ajd, dat->r.of, dat->r.sg); + else { + get_dt_jd(dat); + get_dt_df(dat); + a = rb_ary_new3(5, + LONG2NUM(dat->l.jd), INT2FIX(dat->l.df), + INT2FIX(dat->l.sf), + INT2FIX(dat->l.of), DBL2NUM(dat->l.sg)); + } + + if (FL_TEST(self, FL_EXIVAR)) { + rb_copy_generic_ivar(a, self); + FL_SET(a, FL_EXIVAR); + } + + return a; +} + +static VALUE +dt_lite_marshal_load(VALUE self, VALUE a) +{ + get_dt1(self); + + if (!FIXNUM_P(RARRAY_PTR(a)[0])) { + dat->r.ajd = RARRAY_PTR(a)[0]; + dat->r.of = RARRAY_PTR(a)[1]; + dat->r.sg = RARRAY_PTR(a)[2]; + dat->r.cache = rb_hash_new(); + dat->r.flags = 0; + } + else { + dat->l.jd = NUM2LONG(RARRAY_PTR(a)[0]); + dat->l.df = FIX2INT(RARRAY_PTR(a)[1]); + dat->l.sf = FIX2INT(RARRAY_PTR(a)[2]); + dat->l.of = FIX2INT(RARRAY_PTR(a)[3]); + dat->l.sg = NUM2DBL(RARRAY_PTR(a)[4]); + dat->l.year = 0; + dat->l.mon = 0; + dat->l.mday = 0; + dat->l.hour = 0; + dat->l.min = 0; + dat->l.sec = 0; + dat->l.flags = LIGHT_MODE | HAVE_JD | HAVE_DF; + } + + if (FL_TEST(a, FL_EXIVAR)) { + rb_copy_generic_ivar(self, a); + FL_SET(self, FL_EXIVAR); + } + + return self; +} + +static VALUE +dt_right_cache(VALUE self) +{ + get_dt1(self); + if (light_mode_p(dat)) + return Qnil; + return dat->r.cache; +} + +#ifndef NDEBUG +static int +test_civil(long from, long to, double sg) +{ + long j; + + fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg); + for (j = from; j <= to; j++) { + int y, m, d, ns; + long rj; + + jd_to_civil(j, sg, &y, &m, &d); + civil_to_jd(y, m, d, sg, &rj, &ns); + if (j != rj) { + fprintf(stderr, "%ld != %ld\n", j, rj); + return 0; + } + } + return 1; +} + +static VALUE +date_s_test_civil(VALUE klass) +{ + double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))); + + if (!test_civil(MIN_JD, MIN_JD + 366, greg)) + return Qfalse; + if (!test_civil(2305814, 2598007, greg)) + return Qfalse; + if (!test_civil(MAX_JD - 366, MAX_JD, greg)) + return Qfalse; + + if (!test_civil(MIN_JD, MIN_JD + 366, ITALY)) + return Qfalse; + if (!test_civil(2305814, 2598007, ITALY)) + return Qfalse; + if (!test_civil(MAX_JD - 366, MAX_JD, ITALY)) + return Qfalse; + + return Qtrue; +} + +static int +test_ordinal(long from, long to, double sg) +{ + long j; + + fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg); + for (j = from; j <= to; j++) { + int y, d, ns; + long rj; + + jd_to_ordinal(j, sg, &y, &d); + ordinal_to_jd(y, d, sg, &rj, &ns); + if (j != rj) { + fprintf(stderr, "%ld != %ld\n", j, rj); + return 0; + } + } + return 1; +} + +static VALUE +date_s_test_ordinal(VALUE klass) +{ + double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))); + + if (!test_ordinal(MIN_JD, MIN_JD + 366, greg)) + return Qfalse; + if (!test_ordinal(2305814, 2598007, greg)) + return Qfalse; + if (!test_ordinal(MAX_JD - 366, MAX_JD, greg)) + return Qfalse; + + if (!test_ordinal(MIN_JD, MIN_JD + 366, ITALY)) + return Qfalse; + if (!test_ordinal(2305814, 2598007, ITALY)) + return Qfalse; + if (!test_ordinal(MAX_JD - 366, MAX_JD, ITALY)) + return Qfalse; + + return Qtrue; +} + +static int +test_commercial(long from, long to, double sg) +{ + long j; + + fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg); + for (j = from; j <= to; j++) { + int y, w, d, ns; + long rj; + + jd_to_commercial(j, sg, &y, &w, &d); + commercial_to_jd(y, w, d, sg, &rj, &ns); + if (j != rj) { + fprintf(stderr, "%ld != %ld\n", j, rj); + return 0; + } + } + return 1; +} + +static VALUE +date_s_test_commercial(VALUE klass) +{ + double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))); + + if (!test_commercial(MIN_JD, MIN_JD + 366, greg)) + return Qfalse; + if (!test_commercial(2305814, 2598007, greg)) + return Qfalse; + if (!test_commercial(MAX_JD - 366, MAX_JD, greg)) + return Qfalse; + + if (!test_commercial(MIN_JD, MIN_JD + 366, ITALY)) + return Qfalse; + if (!test_commercial(2305814, 2598007, ITALY)) + return Qfalse; + if (!test_commercial(MAX_JD - 366, MAX_JD, ITALY)) + return Qfalse; + + return Qtrue; +} + +static int +test_weeknum(long from, long to, int f, double sg) +{ + long j; + + fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg); + for (j = from; j <= to; j++) { + int y, w, d, ns; + long rj; + + jd_to_weeknum(j, f, sg, &y, &w, &d); + weeknum_to_jd(y, w, d, f, sg, &rj, &ns); + if (j != rj) { + fprintf(stderr, "%ld != %ld\n", j, rj); + return 0; + } + } + return 1; +} + +static VALUE +date_s_test_weeknum(VALUE klass) +{ + double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))); + int f; + + for (f = 0; f <= 1; f++) { + if (!test_weeknum(MIN_JD, MIN_JD + 366, f, greg)) + return Qfalse; + if (!test_weeknum(2305814, 2598007, f, greg)) + return Qfalse; + if (!test_weeknum(MAX_JD - 366, MAX_JD, f, greg)) + return Qfalse; + + if (!test_weeknum(MIN_JD, MIN_JD + 366, f, ITALY)) + return Qfalse; + if (!test_weeknum(2305814, 2598007, f, ITALY)) + return Qfalse; + if (!test_weeknum(MAX_JD - 366, MAX_JD, f, ITALY)) + return Qfalse; + } + + return Qtrue; +} + + +static int +test_nth_kday(long from, long to, double sg) +{ + long j; + + fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg); + for (j = from; j <= to; j++) { + int y, m, n, k, ns; + long rj; + + jd_to_nth_kday(j, sg, &y, &m, &n, &k); + nth_kday_to_jd(y, m, n, k, sg, &rj, &ns); + if (j != rj) { + fprintf(stderr, "%ld != %ld\n", j, rj); + return 0; + } + } + return 1; +} + +static VALUE +date_s_test_nth_kday(VALUE klass) +{ + double greg = -NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))); + + if (!test_nth_kday(MIN_JD, MIN_JD + 366, greg)) + return Qfalse; + if (!test_nth_kday(2305814, 2598007, greg)) + return Qfalse; + if (!test_nth_kday(MAX_JD - 366, MAX_JD, greg)) + return Qfalse; + + if (!test_nth_kday(MIN_JD, MIN_JD + 366, ITALY)) + return Qfalse; + if (!test_nth_kday(2305814, 2598007, ITALY)) + return Qfalse; + if (!test_nth_kday(MAX_JD - 366, MAX_JD, ITALY)) + return Qfalse; + + return Qtrue; +} + +static VALUE +date_s_test_all(VALUE klass) +{ + if (date_s_test_civil(klass) == Qfalse) + return Qfalse; + if (date_s_test_ordinal(klass) == Qfalse) + return Qfalse; + if (date_s_test_commercial(klass) == Qfalse) + return Qfalse; + if (date_s_test_weeknum(klass) == Qfalse) + return Qfalse; + if (date_s_test_nth_kday(klass) == Qfalse) + return Qfalse; + return Qtrue; +} +#endif + +void +Init_date_core(void) +{ + assert(fprintf(stderr, "assert() is now active\n")); + + rzero = rb_rational_new1(INT2FIX(0)); + rhalf = rb_rational_new2(INT2FIX(1), INT2FIX(2)); + day_in_nanoseconds = rb_ll2inum(DAY_IN_NANOSECONDS); + + rb_gc_register_mark_object(rzero); + rb_gc_register_mark_object(rhalf); + rb_gc_register_mark_object(day_in_nanoseconds); + + /* date */ + + cDate = rb_define_class("Date", rb_cObject); + + rb_define_alloc_func(cDate, d_lite_s_alloc); + rb_define_singleton_method(cDate, "new_r!", date_s_new_r_bang, -1); + rb_define_singleton_method(cDate, "new_l!", date_s_new_l_bang, -1); + + rb_define_singleton_method(cDate, "valid_jd?", date_s_valid_jd_p, -1); + rb_define_singleton_method(cDate, "valid_ordinal?", + date_s_valid_ordinal_p, -1); + rb_define_singleton_method(cDate, "valid_civil?", date_s_valid_civil_p, -1); + rb_define_singleton_method(cDate, "valid_date?", date_s_valid_civil_p, -1); + rb_define_singleton_method(cDate, "valid_commercial?", + date_s_valid_commercial_p, -1); + rb_define_singleton_method(cDate, "jd", date_s_jd, -1); + rb_define_singleton_method(cDate, "ordinal", date_s_ordinal, -1); + rb_define_singleton_method(cDate, "civil", date_s_civil, -1); + rb_define_singleton_method(cDate, "new", date_s_civil, -1); + rb_define_singleton_method(cDate, "commercial", date_s_commercial, -1); + rb_define_singleton_method(cDate, "today", date_s_today, -1); + + rb_define_method(cDate, "ajd", d_lite_ajd, 0); + rb_define_method(cDate, "amjd", d_lite_amjd, 0); + rb_define_method(cDate, "jd", d_lite_jd, 0); + rb_define_method(cDate, "mjd", d_lite_mjd, 0); + rb_define_method(cDate, "ld", d_lite_ld, 0); + + rb_define_method(cDate, "year", d_lite_year, 0); + rb_define_method(cDate, "yday", d_lite_yday, 0); + rb_define_method(cDate, "mon", d_lite_mon, 0); + rb_define_method(cDate, "month", d_lite_mon, 0); + rb_define_method(cDate, "mday", d_lite_mday, 0); + rb_define_method(cDate, "day", d_lite_mday, 0); + rb_define_method(cDate, "day_fraction", d_lite_day_fraction, 0); + + rb_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); + rb_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); + + rb_define_private_method(cDate, "hour", d_lite_hour, 0); + rb_define_private_method(cDate, "min", d_lite_min, 0); + rb_define_private_method(cDate, "minute", d_lite_min, 0); + rb_define_private_method(cDate, "sec", d_lite_sec, 0); + rb_define_private_method(cDate, "second", d_lite_sec, 0); + rb_define_private_method(cDate, "sec_fraction", d_lite_sec_fraction, 0); + rb_define_private_method(cDate, "second_fraction", d_lite_sec_fraction, 0); + rb_define_private_method(cDate, "offset", d_lite_offset, 0); + rb_define_private_method(cDate, "zone", d_lite_zone, 0); + + rb_define_method(cDate, "cwyear", d_lite_cwyear, 0); + rb_define_method(cDate, "cweek", d_lite_cweek, 0); + rb_define_method(cDate, "cwday", d_lite_cwday, 0); + + rb_define_method(cDate, "wday", d_lite_wday, 0); + + rb_define_method(cDate, "julian?", d_lite_julian_p, 0); + rb_define_method(cDate, "gregorian?", d_lite_gregorian_p, 0); + rb_define_method(cDate, "leap?", d_lite_leap_p, 0); + + rb_define_method(cDate, "start", d_lite_start, 0); + rb_define_method(cDate, "new_start", d_lite_new_start, -1); + rb_define_private_method(cDate, "new_offset", d_lite_new_offset, -1); + + rb_define_method(cDate, "+", d_lite_plus, 1); + rb_define_method(cDate, "-", d_lite_minus, 1); + + rb_define_method(cDate, "<=>", d_lite_cmp, 1); + rb_define_method(cDate, "===", d_lite_equal, 1); + rb_define_method(cDate, "eql?", d_lite_eql_p, 1); + rb_define_method(cDate, "hash", d_lite_hash, 0); + + rb_define_method(cDate, "to_s", d_lite_to_s, 0); + rb_define_method(cDate, "inspect", d_lite_inspect, 0); + + rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0); + rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1); + + rb_define_private_method(cDate, "__ca__", d_right_cache, 0); + + /* datetime */ + + cDateTime = rb_define_class("DateTime", cDate); + + rb_define_alloc_func(cDateTime, dt_lite_s_alloc); + rb_define_singleton_method(cDateTime, "new_l!", datetime_s_new_l_bang, -1); + + rb_undef_method(CLASS_OF(cDateTime), "today"); + + rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1); + rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1); + rb_define_singleton_method(cDateTime, "civil", datetime_s_civil, -1); + rb_define_singleton_method(cDateTime, "new", datetime_s_civil, -1); + rb_define_singleton_method(cDateTime, "commercial", + datetime_s_commercial, -1); + rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1); + + rb_define_method(cDateTime, "ajd", dt_lite_ajd, 0); + rb_define_method(cDateTime, "amjd", dt_lite_amjd, 0); + rb_define_method(cDateTime, "jd", dt_lite_jd, 0); + rb_define_method(cDateTime, "mjd", dt_lite_mjd, 0); + rb_define_method(cDateTime, "ld", dt_lite_ld, 0); + + rb_define_method(cDateTime, "year", dt_lite_year, 0); + rb_define_method(cDateTime, "yday", dt_lite_yday, 0); + rb_define_method(cDateTime, "mon", dt_lite_mon, 0); + rb_define_method(cDateTime, "month", dt_lite_mon, 0); + rb_define_method(cDateTime, "mday", dt_lite_mday, 0); + rb_define_method(cDateTime, "day", dt_lite_mday, 0); + rb_define_method(cDateTime, "day_fraction", dt_lite_day_fraction, 0); + + rb_define_private_method(cDateTime, "wnum0", dt_lite_wnum0, 0); + rb_define_private_method(cDateTime, "wnum1", dt_lite_wnum1, 0); + + rb_define_method(cDateTime, "hour", dt_lite_hour, 0); + rb_define_method(cDateTime, "min", dt_lite_min, 0); + rb_define_method(cDateTime, "minute", dt_lite_min, 0); + rb_define_method(cDateTime, "sec", dt_lite_sec, 0); + rb_define_method(cDateTime, "second", dt_lite_sec, 0); + rb_define_method(cDateTime, "sec_fraction", dt_lite_sec_fraction, 0); + rb_define_method(cDateTime, "second_fraction", dt_lite_sec_fraction, 0); + rb_define_method(cDateTime, "offset", dt_lite_offset, 0); + rb_define_method(cDateTime, "zone", dt_lite_zone, 0); + + rb_define_method(cDateTime, "cwyear", dt_lite_cwyear, 0); + rb_define_method(cDateTime, "cweek", dt_lite_cweek, 0); + rb_define_method(cDateTime, "cwday", dt_lite_cwday, 0); + + rb_define_method(cDateTime, "wday", dt_lite_wday, 0); + + rb_define_method(cDateTime, "julian?", dt_lite_julian_p, 0); + rb_define_method(cDateTime, "gregorian?", dt_lite_gregorian_p, 0); + rb_define_method(cDateTime, "leap?", dt_lite_leap_p, 0); + + rb_define_method(cDateTime, "start", dt_lite_start, 0); + rb_define_method(cDateTime, "new_start", dt_lite_new_start, -1); + rb_define_method(cDateTime, "new_offset", dt_lite_new_offset, -1); + + rb_define_method(cDateTime, "+", dt_lite_plus, 1); + rb_define_method(cDateTime, "-", dt_lite_minus, 1); + + rb_define_method(cDateTime, "<=>", dt_lite_cmp, 1); + rb_define_method(cDateTime, "===", dt_lite_equal, 1); + rb_define_method(cDateTime, "eql?", dt_lite_eql_p, 1); + rb_define_method(cDateTime, "hash", dt_lite_hash, 0); + + rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0); + rb_define_method(cDateTime, "inspect", dt_lite_inspect, 0); + + rb_define_method(cDateTime, "marshal_dump", dt_lite_marshal_dump, 0); + rb_define_method(cDateTime, "marshal_load", dt_lite_marshal_load, 1); + + rb_define_private_method(cDateTime, "__ca__", dt_right_cache, 0); + +#ifndef NDEBUG + rb_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0); + rb_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0); + rb_define_singleton_method(cDate, "test_commercial", + date_s_test_commercial, 0); + rb_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0); + rb_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0); + rb_define_singleton_method(cDate, "test_all", date_s_test_all, 0); +#endif +} + +/* +Local variables: +c-file-style: "ruby" +End: +*/ diff --git a/ext/date/extconf.rb b/ext/date/extconf.rb new file mode 100644 index 0000000000..29a36a29f4 --- /dev/null +++ b/ext/date/extconf.rb @@ -0,0 +1,4 @@ +require 'mkmf' +have_func('floorl', 'math.h') +have_func('roundl', 'math.h') +create_makefile('date_core') diff --git a/lib/date.rb b/lib/date.rb index 079a6059bb..66fa67a579 100644 --- a/lib/date.rb +++ b/lib/date.rb @@ -5,10 +5,6 @@ # # Documentation: William Webber <william@williamwebber.com> # -#-- -# $Id: date.rb,v 2.37 2008-01-17 20:16:31+09 tadf Exp $ -#++ -# # == Overview # # This file provides two classes for working with @@ -280,6 +276,15 @@ class Date end end + def to_f + return 0 if @d == 0 + if @d > 0 + Float::INFINITY + else + -Float::INFINITY + end + end + end # The Julian Day Number of the Day of Calendar Reform for Italy @@ -443,8 +448,14 @@ class Date # [commercial_year, week_of_year, day_of_week] def jd_to_commercial(jd, sg=GREGORIAN) # :nodoc: a = jd_to_civil(jd - 3, sg)[0] - y = if jd >= commercial_to_jd(a + 1, 1, 1, sg) then a + 1 else a end - w = 1 + ((jd - commercial_to_jd(y, 1, 1, sg)) / 7).floor + j = commercial_to_jd(a + 1, 1, 1, sg) + if jd >= j + y = a + 1 + else + j = commercial_to_jd(a, 1, 1, sg) + y = a + end + w = 1 + ((jd - j) / 7).floor d = (jd + 1) % 7 d = 7 if d == 0 return y, w, d @@ -719,26 +730,31 @@ class Date def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end class << self; alias_method :leap?, :gregorian_leap? end - class << self; alias_method :new!, :new end - def self.valid_jd? (jd, sg=ITALY) + def self.valid_jd_r? (jd, sg=ITALY) !!_valid_jd?(jd, sg) end - def self.valid_ordinal? (y, d, sg=ITALY) + private_class_method :valid_jd_r? + + def self.valid_ordinal_r? (y, d, sg=ITALY) !!_valid_ordinal?(y, d, sg) end - def self.valid_civil? (y, m, d, sg=ITALY) + private_class_method :valid_ordinal_r? + + def self.valid_civil_r? (y, m, d, sg=ITALY) !!_valid_civil?(y, m, d, sg) end - class << self; alias_method :valid_date?, :valid_civil? end + private_class_method :valid_civil_r? - def self.valid_commercial? (y, w, d, sg=ITALY) + def self.valid_commercial_r? (y, w, d, sg=ITALY) !!_valid_commercial?(y, w, d, sg) end + private_class_method :valid_commercial_r? + def self.valid_weeknum? (y, w, d, f, sg=ITALY) # :nodoc: !!_valid_weeknum?(y, w, d, f, sg) end @@ -757,16 +773,28 @@ class Date private_class_method :valid_time? + def self.new!(ajd=0, of=0, sg=ITALY) + jd, df = ajd_to_jd(ajd, 0) + if !(Fixnum === jd) || + jd < sg || df !=0 || of != 0 || + jd < -327 || jd > 366963925 + return new_r!(ajd, of, sg) + end + new_l!(jd, sg) + end + # Create a new Date object from a Julian Day Number. # # +jd+ is the Julian Day Number; if not specified, it defaults to # 0. # +sg+ specifies the Day of Calendar Reform. - def self.jd(jd=0, sg=ITALY) + def self.jd_r(jd=0, sg=ITALY) # :nodoc: jd = _valid_jd?(jd, sg) - new!(jd_to_ajd(jd, 0, 0), 0, sg) + new_r!(jd_to_ajd(jd, 0, 0), 0, sg) end + private_class_method :jd_r + # Create a new Date object from an Ordinal Date, specified # by year +y+ and day-of-year +d+. +d+ can be negative, # in which it counts backwards from the end of the year. @@ -777,13 +805,15 @@ class Date # Number day 0. # # +sg+ specifies the Day of Calendar Reform. - def self.ordinal(y=-4712, d=1, sg=ITALY) + def self.ordinal_r(y=-4712, d=1, sg=ITALY) # :nodoc: unless jd = _valid_ordinal?(y, d, sg) raise ArgumentError, 'invalid date' end - new!(jd_to_ajd(jd, 0, 0), 0, sg) + new_r!(jd_to_ajd(jd, 0, 0), 0, sg) end + private_class_method :ordinal_r + # Create a new Date object for the Civil Date specified by # year +y+, month +m+, and day-of-month +d+. # @@ -797,14 +827,14 @@ class Date # Julian Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. - def self.civil(y=-4712, m=1, d=1, sg=ITALY) + def self.civil_r(y=-4712, m=1, d=1, sg=ITALY) # :nodoc: unless jd = _valid_civil?(y, m, d, sg) raise ArgumentError, 'invalid date' end - new!(jd_to_ajd(jd, 0, 0), 0, sg) + new_r!(jd_to_ajd(jd, 0, 0), 0, sg) end - class << self; alias_method :new, :civil end + private_class_method :civil_r # Create a new Date object for the Commercial Date specified by # year +y+, week-of-year +w+, and day-of-week +d+. @@ -820,13 +850,15 @@ class Date # Julian Day Number day 0. # # +sg+ specifies the Day of Calendar Reform. - def self.commercial(y=-4712, w=1, d=1, sg=ITALY) + def self.commercial_r(y=-4712, w=1, d=1, sg=ITALY) # :nodoc: unless jd = _valid_commercial?(y, w, d, sg) raise ArgumentError, 'invalid date' end - new!(jd_to_ajd(jd, 0, 0), 0, sg) + new_r!(jd_to_ajd(jd, 0, 0), 0, sg) end + private_class_method :commercial_r + def self.weeknum(y=-4712, w=0, d=1, f=0, sg=ITALY) unless jd = _valid_weeknum?(y, w, d, f, sg) raise ArgumentError, 'invalid date' @@ -1099,7 +1131,7 @@ class Date alias_method :__#{id.object_id}__, :#{id.to_s} private :__#{id.object_id}__ def #{id.to_s}(*args) - @__ca__[#{id.object_id}] ||= __#{id.object_id}__(*args) + __ca__[#{id.object_id}] ||= __#{id.object_id}__(*args) end end; end @@ -1109,96 +1141,69 @@ class Date end - # *NOTE* this is the documentation for the method new!(). If - # you are reading this as the documentation for new(), that is - # because rdoc doesn't fully support the aliasing of the - # initialize() method. - # new() is in - # fact an alias for #civil(): read the documentation for that - # method instead. - # - # Create a new Date object. - # - # +ajd+ is the Astronomical Julian Day Number. - # +of+ is the offset from UTC as a fraction of a day. - # Both default to 0. - # - # +sg+ specifies the Day of Calendar Reform to use for this - # Date object. - # - # Using one of the factory methods such as Date::civil is - # generally easier and safer. - def initialize(ajd=0, of=0, sg=ITALY) - @ajd, @of, @sg = ajd, of, sg - @__ca__ = {} - end - - # Get the date as an Astronomical Julian Day Number. - def ajd() @ajd end - # Get the date as an Astronomical Modified Julian Day Number. - def amjd() ajd_to_amjd(@ajd) end + def amjd_r() ajd_to_amjd(ajd) end - once :amjd + once :amjd_r - def daynum() ajd_to_jd(@ajd, @of) end + def daynum() ajd_to_jd(ajd, offset) end once :daynum private :daynum # Get the date as a Julian Day Number. - def jd() daynum[0] end + def jd_r() daynum[0] end # :nodoc: # Get any fractional day part of the date. - def day_fraction() daynum[1] end + def day_fraction_r() daynum[1] end # :nodoc: # Get the date as a Modified Julian Day Number. - def mjd() jd_to_mjd(jd) end + def mjd_r() jd_to_mjd(jd) end # :nodoc: # Get the date as the number of days since the Day of Calendar # Reform (in Italy and the Catholic countries). - def ld() jd_to_ld(jd) end + def ld_r() jd_to_ld(jd) end # :nodoc: - once :jd, :day_fraction, :mjd, :ld + once :jd_r, :day_fraction_r, :mjd_r, :ld_r + private :jd_r, :day_fraction_r, :mjd_r, :ld_r # Get the date as a Civil Date, [year, month, day_of_month] - def civil() jd_to_civil(jd, @sg) end # :nodoc: + def civil() jd_to_civil(jd, start) end # :nodoc: # Get the date as an Ordinal Date, [year, day_of_year] - def ordinal() jd_to_ordinal(jd, @sg) end # :nodoc: + def ordinal() jd_to_ordinal(jd, start) end # :nodoc: # Get the date as a Commercial Date, [year, week_of_year, day_of_week] - def commercial() jd_to_commercial(jd, @sg) end # :nodoc: + def commercial() jd_to_commercial(jd, start) end # :nodoc: - def weeknum0() jd_to_weeknum(jd, 0, @sg) end # :nodoc: - def weeknum1() jd_to_weeknum(jd, 1, @sg) end # :nodoc: + def weeknum0() jd_to_weeknum(jd, 0, start) end # :nodoc: + def weeknum1() jd_to_weeknum(jd, 1, start) end # :nodoc: once :civil, :ordinal, :commercial, :weeknum0, :weeknum1 private :civil, :ordinal, :commercial, :weeknum0, :weeknum1 # Get the year of this date. - def year() civil[0] end + def year_r() civil[0] end # :nodoc: # Get the day-of-the-year of this date. # # January 1 is day-of-the-year 1 - def yday() ordinal[1] end + def yday_r() ordinal[1] end # :nodoc: # Get the month of this date. # # January is month 1. - def mon() civil[1] end + def mon_r() civil[1] end # :nodoc: # Get the day-of-the-month of this date. - def mday() civil[2] end + def mday_r() civil[2] end # :nodoc: - alias_method :month, :mon - alias_method :day, :mday + private :year_r, :yday_r, :mon_r, :mday_r - def wnum0() weeknum0[1] end # :nodoc: - def wnum1() weeknum1[1] end # :nodoc: + def wnum0_r() weeknum0[1] end # :nodoc: + def wnum1_r() weeknum1[1] end # :nodoc: - private :wnum0, :wnum1 + private :wnum0_r, :wnum1_r # Get the time of this date as [hours, minutes, seconds, # fraction_of_a_second] @@ -1210,25 +1215,20 @@ class Date private :time, :time_wo_sf, :time_sf # Get the hour of this date. - def hour() time_wo_sf[0] end # 4p + def hour_r() time_wo_sf[0] end # :nodoc: # 4p # Get the minute of this date. - def min() time_wo_sf[1] end # 4p + def min_r() time_wo_sf[1] end # :nodoc: # 4p # Get the second of this date. - def sec() time_wo_sf[2] end # 4p + def sec_r() time_wo_sf[2] end # :nodoc: # 4p # Get the fraction-of-a-second of this date. - def sec_fraction() time_sf end # 4p - - alias_method :minute, :min - alias_method :second, :sec - alias_method :second_fraction, :sec_fraction + def sec_fraction_r() time_sf end # 4p - private :hour, :min, :sec, :sec_fraction, - :minute, :second, :second_fraction + private :hour_r, :min_r, :sec_r, :sec_fraction_r - def zone # 4p - strftime('%:z') + def zone_r # :nodoc: # 4p - strftime('%:z') sign = if offset < 0 then '-' else '+' end fr = offset.abs ss = fr.div(SECONDS_IN_DAY) @@ -1237,24 +1237,27 @@ class Date format('%s%02d:%02d', sign, hh, mm) end - private :zone + private :zone_r # Get the commercial year of this date. See *Commercial* *Date* # in the introduction for how this differs from the normal year. - def cwyear() commercial[0] end + def cwyear_r() commercial[0] end # :nodoc: # Get the commercial week of the year of this date. - def cweek() commercial[1] end + def cweek_r() commercial[1] end # :nodoc: # Get the commercial day of the week of this date. Monday is # commercial day-of-week 1; Sunday is commercial day-of-week 7. - def cwday() commercial[2] end + def cwday_r() commercial[2] end # :nodoc: + + private :cwyear_r, :cweek_r, :cwday_r # Get the week day of this date. Sunday is day-of-week 0; # Saturday is day-of-week 6. - def wday() jd_to_wday(jd) end + def wday_r() jd_to_wday(jd) end # :nodoc: - once :wday + once :wday_r + private :wday_r =begin MONTHNAMES.each_with_index do |n, i| @@ -1268,19 +1271,20 @@ class Date define_method(n.downcase + '?'){wday == i} end - def nth_kday? (n, k) + def nth_kday? (n, k) # :nodoc: k == wday && jd === nth_kday_to_jd(year, mon, n, k, start) end private :nth_kday? # Is the current date old-style (Julian Calendar)? - def julian? () jd < @sg end + def julian_r? () jd < start end # :nodoc: # Is the current date new-style (Gregorian Calendar)? - def gregorian? () !julian? end + def gregorian_r? () !julian? end # :nodoc: - once :julian?, :gregorian? + once :julian_r?, :gregorian_r? + private :julian_r?, :gregorian_r? def fix_style # :nodoc: if julian? @@ -1291,18 +1295,21 @@ class Date private :fix_style # Is this a leap year? - def leap? + def leap_r? # :nodoc: jd_to_civil(civil_to_jd(year, 3, 1, fix_style) - 1, fix_style)[-1] == 29 end - once :leap? + once :leap_r? + private :leap_r? # When is the Day of Calendar Reform for this Date object? - def start() @sg end + def start_r() @sg end # :nodoc: # Create a copy of this Date object using a new Day of Calendar Reform. - def new_start(sg=self.class::ITALY) self.class.new!(@ajd, @of, sg) end + def new_start_r(sg=self.class::ITALY) self.class.new_r!(ajd, offset, sg) end # :nodoc: + + private :start_r, :new_start_r # Create a copy of this Date object that uses the Italian/Catholic # Day of Calendar Reform. @@ -1320,16 +1327,16 @@ class Date # Calendar. def gregorian() new_start(self.class::GREGORIAN) end - def offset() @of end - - def new_offset(of=0) + def new_offset_r(of=0) # :nodoc: if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end - self.class.new!(@ajd, of, @sg) + self.class.new_r!(ajd, of, start) end - private :offset, :new_offset + private :new_offset_r # Return a new Date object that is +n+ days later than the # current one. @@ -1340,13 +1347,19 @@ class Date # # If +n+ is not a Numeric, a TypeError will be thrown. In # particular, two Dates cannot be added to each other. - def + (n) + def plus_r (n) # :nodoc: case n - when Numeric; return self.class.new!(@ajd + n, @of, @sg) + when Numeric + if Float === n + n = Rational((n * 86400000000000).round, 86400000000000) + end + return self.class.new_r!(ajd + n, offset, start) end raise TypeError, 'expected numeric' end + private :plus_r + # If +x+ is a Numeric value, create a new Date object that is # +x+ days earlier than the current one. # @@ -1355,14 +1368,21 @@ class Date # date is than +x+. # # If +x+ is neither Numeric nor a Date, a TypeError is raised. - def - (x) + def minus_r (x) # :nodoc: case x - when Numeric; return self.class.new!(@ajd - x, @of, @sg) - when Date; return @ajd - x.ajd + when Numeric + if Float === x + x = Rational((x * 86400000000000).round, 86400000000000) + end + return self.class.new_r!(ajd - x, offset, start) + when Date + return ajd - x.ajd end raise TypeError, 'expected numeric or date' end + private :minus_r + # Compare this date with another date. # # +other+ can also be a Numeric value, in which case it is @@ -1374,10 +1394,10 @@ class Date # two DateTime instances. When comparing a DateTime instance # with a Date instance, the time of the latter will be # considered as falling on midnight UTC. - def <=> (other) + def cmp_r (other) # :nodoc: case other - when Numeric; return @ajd <=> other - when Date; return @ajd <=> other.ajd + when Numeric; return ajd <=> other + when Date; return ajd <=> other.ajd else begin l, r = other.coerce(self) @@ -1388,13 +1408,15 @@ class Date nil end + private :cmp_r + # The relationship operator for Date. # # Compares dates by Julian Day Number. When comparing # two DateTime instances, or a DateTime with a Date, # the instances will be regarded as equivalent if they # fall on the same date in local time. - def === (other) + def equal_r (other) # :nodoc: case other when Numeric; return jd == other when Date; return jd == other.jd @@ -1408,6 +1430,8 @@ class Date false end + private :equal_r + def next_day(n=1) self + n end def prev_day(n=1) self - n end @@ -1426,7 +1450,7 @@ class Date y, m = (year * 12 + (mon - 1) + n).divmod(12) m, = (m + 1) .divmod(1) d = mday - until jd2 = _valid_civil?(y, m, d, @sg) + until jd2 = _valid_civil?(y, m, d, start) d -= 1 raise ArgumentError, 'invalid date' unless d > 0 end @@ -1486,29 +1510,28 @@ class Date # Is this Date equal to +other+? # # +other+ must both be a Date object, and represent the same date. - def eql? (other) Date === other && self == other end + def eql_r? (other) Date === other && self == other end # :nodoc: + + private :eql_r? # Calculate a hash value for this date. - def hash() @ajd.hash end + def hash_r() ajd.hash end # :nodoc: + + private :hash_r # Return internal object state as a programmer-readable string. - def inspect - format('#<%s: %s (%s,%s,%s)>', self.class, to_s, @ajd, @of, @sg) + def inspect_r # :nodoc: + format('#<%s[R]: %s (%s,%s,%s)>', self.class, to_s_r, ajd, offset, start) end + private :inspect_r + # Return the date as a human-readable string. # # The format used is YYYY-MM-DD. - def to_s() format('%.4d-%02d-%02d', year, mon, mday) end # 4p - - # Dump to Marshal format. - def marshal_dump() [@ajd, @of, @sg] end + def to_s_r() format('%.4d-%02d-%02d', year, mon, mday) end # :nodoc: # 4p - # Load from Marshal format. - def marshal_load(a) - @ajd, @of, @sg, = a - @__ca__ = {} - end + private :to_s_r end @@ -1562,6 +1585,19 @@ end # class DateTime < Date + def self.new!(ajd=0, of=0, sg=ITALY) + jd, df = ajd_to_jd(ajd, 0) + df, sf = (df * 86400).divmod(1) + sf, ssf = (sf * 1000000000).divmod(1) + odf, osf = (of * 86400).divmod(1) + if !(Fixnum === jd) || + jd < sg || ssf != 0 || osf != 0 || + jd < -327 || jd > 366963925 + return new_r!(ajd, of, sg) + end + new_l!(jd, df, sf, odf, sg) + end + # Create a new DateTime object corresponding to the specified # Julian Day Number +jd+ and hour +h+, minute +min+, second +s+. # @@ -1575,17 +1611,21 @@ class DateTime < Date # +sg+ specifies the Day of Calendar Reform. # # All day/time values default to 0. - def self.jd(jd=0, h=0, min=0, s=0, of=0, sg=ITALY) + def self.jd_r(jd=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = _valid_jd?(jd, sg)) && (fr = _valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end - new!(jd_to_ajd(jd, fr, of), of, sg) + new_r!(jd_to_ajd(jd, fr, of), of, sg) end + private_class_method :jd_r + # Create a new DateTime object corresponding to the specified # Ordinal Date and hour +h+, minute +min+, second +s+. # @@ -1600,17 +1640,21 @@ class DateTime < Date # # +y+ defaults to -4712, and +d+ to 1; this is Julian Day Number # day 0. The time values default to 0. - def self.ordinal(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY) + def self.ordinal_r(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = _valid_ordinal?(y, d, sg)) && (fr = _valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end - new!(jd_to_ajd(jd, fr, of), of, sg) + new_r!(jd_to_ajd(jd, fr, of), of, sg) end + private_class_method :ordinal_r + # Create a new DateTime object corresponding to the specified # Civil Date and hour +h+, minute +min+, second +s+. # @@ -1625,18 +1669,20 @@ class DateTime < Date # # +y+ defaults to -4712, +m+ to 1, and +d+ to 1; this is Julian Day # Number day 0. The time values default to 0. - def self.civil(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY) + def self.civil_r(y=-4712, m=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = _valid_civil?(y, m, d, sg)) && (fr = _valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end - new!(jd_to_ajd(jd, fr, of), of, sg) + new_r!(jd_to_ajd(jd, fr, of), of, sg) end - class << self; alias_method :new, :civil end + private_class_method :civil_r # Create a new DateTime object corresponding to the specified # Commercial Date and hour +h+, minute +min+, second +s+. @@ -1653,17 +1699,21 @@ class DateTime < Date # +y+ defaults to -4712, +w+ to 1, and +d+ to 1; this is # Julian Day Number day 0. # The time values default to 0. - def self.commercial(y=-4712, w=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY) + def self.commercial_r(y=-4712, w=1, d=1, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = _valid_commercial?(y, w, d, sg)) && (fr = _valid_time?(h, min, s)) raise ArgumentError, 'invalid date' end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end - new!(jd_to_ajd(jd, fr, of), of, sg) + new_r!(jd_to_ajd(jd, fr, of), of, sg) end + private_class_method :commercial_r + def self.weeknum(y=-4712, w=0, d=1, f=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc: unless (jd = _valid_weeknum?(y, w, d, f, sg)) && (fr = _valid_time?(h, min, s)) @@ -1671,6 +1721,8 @@ class DateTime < Date end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end @@ -1684,6 +1736,8 @@ class DateTime < Date end if String === of of = Rational(zone_to_diff(of) || 0, 86400) + elsif Float === of + of = Rational((of * 86400).round, 86400) end new!(jd_to_ajd(jd, fr, of), of, sg) end @@ -1770,14 +1824,13 @@ class DateTime < Date new_by_frags(elem, sg) end - public :hour, :min, :sec, :sec_fraction, :zone, :offset, :new_offset, - :minute, :second, :second_fraction - - def to_s # 4p + def to_s_r # :nodoc: # 4p format('%.4d-%02d-%02dT%02d:%02d:%02d%s', year, mon, mday, hour, min, sec, zone) end + private :to_s_r + end class Time @@ -1795,7 +1848,7 @@ class Time Rational(subsec, 86400) of = Rational(utc_offset, 86400) DateTime.new!(DateTime.__send__(:jd_to_ajd, jd, fr, of), - of, DateTime::ITALY) + of, DateTime::ITALY) end end @@ -1804,30 +1857,7 @@ class Date def to_time() Time.local(year, mon, mday) end def to_date() self end - def to_datetime() DateTime.new!(jd_to_ajd(jd, 0, 0), @of, @sg) end - - # Create a new Date object representing today. - # - # +sg+ specifies the Day of Calendar Reform. - def self.today(sg=ITALY) - t = Time.now - jd = civil_to_jd(t.year, t.mon, t.mday, sg) - new!(jd_to_ajd(jd, 0, 0), 0, sg) - end - - # Create a new DateTime object representing the current time. - # - # +sg+ specifies the Day of Calendar Reform. - def self.now(sg=ITALY) - t = Time.now - jd = civil_to_jd(t.year, t.mon, t.mday, sg) - fr = time_to_day_fraction(t.hour, t.min, [t.sec, 59].min) + - Rational(t.subsec, 86400) - of = Rational(t.utc_offset, 86400) - new!(jd_to_ajd(jd, fr, of), of, sg) - end - - private_class_method :now + def to_datetime() DateTime.new!(jd_to_ajd(jd, 0, 0), offset, start) end end @@ -1839,13 +1869,12 @@ class DateTime < Date Time.utc(year, mon, mday, hour, min, sec + sec_fraction) end. - getlocal + getlocal end - def to_date() Date.new!(jd_to_ajd(jd, 0, 0), 0, @sg) end + def to_date() Date.new!(jd_to_ajd(jd, 0, 0), 0, start) end def to_datetime() self end - private_class_method :today - public_class_method :now - end + +require 'date_core' |