summaryrefslogtreecommitdiff
path: root/ext/date
diff options
context:
space:
mode:
authortadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-05-21 12:25:03 +0000
committertadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-05-21 12:25:03 +0000
commit559c025a22e7a1df0182c505017eec7cb3d2228e (patch)
tree94a871cf9f9b59e144a2d31b44cd0d4c884c98f4 /ext/date
parent42cb637942628ab87119482e4bcf372cdc19f6d6 (diff)
* ext/date/date_{core,parse}.c: moved nearly all core code from ext/date/lib.
* ext/date/lib/{date,date/format}.rb: removed nearly all code. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31668 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/date')
-rw-r--r--ext/date/date_core.c6575
-rw-r--r--ext/date/date_parse.c1191
-rw-r--r--ext/date/date_strftime.c4
-rw-r--r--ext/date/date_strptime.c4
-rw-r--r--ext/date/lib/date.rb1590
-rw-r--r--ext/date/lib/date/format.rb583
6 files changed, 7232 insertions, 2715 deletions
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index b6e2688299..12c393515c 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -10,21 +10,26 @@
#define NDEBUG
#include <assert.h>
+/* #define FORCE_RIGHT */
+
#ifdef RUBY_EXTCONF_H
#include RUBY_EXTCONF_H
#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 (1 << 0)
+#define HAVE_JD (1 << 1)
+#define HAVE_DF (1 << 2)
+#define HAVE_CIVIL (1 << 3)
+#define HAVE_TIME (1 << 4)
+#define DATETIME_OBJ (1 << 7)
#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 datetime_obj_p(x) ((x)->flags & DATETIME_OBJ)
+#define date_obj_p(x) (!datetime_obj_p(x))
#define MIN_YEAR -4713
#define MAX_YEAR 1000000
@@ -40,15 +45,10 @@
#define JULIAN (NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))))
#define GREGORIAN (-NUM2DBL(rb_const_get(rb_cFloat, rb_intern("INFINITY"))))
+#define MINUTE_IN_SECONDS 60
+#define HOUR_IN_SECONDS 3600
#define DAY_IN_SECONDS 86400
#define SECOND_IN_NANOSECONDS 1000000000
-#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
-#define DAY_IN_NANOSECONDS LONG2NUM((long)DAY_IN_SECONDS * SECOND_IN_NANOSECONDS)
-#elif defined HAVE_LONG_LONG
-#define DAY_IN_NANOSECONDS LL2NUM((LONG_LONG)DAY_IN_SECONDS * SECOND_IN_NANOSECONDS)
-#else
-#define DAY_IN_NANOSECONDS f_mul(INT2FIX(DAY_IN_SECONDS), INT2FIX(SECOND_IN_NANOSECONDS))
-#endif
/* copied from time.c */
#define NDIV(x,y) (-(-((x)+1)/(y))-1)
@@ -106,33 +106,43 @@ union DateTimeData
#define get_d1(x)\
union DateData *dat;\
- Data_Get_Struct(x, union DateData, dat)
+ Data_Get_Struct(x, union DateData, dat);\
+ assert(date_obj_p(dat))
#define get_d2(x,y)\
union DateData *adat, *bdat;\
Data_Get_Struct(x, union DateData, adat);\
- Data_Get_Struct(y, union DateData, bdat)
+ Data_Get_Struct(y, union DateData, bdat);\
+ assert(date_obj_p(adat));\
+ assert(date_obj_p(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)
+ Data_Get_Struct(y, union DateTimeData, bdat)\
+ assert(date_obj_p(adat));\
+ assert(datetime_obj_p(bdat))
#define get_dt1(x)\
union DateTimeData *dat;\
- Data_Get_Struct(x, union DateTimeData, dat)
+ Data_Get_Struct(x, union DateTimeData, dat);\
+ assert(datetime_obj_p(dat))
#define get_dt2(x,y)\
union DateTimeData *adat, *bdat;\
Data_Get_Struct(x, union DateTimeData, adat);\
- Data_Get_Struct(y, union DateTimeData, bdat)
+ Data_Get_Struct(y, union DateTimeData, bdat);\
+ assert(datetime_obj_p(adat));\
+ assert(datetime_obj_p(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)
+ Data_Get_Struct(y, union DateData, bdat);\
+ assert(datetime_obj_p(adat));\
+ assert(date_obj_p(bdat))
#define get_dt2_cast(x,y)\
union DateData *atmp, *btmp;\
@@ -152,7 +162,7 @@ union DateTimeData
abuf.l.hour = 0;\
abuf.l.min = 0;\
abuf.l.sec = 0;\
- abuf.flags = HAVE_DF | HAVE_TIME | atmp->l.flags;\
+ abuf.flags = HAVE_DF | HAVE_TIME | DATETIME_OBJ | atmp->l.flags;\
adat = &abuf;\
}\
if (k_datetime_p(y))\
@@ -170,29 +180,614 @@ union DateTimeData
bbuf.l.hour = 0;\
bbuf.l.min = 0;\
bbuf.l.sec = 0;\
- bbuf.flags = HAVE_DF | HAVE_TIME | btmp->l.flags;\
+ bbuf.flags = HAVE_DF | HAVE_TIME | DATETIME_OBJ | btmp->l.flags;\
bdat = &bbuf;\
}
+#define f_abs(x) rb_funcall(x, rb_intern("abs"), 0)
+#define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
#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)
+#define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
+#define f_mod(x,y) rb_funcall(x, '%', 1, y)
+#define f_remainder(x,y) rb_funcall(x, rb_intern("remainder"), 1, y)
+#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
+#define f_floor(x) rb_funcall(x, rb_intern("floor"), 0)
+#define f_ceil(x) rb_funcall(x, rb_intern("ceil"), 0)
+#define f_truncate(x) rb_funcall(x, rb_intern("truncate"), 0)
+#define f_round(x) rb_funcall(x, rb_intern("round"), 0)
+
+#define f_add3(x,y,z) f_add(f_add(x, y), z)
+#define f_sub3(x,y,z) f_sub(f_sub(x, y), z)
+
+#define f_cmp(x,y) rb_funcall(x, rb_intern("<=>"), 1, y)
+#define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
+#define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
+#define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
+#define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
+
+#define f_eqeq_p(x,y) rb_funcall(x, rb_intern("=="), 1, y)
+#define f_equal_p(x,y) rb_funcall(x, rb_intern("==="), 1, y)
+#define f_zero_p(x) rb_funcall(x, rb_intern("zero?"), 0)
+#define f_negative_p(x) f_lt_p(x, INT2FIX(0))
+#define f_positive_p(x) (!f_negative_p(x))
+
+#define f_compact(x) rb_funcall(x, rb_intern("compact"), 0)
+
+#define f_ajd(x) rb_funcall(x, rb_intern("ajd"), 0)
+#define f_jd(x) rb_funcall(x, rb_intern("jd"), 0)
+#define f_year(x) rb_funcall(x, rb_intern("year"), 0)
+#define f_mon(x) rb_funcall(x, rb_intern("mon"), 0)
+#define f_mday(x) rb_funcall(x, rb_intern("mday"), 0)
+#define f_wday(x) rb_funcall(x, rb_intern("wday"), 0)
+#define f_hour(x) rb_funcall(x, rb_intern("hour"), 0)
+#define f_min(x) rb_funcall(x, rb_intern("min"), 0)
+#define f_sec(x) rb_funcall(x, rb_intern("sec"), 0)
+#define f_start(x) rb_funcall(x, rb_intern("start"), 0)
static VALUE cDate, cDateTime;
static VALUE rzero, rhalf, day_in_nanoseconds;
+/* right base */
+
+#define HALF_DAYS_IN_DAY rb_rational_new2(INT2FIX(1), INT2FIX(2))
+#define HOURS_IN_DAY rb_rational_new2(INT2FIX(1), INT2FIX(24))
+#define MINUTES_IN_DAY rb_rational_new2(INT2FIX(1), INT2FIX(1440))
+#define SECONDS_IN_DAY rb_rational_new2(INT2FIX(1), INT2FIX(86400))
+#define MILLISECONDS_IN_DAY\
+ rb_rational_new2(INT2FIX(1), f_mul(INT2FIX(86400), INT2FIX(1000)))
+#define NANOSECONDS_IN_DAY\
+ rb_rational_new2(INT2FIX(1), f_mul(INT2FIX(86400), INT2FIX(1000000000)))
+#define MILLISECONDS_IN_SECOND rb_rational_new2(INT2FIX(1), INT2FIX(1000))
+#define NANOSECONDS_IN_SECOND rb_rational_new2(INT2FIX(1), INT2FIX(1000000000))
+
+#define MJD_EPOCH_IN_AJD\
+ rb_rational_new2(INT2FIX(4800001), INT2FIX(2)) /* 1858-11-17 */
+#define UNIX_EPOCH_IN_AJD\
+ rb_rational_new2(INT2FIX(4881175), INT2FIX(2)) /* 1970-01-01 */
+#define MJD_EPOCH_IN_CJD INT2FIX(2400001)
+#define UNIX_EPOCH_IN_CJD INT2FIX(2440588)
+#define LD_EPOCH_IN_CJD INT2FIX(2299160)
+
+static VALUE rt__valid_civil_p(VALUE, VALUE, VALUE, VALUE);
+
+static VALUE
+rt_find_fdoy(VALUE y, VALUE sg)
+{
+ int d;
+
+ for (d = 1; d < 31; d++) {
+ VALUE j = rt__valid_civil_p(y, INT2FIX(1), INT2FIX(d), sg);
+ if (!NIL_P(j))
+ return j;
+ }
+ return Qnil;
+}
+
+static VALUE
+rt_find_ldoy(VALUE y, VALUE sg)
+{
+ int i;
+
+ for (i = 0; i < 30; i++) {
+ VALUE j = rt__valid_civil_p(y, INT2FIX(12), INT2FIX(31 - i), sg);
+ if (!NIL_P(j))
+ return j;
+ }
+ return Qnil;
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_find_fdom(VALUE y, VALUE m, VALUE sg)
+{
+ int d;
+
+ for (d = 1; d < 31; d++) {
+ VALUE j = rt__valid_civil_p(y, m, INT2FIX(d), sg);
+ if (!NIL_P(j))
+ return j;
+ }
+ return Qnil;
+}
+#endif
+
+static VALUE
+rt_find_ldom(VALUE y, VALUE m, VALUE sg)
+{
+ int i;
+
+ for (i = 0; i < 30; i++) {
+ VALUE j = rt__valid_civil_p(y, m, INT2FIX(31 - i), sg);
+ if (!NIL_P(j))
+ return j;
+ }
+ return Qnil;
+}
+
+static VALUE
+rt_ordinal_to_jd(VALUE y, VALUE d, VALUE sg)
+{
+ return f_sub(f_add(rt_find_fdoy(y, sg), d), INT2FIX(1));
+}
+
+static VALUE rt_jd_to_civil(VALUE jd, VALUE sg);
+
+static VALUE
+rt_jd_to_ordinal(VALUE jd, VALUE sg)
+{
+ VALUE a, y, j, doy;
+
+ a = rt_jd_to_civil(jd, sg);
+ y = RARRAY_PTR(a)[0];
+ j = rt_find_fdoy(y, sg);
+ doy = f_add(f_sub(jd, j), INT2FIX(1));
+ return rb_assoc_new(y, doy);
+}
+
+static VALUE
+rt_civil_to_jd(VALUE y, VALUE m, VALUE d, VALUE sg)
+{
+ VALUE a, b, jd;
+
+ if (f_le_p(m, INT2FIX(2))) {
+ y = f_sub(y, INT2FIX(1));
+ m = f_add(m, INT2FIX(12));
+ }
+ a = f_floor(f_div(y, DBL2NUM(100.0)));
+ b = f_add(f_sub(INT2FIX(2), a), f_floor(f_div(a, DBL2NUM(4.0))));
+ jd = f_add3(f_floor(f_mul(DBL2NUM(365.25), f_add(y, INT2FIX(4716)))),
+ f_floor(f_mul(DBL2NUM(30.6001), f_add(m, INT2FIX(1)))),
+ f_sub(f_add(d, b), INT2FIX(1524)));
+ if (f_lt_p(jd, sg))
+ jd = f_sub(jd, b);
+ return jd;
+}
+
+static VALUE
+rt_jd_to_civil(VALUE jd, VALUE sg)
+{
+ VALUE a, x, b, c, d, e, dom, m, y;
+
+ if (f_lt_p(jd, sg))
+ a = jd;
+ else {
+ x = f_floor(f_div(f_sub(jd, DBL2NUM(1867216.25)), DBL2NUM(36524.25)));
+ a = f_sub(f_add3(jd, INT2FIX(1), x), f_floor(f_div(x, DBL2NUM(4.0))));
+ }
+ b = f_add(a, INT2FIX(1524));
+ c = f_floor(f_div(f_sub(b, DBL2NUM(122.1)), DBL2NUM(365.25)));
+ d = f_floor(f_mul(DBL2NUM(365.25), c));
+ e = f_floor(f_div(f_sub(b, d), DBL2NUM(30.6001)));
+ dom = f_sub3(b, d, f_floor(f_mul(DBL2NUM(30.6001), e)));
+ if (f_le_p(e, INT2FIX(13))) {
+ m = f_sub(e, INT2FIX(1));
+ y = f_sub(c, INT2FIX(4716));
+ }
+ else {
+ m = f_sub(e, INT2FIX(13));
+ y = f_sub(c, INT2FIX(4715));
+ }
+ return rb_ary_new3(3, y, m, dom);
+}
+
+static VALUE
+rt_commercial_to_jd(VALUE y, VALUE w, VALUE d, VALUE sg)
+{
+ VALUE j;
+
+ j = f_add(rt_find_fdoy(y, sg), INT2FIX(3));
+ return f_add3(f_sub(j, f_mod(j, INT2FIX(7))),
+ f_mul(INT2FIX(7), f_sub(w, INT2FIX(1))),
+ f_sub(d, INT2FIX(1)));
+}
+
+static VALUE
+rt_jd_to_commercial(VALUE jd, VALUE sg)
+{
+ VALUE t, a, j, y, w, d;
+
+ t = rt_jd_to_civil(f_sub(jd, INT2FIX(3)), sg);
+ a = RARRAY_PTR(t)[0];
+ j = rt_commercial_to_jd(f_add(a, INT2FIX(1)), INT2FIX(1), INT2FIX(1), sg);
+ if (f_ge_p(jd, j))
+ y = f_add(a, INT2FIX(1));
+ else {
+ j = rt_commercial_to_jd(a, INT2FIX(1), INT2FIX(1), sg);
+ y = a;
+ }
+ w = f_add(INT2FIX(1), f_idiv(f_sub(jd, j), INT2FIX(7)));
+ d = f_mod(f_add(jd, INT2FIX(1)), INT2FIX(7));
+ if (f_zero_p(d))
+ d = INT2FIX(7);
+ return rb_ary_new3(3, y, w, d);
+}
+
+static VALUE
+rt_weeknum_to_jd(VALUE y, VALUE w, VALUE d, VALUE f, VALUE sg)
+{
+ VALUE a;
+
+ a = f_add(rt_find_fdoy(y, sg), INT2FIX(6));
+ return f_add3(f_sub3(a,
+ f_mod(f_add(f_sub(a, f), INT2FIX(1)), INT2FIX(7)),
+ INT2FIX(7)),
+ f_mul(INT2FIX(7), w),
+ d);
+}
+
+static VALUE
+rt_jd_to_weeknum(VALUE jd, VALUE f, VALUE sg)
+{
+ VALUE t, y, d, a, w;
+
+ t = rt_jd_to_civil(jd, sg);
+ y = RARRAY_PTR(t)[0];
+ d = RARRAY_PTR(t)[2];
+ a = f_add(rt_find_fdoy(y, sg), INT2FIX(6));
+ t = f_add(f_sub(jd,
+ f_sub(a, f_mod(f_add(f_sub(a, f), INT2FIX(1)),
+ INT2FIX(7)))),
+ INT2FIX(7));
+ w = f_idiv(t, INT2FIX(7));
+ d = f_mod(t, INT2FIX(7));
+ return rb_ary_new3(3, y, w, d);
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_nth_kday_to_jd(VALUE y, VALUE m, VALUE n, VALUE k, VALUE sg)
+{
+ VALUE j;
+
+ if (f_gt_p(n, INT2FIX(0)))
+ j = f_sub(rt_find_fdom(y, m, sg), INT2FIX(1));
+ else
+ j = f_add(rt_find_ldom(y, m, sg), INT2FIX(7));
+ return f_add(f_sub(j,
+ f_mod(f_add(f_sub(j, k), INT2FIX(1)), INT2FIX(7))),
+ f_mul(INT2FIX(7), n));
+}
+
+static VALUE rt_jd_to_wday(VALUE);
+
+static VALUE
+rt_jd_to_nth_kday(VALUE jd, VALUE sg)
+{
+ VALUE t, y, m, n, k, j;
+
+ t = rt_jd_to_civil(jd, sg);
+ y = RARRAY_PTR(t)[0];
+ m = RARRAY_PTR(t)[1];
+ j = rt_find_fdom(y, m, sg);
+ n = f_add(f_idiv(f_sub(jd, j), INT2FIX(7)), INT2FIX(1));
+ k = rt_jd_to_wday(jd);
+ return rb_ary_new3(4, y, m, n, k);
+}
+#endif
+
+static VALUE
+rt_ajd_to_jd(VALUE ajd, VALUE of)
+{
+ VALUE t, jd, fr;
+
+ t = f_add3(ajd, of, HALF_DAYS_IN_DAY);
+ jd = f_idiv(t, INT2FIX(1));
+ fr = f_mod(t, INT2FIX(1));
+ return rb_assoc_new(jd, fr);
+}
+
+static VALUE
+rt_jd_to_ajd(VALUE jd, VALUE fr, VALUE of)
+{
+ return f_sub3(f_add(jd, fr), of, HALF_DAYS_IN_DAY);
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_day_fraction_to_time(VALUE fr)
+{
+ VALUE h, min, s, ss;
+
+ ss = f_idiv(fr, SECONDS_IN_DAY);
+ fr = f_mod(fr, SECONDS_IN_DAY);
+
+ h = f_idiv(ss, INT2FIX(HOUR_IN_SECONDS));
+ ss = f_mod(ss, INT2FIX(HOUR_IN_SECONDS));
+
+ min = f_idiv(ss, INT2FIX(MINUTE_IN_SECONDS));
+ s = f_mod(ss, INT2FIX(MINUTE_IN_SECONDS));
+
+ return rb_ary_new3(4, h, min, s, f_mul(fr, INT2FIX(DAY_IN_SECONDS)));
+}
+#endif
+
+static VALUE
+rt_day_fraction_to_time_wo_sf(VALUE fr)
+{
+ VALUE h, min, s, ss;
+
+ ss = f_idiv(fr, SECONDS_IN_DAY);
+
+ h = f_idiv(ss, INT2FIX(HOUR_IN_SECONDS));
+ ss = f_mod(ss, INT2FIX(HOUR_IN_SECONDS));
+
+ min = f_idiv(ss, INT2FIX(MINUTE_IN_SECONDS));
+ s = f_mod(ss, INT2FIX(MINUTE_IN_SECONDS));
+
+ return rb_ary_new3(3, h, min, s);
+}
+
+static VALUE
+rt_time_to_day_fraction(VALUE h, VALUE min, VALUE s)
+{
+ return rb_Rational(f_add3(f_mul(h, INT2FIX(HOUR_IN_SECONDS)),
+ f_mul(min, INT2FIX(MINUTE_IN_SECONDS)),
+ s),
+ INT2FIX(DAY_IN_SECONDS));
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_amjd_to_ajd(VALUE amjd)
+{
+ return f_add(amjd, MJD_EPOCH_IN_AJD);
+}
+#endif
+
+static VALUE
+rt_ajd_to_amjd(VALUE ajd)
+{
+ return f_sub(ajd, MJD_EPOCH_IN_AJD);
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_mjd_to_jd(VALUE mjd)
+{
+ return f_add(mjd, MJD_EPOCH_IN_CJD);
+}
+#endif
+
+static VALUE
+rt_jd_to_mjd(VALUE jd)
+{
+ return f_sub(jd, MJD_EPOCH_IN_CJD);
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_ld_to_jd(VALUE ld)
+{
+ return f_add(ld, LD_EPOCH_IN_CJD);
+}
+#endif
+
+static VALUE
+rt_jd_to_ld(VALUE jd)
+{
+ return f_sub(jd, LD_EPOCH_IN_CJD);
+}
+
+static VALUE
+rt_jd_to_wday(VALUE jd)
+{
+ return f_mod(f_add(jd, INT2FIX(1)), INT2FIX(7));
+}
+
+static VALUE
+rt__valid_jd_p(VALUE jd, VALUE sg)
+{
+ return jd;
+}
+
+static VALUE
+rt__valid_ordinal_p(VALUE y, VALUE d, VALUE sg)
+{
+ VALUE jd, t, ny, nd;
+
+ if (f_negative_p(d)) {
+ VALUE j;
+
+ j = rt_find_ldoy(y, sg);
+ if (NIL_P(j))
+ return Qnil;
+ t = rt_jd_to_ordinal(f_add3(j, d, INT2FIX(1)), sg);
+ ny = RARRAY_PTR(t)[0];
+ nd = RARRAY_PTR(t)[1];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ d = nd;
+ }
+ jd = rt_ordinal_to_jd(y, d, sg);
+ t = rt_jd_to_ordinal(jd, sg);
+ ny = RARRAY_PTR(t)[0];
+ nd = RARRAY_PTR(t)[1];
+ if (!f_eqeq_p(y, ny))
+ return Qnil;
+ if (!f_eqeq_p(d, nd))
+ return Qnil;
+ return jd;
+}
+
+static VALUE
+rt__valid_civil_p(VALUE y, VALUE m, VALUE d, VALUE sg)
+{
+ VALUE t, ny, nm, nd, jd;
+
+ if (f_negative_p(m))
+ m = f_add(m, INT2FIX(13));
+ if (f_negative_p(d)) {
+ VALUE j;
+
+ j = rt_find_ldom(y, m, sg);
+ if (NIL_P(j))
+ return Qnil;
+ t = rt_jd_to_civil(f_add3(j, d, INT2FIX(1)), sg);
+ ny = RARRAY_PTR(t)[0];
+ nm = RARRAY_PTR(t)[1];
+ nd = RARRAY_PTR(t)[2];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ if (!f_eqeq_p(nm, m))
+ return Qnil;
+ d = nd;
+ }
+ jd = rt_civil_to_jd(y, m, d, sg);
+ t = rt_jd_to_civil(jd, sg);
+ ny = RARRAY_PTR(t)[0];
+ nm = RARRAY_PTR(t)[1];
+ nd = RARRAY_PTR(t)[2];
+ if (!f_eqeq_p(y, ny))
+ return Qnil;
+ if (!f_eqeq_p(m, nm))
+ return Qnil;
+ if (!f_eqeq_p(d, nd))
+ return Qnil;
+ return jd;
+}
+
+static VALUE
+rt__valid_commercial_p(VALUE y, VALUE w, VALUE d, VALUE sg)
+{
+ VALUE t, ny, nw, nd, jd;
+
+ if (f_negative_p(d))
+ d = f_add(d, INT2FIX(8));
+ if (f_negative_p(w)) {
+ VALUE j;
+
+ j = rt_commercial_to_jd(f_add(y, INT2FIX(1)),
+ INT2FIX(1), INT2FIX(1), sg);
+ t = rt_jd_to_commercial(f_add(j, f_mul(w, INT2FIX(7))), sg);
+ ny = RARRAY_PTR(t)[0];
+ nw = RARRAY_PTR(t)[1];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ w = nw;
+ }
+ jd = rt_commercial_to_jd(y, w, d, sg);
+ t = rt_jd_to_commercial(jd, sg);
+ ny = RARRAY_PTR(t)[0];
+ nw = RARRAY_PTR(t)[1];
+ nd = RARRAY_PTR(t)[2];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ if (!f_eqeq_p(nw, w))
+ return Qnil;
+ if (!f_eqeq_p(nd, d))
+ return Qnil;
+ return jd;
+}
+
+static VALUE
+rt__valid_weeknum_p(VALUE y, VALUE w, VALUE d, VALUE f, VALUE sg)
+{
+ VALUE t, ny, nw, nd, jd;
+
+ if (f_negative_p(d))
+ d = f_add(d, INT2FIX(7));
+ if (f_negative_p(w)) {
+ VALUE j;
+
+ j = rt_weeknum_to_jd(f_add(y, INT2FIX(1)),
+ INT2FIX(1), f, f, sg);
+ t = rt_jd_to_weeknum(f_add(j, f_mul(w, INT2FIX(7))), f, sg);
+ ny = RARRAY_PTR(t)[0];
+ nw = RARRAY_PTR(t)[1];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ w = nw;
+ }
+ jd = rt_weeknum_to_jd(y, w, d, f, sg);
+ t = rt_jd_to_weeknum(jd, f, sg);
+ ny = RARRAY_PTR(t)[0];
+ nw = RARRAY_PTR(t)[1];
+ nd = RARRAY_PTR(t)[2];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ if (!f_eqeq_p(nw, w))
+ return Qnil;
+ if (!f_eqeq_p(nd, d))
+ return Qnil;
+ return jd;
+}
+
+#ifndef NDEBUG
+static VALUE
+rt__valid_nth_kday_p(VALUE y, VALUE m, VALUE n, VALUE k, VALUE sg)
+{
+ VALUE t, ny, nm, nn, nk, jd;
+
+ if (f_negative_p(k))
+ k = f_add(k, INT2FIX(7));
+ if (f_negative_p(n)) {
+ VALUE j;
+
+ t = f_add(f_mul(y, INT2FIX(12)), m);
+ ny = f_idiv(t, INT2FIX(12));
+ nm = f_mod(t, INT2FIX(12));
+ nm = f_floor(f_add(nm, INT2FIX(1)));
+
+ j = rt_nth_kday_to_jd(ny, nm, INT2FIX(1), k, sg);
+ t = rt_jd_to_nth_kday(f_add(j, f_mul(n, INT2FIX(7))), sg);
+ ny = RARRAY_PTR(t)[0];
+ nm = RARRAY_PTR(t)[1];
+ nn = RARRAY_PTR(t)[2];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ if (!f_eqeq_p(nm, m))
+ return Qnil;
+ n = nn;
+ }
+ jd = rt_nth_kday_to_jd(y, m, n, k, sg);
+ t = rt_jd_to_nth_kday(jd, sg);
+ ny = RARRAY_PTR(t)[0];
+ nm = RARRAY_PTR(t)[1];
+ nn = RARRAY_PTR(t)[2];
+ nk = RARRAY_PTR(t)[3];
+ if (!f_eqeq_p(ny, y))
+ return Qnil;
+ if (!f_eqeq_p(nm, m))
+ return Qnil;
+ if (!f_eqeq_p(nn, n))
+ return Qnil;
+ if (!f_eqeq_p(nk, k))
+ return Qnil;
+ return jd;
+}
+#endif
+
+static VALUE
+rt__valid_time_p(VALUE h, VALUE min, VALUE s)
+{
+ if (f_negative_p(h))
+ h = f_add(h, INT2FIX(24));
+ if (f_negative_p(min))
+ min = f_add(min, INT2FIX(MINUTE_IN_SECONDS));
+ if (f_negative_p(s))
+ s = f_add(s, INT2FIX(MINUTE_IN_SECONDS));
+ if (f_eqeq_p(h, INT2FIX(24))) {
+ if (!f_eqeq_p(min, INT2FIX(0)))
+ return Qnil;
+ if (!f_eqeq_p(s, INT2FIX(0)))
+ return Qnil;
+ }
+ else {
+ if (f_lt_p(h, INT2FIX(0)) || f_ge_p(h, INT2FIX(24)))
+ return Qnil;
+ if (f_lt_p(min, INT2FIX(0)) || f_ge_p(min, INT2FIX(60)))
+ return Qnil;
+ if (f_lt_p(s, INT2FIX(0)) || f_ge_p(s, INT2FIX(60)))
+ return Qnil;
+ }
+ return rt_time_to_day_fraction(h, min, s);
+}
+
+/* light base */
+
static int valid_civil_p(int y, int m, int d, double sg,
int *rm, int *rd, long *rjd, int *ns);
@@ -523,6 +1118,61 @@ valid_commercial_p(int y, int w, int d, double sg,
return 1;
}
+#ifndef NDEBUG
+static int
+valid_weeknum_p(int y, int w, int d, int f, double sg,
+ int *rw, int *rd, long *rjd, int *ns)
+{
+ int ns2, ry2, rw2, rd2;
+
+ if (d < 0)
+ d += 7;
+ if (w < 0) {
+ long rjd2;
+
+ weeknum_to_jd(y + 1, 1, f, f, sg, &rjd2, &ns2);
+ jd_to_weeknum(rjd2 + w * 7, f, sg, &ry2, &rw2, &rd2);
+ if (ry2 != y)
+ return 0;
+ w = rw2;
+ }
+ weeknum_to_jd(y, w, d, f, sg, rjd, ns);
+ jd_to_weeknum(*rjd, f, sg, &ry2, rw, rd);
+ if (y != ry2 || w != *rw || d != *rd)
+ return 0;
+ return 1;
+}
+
+static int
+valid_nth_kday_p(int y, int m, int n, int k, double sg,
+ int *rm, int *rn, int *rk, long *rjd, int *ns)
+{
+ int ns2, ry2, rm2, rn2, rk2;
+
+ if (k < 0)
+ k += 7;
+ if (n < 0) {
+ long rjd2;
+ int t, ny, nm;
+
+ t = y * 12 + m;
+ ny = DIV(t, 12);
+ nm = MOD(t, 12) + 1;
+
+ nth_kday_to_jd(ny, nm, 1, k, sg, &rjd2, &ns2);
+ jd_to_nth_kday(rjd2 + n * 7, sg, &ry2, &rm2, &rn2, &rk2);
+ if (ry2 != y || rm2 != m)
+ return 0;
+ n = rn2;
+ }
+ nth_kday_to_jd(y, m, n, k, sg, rjd, ns);
+ jd_to_nth_kday(*rjd, sg, &ry2, rm, rn, rk);
+ if (y != ry2 || m != *rm || n != *rn || k != *rk)
+ return 0;
+ return 1;
+}
+#endif
+
static int
valid_time_p(int h, int min, int s, int *rh, int *rmin, int *rs)
{
@@ -588,7 +1238,7 @@ jd_utc_to_local(long jd, int df, int of)
inline static int
time_to_df(int h, int min, int s)
{
- return h * 3600 + min * 60 + s;
+ return h * HOUR_IN_SECONDS + min * MINUTE_IN_SECONDS + s;
}
inline static int
@@ -597,11 +1247,7 @@ jd_to_wday(long jd)
return (int)MOD(jd + 1, 7);
}
-VALUE
-date_zone_to_diff(VALUE s)
-{
- return rb_funcall(cDate, rb_intern("zone_to_diff"), 1, s);
-}
+VALUE date_zone_to_diff(VALUE);
static int
daydiff_to_sec(VALUE vof, int *rof)
@@ -714,10 +1360,10 @@ get_dt_time(union DateTimeData *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.hour = r / HOUR_IN_SECONDS;
+ r %= HOUR_IN_SECONDS;
+ x->l.min = r / MINUTE_IN_SECONDS;
+ x->l.sec = r % MINUTE_IN_SECONDS;
x->l.flags |= HAVE_TIME;
}
}
@@ -799,10 +1445,19 @@ k_numeric_p(VALUE x)
return f_kind_of_p(x, rb_cNumeric);
}
+/* date light */
+
+static VALUE
+rtv__valid_jd_p(int argc, VALUE *argv)
+{
+ assert(argc == 2);
+ return rt__valid_jd_p(argv[0], argv[1]);
+}
+
static VALUE
valid_jd_sub(int argc, VALUE *argv, VALUE klass)
{
- return argv[0];
+ return rtv__valid_jd_p(argc, argv);
}
#ifndef NDEBUG
@@ -824,6 +1479,13 @@ date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass)
}
#endif
+/*
+ * call-seq:
+ * Date.valid_jd?(jd[, start=Date::ITALY])
+ *
+ * Is +jd+ a valid Julian Day Number?
+ * Returns true or false.
+ */
static VALUE
date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass)
{
@@ -844,19 +1506,30 @@ date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass)
}
static VALUE
+rtv__valid_civil_p(int argc, VALUE *argv)
+{
+ assert(argc == 4);
+ return rt__valid_civil_p(argv[0], argv[1], argv[2], argv[3]);
+}
+
+static VALUE
valid_civil_sub(int argc, VALUE *argv, VALUE klass, int need_jd)
{
int y, m, d, rm, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return rtv__valid_civil_p(argc, argv);
+#endif
+
if (!(FIXNUM_P(argv[0]) &&
FIXNUM_P(argv[1]) &&
FIXNUM_P(argv[2])))
- return cforwardv("_valid_civil_r?");
+ return rtv__valid_civil_p(argc, argv);
y = NUM2INT(argv[0]);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("_valid_civil_r?");
+ return rtv__valid_civil_p(argc, argv);
m = NUM2INT(argv[1]);
d = NUM2INT(argv[2]);
@@ -898,6 +1571,22 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
}
#endif
+/*
+ * call-seq:
+ * Date.valid_civil?(year, month, mday[, start=Date::ITALY])
+ *
+ * Do year +y+, month +m+, and day-of-month +d+ make a
+ * valid Civil Date? Returns true or false.
+ *
+ * +m+ and +d+ can be negative, in which case they count
+ * backwards from the end of the year and the end of the
+ * month respectively. No wraparound is performed, however,
+ * and invalid values cause an ArgumentError to be raised.
+ * A date falling in the period skipped in the Day of Calendar
+ * Reform adjustment is not valid.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ */
static VALUE
date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass)
{
@@ -920,18 +1609,29 @@ date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass)
}
static VALUE
+rtv__valid_ordinal_p(int argc, VALUE *argv)
+{
+ assert(argc == 3);
+ return rt__valid_ordinal_p(argv[0], argv[1], argv[2]);
+}
+
+static VALUE
valid_ordinal_sub(int argc, VALUE *argv, VALUE klass)
{
int y, d, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return rtv__valid_ordinal_p(argc, argv);
+#endif
+
if (!(FIXNUM_P(argv[0]) &&
FIXNUM_P(argv[1])))
- return cforwardv("_valid_ordinal_r?");
+ return rtv__valid_ordinal_p(argc, argv);
y = NUM2INT(argv[0]);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("_valid_ordinal_r?");
+ return rtv__valid_ordinal_p(argc, argv);
d = NUM2INT(argv[1]);
sg = NUM2DBL(argv[2]);
@@ -966,6 +1666,23 @@ date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
}
#endif
+/*
+ * call-seq:
+ * Date.valid_ordinal?(year, yday[, start=Date::ITALY])
+ *
+ * Do the year +y+ and day-of-year +d+ make a valid Ordinal Date?
+ * Returns true or false.
+ *
+ * +d+ can be a negative number, in which case it counts backwards
+ * from the end of the year (-1 being the last day of the year).
+ * No year wraparound is performed, however, so valid values of
+ * +d+ are -365 .. -1, 1 .. 365 on a non-leap-year,
+ * -366 .. -1, 1 .. 366 on a leap year.
+ * A date falling in the period skipped in the Day of Calendar Reform
+ * adjustment is not valid.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ */
static VALUE
date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
{
@@ -987,19 +1704,30 @@ date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass)
}
static VALUE
+rtv__valid_commercial_p(int argc, VALUE *argv)
+{
+ assert(argc == 4);
+ return rt__valid_commercial_p(argv[0], argv[1], argv[2], argv[3]);
+}
+
+static VALUE
valid_commercial_sub(int argc, VALUE *argv, VALUE klass)
{
int y, w, d, rw, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return rtv__valid_commercial_p(argc, argv);
+#endif
+
if (!(FIXNUM_P(argv[0]) &&
FIXNUM_P(argv[1]) &&
FIXNUM_P(argv[2])))
- return cforwardv("_valid_commercial_r?");
+ return rtv__valid_commercial_p(argc, argv);
y = NUM2INT(argv[0]);
if (!LIGHTABLE_CWYEAR(y))
- return cforwardv("_valid_commercial_r?");
+ return rtv__valid_commercial_p(argc, argv);
w = NUM2INT(argv[1]);
d = NUM2INT(argv[2]);
@@ -1036,6 +1764,24 @@ date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass)
}
#endif
+/*
+ * call-seq:
+ * Date.valid_commercial?(year, week, day[, start=Date::ITALY])
+ *
+ * Do year +y+, week-of-year +w+, and day-of-week +d+ make a
+ * valid Commercial Date? Returns true or false.
+ *
+ * Monday is day-of-week 1; Sunday is day-of-week 7.
+ *
+ * +w+ and +d+ can be negative, in which case they count
+ * backwards from the end of the year and the end of the
+ * week respectively. No wraparound is performed, however,
+ * and invalid values cause an ArgumentError to be raised.
+ * A date falling in the period skipped in the Day of Calendar
+ * Reform adjustment is not valid.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ */
static VALUE
date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass)
{
@@ -1057,25 +1803,233 @@ date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass)
return Qtrue;
}
+#ifndef NDEBUG
+static VALUE
+rtv__valid_weeknum_p(int argc, VALUE *argv)
+{
+ assert(argc == 5);
+ return rt__valid_weeknum_p(argv[0], argv[1], argv[2], argv[3], argv[4]);
+}
+
+static VALUE
+valid_weeknum_sub(int argc, VALUE *argv, VALUE klass)
+{
+ int y, w, d, f, rw, rd;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return rtv__valid_weeknum_p(argc, argv);
+#endif
+
+ if (!(FIXNUM_P(argv[0]) &&
+ FIXNUM_P(argv[1]) &&
+ FIXNUM_P(argv[2]) &&
+ FIXNUM_P(argv[3])))
+ return rtv__valid_weeknum_p(argc, argv);
+
+ y = NUM2INT(argv[0]);
+ if (!LIGHTABLE_YEAR(y))
+ return rtv__valid_weeknum_p(argc, argv);
+
+ w = NUM2INT(argv[1]);
+ d = NUM2INT(argv[2]);
+ f = NUM2INT(argv[3]);
+ sg = NUM2DBL(argv[4]);
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_weeknum_p(y, w, d, f, sg, &rw, &rd, &jd, &ns))
+ return Qnil;
+ return LONG2NUM(jd);
+ }
+}
+
+static VALUE
+date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vw, vd, vf, vsg;
+ VALUE argv2[5];
+
+ rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg);
+
+ argv2[0] = vy;
+ argv2[1] = vw;
+ argv2[2] = vd;
+ argv2[3] = vf;
+ if (argc < 5)
+ argv2[4] = DBL2NUM(GREGORIAN);
+ else
+ argv2[4] = vsg;
+
+ return valid_weeknum_sub(5, argv2, klass);
+}
+
+static VALUE
+date_s_valid_weeknum_p(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vw, vd, vf, vsg;
+ VALUE argv2[5];
+
+ rb_scan_args(argc, argv, "41", &vy, &vw, &vd, &vf, &vsg);
+
+ argv2[0] = vy;
+ argv2[1] = vw;
+ argv2[2] = vd;
+ argv2[3] = vf;
+ if (argc < 5)
+ argv2[4] = INT2FIX(ITALY);
+ else
+ argv2[4] = vsg;
+
+ if (NIL_P(valid_weeknum_sub(5, argv2, klass)))
+ return Qfalse;
+ return Qtrue;
+}
+
+static VALUE
+rtv__valid_nth_kday_p(int argc, VALUE *argv)
+{
+ assert(argc == 5);
+ return rt__valid_nth_kday_p(argv[0], argv[1], argv[2], argv[3], argv[4]);
+}
+static VALUE
+valid_nth_kday_sub(int argc, VALUE *argv, VALUE klass)
+{
+ int y, m, n, k, rm, rn, rk;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return rtv__valid_nth_kday_p(argc, argv);
+#endif
+
+ if (!(FIXNUM_P(argv[0]) &&
+ FIXNUM_P(argv[1]) &&
+ FIXNUM_P(argv[2]) &&
+ FIXNUM_P(argv[3])))
+ return rtv__valid_nth_kday_p(argc, argv);
+
+ y = NUM2INT(argv[0]);
+ if (!LIGHTABLE_YEAR(y))
+ return rtv__valid_nth_kday_p(argc, argv);
+
+ m = NUM2INT(argv[1]);
+ n = NUM2INT(argv[2]);
+ k = NUM2INT(argv[3]);
+ sg = NUM2DBL(argv[4]);
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_nth_kday_p(y, m, n, k, sg, &rm, &rn, &rk, &jd, &ns))
+ return Qnil;
+ return LONG2NUM(jd);
+ }
+}
+
+static VALUE
+date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vm, vn, vk, vsg;
+ VALUE argv2[5];
+
+ rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg);
+
+ argv2[0] = vy;
+ argv2[1] = vm;
+ argv2[2] = vn;
+ argv2[3] = vk;
+ if (argc < 5)
+ argv2[4] = DBL2NUM(GREGORIAN);
+ else
+ argv2[4] = vsg;
+
+ return valid_nth_kday_sub(5, argv2, klass);
+}
+
+static VALUE
+date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vm, vn, vk, vsg;
+ VALUE argv2[5];
+
+ rb_scan_args(argc, argv, "41", &vy, &vm, &vn, &vk, &vsg);
+
+ argv2[0] = vy;
+ argv2[1] = vm;
+ argv2[2] = vn;
+ argv2[3] = vk;
+ if (argc < 5)
+ argv2[4] = INT2FIX(ITALY);
+ else
+ argv2[4] = vsg;
+
+ if (NIL_P(valid_nth_kday_sub(5, argv2, klass)))
+ return Qfalse;
+ return Qtrue;
+}
+
+static VALUE
+date_s_zone_to_diff(VALUE klass, VALUE str)
+{
+ return date_zone_to_diff(str);
+}
+#endif
+
+/*
+ * call-seq:
+ * Date.julian_leap?(year)
+ *
+ * Return true if the given year is a leap year on Julian calendar.
+ */
+static VALUE
+date_s_julian_leap_p(VALUE klass, VALUE y)
+{
+ if (f_zero_p(f_mod(y, INT2FIX(4))))
+ return Qtrue;
+ return Qfalse;
+}
+
+/*
+ * call-seq:
+ * Date.gregorian_leap?(year)
+ * Date.leap?(year)
+ *
+ * Return true if the given year is a leap year on Gregorian calendar.
+ */
+static VALUE
+date_s_gregorian_leap_p(VALUE klass, VALUE y)
+{
+ if (f_zero_p(f_mod(y, INT2FIX(4))) &&
+ !f_zero_p(f_mod(y, INT2FIX(100))) ||
+ f_zero_p(f_mod(y, INT2FIX(400))))
+ return Qtrue;
+ return Qfalse;
+}
+
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);
- }
+ assert(!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);
}
+#define d_lite_gc_mark 0
+
inline static VALUE
-d_right_s_new_internal(VALUE klass, VALUE ajd, VALUE of, VALUE sg,
- unsigned flags)
+d_right_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);
+ obj = Data_Make_Struct(klass, union DateData,
+ d_right_gc_mark, -1, dat);
dat->r.ajd = ajd;
dat->r.of = of;
@@ -1087,93 +2041,199 @@ d_right_s_new_internal(VALUE klass, VALUE ajd, VALUE of, VALUE sg,
}
inline static VALUE
-d_lite_s_new_internal(VALUE klass, long jd, double sg,
- int y, int m, int d, unsigned flags)
+d_lite_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);
+ obj = Data_Make_Struct(klass, union DateData,
+ d_lite_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;
+ dat->l.flags = flags | LIGHT_MODE;
return obj;
}
static VALUE
-d_lite_s_new_internal_wo_civil(VALUE klass, long jd, double sg,
+d_lite_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);
+ return d_lite_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, LIGHT_MODE);
+ return d_lite_new_internal_wo_civil(klass, 0, 0, 0);
+}
+
+static VALUE
+d_right_new(VALUE klass, VALUE ajd, VALUE of, VALUE sg)
+{
+ return d_right_new_internal(klass, ajd, of, sg, 0);
}
static VALUE
-d_right_s_new_r_bang(int argc, VALUE *argv, VALUE klass)
+d_lite_new(VALUE klass, VALUE jd, VALUE sg)
{
- VALUE vajd, vof, vsg;
+ return d_lite_new_internal_wo_civil(klass,
+ NUM2LONG(jd),
+ NUM2DBL(sg),
+ HAVE_JD);
+}
- rb_scan_args(argc, argv, "03", &vajd, &vof, &vsg);
+static VALUE
+d_switch_new(VALUE klass, VALUE ajd, VALUE of, VALUE sg)
+{
+ VALUE t, jd, df;
- if (argc < 1)
- vajd = INT2FIX(0);
- if (argc < 2)
- vof = INT2FIX(0);
- if (argc < 3)
- vsg = DBL2NUM(ITALY);
+ t = rt_ajd_to_jd(ajd, INT2FIX(0)); /* as utc */
+ jd = RARRAY_PTR(t)[0];
+ df = RARRAY_PTR(t)[1];
+
+#ifdef FORCE_RIGHT
+ if (1)
+#else
+ if (!FIXNUM_P(jd) ||
+ f_lt_p(jd, sg) || !f_zero_p(df) || !f_zero_p(of) ||
+ !LIGHTABLE_JD(NUM2LONG(jd)))
+#endif
+ return d_right_new(klass, ajd, of, sg);
+ else
+ return d_lite_new(klass, jd, sg);
+}
+
+#ifndef NDEBUG
+static VALUE
+d_right_new_m(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE ajd, of, sg;
+
+ rb_scan_args(argc, argv, "03", &ajd, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ ajd = INT2FIX(0);
+ case 1:
+ of = INT2FIX(0);
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
- return d_right_s_new_internal(klass, vajd, vof, vsg, 0);
+ return d_right_new(klass, ajd, of, sg);
}
static VALUE
-d_lite_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
+d_lite_new_m(int argc, VALUE *argv, VALUE klass)
{
- VALUE vjd, vsg;
- long jd;
- double sg;
+ VALUE jd, sg;
- rb_scan_args(argc, argv, "02", &vjd, &vsg);
+ rb_scan_args(argc, argv, "02", &jd, &sg);
- 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");
+ switch (argc) {
+ case 0:
+ jd = INT2FIX(0);
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ return d_lite_new(klass, jd, sg);
+}
+
+static VALUE
+d_switch_new_m(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE ajd, of, sg;
+
+ rb_scan_args(argc, argv, "03", &ajd, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ ajd = INT2FIX(0);
+ case 1:
+ of = INT2FIX(0);
+ case 2:
+ sg = INT2FIX(ITALY);
}
- if (argc < 2)
- sg = 0;
- else
- sg = NUM2DBL(vsg);
- return d_lite_s_new_internal_wo_civil(klass,
- jd,
- sg,
- LIGHT_MODE | HAVE_JD);
+ return d_switch_new(klass, ajd, of, sg);
}
+#endif
static VALUE
+d_right_new_jd(VALUE klass, VALUE jd, VALUE sg)
+{
+ return d_right_new(klass,
+ rt_jd_to_ajd(jd, INT2FIX(0), INT2FIX(0)),
+ INT2FIX(0),
+ sg);
+}
+
+#ifndef NDEBUG
+static VALUE
+d_lite_new_jd(VALUE klass, VALUE jd, VALUE sg)
+{
+ return d_lite_new(klass, jd, sg);
+}
+#endif
+
+static VALUE
+d_switch_new_jd(VALUE klass, VALUE jd, VALUE sg)
+{
+ return d_switch_new(klass,
+ rt_jd_to_ajd(jd, INT2FIX(0), INT2FIX(0)),
+ INT2FIX(0),
+ sg);
+}
+
+#ifndef NDEBUG
+static VALUE
date_s_new_r_bang(int argc, VALUE *argv, VALUE klass)
{
- return d_right_s_new_r_bang(argc, argv, klass);
+ return d_right_new_m(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);
+ return d_lite_new_m(argc, argv, klass);
+}
+
+static VALUE
+date_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+ return d_switch_new_m(argc, argv, klass);
+}
+#endif
+
+#define c_cforwardv(m) rt_date_s_##m(argc, argv, klass)
+
+static VALUE
+rt_date_s_jd(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE jd, sg;
+
+ rb_scan_args(argc, argv, "02", &jd, &sg);
+
+ switch (argc) {
+ case 0:
+ jd = INT2FIX(0);
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_jd_p(jd, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
}
/*
@@ -1192,28 +2252,55 @@ date_s_jd(int argc, VALUE *argv, VALUE klass)
long jd;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(jd);
+#endif
+
rb_scan_args(argc, argv, "02", &vjd, &vsg);
if (!FIXNUM_P(vjd))
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
- if (!NIL_P(vsg))
- sg = NUM2DBL(vsg);
- else
- sg = ITALY;
+ jd = 0;
+ sg = ITALY;
- if (argc >= 1) {
+ switch (argc) {
+ case 2:
+ sg = NUM2DBL(vsg);
+ case 1:
jd = NUM2LONG(vjd);
if (!LIGHTABLE_JD(jd))
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
}
- else
- jd = 0;
if (jd < sg)
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
+
+ return d_lite_new_internal_wo_civil(klass, jd, sg, HAVE_JD);
+}
+
+static VALUE
+rt_date_s_ordinal(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, d, sg, jd;
+
+ rb_scan_args(argc, argv, "03", &y, &d, &sg);
- return d_lite_s_new_internal_wo_civil(klass, jd, sg, LIGHT_MODE | HAVE_JD);
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ d = INT2FIX(1);
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_ordinal_p(y, d, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
}
/*
@@ -1238,28 +2325,29 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass)
int y, d, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(ordinal);
+#endif
+
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;
+ return c_cforwardv(ordinal);
y = -4712;
d = 1;
+ sg = ITALY;
switch (argc) {
case 3:
+ sg = NUM2DBL(vsg);
case 2:
d = NUM2INT(vd);
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("ordinal_r");
+ return c_cforwardv(ordinal);
}
{
@@ -1270,11 +2358,37 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("ordinal_r");
+ return c_cforwardv(ordinal);
+
+ return d_lite_new_internal_wo_civil(klass, jd, sg,
+ HAVE_JD);
+ }
+}
+
+static VALUE
+rt_date_s_civil(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, m, d, sg, jd;
+
+ rb_scan_args(argc, argv, "04", &y, &m, &d, &sg);
- return d_lite_s_new_internal_wo_civil(klass, jd, sg,
- LIGHT_MODE | HAVE_JD);
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ m = INT2FIX(1);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ sg = INT2FIX(ITALY);
}
+
+ jd = rt__valid_civil_p(y, m, d, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
}
/*
@@ -1303,24 +2417,25 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
int y, m, d, rm, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(civil);
+#endif
+
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;
+ return c_cforwardv(civil);
y = -4712;
m = 1;
d = 1;
+ sg = ITALY;
switch (argc) {
case 4:
+ sg = NUM2DBL(vsg);
case 3:
d = NUM2INT(vd);
case 2:
@@ -1328,15 +2443,15 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("civil_r");
+ return c_cforwardv(civil);
}
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);
+ return d_lite_new_internal(klass, 0, sg, y, rm, rd,
+ HAVE_CIVIL);
}
else {
long jd;
@@ -1346,11 +2461,37 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("civil_r");
+ return c_cforwardv(civil);
+
+ return d_lite_new_internal(klass, jd, sg, y, rm, rd,
+ HAVE_JD | HAVE_CIVIL);
+ }
+}
+
+static VALUE
+rt_date_s_commercial(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, w, d, sg, jd;
+
+ rb_scan_args(argc, argv, "04", &y, &w, &d, &sg);
- return d_lite_s_new_internal(klass, jd, sg, y, rm, rd,
- LIGHT_MODE | HAVE_JD | HAVE_CIVIL);
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ w = INT2FIX(1);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ sg = INT2FIX(ITALY);
}
+
+ jd = rt__valid_commercial_p(y, w, d, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
}
/*
@@ -1379,24 +2520,25 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass)
int y, w, d, rw, rd;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(commercial);
+#endif
+
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;
+ return c_cforwardv(commercial);
y = -4712;
w = 1;
d = 1;
+ sg = ITALY;
switch (argc) {
case 4:
+ sg = NUM2DBL(vsg);
case 3:
d = NUM2INT(vd);
case 2:
@@ -1404,7 +2546,7 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass)
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_CWYEAR(y))
- return cforwardv("commercial_r");
+ return c_cforwardv(commercial);
}
{
@@ -1415,12 +2557,180 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("commercial_r");
+ return c_cforwardv(commercial);
+
+ return d_lite_new_internal_wo_civil(klass, jd, sg,
+ HAVE_JD);
+ }
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_date_s_weeknum(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, w, d, f, sg, jd;
+
+ rb_scan_args(argc, argv, "05", &y, &w, &d, &f, &sg);
+
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ w = INT2FIX(0);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ f = INT2FIX(0);
+ case 4:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_weeknum_p(y, w, d, f, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
+}
+
+static VALUE
+date_s_weeknum(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vw, vd, vf, vsg;
+ int y, w, d, f, rw, rd;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return c_cforwardv(weeknum);
+#endif
+
+ rb_scan_args(argc, argv, "05", &vy, &vw, &vd, &vf, &vsg);
+
+ if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+ (NIL_P(vw) || FIXNUM_P(vw)) &&
+ (NIL_P(vd) || FIXNUM_P(vd)) &&
+ (NIL_P(vf) || FIXNUM_P(vf))))
+ return c_cforwardv(weeknum);
+
+ y = -4712;
+ w = 0;
+ d = 1;
+ f = 0;
+ sg = ITALY;
+
+ switch (argc) {
+ case 5:
+ sg = NUM2DBL(vsg);
+ case 4:
+ f = NUM2INT(vf);
+ case 3:
+ d = NUM2INT(vd);
+ case 2:
+ w = NUM2INT(vw);
+ case 1:
+ y = NUM2INT(vy);
+ if (!LIGHTABLE_YEAR(y))
+ return c_cforwardv(weeknum);
+ }
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_weeknum_p(y, w, d, f, sg, &rw, &rd, &jd, &ns))
+ rb_raise(rb_eArgError, "invalid date");
+
+ if (!LIGHTABLE_JD(jd) || !ns)
+ return c_cforwardv(weeknum);
+
+ return d_lite_new_internal_wo_civil(klass, jd, sg,
+ HAVE_JD);
+ }
+}
+
+static VALUE
+rt_date_s_nth_kday(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, m, n, k, sg, jd;
+
+ rb_scan_args(argc, argv, "05", &y, &m, &n, &k, &sg);
+
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ m = INT2FIX(1);
+ case 2:
+ n = INT2FIX(1);
+ case 3:
+ k = INT2FIX(1);
+ case 4:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_nth_kday_p(y, m, n, k, sg);
+
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+
+ return d_right_new_jd(klass, jd, sg);
+}
+
+static VALUE
+date_s_nth_kday(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vm, vn, vk, vsg;
+ int y, m, n, k, rm, rn, rk;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return c_cforwardv(nth_kday);
+#endif
+
+ rb_scan_args(argc, argv, "05", &vy, &vm, &vn, &vk, &vsg);
+
+ if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+ (NIL_P(vm) || FIXNUM_P(vm)) &&
+ (NIL_P(vn) || FIXNUM_P(vn)) &&
+ (NIL_P(vk) || FIXNUM_P(vk))))
+ return c_cforwardv(nth_kday);
+
+ y = -4712;
+ m = 1;
+ n = 1;
+ k = 1;
+ sg = ITALY;
+
+ switch (argc) {
+ case 5:
+ sg = NUM2DBL(vsg);
+ case 4:
+ k = NUM2INT(vk);
+ case 3:
+ n = NUM2INT(vn);
+ case 2:
+ m = NUM2INT(vm);
+ case 1:
+ y = NUM2INT(vy);
+ if (!LIGHTABLE_YEAR(y))
+ return c_cforwardv(nth_kday);
+ }
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_nth_kday_p(y, m, n, k, sg, &rm, &rn, &rk, &jd, &ns))
+ rb_raise(rb_eArgError, "invalid date");
+
+ if (!LIGHTABLE_JD(jd) || !ns)
+ return c_cforwardv(nth_kday);
- return d_lite_s_new_internal_wo_civil(klass, jd, sg,
- LIGHT_MODE | HAVE_JD);
+ return d_lite_new_internal_wo_civil(klass, jd, sg,
+ HAVE_JD);
}
}
+#endif
#if !defined(HAVE_GMTIME_R)
static struct tm*
@@ -1453,10 +2763,10 @@ date_s_today(int argc, VALUE *argv, VALUE klass)
rb_scan_args(argc, argv, "01", &vsg);
- if (!NIL_P(vsg))
- sg = NUM2DBL(vsg);
- else
+ if (argc < 1)
sg = ITALY;
+ else
+ sg = NUM2DBL(vsg);
if (time(&t) == -1)
rb_sys_fail("time");
@@ -1466,23 +2776,441 @@ date_s_today(int argc, VALUE *argv, VALUE klass)
m = tm.tm_mon + 1;
d = tm.tm_mday;
+#ifdef FORCE_RIGHT
+ goto right;
+#endif
+
if (!LIGHTABLE_YEAR(y))
- rb_raise(rb_eArgError, "cannot create");
+ goto right;
if (isinf(sg) && sg < 0)
- return d_lite_s_new_internal(klass, 0, sg, y, m, d,
- LIGHT_MODE | HAVE_CIVIL);
+ return d_lite_new_internal(klass, 0, sg, y, m, d,
+ HAVE_CIVIL);
else {
long jd;
int ns;
civil_to_jd(y, m, d, sg, &jd, &ns);
- return d_lite_s_new_internal(klass, jd, sg, y, m, d,
- LIGHT_MODE | HAVE_JD | HAVE_CIVIL);
+ return d_lite_new_internal(klass, jd, sg, y, m, d,
+ HAVE_JD | HAVE_CIVIL);
+ }
+ right:
+ {
+ VALUE jd, ajd;
+
+ jd = rt_civil_to_jd(INT2FIX(y), INT2FIX(m), INT2FIX(d), DBL2NUM(sg));
+ ajd = rt_jd_to_ajd(jd, INT2FIX(0), INT2FIX(0));
+ return d_right_new(klass, ajd, INT2FIX(0), DBL2NUM(sg));
}
}
+#define set_hash0(k,v) rb_hash_aset(hash, k, v)
+#define ref_hash0(k) rb_hash_aref(hash, k)
+#define del_hash0(k) rb_hash_delete(hash, k)
+
+#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
+#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
+#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
+
+static VALUE
+rt_rewrite_frags(VALUE hash)
+{
+ VALUE seconds;
+
+ if (NIL_P(hash))
+ hash = rb_hash_new();
+
+ seconds = ref_hash("seconds");
+ if (!NIL_P(seconds)) {
+ VALUE d, h, min, s, fr;
+
+ d = f_idiv(seconds, INT2FIX(DAY_IN_SECONDS));
+ fr = f_mod(seconds, INT2FIX(DAY_IN_SECONDS));
+
+ h = f_idiv(fr, INT2FIX(HOUR_IN_SECONDS));
+ fr = f_mod(fr, INT2FIX(HOUR_IN_SECONDS));
+
+ min = f_idiv(fr, INT2FIX(MINUTE_IN_SECONDS));
+ fr = f_mod(fr, INT2FIX(MINUTE_IN_SECONDS));
+
+ s = f_idiv(fr, INT2FIX(1));
+ fr = f_mod(fr, INT2FIX(1));
+
+ set_hash("jd", f_add(UNIX_EPOCH_IN_CJD, d));
+ set_hash("hour", h);
+ set_hash("min", min);
+ set_hash("sec", s);
+ set_hash("sec_fraction", fr);
+ del_hash("seconds");
+ del_hash("offset");
+ }
+ return hash;
+}
+
+#define sym(x) ID2SYM(rb_intern(x))
+
+static VALUE
+fv_values_at(VALUE h, VALUE a)
+{
+ return rb_funcall2(h, rb_intern("values_at"),
+ RARRAY_LENINT(a), RARRAY_PTR(a));
+}
+
+static VALUE
+rt_complete_frags(VALUE klass, VALUE hash)
+{
+ static VALUE tab = Qnil;
+ VALUE t, l, g, d;
+
+ if (NIL_P(tab)) {
+ tab = rb_ary_new3(11,
+ rb_ary_new3(2,
+ sym("time"),
+ rb_ary_new3(3,
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ Qnil,
+ rb_ary_new3(1,
+ sym("jd"))),
+ rb_ary_new3(2,
+ sym("ordinal"),
+ rb_ary_new3(5,
+ sym("year"),
+ sym("yday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ sym("civil"),
+ rb_ary_new3(6,
+ sym("year"),
+ sym("mon"),
+ sym("mday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ sym("commercial"),
+ rb_ary_new3(6,
+ sym("cwyear"),
+ sym("cweek"),
+ sym("cwday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ sym("wday"),
+ rb_ary_new3(4,
+ sym("wday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ sym("wnum0"),
+ rb_ary_new3(6,
+ sym("year"),
+ sym("wnum0"),
+ sym("wday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ sym("wnum1"),
+ rb_ary_new3(6,
+ sym("year"),
+ sym("wnum1"),
+ sym("wday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ Qnil,
+ rb_ary_new3(6,
+ sym("cwyear"),
+ sym("cweek"),
+ sym("wday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ Qnil,
+ rb_ary_new3(6,
+ sym("year"),
+ sym("wnum0"),
+ sym("cwday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))),
+ rb_ary_new3(2,
+ Qnil,
+ rb_ary_new3(6,
+ sym("year"),
+ sym("wnum1"),
+ sym("cwday"),
+ sym("hour"),
+ sym("min"),
+ sym("sec"))));
+ rb_gc_register_mark_object(tab);
+ }
+
+ {
+ int i;
+
+ t = rb_ary_new2(RARRAY_LEN(tab));
+
+ for (i = 0; i < RARRAY_LENINT(tab); i++) {
+ VALUE x, k, a, e;
+
+ x = RARRAY_PTR(tab)[i];
+ k = RARRAY_PTR(x)[0];
+ a = RARRAY_PTR(x)[1];
+ e = f_compact(fv_values_at(hash, a));
+
+ if (RARRAY_LEN(e) > 0)
+ rb_ary_push(t, rb_ary_new3(5,
+ INT2FIX(RARRAY_LENINT(e)),
+ INT2FIX(-i),
+ k, a, e));
+ }
+
+ if (RARRAY_LEN(t) == 0)
+ g = Qnil;
+ else {
+ rb_ary_sort_bang(t);
+ l = RARRAY_PTR(t)[RARRAY_LENINT(t) - 1];
+ g = rb_ary_new3(3,
+ RARRAY_PTR(l)[2],
+ RARRAY_PTR(l)[3],
+ RARRAY_PTR(l)[4]);
+ }
+ }
+
+ d = Qnil;
+
+ if (!NIL_P(g) && !NIL_P(RARRAY_PTR(g)[0]) &&
+ (RARRAY_LEN(RARRAY_PTR(g)[1]) -
+ RARRAY_LEN(RARRAY_PTR(g)[2]))) {
+ VALUE k, a;
+
+ if (NIL_P(d))
+ d = date_s_today(0, (VALUE *)0, cDate);
+
+ k = RARRAY_PTR(g)[0];
+ a = RARRAY_PTR(g)[1];
+
+ if (k == sym("ordinal")) {
+ if (NIL_P(ref_hash("year")))
+ set_hash("year", f_year(d));
+ if (NIL_P(ref_hash("yday")))
+ set_hash("yday", INT2FIX(1));
+ }
+ else if (k == sym("civil")) {
+ int i;
+
+ for (i = 0; i < RARRAY_LENINT(a); i++) {
+ VALUE e = RARRAY_PTR(a)[i];
+
+ if (!NIL_P(ref_hash0(e)))
+ break;
+ set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
+ }
+ if (NIL_P(ref_hash("mon")))
+ set_hash("mon", INT2FIX(1));
+ if (NIL_P(ref_hash("mday")))
+ set_hash("mday", INT2FIX(1));
+ }
+ else if (k == sym("commercial")) {
+ int i;
+
+ for (i = 0; i < RARRAY_LENINT(a); i++) {
+ VALUE e = RARRAY_PTR(a)[i];
+
+ if (!NIL_P(ref_hash0(e)))
+ break;
+ set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
+ }
+ if (NIL_P(ref_hash("cweek")))
+ set_hash("cweek", INT2FIX(1));
+ if (NIL_P(ref_hash("cwday")))
+ set_hash("cwday", INT2FIX(1));
+ }
+ else if (k == sym("wday")) {
+ set_hash("jd", f_jd(f_add(f_sub(d, f_wday(d)), ref_hash("wday"))));
+ }
+ else if (k == sym("wnum0")) {
+ int i;
+
+ for (i = 0; i < RARRAY_LENINT(a); i++) {
+ VALUE e = RARRAY_PTR(a)[i];
+
+ if (!NIL_P(ref_hash0(e)))
+ break;
+ set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
+ }
+ if (NIL_P(ref_hash("wnum0")))
+ set_hash("wnum0", INT2FIX(0));
+ if (NIL_P(ref_hash("wday")))
+ set_hash("wday", INT2FIX(0));
+ }
+ else if (k == sym("wnum1")) {
+ int i;
+
+ for (i = 0; i < RARRAY_LENINT(a); i++) {
+ VALUE e = RARRAY_PTR(a)[i];
+
+ if (!NIL_P(ref_hash0(e)))
+ break;
+ set_hash0(e, rb_funcall(d, SYM2ID(e), 0));
+ }
+ if (NIL_P(ref_hash("wnum1")))
+ set_hash("wnum1", INT2FIX(0));
+ if (NIL_P(ref_hash("wday")))
+ set_hash("wday", INT2FIX(1));
+ }
+ }
+
+ if (!NIL_P(g) && RARRAY_PTR(g)[0] == sym("time")) {
+ if (f_le_p(klass, cDateTime)) {
+ if (NIL_P(d))
+ d = date_s_today(0, (VALUE *)0, cDate);
+ if (NIL_P(ref_hash("jd")))
+ set_hash("jd", f_jd(d));
+ }
+ }
+
+ if (NIL_P(ref_hash("hour")))
+ set_hash("hour", INT2FIX(0));
+ if (NIL_P(ref_hash("min")))
+ set_hash("min", INT2FIX(0));
+ if (NIL_P(ref_hash("sec")))
+ set_hash("sec", INT2FIX(0));
+ else if (f_gt_p(ref_hash("sec"), INT2FIX(59)))
+ set_hash("sec", INT2FIX(59));
+
+ return hash;
+}
+
+#define f_values_at1(o,k1) rb_funcall(o, rb_intern("values_at"), 1, k1)
+#define f_values_at2(o,k1,k2) rb_funcall(o, rb_intern("values_at"), 2, k1, k2)
+#define f_values_at3(o,k1,k2,k3) rb_funcall(o, rb_intern("values_at"), 3, k1, k2, k3)
+
+static VALUE
+f_all_p(VALUE a)
+{
+ int i;
+
+ for (i = 0; i < RARRAY_LENINT(a); i++)
+ if (NIL_P(RARRAY_PTR(a)[i]))
+ return Qfalse;
+ return Qtrue;
+}
+
+static VALUE
+rt__valid_date_frags_p(VALUE hash, VALUE sg)
+{
+ VALUE a;
+
+ a = f_values_at1(hash, sym("jd"));
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_jd_p(RARRAY_PTR(a)[0],
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+
+ a = f_values_at2(hash, sym("year"), sym("yday"));
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_ordinal_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+
+ a = f_values_at3(hash, sym("year"), sym("mon"), sym("mday"));
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_civil_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ RARRAY_PTR(a)[2],
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+
+ a = f_values_at3(hash, sym("cwyear"), sym("cweek"), sym("cwday"));
+ if (NIL_P(RARRAY_PTR(a)[2]) && !NIL_P(ref_hash("wday")))
+ if (f_zero_p(ref_hash("wday")))
+ RARRAY_PTR(a)[2] = INT2FIX(7);
+ else
+ RARRAY_PTR(a)[2] = ref_hash("wday");
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_commercial_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ RARRAY_PTR(a)[2],
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+
+ a = f_values_at3(hash, sym("year"), sym("wnum0"), sym("wday"));
+ if (NIL_P(RARRAY_PTR(a)[2]) && !NIL_P(ref_hash("cwday")))
+ RARRAY_PTR(a)[2] = f_mod(ref_hash("cwday"), INT2FIX(7));
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_weeknum_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ RARRAY_PTR(a)[2],
+ INT2FIX(0),
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+
+ a = f_values_at3(hash, sym("year"), sym("wnum1"), sym("wday"));
+ if (!NIL_P(RARRAY_PTR(a)[2]))
+ RARRAY_PTR(a)[2] = f_mod(f_sub(RARRAY_PTR(a)[2], INT2FIX(1)),
+ INT2FIX(7));
+ if (NIL_P(RARRAY_PTR(a)[2]) && !NIL_P(ref_hash("cwday")))
+ RARRAY_PTR(a)[2] = f_mod(f_sub(ref_hash("cwday"), INT2FIX(1)),
+ INT2FIX(7));
+ if (f_all_p(a)) {
+ VALUE jd = rt__valid_weeknum_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ RARRAY_PTR(a)[2],
+ INT2FIX(1),
+ sg);
+ if (!NIL_P(jd))
+ return jd;
+ }
+ return Qnil;
+}
+
+static VALUE
+rt__valid_time_frags_p(VALUE hash)
+{
+ VALUE a;
+
+ a = f_values_at3(hash, sym("hour"), sym("min"), sym("sec"));
+ return rt__valid_time_p(RARRAY_PTR(a)[0],
+ RARRAY_PTR(a)[1],
+ RARRAY_PTR(a)[2]);
+}
+
+static VALUE
+d_switch_new_by_frags(VALUE klass, VALUE hash, VALUE sg)
+{
+ VALUE jd;
+
+ hash = rt_rewrite_frags(hash);
+ hash = rt_complete_frags(klass, hash);
+ jd = rt__valid_date_frags_p(hash, sg);
+ if (NIL_P(jd))
+ rb_raise(rb_eArgError, "invalid date");
+ return d_switch_new_jd(klass, jd, sg);
+}
+
VALUE
date__strptime(const char *str, size_t slen,
const char *fmt, size_t flen, VALUE hash);
@@ -1525,10 +3253,12 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass,
if (!NIL_P(zone)) {
rb_enc_copy(zone, vstr);
+ OBJ_INFECT(zone, vstr);
rb_hash_aset(hash, ID2SYM(rb_intern("zone")), zone);
}
if (!NIL_P(left)) {
rb_enc_copy(left, vstr);
+ OBJ_INFECT(left, vstr);
rb_hash_aset(hash, ID2SYM(rb_intern("leftover")), left);
}
}
@@ -1548,6 +3278,52 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass)
return date_s__strptime_internal(argc, argv, klass, "%F");
}
+/*
+ * call-seq:
+ * Date.strptime([string="-4712-01-01"[, format="%F"[,start=ITALY]]])
+ *
+ * Create a new Date object by parsing from a String
+ * according to a specified format.
+ *
+ * +str+ is a String holding a date representation.
+ * +fmt+ is the format that the date is in. See
+ * date/format.rb for details on supported formats.
+ *
+ * The default +str+ is '-4712-01-01', and the default
+ * +fmt+ is '%F', which means Year-Month-Day_of_Month.
+ * This gives Julian Day Number day 0.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ *
+ * An ArgumentError will be raised if +str+ cannot be
+ * parsed.
+ */
+static VALUE
+date_s_strptime(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, fmt, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &fmt, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01");
+ case 1:
+ fmt = rb_str_new2("%F");
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE argv2[2], hash;
+
+ argv2[0] = str;
+ argv2[1] = fmt;
+ hash = date_s__strptime(2, argv2, klass);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
VALUE
date__parse(VALUE str, VALUE comp);
@@ -1571,6 +3347,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
if (!NIL_P(zone)) {
rb_enc_copy(zone, vstr);
+ OBJ_INFECT(zone, vstr);
rb_hash_aset(hash, ID2SYM(rb_intern("zone")), zone);
}
}
@@ -1592,6 +3369,295 @@ date_s__parse(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
+ * Date.parse(string="-4712-01-01"[, comp=true[,start=ITALY]])
+ *
+ * Create a new Date object by parsing from a String,
+ * without specifying the format.
+ *
+ * +str+ is a String holding a date representation.
+ * +comp+ specifies whether to interpret 2-digit years
+ * as 19XX (>= 69) or 20XX (< 69); the default is to.
+ * The method will attempt to parse a date from the String
+ * using various heuristics; see #_parse in date/format.rb
+ * for more details. If parsing fails, an ArgumentError
+ * will be raised.
+ *
+ * The default +str+ is '-4712-01-01'; this is Julian
+ * Day Number day 0.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ */
+static VALUE
+date_s_parse(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE argv2[2], hash;
+
+ argv2[0] = str;
+ argv2[1] = comp;
+ hash = date_s__parse(2, argv2, klass);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+VALUE date__iso8601(VALUE);
+VALUE date__rfc3339(VALUE);
+VALUE date__xmlschema(VALUE);
+VALUE date__rfc2822(VALUE);
+VALUE date__httpdate(VALUE);
+VALUE date__jisx0301(VALUE);
+
+/*
+ * call-seq:
+ * Date._iso8601(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__iso8601(VALUE klass, VALUE str)
+{
+ return date__iso8601(str);
+}
+
+/*
+ * call-seq:
+ * Date.iso8601(string="-4712-01-01"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical ISO 8601 format.
+ */
+static VALUE
+date_s_iso8601(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__iso8601(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date._rfc3339(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__rfc3339(VALUE klass, VALUE str)
+{
+ return date__rfc3339(str);
+}
+
+/*
+ * call-seq:
+ * Date.rfc3339(string="-4712-01-01T00:00:00+00:00"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical RFC 3339 format.
+ */
+static VALUE
+date_s_rfc3339(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__rfc3339(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date._xmlschema(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__xmlschema(VALUE klass, VALUE str)
+{
+ return date__xmlschema(str);
+}
+
+/*
+ * call-seq:
+ * Date.xmlschema(string="-4712-01-01"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical XML Schema format.
+ */
+static VALUE
+date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__xmlschema(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date._rfc2822(string)
+ * Date._rfc822(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__rfc2822(VALUE klass, VALUE str)
+{
+ return date__rfc2822(str);
+}
+
+/*
+ * call-seq:
+ * Date.rfc2822(string="Mon, 1 Jan -4712 00:00:00 +0000"[,start=ITALY])
+ * Date.rfc822(string="Mon, 1 Jan -4712 00:00:00 +0000"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical RFC 2822 format.
+ */
+static VALUE
+date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__rfc2822(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date._httpdate(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__httpdate(VALUE klass, VALUE str)
+{
+ return date__httpdate(str);
+}
+
+/*
+ * call-seq:
+ * Date.httpdate(string="Mon, 01 Jan -4712 00:00:00 GMT"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some RFC 2616 format.
+ */
+static VALUE
+date_s_httpdate(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__httpdate(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date._jisx0301(string)
+ *
+ * Return a hash of parsed elements.
+ */
+static VALUE
+date_s__jisx0301(VALUE klass, VALUE str)
+{
+ return date__jisx0301(str);
+}
+
+/*
+ * call-seq:
+ * Date.jisx0301(string="-4712-01-01"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical JIS X 0301 format.
+ */
+static VALUE
+date_s_jisx0301(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, sg;
+
+ rb_scan_args(argc, argv, "02", &str, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01");
+ case 1:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__jisx0301(klass, str);
+ return d_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
* d.ajd
*
* Get the date as an Astronomical Julian Day Number.
@@ -1608,6 +3674,18 @@ d_lite_ajd(VALUE self)
}
}
+#define c_iforward0(m) d_right_##m(self)
+#define c_iforwardv(m) d_right_##m(argc, argv, self)
+#define c_iforwardop(m) d_right_##m(self, other)
+
+static VALUE
+d_right_amjd(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return rt_ajd_to_amjd(dat->r.ajd);
+}
+
/*
* call-seq:
* d.amjd
@@ -1619,13 +3697,40 @@ d_lite_amjd(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("amjd_r");
+ return c_iforward0(amjd);
{
get_d_jd(dat);
return rb_rational_new1(LONG2NUM(dat->l.jd - 2400001L));
}
}
+#define return_once(k, expr)\
+{\
+ VALUE id, val;\
+ get_d1(self);\
+ id = ID2SYM(rb_intern(#k));\
+ val = rb_hash_aref(dat->r.cache, id);\
+ if (!NIL_P(val))\
+ return val;\
+ val = expr;\
+ rb_hash_aset(dat->r.cache, id, val);\
+ return val;\
+}
+
+static VALUE
+d_right_daynum(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(daynum, rt_ajd_to_jd(dat->r.ajd, dat->r.of));
+}
+
+static VALUE
+d_right_jd(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(daynum))[0];
+}
+
/*
* call-seq:
* d.jd
@@ -1637,13 +3742,21 @@ d_lite_jd(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("jd_r");
+ return c_iforward0(jd);
{
get_d_jd(dat);
return INT2FIX(dat->l.jd);
}
}
+static VALUE
+d_right_mjd(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return rt_jd_to_mjd(d_right_jd(self));
+}
+
/*
* call-seq:
* d.mjd
@@ -1655,13 +3768,21 @@ d_lite_mjd(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("mjd_r");
+ return c_iforward0(mjd);
{
get_d_jd(dat);
return LONG2NUM(dat->l.jd - 2400001L);
}
}
+static VALUE
+d_right_ld(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return rt_jd_to_ld(d_right_jd(self));
+}
+
/*
* call-seq:
* d.ld
@@ -1673,13 +3794,27 @@ d_lite_ld(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("ld_r");
+ return c_iforward0(ld);
{
get_d_jd(dat);
return LONG2NUM(dat->l.jd - 2299160L);
}
}
+static VALUE
+d_right_civil(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(civil, rt_jd_to_civil(d_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+d_right_year(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[0];
+}
+
/*
* call-seq:
* d.year
@@ -1691,13 +3826,27 @@ d_lite_year(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("year_r");
+ return c_iforward0(year);
{
get_d_civil(dat);
return INT2FIX(dat->l.year);
}
}
+static VALUE
+d_right_ordinal(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(ordinal, rt_jd_to_ordinal(d_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+d_right_yday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(ordinal))[1];
+}
+
static const int yeartab[2][13] = {
{ 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
{ 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
@@ -1722,13 +3871,19 @@ d_lite_yday(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("yday_r");
+ return c_iforward0(yday);
{
get_d_civil(dat);
return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
+static VALUE
+d_right_mon(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[1];
+}
+
/*
* call-seq:
* d.mon
@@ -1742,13 +3897,19 @@ d_lite_mon(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("mon_r");
+ return c_iforward0(mon);
{
get_d_civil(dat);
return INT2FIX(dat->l.mon);
}
}
+static VALUE
+d_right_mday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[2];
+}
+
/*
* call-seq:
* d.mday
@@ -1760,13 +3921,19 @@ d_lite_mday(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("mday_r");
+ return c_iforward0(mday);
{
get_d_civil(dat);
return INT2FIX(dat->l.mday);
}
}
+static VALUE
+d_right_day_fraction(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(daynum))[1];
+}
+
/*
* call-seq:
* d.day_fraction
@@ -1778,18 +3945,33 @@ d_lite_day_fraction(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("day_fraction_r");
+ return c_iforward0(day_fraction);
return INT2FIX(0);
}
static VALUE
+d_right_weeknum0(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(weeknum0, rt_jd_to_weeknum(d_right_jd(self),
+ INT2FIX(0), dat->r.sg));
+}
+
+static VALUE
+d_right_wnum0(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(weeknum0))[1];
+}
+
+static VALUE
d_lite_wnum0(VALUE self)
{
int ry, rw, rd;
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("wnum0_r");
+ return c_iforward0(wnum0);
{
get_d_jd(dat);
jd_to_weeknum(dat->l.jd, 0, dat->l.sg, &ry, &rw, &rd);
@@ -1798,13 +3980,28 @@ d_lite_wnum0(VALUE self)
}
static VALUE
+d_right_weeknum1(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(weeknum1, rt_jd_to_weeknum(d_right_jd(self),
+ INT2FIX(1), dat->r.sg));
+}
+
+static VALUE
+d_right_wnum1(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(weeknum1))[1];
+}
+
+static VALUE
d_lite_wnum1(VALUE self)
{
int ry, rw, rd;
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("wnum1_r");
+ return c_iforward0(wnum1);
{
get_d_jd(dat);
jd_to_weeknum(dat->l.jd, 1, dat->l.sg, &ry, &rw, &rd);
@@ -1812,6 +4009,45 @@ d_lite_wnum1(VALUE self)
}
}
+#ifndef NDEBUG
+static VALUE
+d_right_time(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(time, rt_day_fraction_to_time(d_right_day_fraction(self)));
+}
+#endif
+
+static VALUE
+d_right_time_wo_sf(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(time_wo_sf,
+ rt_day_fraction_to_time_wo_sf(d_right_day_fraction(self)));
+}
+
+static VALUE
+d_right_time_sf(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(time_sf, f_mul(f_mod(d_right_day_fraction(self),
+ SECONDS_IN_DAY),
+ INT2FIX(DAY_IN_SECONDS)));
+}
+
+static VALUE
+d_right_hour(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[0];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[0];
+#endif
+}
+
/*
* call-seq:
* d.hour
@@ -1823,10 +4059,20 @@ d_lite_hour(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("hour_r");
+ return c_iforward0(hour);
return INT2FIX(0);
}
+static VALUE
+d_right_min(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[1];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[1];
+#endif
+}
+
/*
* call-seq:
* d.min
@@ -1839,10 +4085,20 @@ d_lite_min(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("min_r");
+ return c_iforward0(min);
return INT2FIX(0);
}
+static VALUE
+d_right_sec(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[2];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[2];
+#endif
+}
+
/*
* call-seq:
* d.sec
@@ -1855,10 +4111,20 @@ d_lite_sec(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("sec_r");
+ return c_iforward0(sec);
return INT2FIX(0);
}
+static VALUE
+d_right_sec_fraction(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[3];
+#else
+ return c_iforward0(time_sf);
+#endif
+}
+
/*
* call-seq:
* d.sec_fraction
@@ -1871,7 +4137,7 @@ d_lite_sec_fraction(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("sec_fraction_r");
+ return c_iforward0(sec_fraction);
return INT2FIX(0);
}
@@ -1890,6 +4156,36 @@ d_lite_offset(VALUE self)
return INT2FIX(0);
}
+static VALUE
+d_right_zone(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ {
+ int sign;
+ VALUE hh, mm, ss, fr;
+
+ if (f_negative_p(dat->r.of)) {
+ sign = '-';
+ fr = f_abs(dat->r.of);
+ }
+ else {
+ sign = '+';
+ fr = dat->r.of;
+ }
+ ss = f_div(fr, SECONDS_IN_DAY);
+
+ hh = f_idiv(ss, INT2FIX(HOUR_IN_SECONDS));
+ ss = f_mod(ss, INT2FIX(HOUR_IN_SECONDS));
+
+ mm = f_idiv(ss, INT2FIX(MINUTE_IN_SECONDS));
+
+ return rb_enc_sprintf(rb_usascii_encoding(),
+ "%c%02d:%02d",
+ sign, NUM2INT(hh), NUM2INT(mm));
+ }
+}
+
/*
* call-seq:
* d.zone
@@ -1901,10 +4197,24 @@ d_lite_zone(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("zone_r");
+ return c_iforward0(zone);
return rb_usascii_str_new2("+00:00");
}
+static VALUE
+d_right_commercial(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return_once(commercial, rt_jd_to_commercial(d_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+d_right_cwyear(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[0];
+}
+
/*
* call-seq:
* d.cwyear
@@ -1919,7 +4229,7 @@ d_lite_cwyear(VALUE self)
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("cwyear_r");
+ return c_iforward0(cwyear);
{
get_d_jd(dat);
jd_to_commercial(dat->l.jd, dat->l.sg, &ry, &rw, &rd);
@@ -1927,6 +4237,12 @@ d_lite_cwyear(VALUE self)
}
}
+static VALUE
+d_right_cweek(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[1];
+}
+
/*
* call-seq:
* d.cweek
@@ -1940,7 +4256,7 @@ d_lite_cweek(VALUE self)
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("cweek_r");
+ return c_iforward0(cweek);
{
get_d_jd(dat);
jd_to_commercial(dat->l.jd, dat->l.sg, &ry, &rw, &rd);
@@ -1948,6 +4264,12 @@ d_lite_cweek(VALUE self)
}
}
+static VALUE
+d_right_cwday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[2];
+}
+
/*
* call-seq:
* d.cwday
@@ -1962,7 +4284,7 @@ d_lite_cwday(VALUE self)
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("cwday_r");
+ return c_iforward0(cwday);
{
get_d_jd(dat);
w = jd_to_wday(dat->l.jd);
@@ -1972,6 +4294,12 @@ d_lite_cwday(VALUE self)
}
}
+static VALUE
+d_right_wday(VALUE self)
+{
+ return rt_jd_to_wday(d_right_jd(self));
+}
+
/*
* call-seq:
* d.wday
@@ -1984,7 +4312,7 @@ d_lite_wday(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("wday_r");
+ return c_iforward0(wday);
{
get_d_jd(dat);
return INT2FIX(jd_to_wday(dat->l.jd));
@@ -1993,6 +4321,112 @@ d_lite_wday(VALUE self)
/*
* call-seq:
+ * d.sunday?
+ *
+ * Is the current date Sunday?
+ */
+static VALUE
+d_lite_sunday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(0));
+}
+
+/*
+ * call-seq:
+ * d.monday?
+ *
+ * Is the current date Monday?
+ */
+static VALUE
+d_lite_monday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(1));
+}
+
+/*
+ * call-seq:
+ * d.tuesday?
+ *
+ * Is the current date Tuesday?
+ */
+static VALUE
+d_lite_tuesday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(2));
+}
+
+/*
+ * call-seq:
+ * d.wednesday?
+ *
+ * Is the current date Wednesday?
+ */
+static VALUE
+d_lite_wednesday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(3));
+}
+
+/*
+ * call-seq:
+ * d.thursday?
+ *
+ * Is the current date Thursday?
+ */
+static VALUE
+d_lite_thursday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(4));
+}
+
+/*
+ * call-seq:
+ * d.friday?
+ *
+ * Is the current date Friday?
+ */
+static VALUE
+d_lite_friday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(5));
+}
+
+/*
+ * call-seq:
+ * d.saturday?
+ *
+ * Is the current date Saturday?
+ */
+static VALUE
+d_lite_saturday_p(VALUE self)
+{
+ return f_eqeq_p(d_lite_wday(self), INT2FIX(6));
+}
+
+#ifndef NDEBUG
+static VALUE
+generic_nth_kday_p(VALUE self, VALUE n, VALUE k)
+{
+ if (f_eqeq_p(k, f_wday(self)) &&
+ f_equal_p(f_jd(self), rt_nth_kday_to_jd(f_year(self),
+ f_mon(self),
+ n, k,
+ f_start(self))))
+ return Qtrue;
+ return Qfalse;
+}
+#endif
+
+static VALUE
+d_right_julian_p(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return f_lt_p(d_right_jd(self), dat->r.sg);
+}
+
+/*
+ * call-seq:
* d.julian?
*
* Is the current date old-style (Julian Calendar)?
@@ -2002,10 +4436,18 @@ d_lite_julian_p(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("julian_r?");
+ return c_iforward0(julian_p);
return Qfalse;
}
+static VALUE
+d_right_gregorian_p(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return d_right_julian_p(self) ? Qfalse : Qtrue;
+}
+
/*
* call-seq:
* d.gregorian?
@@ -2017,10 +4459,33 @@ d_lite_gregorian_p(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("gregorian_r?");
+ return c_iforward0(gregorian_p);
return Qtrue;
}
+static VALUE
+d_right_fix_style(VALUE self)
+{
+ if (d_right_julian_p(self))
+ return DBL2NUM(JULIAN);
+ return DBL2NUM(GREGORIAN);
+}
+
+static VALUE
+d_right_leap_p(VALUE self)
+{
+ VALUE style, a;
+
+ style = d_right_fix_style(self);
+ a = rt_jd_to_civil(f_sub(rt_civil_to_jd(d_right_year(self),
+ INT2FIX(3), INT2FIX(1), style),
+ INT2FIX(1)),
+ style);
+ if (f_eqeq_p(RARRAY_PTR(a)[2], INT2FIX(29)))
+ return Qtrue;
+ return Qfalse;
+}
+
/*
* call-seq:
* d.leap?
@@ -2032,7 +4497,7 @@ d_lite_leap_p(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("leap_r?");
+ return c_iforward0(leap_p);
{
get_d_civil(dat);
return leap_p(dat->l.year) ? Qtrue : Qfalse;
@@ -2054,6 +4519,16 @@ d_lite_start(VALUE self)
return DBL2NUM(dat->l.sg);
}
+static VALUE
+d_right_new_start(int argc, VALUE *argv, VALUE self)
+{
+ get_d1(self);
+ return d_right_new(CLASS_OF(self),
+ d_lite_ajd(self),
+ d_lite_offset(self),
+ (argc >= 1) ? argv[0] : INT2FIX(ITALY));
+}
+
/*
* call-seq:
* d.new_start([start=Date::ITALY])
@@ -2069,26 +4544,112 @@ d_lite_new_start(int argc, VALUE *argv, VALUE self)
get_d1(self);
if (!light_mode_p(dat))
- return iforwardv("new_start_r");
+ return c_iforwardv(new_start);
rb_scan_args(argc, argv, "01", &vsg);
- if (!NIL_P(vsg))
+ sg = ITALY;
+ if (argc >= 1)
sg = NUM2DBL(vsg);
- else
- sg = ITALY;
{
get_d_jd(dat);
if (dat->l.jd < sg)
- return iforwardv("new_start_r");
+ return c_iforwardv(new_start);
+
+ return d_lite_new_internal_wo_civil(CLASS_OF(self),
+ dat->l.jd,
+ sg,
+ HAVE_JD);
+ }
+}
+
+/*
+ * call-seq:
+ * d.italy
+ *
+ * Create a copy of this Date object that uses the Italian/Catholic
+ * Day of Calendar Reform.
+ */
+static VALUE
+d_lite_italy(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = INT2FIX(ITALY);
+ return d_lite_new_start(1, argv, self);
+}
+
+/*
+ * call-seq:
+ * d.england
+ *
+ * Create a copy of this Date object that uses the English/Colonial
+ * Day of Calendar Reform.
+ */
+static VALUE
+d_lite_england(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = INT2FIX(ENGLAND);
+ return d_lite_new_start(1, argv, self);
+}
+
+/*
+ * call-seq:
+ * d.julian
+ *
+ * Create a copy of this Date object that always uses the Julian
+ * Calendar.
+ */
+static VALUE
+d_lite_julian(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = DBL2NUM(JULIAN);
+ return d_lite_new_start(1, argv, self);
+}
- return d_lite_s_new_internal_wo_civil(CLASS_OF(self),
- dat->l.jd,
- sg,
- LIGHT_MODE | HAVE_JD);
+/*
+ * call-seq:
+ * d.gregorian
+ *
+ * Create a copy of this Date object that always uses the Gregorian
+ * Calendar.
+ */
+static VALUE
+d_lite_gregorian(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = DBL2NUM(GREGORIAN);
+ return d_lite_new_start(1, argv, self);
+}
+
+static VALUE
+sof2nof(VALUE of)
+{
+ if (TYPE(of) == T_STRING) {
+ VALUE n = date_zone_to_diff(of);
+ if (NIL_P(n))
+ of = INT2FIX(0);
+ else
+ of = rb_rational_new2(n, INT2FIX(DAY_IN_SECONDS));
}
+ else if (TYPE(of) == T_FLOAT) {
+ of = rb_rational_new2(f_truncate(f_mul(of, INT2FIX(DAY_IN_SECONDS))),
+ INT2FIX(DAY_IN_SECONDS));
+ }
+ return of;
+}
+
+static VALUE
+d_right_new_offset(int argc, VALUE *argv, VALUE self)
+{
+ get_d1(self);
+ return d_right_new(CLASS_OF(self),
+ d_lite_ajd(self),
+ (argc >= 1) ? sof2nof(argv[0]) : INT2FIX(0),
+ d_lite_start(self));
}
/*
@@ -2106,25 +4667,42 @@ d_lite_new_offset(int argc, VALUE *argv, VALUE self)
get_d1(self);
if (!light_mode_p(dat))
- return iforwardv("new_offset_r");
+ return c_iforwardv(new_offset);
rb_scan_args(argc, argv, "01", &vof);
if (NIL_P(vof))
rof = 0;
else {
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof) || rof != 0)
- return iforwardv("new_offset_r");
+ return c_iforwardv(new_offset);
}
{
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);
+ return d_lite_new_internal_wo_civil(CLASS_OF(self),
+ dat->l.jd,
+ dat->l.sg,
+ HAVE_JD);
+ }
+}
+
+static VALUE
+d_right_plus(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_d1(self);
+ if (TYPE(other) == T_FLOAT)
+ other = rb_rational_new2(f_round(f_mul(other, day_in_nanoseconds)),
+ day_in_nanoseconds);
+ return d_right_new(CLASS_OF(self),
+ f_add(d_lite_ajd(self), other),
+ d_lite_offset(self),
+ d_lite_start(self));
}
+ rb_raise(rb_eTypeError, "expected numeric");
}
/*
@@ -2147,7 +4725,7 @@ d_lite_plus(VALUE self, VALUE other)
get_d1(self);
if (!light_mode_p(dat))
- return iforwardop("plus_r");
+ return c_iforwardop(plus);
switch (TYPE(other)) {
case T_FIXNUM:
@@ -2159,10 +4737,11 @@ d_lite_plus(VALUE self, VALUE other)
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);
+ return d_lite_new_internal(CLASS_OF(self),
+ jd, dat->l.sg,
+ 0, 0, 0,
+ (dat->l.flags | HAVE_JD) &
+ ~HAVE_CIVIL);
}
break;
case T_FLOAT:
@@ -2174,10 +4753,32 @@ d_lite_plus(VALUE self, VALUE other)
}
break;
}
- return iforwardop("plus_r");
+ return c_iforwardop(plus);
}
static VALUE
+d_right_minus(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_d1(self);
+ if (TYPE(other) == T_FLOAT)
+ other = rb_rational_new2(f_round(f_mul(other, day_in_nanoseconds)),
+ day_in_nanoseconds);
+ return d_right_new(CLASS_OF(self),
+ f_sub(d_lite_ajd(self), other),
+ d_lite_offset(self),
+ d_lite_start(self));
+
+ }
+ else if (k_date_p(other)) {
+ return f_sub(d_lite_ajd(self), f_ajd(other));
+ }
+ rb_raise(rb_eTypeError, "expected numeric");
+}
+
+static VALUE dt_right_minus(VALUE, VALUE);
+
+static VALUE
minus_dd(VALUE self, VALUE other)
{
get_dt2_cast(self, other);
@@ -2217,10 +4818,12 @@ minus_dd(VALUE self, VALUE other)
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));
+ r = f_add(r, rb_rational_new2(LONG2NUM(sf), day_in_nanoseconds));
return r;
}
- return iforwardop("minus_r");
+ if (!k_datetime_p(self))
+ return d_right_minus(self, other);
+ return dt_right_minus(self, other);
}
/*
@@ -2265,10 +4868,286 @@ d_lite_minus(VALUE self, VALUE other)
case T_FLOAT:
return d_lite_plus(self, DBL2NUM(-NUM2DBL(other)));
}
- return iforwardop("minus_r");
+ return c_iforwardop(minus);
+}
+
+/*
+ * call-seq:
+ * d.next_day([n=1])
+ *
+ * Equivalent to d + n.
+ */
+static VALUE
+d_lite_next_day(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_plus(self, n);
+}
+
+/*
+ * call-seq:
+ * d.prev_day([n=1])
+ *
+ * Equivalent to d - n.
+ */
+static VALUE
+d_lite_prev_day(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_minus(self, n);
+}
+
+/*
+ * call-seq:
+ * d.next
+ *
+ * Return a new Date one day after this one.
+ */
+static VALUE
+d_lite_next(VALUE self)
+{
+ return d_lite_next_day(0, (VALUE *)NULL, self);
+}
+
+/*
+ * call-seq:
+ * d >> n
+ *
+ * Return a new Date object that is +n+ months later than
+ * the current one.
+ *
+ * If the day-of-the-month of the current Date is greater
+ * than the last day of the target month, the day-of-the-month
+ * of the returned Date will be the last day of the target month.
+ */
+static VALUE
+d_lite_rshift(VALUE self, VALUE other)
+{
+ VALUE t, y, m, d, sg, j;
+
+ t = f_add3(f_mul(d_lite_year(self), INT2FIX(12)),
+ f_sub(d_lite_mon(self), INT2FIX(1)),
+ other);
+ y = f_idiv(t, INT2FIX(12));
+ m = f_mod(t, INT2FIX(12));
+ m = f_add(m, INT2FIX(1));
+ d = d_lite_mday(self);
+ sg = d_lite_start(self);
+
+ while (NIL_P(j = rt__valid_civil_p(y, m, d, sg))) {
+ d = f_sub(d, INT2FIX(1));
+ if (f_lt_p(d, INT2FIX(1)))
+ rb_raise(rb_eArgError, "invalid date");
+ }
+ return f_add(self, f_sub(j, d_lite_jd(self)));
+}
+
+/*
+ * call-seq:
+ * d << n
+ *
+ * Return a new Date object that is +n+ months earlier than
+ * the current one.
+ *
+ * If the day-of-the-month of the current Date is greater
+ * than the last day of the target month, the day-of-the-month
+ * of the returned Date will be the last day of the target month.
+ */
+static VALUE
+d_lite_lshift(VALUE self, VALUE other)
+{
+ return d_lite_rshift(self, f_negate(other));
+}
+
+/*
+ * call-seq:
+ * d.next_month([n=1])
+ *
+ * Equivalent to d >> n
+ */
+static VALUE
+d_lite_next_month(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_rshift(self, n);
+}
+
+/*
+ * call-seq:
+ * d.prev_month([n=1])
+ *
+ * Equivalent to d << n
+ */
+static VALUE
+d_lite_prev_month(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_lshift(self, n);
+}
+
+/*
+ * call-seq:
+ * d.next_year([n=1])
+ *
+ * Equivalent to d >> (n * 12)
+ */
+static VALUE
+d_lite_next_year(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_rshift(self, f_mul(n, INT2FIX(12)));
+}
+
+/*
+ * call-seq:
+ * d.prev_year([n=1])
+ *
+ * Equivalent to d << (n * 12)
+ */
+static VALUE
+d_lite_prev_year(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return d_lite_lshift(self, f_mul(n, INT2FIX(12)));
+}
+
+/*
+ * call-seq:
+ * d.step(limit[, step=1])
+ * d.step(limit[, step=1]){|date| ...}
+ *
+ * Step the current date forward +step+ days at a
+ * time (or backward, if +step+ is negative) until
+ * we reach +limit+ (inclusive), yielding the resultant
+ * date at each step.
+ */
+static VALUE
+generic_step(int argc, VALUE *argv, VALUE self)
+{
+ VALUE limit, step, date;
+
+ rb_scan_args(argc, argv, "11", &limit, &step);
+
+ if (argc < 2)
+ step = INT2FIX(1);
+
+#if 0
+ if (f_zero_p(step))
+ rb_raise(rb_eArgError, "step can't be 0");
+#endif
+
+ RETURN_ENUMERATOR(self, argc, argv);
+
+ date = self;
+ switch (FIX2INT(f_cmp(step, INT2FIX(0)))) {
+ case -1:
+ while (f_ge_p(date, limit)) {
+ rb_yield(date);
+ date = f_add(date, step);
+ }
+ break;
+ case 0:
+ while (1)
+ rb_yield(date);
+ break;
+ case 1:
+ while (f_le_p(date, limit)) {
+ rb_yield(date);
+ date = f_add(date, step);
+ }
+ break;
+ default:
+ abort();
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * d.upto(max)
+ * d.upto(max){|date| ...}
+ *
+ * Step forward one day at a time until we reach +max+
+ * (inclusive), yielding each date as we go.
+ */
+static VALUE
+generic_upto(VALUE self, VALUE max)
+{
+ VALUE date;
+
+ RETURN_ENUMERATOR(self, 1, &max);
+
+ date = self;
+ while (f_le_p(date, max)) {
+ rb_yield(date);
+ date = f_add(date, INT2FIX(1));
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * d.downto(min)
+ * d.downto(min){|date| ...}
+ *
+ * Step backward one day at a time until we reach +min+
+ * (inclusive), yielding each date as we go.
+ */
+static VALUE
+generic_downto(VALUE self, VALUE min)
+{
+ VALUE date;
+
+ RETURN_ENUMERATOR(self, 1, &min);
+
+ date = self;
+ while (f_ge_p(date, min)) {
+ rb_yield(date);
+ date = f_add(date, INT2FIX(-1));
+ }
+ return self;
}
static VALUE
+d_right_cmp(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_d1(self);
+ return f_cmp(d_lite_ajd(self), other);
+ }
+ else if (k_date_p(other)) {
+ return f_cmp(d_lite_ajd(self), f_ajd(other));
+ }
+ return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
+}
+
+static VALUE dt_right_cmp(VALUE, VALUE);
+
+static VALUE
cmp_dd(VALUE self, VALUE other)
{
get_dt2_cast(self, other);
@@ -2306,7 +5185,9 @@ cmp_dd(VALUE self, VALUE other)
return INT2FIX(1);
}
}
- return iforwardop("cmp_r");
+ if (!k_datetime_p(self))
+ return d_right_cmp(self, other);
+ return dt_right_cmp(self, other);
}
/*
@@ -2378,9 +5259,24 @@ d_lite_cmp(VALUE self, VALUE other)
}
}
}
- return iforwardop("cmp_r");
+ return c_iforwardop(cmp);
+}
+
+static VALUE
+d_right_equal(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_d1(self);
+ return f_eqeq_p(d_lite_jd(self), other);
+ }
+ else if (k_date_p(other)) {
+ return f_eqeq_p(d_lite_jd(self), f_jd(other));
+ }
+ return rb_num_coerce_cmp(self, other, rb_intern("=="));
}
+static VALUE dt_right_equal(VALUE, VALUE);
+
static VALUE
equal_dd(VALUE self, VALUE other)
{
@@ -2397,7 +5293,9 @@ equal_dd(VALUE self, VALUE other)
return Qtrue;
return Qfalse;
}
- return iforwardop("equal_r");
+ if (!k_datetime_p(self))
+ return d_right_equal(self, other);
+ return dt_right_equal(self, other);
}
/*
@@ -2441,7 +5339,15 @@ d_lite_equal(VALUE self, VALUE other)
}
}
}
- return iforwardop("equal_r");
+ return c_iforwardop(equal);
+}
+
+static VALUE
+d_right_eql_p(VALUE self, VALUE other)
+{
+ if (k_date_p(other) && f_eqeq_p(self, other))
+ return Qtrue;
+ return Qfalse;
}
static VALUE
@@ -2462,7 +5368,7 @@ eql_p_dd(VALUE self, VALUE other)
return Qtrue;
return Qfalse;
}
- return iforwardop("eql_r?");
+ return c_iforwardop(eql_p);
}
/*
@@ -2503,7 +5409,15 @@ d_lite_eql_p(VALUE self, VALUE other)
}
}
}
- return iforwardop("eql_r?");
+ return c_iforwardop(eql_p);
+}
+
+static VALUE
+d_right_hash(VALUE self)
+{
+ get_d1(self);
+ assert(!light_mode_p(dat));
+ return rb_hash(dat->r.ajd);
}
/*
@@ -2517,10 +5431,26 @@ d_lite_hash(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("hash_r");
+ return c_iforward0(hash);
return rb_hash(d_lite_ajd(self));
}
+static VALUE
+d_right_to_s(VALUE self)
+{
+ VALUE a, argv[4];
+
+ get_d1(self);
+ assert(!light_mode_p(dat));
+
+ argv[0] = rb_usascii_str_new2("%.4d-%02d-%02d");
+ a = d_right_civil(self);
+ argv[1] = RARRAY_PTR(a)[0];
+ argv[2] = RARRAY_PTR(a)[1];
+ argv[3] = RARRAY_PTR(a)[2];
+ return rb_f_sprintf(4, argv);
+}
+
/*
* call-seq:
* d.to_s
@@ -2532,7 +5462,7 @@ d_lite_to_s(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("to_s_r");
+ return c_iforward0(to_s);
{
get_d_civil(dat);
return rb_enc_sprintf(rb_usascii_encoding(),
@@ -2541,6 +5471,23 @@ d_lite_to_s(VALUE self)
}
}
+static VALUE
+d_right_inspect(VALUE self)
+{
+ VALUE argv[6];
+
+ get_d1(self);
+ assert(!light_mode_p(dat));
+
+ argv[0] = rb_usascii_str_new2("#<%s[R]: %s (%s,%s,%s)>");
+ argv[1] = rb_class_name(CLASS_OF(self));
+ argv[2] = d_right_to_s(self);
+ argv[3] = dat->r.ajd;
+ argv[4] = dat->r.of;
+ argv[5] = dat->r.sg;
+ return rb_f_sprintf(6, argv);
+}
+
/*
* call-seq:
* d.inspect
@@ -2552,7 +5499,7 @@ d_lite_inspect(VALUE self)
{
get_d1(self);
if (!light_mode_p(dat))
- return iforward0("inspect_r");
+ return c_iforward0(inspect);
{
get_d_civil(dat);
get_d_jd(dat);
@@ -2609,20 +5556,18 @@ d_lite_set_tmx(VALUE self, struct tmx *tmx)
get_d1(self);
if (!light_mode_p(dat)) {
- tmx->year = iforward0("year_r");
- tmx->yday = FIX2INT(iforward0("yday_r"));
- tmx->mon = FIX2INT(iforward0("mon_r"));
- tmx->mday = FIX2INT(iforward0("mday_r"));
- tmx->hour = FIX2INT(iforward0("hour_r"));
- tmx->min = FIX2INT(iforward0("min_r"));
- tmx->sec = FIX2INT(iforward0("sec_r"));
- tmx->wday = FIX2INT(iforward0("wday_r"));
- tmx->offset = INT2FIX(0);
- tmx->zone = RSTRING_PTR(iforward0("zone_r"));
- tmx->timev = f_mul(f_sub(dat->r.ajd,
- rb_rational_new2(INT2FIX(4881175),
- INT2FIX(2))),
- INT2FIX(86400));
+ tmx->year = d_right_year(self);
+ tmx->yday = FIX2INT(d_right_yday(self));
+ tmx->mon = FIX2INT(d_right_mon(self));
+ tmx->mday = FIX2INT(d_right_mday(self));
+ tmx->hour = FIX2INT(d_right_hour(self));
+ tmx->min = FIX2INT(d_right_min(self));
+ tmx->sec = FIX2INT(d_right_sec(self));
+ tmx->wday = FIX2INT(d_right_wday(self));
+ tmx->offset = f_mul(dat->r.of, INT2FIX(DAY_IN_SECONDS));
+ tmx->zone = RSTRING_PTR(d_right_zone(self));
+ tmx->timev = f_mul(f_sub(dat->r.ajd, UNIX_EPOCH_IN_AJD),
+ INT2FIX(DAY_IN_SECONDS));
}
else {
get_d_jd(dat);
@@ -2639,7 +5584,7 @@ d_lite_set_tmx(VALUE self, struct tmx *tmx)
tmx->offset = INT2FIX(0);
tmx->zone = "+00:00";
tmx->timev = f_mul(INT2FIX(dat->l.jd - 2440588),
- INT2FIX(86400));
+ INT2FIX(DAY_IN_SECONDS));
}
}
@@ -2648,7 +5593,6 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self,
const char *default_fmt,
void (*func)(VALUE, struct tmx *))
{
- get_d1(self);
{
VALUE vfmt;
const char *fmt;
@@ -2695,6 +5639,7 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self,
str = rb_str_new(buf, len);
if (buf != buffer) xfree(buf);
rb_enc_copy(str, vfmt);
+ OBJ_INFECT(str, vfmt);
return str;
}
}
@@ -2712,6 +5657,134 @@ d_lite_strftime(int argc, VALUE *argv, VALUE self)
"%F", d_lite_set_tmx);
}
+static VALUE
+strftimev(const char *fmt, VALUE self,
+ void (*func)(VALUE, struct tmx *))
+{
+ char buffer[SMALLBUF], *buf = buffer;
+ struct tmx tmx;
+ long len;
+ VALUE str;
+
+ (*func)(self, &tmx);
+ len = date_strftime_alloc(&buf, fmt, &tmx);
+ str = rb_usascii_str_new(buf, len);
+ if (buf != buffer) xfree(buf);
+ return str;
+}
+
+/*
+ * call-seq:
+ * d.asctime
+ * d.ctime
+ *
+ * Equivalent to strftime('%c').
+ * See also asctime(3) or ctime(3).
+ */
+static VALUE
+d_lite_asctime(VALUE self)
+{
+ return strftimev("%c", self, d_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * d.iso8601
+ * d.xmlschema
+ *
+ * Equivalent to strftime('%F').
+ */
+static VALUE
+d_lite_iso8601(VALUE self)
+{
+ return strftimev("%F", self, d_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * d.rfc3339
+ *
+ * Equivalent to strftime('%FT%T%:z').
+ */
+static VALUE
+d_lite_rfc3339(VALUE self)
+{
+ return strftimev("%FT%T%:z", self, d_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * d.rfc2822
+ * d.rfc822
+ *
+ * Equivalent to strftime('%a, %-d %b %Y %T %z').
+ */
+static VALUE
+d_lite_rfc2822(VALUE self)
+{
+ return strftimev("%a, %-d %b %Y %T %z", self, d_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * d.httpdate
+ *
+ * Equivalent to strftime('%a, %d %b %Y %T GMT').
+ * See also RFC 2616.
+ */
+static VALUE
+d_lite_httpdate(VALUE self)
+{
+ VALUE argv[1], d;
+
+ argv[0] = INT2FIX(0);
+ d = d_lite_new_offset(1, argv, self);
+ return strftimev("%a, %d %b %Y %T GMT", d, d_lite_set_tmx);
+}
+
+static VALUE
+gengo(VALUE jd, VALUE y, VALUE *a)
+{
+ if (f_lt_p(jd, INT2FIX(2405160)))
+ return 0;
+ if (f_lt_p(jd, INT2FIX(2419614))) {
+ a[0] = rb_usascii_str_new2("M%02d");
+ a[1] = f_sub(y, INT2FIX(1867));
+ }
+ else if (f_lt_p(jd, INT2FIX(2424875))) {
+ a[0] = rb_usascii_str_new2("T%02d");
+ a[1] = f_sub(y, INT2FIX(1911));
+ }
+ else if (f_lt_p(jd, INT2FIX(2447535))) {
+ a[0] = rb_usascii_str_new2("S%02d");
+ a[1] = f_sub(y, INT2FIX(1925));
+ }
+ else {
+ a[0] = rb_usascii_str_new2("H%02d");
+ a[1] = f_sub(y, INT2FIX(1988));
+ }
+ return 1;
+}
+
+/*
+ * call-seq:
+ * d.jisx0301
+ *
+ * Return a string as a JIS X 0301 format.
+ */
+static VALUE
+d_lite_jisx0301(VALUE self)
+{
+ VALUE argv[2];
+
+ if (!gengo(d_lite_jd(self),
+ d_lite_year(self),
+ argv))
+ return strftimev("%F", self, d_lite_set_tmx);
+ return f_add(rb_f_sprintf(2, argv),
+ strftimev(".%m.%d", self, d_lite_set_tmx));
+}
+
/*
* call-seq:
* d.marshal_dump
@@ -2783,28 +5856,51 @@ d_lite_marshal_load(VALUE self, VALUE a)
return self;
}
-static VALUE
-d_right_cache(VALUE self)
+/* datetime light */
+
+static void
+dt_right_gc_mark(union DateTimeData *dat)
{
- get_d1(self);
- if (light_mode_p(dat))
- return Qnil;
- return dat->r.cache;
+ assert(!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);
}
-/* datetime light */
+#define dt_lite_gc_mark 0
+
+inline static VALUE
+dt_right_new_internal(VALUE klass, VALUE ajd, VALUE of, VALUE sg,
+ unsigned flags)
+{
+ union DateTimeData *dat;
+ VALUE obj;
+
+ obj = Data_Make_Struct(klass, union DateTimeData,
+ dt_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 | DATETIME_OBJ;
+
+ return obj;
+}
inline static VALUE
-dt_lite_s_new_internal(VALUE klass, long jd, int df,
- long sf, int of, double sg,
- int y, int m, int d,
- int h, int min, int s,
- unsigned flags)
+dt_lite_new_internal(VALUE klass, long jd, int df,
+ 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);
+ obj = Data_Make_Struct(klass, union DateTimeData,
+ dt_lite_gc_mark, -1, dat);
dat->l.jd = jd;
dat->l.df = df;
@@ -2817,67 +5913,227 @@ dt_lite_s_new_internal(VALUE klass, long jd, int df,
dat->l.hour = h;
dat->l.min = min;
dat->l.sec = s;
- dat->l.flags = flags;
+ dat->l.flags = flags | LIGHT_MODE | DATETIME_OBJ;
return obj;
}
static VALUE
-dt_lite_s_new_internal_wo_civil(VALUE klass, long jd, int df,
- long sf, int of, double sg,
- unsigned flags)
+dt_lite_new_internal_wo_civil(VALUE klass, long jd, int df,
+ long sf, int of, double sg,
+ unsigned flags)
{
- return dt_lite_s_new_internal(klass, jd, df, sf, of, sg,
+ return dt_lite_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, LIGHT_MODE);
+ return dt_lite_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)
+dt_right_new(VALUE klass, VALUE ajd, VALUE of, VALUE sg)
{
- VALUE vjd, vdf, vsf, vof, vsg;
- long jd;
+ return dt_right_new_internal(klass, ajd, of, sg, 0);
+}
+
+static VALUE
+dt_lite_new(VALUE klass, VALUE jd, VALUE df, VALUE sf, VALUE of, VALUE sg)
+{
+ return dt_lite_new_internal_wo_civil(klass,
+ NUM2LONG(jd),
+ FIX2INT(df),
+ NUM2LONG(sf),
+ FIX2INT(of),
+ NUM2DBL(sg),
+ HAVE_JD | HAVE_DF);
+}
- rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg);
+static VALUE
+dt_switch_new(VALUE klass, VALUE ajd, VALUE of, VALUE sg)
+{
+ VALUE t, jd, df, sf, ssf, odf, osf;
- 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);
+ t = rt_ajd_to_jd(ajd, INT2FIX(0)); /* as utc */
+ jd = RARRAY_PTR(t)[0];
+ df = RARRAY_PTR(t)[1];
+
+ t = f_mul(df, INT2FIX(DAY_IN_SECONDS));
+ df = f_idiv(t, INT2FIX(1));
+ sf = f_mod(t, INT2FIX(1));
+
+ t = f_mul(sf, INT2FIX(SECOND_IN_NANOSECONDS));
+ sf = f_idiv(t, INT2FIX(1));
+ ssf = f_mod(t, INT2FIX(1));
+
+ t = f_mul(of, INT2FIX(DAY_IN_SECONDS));
+ odf = f_truncate(t);
+ osf = f_remainder(t, INT2FIX(1));
+
+#ifdef FORCE_RIGHT
+ if (1)
+#else
+ if (!FIXNUM_P(jd) ||
+ f_lt_p(jd, sg) || !f_zero_p(ssf) || !f_zero_p(osf) ||
+ !LIGHTABLE_JD(NUM2LONG(jd)))
+#endif
+ return dt_right_new(klass, ajd, of, sg);
+ else
+ return dt_lite_new(klass, jd, df, sf, odf, sg);
+}
+
+#ifndef NDEBUG
+static VALUE
+dt_right_new_m(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE ajd, of, sg;
+
+ rb_scan_args(argc, argv, "03", &ajd, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ ajd = INT2FIX(0);
+ case 1:
+ of = INT2FIX(0);
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ return dt_right_new(klass, ajd, of, sg);
+}
+
+static VALUE
+dt_lite_new_m(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE jd, df, sf, of, sg;
+
+ rb_scan_args(argc, argv, "05", &jd, &df, &sf, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ jd = INT2FIX(0);
+ case 1:
+ df = INT2FIX(0);
+ case 2:
+ sf = INT2FIX(0);
+ case 3:
+ of = INT2FIX(0);
+ case 4:
+ sg = INT2FIX(ITALY);
+ }
+
+ return dt_lite_new(klass, jd, df, sf, of, sg);
+}
+
+static VALUE
+dt_switch_new_m(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE ajd, of, sg;
+
+ rb_scan_args(argc, argv, "03", &ajd, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ ajd = INT2FIX(0);
+ case 1:
+ of = INT2FIX(0);
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ return dt_switch_new(klass, ajd, of, sg);
+}
+#endif
+
+static VALUE
+dt_right_new_jd(VALUE klass, VALUE jd, VALUE fr, VALUE of, VALUE sg)
+{
+ return dt_right_new(klass,
+ rt_jd_to_ajd(jd, fr, of),
+ of,
+ sg);
+}
+
+#ifndef NDEBUG
+static VALUE
+dt_lite_new_jd(VALUE klass, VALUE jd, VALUE fr, VALUE of, VALUE sg)
+{
+ VALUE n, df, sf;
+
+ n = f_mul(fr, INT2FIX(DAY_IN_SECONDS));
+ df = f_idiv(n, INT2FIX(1));
+ sf = f_mod(n, INT2FIX(1));
+ n = f_mul(sf, INT2FIX(SECOND_IN_NANOSECONDS));
+ sf = f_idiv(n, INT2FIX(1));
+ return dt_lite_new(klass, jd, df, sf, of, sg);
+}
+#endif
- 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");
+static VALUE
+dt_switch_new_jd(VALUE klass, VALUE jd, VALUE fr, VALUE of, VALUE sg)
+{
+ return dt_switch_new(klass,
+ rt_jd_to_ajd(jd, fr, of),
+ of,
+ sg);
+}
- return dt_lite_s_new_internal_wo_civil(klass,
- jd,
- FIX2INT(vdf),
- FIX2INT(vsf),
- FIX2INT(vof),
- NUM2DBL(vsg),
- LIGHT_MODE | HAVE_JD | HAVE_DF);
+#ifndef NDEBUG
+static VALUE
+datetime_s_new_r_bang(int argc, VALUE *argv, VALUE klass)
+{
+ return dt_right_new_m(argc, argv, klass);
}
static VALUE
datetime_s_new_l_bang(int argc, VALUE *argv, VALUE klass)
{
- return dt_lite_s_new_l_bang(argc, argv, klass);
+ return dt_lite_new_m(argc, argv, klass);
+}
+
+static VALUE
+datetime_s_new_bang(int argc, VALUE *argv, VALUE klass)
+{
+ return dt_switch_new_m(argc, argv, klass);
+}
+#endif
+
+#undef c_cforwardv
+#define c_cforwardv(m) rt_datetime_s_##m(argc, argv, klass)
+
+static VALUE
+rt_datetime_s_jd(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE jd, h, min, s, of, sg, fr;
+
+ rb_scan_args(argc, argv, "06", &jd, &h, &min, &s, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ jd = INT2FIX(0);
+ case 1:
+ h = INT2FIX(0);
+ case 2:
+ min = INT2FIX(0);
+ case 3:
+ s = INT2FIX(0);
+ case 4:
+ of = INT2FIX(0);
+ case 5:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_jd_p(jd, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
}
/*
@@ -2906,24 +6162,26 @@ datetime_s_jd(int argc, VALUE *argv, VALUE klass)
int h, min, s, rh, rmin, rs, rof;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(jd);
+#endif
+
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;
+ return c_cforwardv(jd);
jd = h = min = s = 0;
rof = 0;
+ sg = ITALY;
switch (argc) {
case 6:
+ sg = NUM2DBL(vsg);
case 5:
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof))
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
case 4:
s = NUM2INT(vs);
case 3:
@@ -2933,21 +6191,56 @@ datetime_s_jd(int argc, VALUE *argv, VALUE klass)
case 1:
jd = NUM2LONG(vjd);
if (!LIGHTABLE_JD(jd))
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
}
if (jd < sg)
- return cforwardv("jd_r");
+ return c_cforwardv(jd);
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);
+ return dt_lite_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,
+ HAVE_JD | HAVE_TIME);
+}
+
+static VALUE
+rt_datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, d, h, min, s, of, sg, jd, fr;
+
+ rb_scan_args(argc, argv, "07", &y, &d, &h, &min, &s, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ d = INT2FIX(1);
+ case 2:
+ h = INT2FIX(0);
+ case 3:
+ min = INT2FIX(0);
+ case 4:
+ s = INT2FIX(0);
+ case 5:
+ of = INT2FIX(0);
+ case 6:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_ordinal_p(y, d, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
}
/*
@@ -2976,6 +6269,10 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
int y, d, rd, h, min, s, rh, rmin, rs, rof;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(ordinal);
+#endif
+
rb_scan_args(argc, argv, "07", &vy, &vd, &vh, &vmin, &vs, &vof, &vsg);
if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
@@ -2983,24 +6280,22 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
(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;
+ return c_cforwardv(ordinal);
y = -4712;
d = 1;
h = min = s = 0;
rof = 0;
+ sg = ITALY;
switch (argc) {
case 7:
+ sg = NUM2DBL(vsg);
case 6:
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof))
- return cforwardv("ordinal_r");
+ return c_cforwardv(ordinal);
case 5:
s = NUM2INT(vs);
case 4:
@@ -3012,7 +6307,7 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("ordinal_r");
+ return c_cforwardv(ordinal);
}
{
@@ -3025,16 +6320,53 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("ordinal_r");
+ return c_cforwardv(ordinal);
+
+ return dt_lite_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,
+ HAVE_JD | HAVE_TIME);
+ }
+}
+
+static VALUE
+rt_datetime_s_civil(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, m, d, h, min, s, of, sg, jd, fr;
+
+ rb_scan_args(argc, argv, "08", &y, &m, &d, &h, &min, &s, &of, &sg);
- 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);
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ m = INT2FIX(1);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ h = INT2FIX(0);
+ case 4:
+ min = INT2FIX(0);
+ case 5:
+ s = INT2FIX(0);
+ case 6:
+ of = INT2FIX(0);
+ case 7:
+ sg = INT2FIX(ITALY);
}
+
+ jd = rt__valid_civil_p(y, m, d, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
}
/*
@@ -3064,6 +6396,10 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
int y, m, d, rm, rd, h, min, s, rh, rmin, rs, rof;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(civil);
+#endif
+
rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg);
if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
@@ -3072,12 +6408,7 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
(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;
+ return c_cforwardv(civil);
y = -4712;
m = 1;
@@ -3085,12 +6416,15 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
h = min = s = 0;
rof = 0;
+ sg = ITALY;
switch (argc) {
case 8:
+ sg = NUM2DBL(vsg);
case 7:
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof))
- return cforwardv("civil_r");
+ return c_cforwardv(civil);
case 6:
s = NUM2INT(vs);
case 5:
@@ -3104,7 +6438,7 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_YEAR(y))
- return cforwardv("civil_r");
+ return c_cforwardv(civil);
}
if (isinf(sg) && sg < 0) {
@@ -3113,9 +6447,9 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
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);
+ return dt_lite_new_internal(klass, 0, 0, 0, rof, sg,
+ y, rm, rd, rh, rmin, rs,
+ HAVE_CIVIL | HAVE_TIME);
}
else {
long jd;
@@ -3127,17 +6461,53 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("civil_r");
+ return c_cforwardv(civil);
+
+ return dt_lite_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,
+ HAVE_JD | HAVE_CIVIL | HAVE_TIME);
+ }
+}
+
+static VALUE
+rt_datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, w, d, h, min, s, of, sg, jd, fr;
- 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);
+ rb_scan_args(argc, argv, "08", &y, &w, &d, &h, &min, &s, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ w = INT2FIX(1);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ h = INT2FIX(0);
+ case 4:
+ min = INT2FIX(0);
+ case 5:
+ s = INT2FIX(0);
+ case 6:
+ of = INT2FIX(0);
+ case 7:
+ sg = INT2FIX(ITALY);
}
+
+ jd = rt__valid_commercial_p(y, w, d, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
}
/*
@@ -3167,6 +6537,10 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
int y, w, d, rw, rd, h, min, s, rh, rmin, rs, rof;
double sg;
+#ifdef FORCE_RIGHT
+ return c_cforwardv(commercial);
+#endif
+
rb_scan_args(argc, argv, "08", &vy, &vw, &vd, &vh, &vmin, &vs, &vof, &vsg);
if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
@@ -3175,12 +6549,7 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
(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;
+ return c_cforwardv(commercial);
y = -4712;
w = 1;
@@ -3188,12 +6557,15 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
h = min = s = 0;
rof = 0;
+ sg = ITALY;
switch (argc) {
case 8:
+ sg = NUM2DBL(vsg);
case 7:
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof))
- return cforwardv("commercial_r");
+ return c_cforwardv(commercial);
case 6:
s = NUM2INT(vs);
case 5:
@@ -3207,7 +6579,7 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
case 1:
y = NUM2INT(vy);
if (!LIGHTABLE_CWYEAR(y))
- return cforwardv("commercial_r");
+ return c_cforwardv(commercial);
}
{
@@ -3220,18 +6592,256 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass)
rb_raise(rb_eArgError, "invalid date");
if (!LIGHTABLE_JD(jd) || !ns)
- return cforwardv("commercial_r");
+ return c_cforwardv(commercial);
+
+ return dt_lite_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,
+ HAVE_JD | HAVE_TIME);
+ }
+}
+
+#ifndef NDEBUG
+static VALUE
+rt_datetime_s_weeknum(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, w, d, f, h, min, s, of, sg, jd, fr;
+
+ rb_scan_args(argc, argv, "09", &y, &w, &d, &f, &h, &min, &s, &of, &sg);
- 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);
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ w = INT2FIX(0);
+ case 2:
+ d = INT2FIX(1);
+ case 3:
+ f = INT2FIX(0);
+ case 4:
+ h = INT2FIX(0);
+ case 5:
+ min = INT2FIX(0);
+ case 6:
+ s = INT2FIX(0);
+ case 7:
+ of = INT2FIX(0);
+ case 8:
+ sg = INT2FIX(ITALY);
}
+
+ jd = rt__valid_weeknum_p(y, w, d, f, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
}
+static VALUE
+datetime_s_weeknum(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vw, vd, vf, vh, vmin, vs, vof, vsg;
+ int y, w, d, f, rw, rd, h, min, s, rh, rmin, rs, rof;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return c_cforwardv(weeknum);
+#endif
+
+ rb_scan_args(argc, argv, "09", &vy, &vw, &vd, &vf,
+ &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(vf) || FIXNUM_P(vf)) &&
+ (NIL_P(vh) || FIXNUM_P(vh)) &&
+ (NIL_P(vmin) || FIXNUM_P(vmin)) &&
+ (NIL_P(vs) || FIXNUM_P(vs))))
+ return c_cforwardv(weeknum);
+
+ y = -4712;
+ w = 0;
+ d = 1;
+ f = 0;
+
+ h = min = s = 0;
+ rof = 0;
+ sg = ITALY;
+
+ switch (argc) {
+ case 9:
+ sg = NUM2DBL(vsg);
+ case 8:
+ vof = sof2nof(vof);
+ if (!daydiff_to_sec(vof, &rof))
+ return c_cforwardv(weeknum);
+ case 7:
+ s = NUM2INT(vs);
+ case 6:
+ min = NUM2INT(vmin);
+ case 5:
+ h = NUM2INT(vh);
+ case 4:
+ f = NUM2INT(vf);
+ case 3:
+ d = NUM2INT(vd);
+ case 2:
+ w = NUM2INT(vw);
+ case 1:
+ y = NUM2INT(vy);
+ if (!LIGHTABLE_YEAR(y))
+ return c_cforwardv(weeknum);
+ }
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_weeknum_p(y, w, d, f, 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 c_cforwardv(weeknum);
+
+ return dt_lite_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,
+ HAVE_JD | HAVE_TIME);
+ }
+}
+
+static VALUE
+rt_datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE y, m, n, k, h, min, s, of, sg, jd, fr;
+
+ rb_scan_args(argc, argv, "09", &y, &m, &n, &k, &h, &min, &s, &of, &sg);
+
+ switch (argc) {
+ case 0:
+ y = INT2FIX(-4712);
+ case 1:
+ m = INT2FIX(1);
+ case 2:
+ n = INT2FIX(1);
+ case 3:
+ k = INT2FIX(1);
+ case 4:
+ h = INT2FIX(0);
+ case 5:
+ min = INT2FIX(0);
+ case 6:
+ s = INT2FIX(0);
+ case 7:
+ of = INT2FIX(0);
+ case 8:
+ sg = INT2FIX(ITALY);
+ }
+
+ jd = rt__valid_nth_kday_p(y, m, n, k, sg);
+ fr = rt__valid_time_p(h, min, s);
+
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+
+ of = sof2nof(of);
+
+ return dt_right_new_jd(klass, jd, fr, of, sg);
+}
+
+static VALUE
+datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE vy, vm, vn, vk, vh, vmin, vs, vof, vsg;
+ int y, m, n, k, rm, rn, rk, h, min, s, rh, rmin, rs, rof;
+ double sg;
+
+#ifdef FORCE_RIGHT
+ return c_cforwardv(nth_kday);
+#endif
+
+ rb_scan_args(argc, argv, "09", &vy, &vm, &vn, &vk,
+ &vh, &vmin, &vs, &vof, &vsg);
+
+ if (!((NIL_P(vy) || FIXNUM_P(vy)) &&
+ (NIL_P(vm) || FIXNUM_P(vm)) &&
+ (NIL_P(vn) || FIXNUM_P(vn)) &&
+ (NIL_P(vk) || FIXNUM_P(vk)) &&
+ (NIL_P(vh) || FIXNUM_P(vh)) &&
+ (NIL_P(vmin) || FIXNUM_P(vmin)) &&
+ (NIL_P(vs) || FIXNUM_P(vs))))
+ return c_cforwardv(nth_kday);
+
+ y = -4712;
+ m = 1;
+ n = 1;
+ k = 1;
+
+ h = min = s = 0;
+ rof = 0;
+ sg = ITALY;
+
+ switch (argc) {
+ case 9:
+ sg = NUM2DBL(vsg);
+ case 8:
+ vof = sof2nof(vof);
+ if (!daydiff_to_sec(vof, &rof))
+ return c_cforwardv(nth_kday);
+ case 7:
+ s = NUM2INT(vs);
+ case 6:
+ min = NUM2INT(vmin);
+ case 5:
+ h = NUM2INT(vh);
+ case 4:
+ k = NUM2INT(vk);
+ case 3:
+ n = NUM2INT(vn);
+ case 2:
+ m = NUM2INT(vm);
+ case 1:
+ y = NUM2INT(vy);
+ if (!LIGHTABLE_YEAR(y))
+ return c_cforwardv(nth_kday);
+ }
+
+ {
+ long jd;
+ int ns;
+
+ if (!valid_nth_kday_p(y, m, n, k, sg, &rm, &rn, &rk, &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 c_cforwardv(nth_kday);
+
+ return dt_lite_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,
+ HAVE_JD | HAVE_TIME);
+ }
+}
+#endif
+
/*
* call-seq:
* DateTime.now([start=Date::ITALY])
@@ -3252,15 +6862,15 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass)
#endif
time_t sec;
struct tm tm;
- long sf;
- int y, m, d, h, min, s, of;
+ long sf, of;
+ int y, m, d, h, min, s;
rb_scan_args(argc, argv, "01", &vsg);
- if (!NIL_P(vsg))
- sg = NUM2DBL(vsg);
- else
+ if (argc < 1)
sg = ITALY;
+ else
+ sg = NUM2DBL(vsg);
#ifdef HAVE_CLOCK_GETTIME
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
@@ -3282,9 +6892,9 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass)
if (s == 60)
s = 59;
#ifdef HAVE_STRUCT_TM_TM_GMTOFF
- of = (int)tm.tm_gmtoff;
+ of = tm.tm_gmtoff;
#else
- of = (int)-timezone;
+ of = -timezone;
#endif
#ifdef HAVE_CLOCK_GETTIME
sf = ts.tv_nsec;
@@ -3292,28 +6902,67 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass)
sf = tv.tv_usec * 1000;
#endif
+#ifdef FORCE_RIGHT
+ goto right;
+#endif
+
if (!LIGHTABLE_YEAR(y))
- rb_raise(rb_eArgError, "cannot create");
+ goto right;
+
+ if (of < -DAY_IN_SECONDS || of > DAY_IN_SECONDS)
+ goto right;
if (isinf(sg) && sg < 0)
- return dt_lite_s_new_internal(klass, 0, 0, sf, of, sg,
- y, m, d, h, min, s,
- LIGHT_MODE | HAVE_CIVIL | HAVE_TIME);
+ return dt_lite_new_internal(klass, 0, 0, sf, (int)of, sg,
+ y, m, d, h, min, s,
+ HAVE_CIVIL | HAVE_TIME);
else {
long jd;
int ns;
civil_to_jd(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,
- y, m, d, h, min, s,
- LIGHT_MODE | HAVE_JD |
- HAVE_CIVIL | HAVE_TIME);
+ return dt_lite_new_internal(klass,
+ jd_local_to_utc(jd,
+ time_to_df(h, min, s),
+ of),
+ 0, sf, of, sg,
+ y, m, d, h, min, s,
+ HAVE_JD | HAVE_CIVIL | HAVE_TIME);
}
+ right:
+ {
+ VALUE jd, fr, vof, ajd;
+
+ jd = rt_civil_to_jd(INT2FIX(y), INT2FIX(m), INT2FIX(d), DBL2NUM(sg));
+ fr = rt_time_to_day_fraction(INT2FIX(h), INT2FIX(min), INT2FIX(s));
+ fr = f_add(fr, rb_rational_new(LONG2NUM(sf), day_in_nanoseconds));
+ vof = rb_rational_new(LONG2NUM(of), INT2FIX(DAY_IN_SECONDS));
+ ajd = rt_jd_to_ajd(jd, fr, vof);
+ return dt_right_new(klass, ajd, vof, DBL2NUM(sg));
+ }
+}
+
+static VALUE
+dt_switch_new_by_frags(VALUE klass, VALUE hash, VALUE sg)
+{
+ VALUE jd, fr, of, t;
+
+ hash = rt_rewrite_frags(hash);
+ hash = rt_complete_frags(klass, hash);
+ jd = rt__valid_date_frags_p(hash, sg);
+ fr = rt__valid_time_frags_p(hash);
+ if (NIL_P(jd) || NIL_P(fr))
+ rb_raise(rb_eArgError, "invalid date");
+ t = ref_hash("sec_fraction");
+ if (!NIL_P(t))
+ fr = f_add(fr, f_div(t, INT2FIX(DAY_IN_SECONDS)));
+ t = ref_hash("offset");
+ if (NIL_P(t))
+ of = INT2FIX(0);
+ else
+ of = rb_rational_new2(t, INT2FIX(DAY_IN_SECONDS));
+ return dt_switch_new_jd(klass, jd, fr, of, sg);
}
/*
@@ -3330,6 +6979,272 @@ datetime_s__strptime(int argc, VALUE *argv, VALUE klass)
/*
* call-seq:
+ * DateTime.strptime([string="-4712-01-01T00:00:00+00:00"[, format="%FT%T%z"[,start=ITALY]]])
+ *
+ * Create a new DateTime object by parsing from a String
+ * according to a specified format.
+ *
+ * +str+ is a String holding a date-time representation.
+ * +fmt+ is the format that the date-time is in. See
+ * date/format.rb for details on supported formats.
+ *
+ * The default +str+ is '-4712-01-01T00:00:00+00:00', and the default
+ * +fmt+ is '%FT%T%z'. This gives midnight on Julian Day Number day 0.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ *
+ * An ArgumentError will be raised if +str+ cannot be
+ * parsed.
+ */
+static VALUE
+datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, fmt, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &fmt, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ fmt = rb_str_new2("%FT%T%z");
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE argv2[2], hash;
+
+ argv2[0] = str;
+ argv2[1] = fmt;
+ hash = date_s__strptime(2, argv2, klass);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * Date.parse(string="-4712-01-01T00:00:00+00:00"[, comp=true[,start=ITALY]])
+ *
+ * Create a new DateTime object by parsing from a String,
+ * without specifying the format.
+ *
+ * +str+ is a String holding a date-time representation.
+ * +comp+ specifies whether to interpret 2-digit years
+ * as 19XX (>= 69) or 20XX (< 69); the default is to.
+ * The method will attempt to parse a date-time from the String
+ * using various heuristics; see #_parse in date/format.rb
+ * for more details. If parsing fails, an ArgumentError
+ * will be raised.
+ *
+ * The default +str+ is '-4712-01-01T00:00:00+00:00'; this is Julian
+ * Day Number day 0.
+ *
+ * +sg+ specifies the Day of Calendar Reform.
+ */
+static VALUE
+datetime_s_parse(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE argv2[2], hash;
+
+ argv2[0] = str;
+ argv2[1] = comp;
+ hash = date_s__parse(2, argv2, klass);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.iso8601(string="-4712-01-01T00:00:00+00:00"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical ISO 8601 format.
+ */
+static VALUE
+datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__iso8601(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.rfc3339(string="-4712-01-01T00:00:00+00:00"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical RFC 3339 format.
+ */
+static VALUE
+datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__rfc3339(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.xmlschema(string="-4712-01-01T00:00:00+00:00"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical XML Schema format.
+ */
+static VALUE
+datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__xmlschema(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.rfc2822(string="Mon, 1 Jan -4712 00:00:00 +0000"[,start=ITALY])
+ * DateTime.rfc822(string="Mon, 1 Jan -4712 00:00:00 +0000"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical RFC 2822 format.
+ */
+static VALUE
+datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__rfc2822(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.httpdate(string="Mon, 01 Jan -4712 00:00:00 GMT"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some RFC 2616 format.
+ */
+static VALUE
+datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__httpdate(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
+ * DateTime.jisx0301(string="-4712-01-01T00:00:00+00:00"[,start=ITALY])
+ *
+ * Create a new Date object by parsing from a String
+ * according to some typical JIS X 0301 format.
+ */
+static VALUE
+datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
+{
+ VALUE str, comp, sg;
+
+ rb_scan_args(argc, argv, "03", &str, &comp, &sg);
+
+ switch (argc) {
+ case 0:
+ str = rb_str_new2("-4712-01-01T00:00:00+00:00");
+ case 1:
+ comp = Qtrue;
+ case 2:
+ sg = INT2FIX(ITALY);
+ }
+
+ {
+ VALUE hash = date_s__jisx0301(klass, str);
+ return dt_switch_new_by_frags(klass, hash, sg);
+ }
+}
+
+/*
+ * call-seq:
* dt.ajd
*
* Get the date as an Astronomical Julian Day Number.
@@ -3356,6 +7271,21 @@ dt_lite_ajd(VALUE self)
}
}
+#undef c_iforward0
+#undef c_iforwardv
+#undef c_iforwardop
+#define c_iforward0(m) dt_right_##m(self)
+#define c_iforwardv(m) dt_right_##m(argc, argv, self)
+#define c_iforwardop(m) dt_right_##m(self, other)
+
+static VALUE
+dt_right_amjd(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return rt_ajd_to_amjd(dat->r.ajd);
+}
+
/*
* call-seq:
* dt.amjd
@@ -3367,7 +7297,7 @@ dt_lite_amjd(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("amjd_r");
+ return c_iforward0(amjd);
{
VALUE r;
@@ -3384,6 +7314,34 @@ dt_lite_amjd(VALUE self)
}
}
+#undef return_once
+#define return_once(k, expr)\
+{\
+ VALUE id, val;\
+ get_dt1(self);\
+ id = ID2SYM(rb_intern(#k));\
+ val = rb_hash_aref(dat->r.cache, id);\
+ if (!NIL_P(val))\
+ return val;\
+ val = expr;\
+ rb_hash_aset(dat->r.cache, id, val);\
+ return val;\
+}
+
+static VALUE
+dt_right_daynum(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(daynum, rt_ajd_to_jd(dat->r.ajd, dat->r.of));
+}
+
+static VALUE
+dt_right_jd(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(daynum))[0];
+}
+
/*
* call-seq:
* dt.jd
@@ -3395,7 +7353,7 @@ dt_lite_jd(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("jd_r");
+ return c_iforward0(jd);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3403,6 +7361,14 @@ dt_lite_jd(VALUE self)
}
}
+static VALUE
+dt_right_mjd(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return rt_jd_to_mjd(dt_right_jd(self));
+}
+
/*
* call-seq:
* dt.mjd
@@ -3414,7 +7380,7 @@ dt_lite_mjd(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("mjd_r");
+ return c_iforward0(mjd);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3422,6 +7388,14 @@ dt_lite_mjd(VALUE self)
}
}
+static VALUE
+dt_right_ld(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return rt_jd_to_ld(dt_right_jd(self));
+}
+
/*
* call-seq:
* dt.ld
@@ -3433,7 +7407,7 @@ dt_lite_ld(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("ld_r");
+ return c_iforward0(ld);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3441,6 +7415,20 @@ dt_lite_ld(VALUE self)
}
}
+static VALUE
+dt_right_civil(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(civil, rt_jd_to_civil(dt_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+dt_right_year(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[0];
+}
+
/*
* call-seq:
* dt.year
@@ -3452,13 +7440,27 @@ dt_lite_year(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("year_r");
+ return c_iforward0(year);
{
get_dt_civil(dat);
return INT2FIX(dat->l.year);
}
}
+static VALUE
+dt_right_ordinal(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(ordinal, rt_jd_to_ordinal(dt_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+dt_right_yday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(ordinal))[1];
+}
+
/*
* call-seq:
* dt.yday
@@ -3472,13 +7474,19 @@ dt_lite_yday(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("yday_r");
+ return c_iforward0(yday);
{
get_dt_civil(dat);
return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
+static VALUE
+dt_right_mon(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[1];
+}
+
/*
* call-seq:
* dt.mon
@@ -3492,13 +7500,19 @@ dt_lite_mon(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("mon_r");
+ return c_iforward0(mon);
{
get_dt_civil(dat);
return INT2FIX(dat->l.mon);
}
}
+static VALUE
+dt_right_mday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(civil))[2];
+}
+
/*
* call-seq:
* dt.mday
@@ -3510,13 +7524,19 @@ dt_lite_mday(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("mday_r");
+ return c_iforward0(mday);
{
get_dt_civil(dat);
return INT2FIX(dat->l.mday);
}
}
+static VALUE
+dt_right_day_fraction(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(daynum))[1];
+}
+
/*
* call-seq:
* dt.day_fraction
@@ -3528,7 +7548,7 @@ dt_lite_day_fraction(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("day_fraction_r");
+ return c_iforward0(day_fraction);
{
get_dt_df(dat);
return rb_rational_new2(INT2FIX(local_df(dat)),
@@ -3537,13 +7557,28 @@ dt_lite_day_fraction(VALUE self)
}
static VALUE
+dt_right_weeknum0(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(weeknum0, rt_jd_to_weeknum(dt_right_jd(self),
+ INT2FIX(0), dat->r.sg));
+}
+
+static VALUE
+dt_right_wnum0(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(weeknum0))[1];
+}
+
+static VALUE
dt_lite_wnum0(VALUE self)
{
int ry, rw, rd;
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("wnum0_r");
+ return c_iforward0(wnum0);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3553,13 +7588,28 @@ dt_lite_wnum0(VALUE self)
}
static VALUE
+dt_right_weeknum1(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(weeknum1, rt_jd_to_weeknum(dt_right_jd(self),
+ INT2FIX(1), dat->r.sg));
+}
+
+static VALUE
+dt_right_wnum1(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(weeknum1))[1];
+}
+
+static VALUE
dt_lite_wnum1(VALUE self)
{
int ry, rw, rd;
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("wnum1_r");
+ return c_iforward0(wnum1);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3568,6 +7618,45 @@ dt_lite_wnum1(VALUE self)
}
}
+#ifndef NDEBUG
+static VALUE
+dt_right_time(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(time, rt_day_fraction_to_time(dt_right_day_fraction(self)));
+}
+#endif
+
+static VALUE
+dt_right_time_wo_sf(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(time_wo_sf,
+ rt_day_fraction_to_time_wo_sf(dt_right_day_fraction(self)));
+}
+
+static VALUE
+dt_right_time_sf(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(time_sf, f_mul(f_mod(dt_right_day_fraction(self),
+ SECONDS_IN_DAY),
+ INT2FIX(DAY_IN_SECONDS)));
+}
+
+static VALUE
+dt_right_hour(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[0];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[0];
+#endif
+}
+
/*
* call-seq:
* dt.hour
@@ -3579,13 +7668,23 @@ dt_lite_hour(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("hour_r");
+ return c_iforward0(hour);
{
get_dt_time(dat);
return INT2FIX(dat->l.hour);
}
}
+static VALUE
+dt_right_min(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[1];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[1];
+#endif
+}
+
/*
* call-seq:
* dt.min
@@ -3598,13 +7697,23 @@ dt_lite_min(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("min_r");
+ return c_iforward0(min);
{
get_dt_time(dat);
return INT2FIX(dat->l.min);
}
}
+static VALUE
+dt_right_sec(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[2];
+#else
+ return RARRAY_PTR(c_iforward0(time_wo_sf))[2];
+#endif
+}
+
/*
* call-seq:
* dt.sec
@@ -3617,13 +7726,23 @@ dt_lite_sec(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("sec_r");
+ return c_iforward0(sec);
{
get_dt_time(dat);
return INT2FIX(dat->l.sec);
}
}
+static VALUE
+dt_right_sec_fraction(VALUE self)
+{
+#if 0
+ return RARRAY_PTR(c_iforward0(time))[3];
+#else
+ return c_iforward0(time_sf);
+#endif
+}
+
/*
* call-seq:
* dt.sec_fraction
@@ -3636,7 +7755,7 @@ dt_lite_sec_fraction(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("sec_fraction_r");
+ return c_iforward0(sec_fraction);
return rb_rational_new2(INT2FIX(dat->l.sf), INT2FIX(SECOND_IN_NANOSECONDS));
}
@@ -3660,8 +7779,38 @@ dt_lite_offset(VALUE self)
int a;\
s = (of < 0) ? '-' : '+';\
a = (of < 0) ? -of : of;\
- h = a / 3600;\
- m = a % 3600 / 60;\
+ h = a / HOUR_IN_SECONDS;\
+ m = a % HOUR_IN_SECONDS / MINUTE_IN_SECONDS;\
+}
+
+static VALUE
+dt_right_zone(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ {
+ int sign;
+ VALUE hh, mm, ss, fr;
+
+ if (f_negative_p(dat->r.of)) {
+ sign = '-';
+ fr = f_abs(dat->r.of);
+ }
+ else {
+ sign = '+';
+ fr = dat->r.of;
+ }
+ ss = f_div(fr, SECONDS_IN_DAY);
+
+ hh = f_idiv(ss, INT2FIX(HOUR_IN_SECONDS));
+ ss = f_mod(ss, INT2FIX(HOUR_IN_SECONDS));
+
+ mm = f_idiv(ss, INT2FIX(MINUTE_IN_SECONDS));
+
+ return rb_enc_sprintf(rb_usascii_encoding(),
+ "%c%02d:%02d",
+ sign, NUM2INT(hh), NUM2INT(mm));
+ }
}
/*
@@ -3677,11 +7826,25 @@ dt_lite_zone(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("zone_r");
+ return c_iforward0(zone);
decode_offset(dat->l.of, s, h, m);
return rb_enc_sprintf(rb_usascii_encoding(), "%c%02d:%02d", s, h, m);
}
+static VALUE
+dt_right_commercial(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return_once(commercial, rt_jd_to_commercial(dt_right_jd(self), dat->r.sg));
+}
+
+static VALUE
+dt_right_cwyear(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[0];
+}
+
/*
* call-seq:
* dt.cwyear
@@ -3696,7 +7859,7 @@ dt_lite_cwyear(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("cwyear_r");
+ return c_iforward0(cwyear);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3705,6 +7868,12 @@ dt_lite_cwyear(VALUE self)
}
}
+static VALUE
+dt_right_cweek(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[1];
+}
+
/*
* call-seq:
* dt.cweek
@@ -3718,7 +7887,7 @@ dt_lite_cweek(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("cweek_r");
+ return c_iforward0(cweek);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3727,6 +7896,12 @@ dt_lite_cweek(VALUE self)
}
}
+static VALUE
+dt_right_cwday(VALUE self)
+{
+ return RARRAY_PTR(c_iforward0(commercial))[2];
+}
+
/*
* call-seq:
* dt.cwday
@@ -3741,7 +7916,7 @@ dt_lite_cwday(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("cwday_r");
+ return c_iforward0(cwday);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3752,6 +7927,12 @@ dt_lite_cwday(VALUE self)
}
}
+static VALUE
+dt_right_wday(VALUE self)
+{
+ return rt_jd_to_wday(dt_right_jd(self));
+}
+
/*
* call-seq:
* dt.wday
@@ -3766,7 +7947,7 @@ dt_lite_wday(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("wday_r");
+ return c_iforward0(wday);
{
get_dt_jd(dat);
get_dt_df(dat);
@@ -3777,6 +7958,98 @@ dt_lite_wday(VALUE self)
/*
* call-seq:
+ * dt.monday?
+ *
+ * Is the current date Monday?
+ */
+static VALUE
+dt_lite_sunday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(0));
+}
+
+/*
+ * call-seq:
+ * dt.monday?
+ *
+ * Is the current date Monday?
+ */
+static VALUE
+dt_lite_monday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(1));
+}
+
+/*
+ * call-seq:
+ * dt.tuesday?
+ *
+ * Is the current date Tuesday?
+ */
+static VALUE
+dt_lite_tuesday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(2));
+}
+
+/*
+ * call-seq:
+ * dt.wednesday?
+ *
+ * Is the current date Wednesday?
+ */
+static VALUE
+dt_lite_wednesday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(3));
+}
+
+/*
+ * call-seq:
+ * dt.thursday?
+ *
+ * Is the current date Thursday?
+ */
+static VALUE
+dt_lite_thursday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(4));
+}
+
+/*
+ * call-seq:
+ * dt.friday?
+ *
+ * Is the current date Friday?
+ */
+static VALUE
+dt_lite_friday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(5));
+}
+
+/*
+ * call-seq:
+ * dt.saturday?
+ *
+ * Is the current date Saturday?
+ */
+static VALUE
+dt_lite_saturday_p(VALUE self)
+{
+ return f_eqeq_p(dt_lite_wday(self), INT2FIX(6));
+}
+
+static VALUE
+dt_right_julian_p(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return f_lt_p(dt_right_jd(self), dat->r.sg);
+}
+
+/*
+ * call-seq:
* dt.julian?
*
* Is the current date old-style (Julian Calendar)?
@@ -3786,10 +8059,18 @@ dt_lite_julian_p(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("julian_r?");
+ return c_iforward0(julian_p);
return Qfalse;
}
+static VALUE
+dt_right_gregorian_p(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return dt_right_julian_p(self) ? Qfalse : Qtrue;
+}
+
/*
* call-seq:
* dt.gregorian?
@@ -3801,10 +8082,33 @@ dt_lite_gregorian_p(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("gregorian_r?");
+ return c_iforward0(gregorian_p);
return Qtrue;
}
+static VALUE
+dt_right_fix_style(VALUE self)
+{
+ if (dt_right_julian_p(self))
+ return DBL2NUM(JULIAN);
+ return DBL2NUM(GREGORIAN);
+}
+
+static VALUE
+dt_right_leap_p(VALUE self)
+{
+ VALUE style, a;
+
+ style = dt_right_fix_style(self);
+ a = rt_jd_to_civil(f_sub(rt_civil_to_jd(dt_right_year(self),
+ INT2FIX(3), INT2FIX(1), style),
+ INT2FIX(1)),
+ style);
+ if (f_eqeq_p(RARRAY_PTR(a)[2], INT2FIX(29)))
+ return Qtrue;
+ return Qfalse;
+}
+
/*
* call-seq:
* dt.leap?
@@ -3816,7 +8120,7 @@ dt_lite_leap_p(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("leap_r?");
+ return c_iforward0(leap_p);
{
get_dt_civil(dat);
return leap_p(dat->l.year) ? Qtrue : Qfalse;
@@ -3838,6 +8142,16 @@ dt_lite_start(VALUE self)
return DBL2NUM(dat->l.sg);
}
+static VALUE
+dt_right_new_start(int argc, VALUE *argv, VALUE self)
+{
+ get_dt1(self);
+ return dt_right_new(CLASS_OF(self),
+ dt_lite_ajd(self),
+ dt_lite_offset(self),
+ (argc >= 1) ? argv[0] : INT2FIX(ITALY));
+}
+
/*
* call-seq:
* dt.new_start([start=Date::ITALY])
@@ -3853,34 +8167,103 @@ dt_lite_new_start(int argc, VALUE *argv, VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforwardv("new_start_r");
+ return c_iforwardv(new_start);
rb_scan_args(argc, argv, "01", &vsg);
- if (!NIL_P(vsg))
+ sg = ITALY;
+ if (argc >= 1)
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);
+ return c_iforwardv(new_start);
+
+ return dt_lite_new_internal_wo_civil(CLASS_OF(self),
+ dat->l.jd,
+ dat->l.df,
+ dat->l.sf,
+ dat->l.of,
+ sg,
+ HAVE_JD | HAVE_DF);
}
}
/*
* call-seq:
+ * dt.italy
+ *
+ * Create a copy of this Date object that uses the Italian/Catholic
+ * Day of Calendar Reform.
+ */
+static VALUE
+dt_lite_italy(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = INT2FIX(ITALY);
+ return dt_lite_new_start(1, argv, self);
+}
+
+/*
+ * call-seq:
+ * dt.england
+ *
+ * Create a copy of this Date object that uses the English/Colonial
+ * Day of Calendar Reform.
+ */
+static VALUE
+dt_lite_england(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = INT2FIX(ENGLAND);
+ return dt_lite_new_start(1, argv, self);
+}
+
+/*
+ * call-seq:
+ * dt.julian
+ *
+ * Create a copy of this Date object that always uses the Julian
+ * Calendar.
+ */
+static VALUE
+dt_lite_julian(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = DBL2NUM(JULIAN);
+ return dt_lite_new_start(1, argv, self);
+}
+
+/*
+ * call-seq:
+ * dt.gregorian
+ *
+ * Create a copy of this Date object that always uses the Gregorian
+ * Calendar.
+ */
+static VALUE
+dt_lite_gregorian(VALUE self)
+{
+ VALUE argv[1];
+ argv[0] = DBL2NUM(GREGORIAN);
+ return dt_lite_new_start(1, argv, self);
+}
+
+static VALUE
+dt_right_new_offset(int argc, VALUE *argv, VALUE self)
+{
+ get_dt1(self);
+ return dt_right_new(CLASS_OF(self),
+ dt_lite_ajd(self),
+ (argc >= 1) ? sof2nof(argv[0]) : INT2FIX(0),
+ dt_lite_start(self));
+}
+
+/*
+ * call-seq:
* dt.new_offset([offset=0])
*
* Create a copy of this Date object using a new offset.
@@ -3894,31 +8277,48 @@ dt_lite_new_offset(int argc, VALUE *argv, VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforwardv("new_offset_r");
+ return c_iforwardv(new_offset);
rb_scan_args(argc, argv, "01", &vof);
if (NIL_P(vof))
rof = 0;
else {
+ vof = sof2nof(vof);
if (!daydiff_to_sec(vof, &rof))
- return iforwardv("new_offset_r");
+ return c_iforwardv(new_offset);
}
{
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);
+ return dt_lite_new_internal_wo_civil(CLASS_OF(self),
+ dat->l.jd,
+ dat->l.df,
+ dat->l.sf,
+ rof,
+ dat->l.sg,
+ HAVE_JD | HAVE_DF);
}
}
+static VALUE
+dt_right_plus(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_dt1(self);
+ if (TYPE(other) == T_FLOAT)
+ other = rb_rational_new2(f_round(f_mul(other, day_in_nanoseconds)),
+ day_in_nanoseconds);
+ return dt_right_new(CLASS_OF(self),
+ f_add(dt_lite_ajd(self), other),
+ dt_lite_offset(self),
+ dt_lite_start(self));
+ }
+ rb_raise(rb_eTypeError, "expected numeric");
+}
+
/*
* call-seq:
* dt + n
@@ -3939,7 +8339,7 @@ dt_lite_plus(VALUE self, VALUE other)
get_dt1(self);
if (!light_mode_p(dat))
- return iforwardop("plus_r");
+ return c_iforwardop(plus);
switch (TYPE(other)) {
case T_FIXNUM:
@@ -3953,17 +8353,18 @@ dt_lite_plus(VALUE self, VALUE other)
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);
+ return dt_lite_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_JD) &
+ ~HAVE_CIVIL);
}
break;
case T_FLOAT:
@@ -4022,23 +8423,43 @@ dt_lite_plus(VALUE self, VALUE other)
jd = dat->l.jd + jd;
if (LIGHTABLE_JD(jd) && jd >= dat->l.sg)
- return dt_lite_s_new_internal(CLASS_OF(self),
- (long)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);
+ return dt_lite_new_internal(CLASS_OF(self),
+ (long)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_JD | HAVE_DF) &
+ ~HAVE_CIVIL &
+ ~HAVE_TIME);
}
break;
}
- return iforwardop("plus_r");
+ return c_iforwardop(plus);
+}
+
+static VALUE
+dt_right_minus(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_dt1(self);
+ if (TYPE(other) == T_FLOAT)
+ other = rb_rational_new2(f_round(f_mul(other, day_in_nanoseconds)),
+ day_in_nanoseconds);
+ return dt_right_new(CLASS_OF(self),
+ f_sub(dt_lite_ajd(self), other),
+ dt_lite_offset(self),
+ dt_lite_start(self));
+ }
+ else if (k_date_p(other)) {
+ return f_sub(dt_lite_ajd(self), f_ajd(other));
+ }
+ rb_raise(rb_eTypeError, "expected numeric");
}
/*
@@ -4067,9 +8488,185 @@ dt_lite_minus(VALUE self, VALUE other)
case T_FLOAT:
return dt_lite_plus(self, DBL2NUM(-NUM2DBL(other)));
}
- return iforwardop("minus_r");
+ return c_iforwardop(minus);
+}
+
+/*
+ * call-seq:
+ * dt.next_day([n=1])
+ *
+ * Equivalent to dt + n.
+ */
+static VALUE
+dt_lite_next_day(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_plus(self, n);
+}
+
+/*
+ * call-seq:
+ * dt.prev_day([n=1])
+ *
+ * Equivalent to dt - n.
+ */
+static VALUE
+dt_lite_prev_day(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_minus(self, n);
+}
+
+/*
+ * call-seq:
+ * dt.next
+ *
+ * Return a new Date one day after this one.
+ */
+static VALUE
+dt_lite_next(VALUE self)
+{
+ return dt_lite_next_day(0, (VALUE *)NULL, self);
+}
+
+/*
+ * call-seq:
+ * dt >> n
+ *
+ * Return a new Date object that is +n+ months later than
+ * the current one.
+ *
+ * If the day-of-the-month of the current Date is greater
+ * than the last day of the target month, the day-of-the-month
+ * of the returned Date will be the last day of the target month.
+ */
+static VALUE
+dt_lite_rshift(VALUE self, VALUE other)
+{
+ VALUE t, y, m, d, sg, j;
+
+ t = f_add3(f_mul(dt_lite_year(self), INT2FIX(12)),
+ f_sub(dt_lite_mon(self), INT2FIX(1)),
+ other);
+ y = f_idiv(t, INT2FIX(12));
+ m = f_mod(t, INT2FIX(12));
+ m = f_add(m, INT2FIX(1));
+ d = dt_lite_mday(self);
+ sg = dt_lite_start(self);
+
+ while (NIL_P(j = rt__valid_civil_p(y, m, d, sg))) {
+ d = f_sub(d, INT2FIX(1));
+ if (f_lt_p(d, INT2FIX(1)))
+ rb_raise(rb_eArgError, "invalid date");
+ }
+ return f_add(self, f_sub(j, dt_lite_jd(self)));
+}
+
+/*
+ * call-seq:
+ * dt << n
+ *
+ * Return a new Date object that is +n+ months earlier than
+ * the current one.
+ *
+ * If the day-of-the-month of the current Date is greater
+ * than the last day of the target month, the day-of-the-month
+ * of the returned Date will be the last day of the target month.
+ */
+static VALUE
+dt_lite_lshift(VALUE self, VALUE other)
+{
+ return dt_lite_rshift(self, f_negate(other));
+}
+
+/*
+ * call-seq:
+ * dt.next_month([n=1])
+ *
+ * Equivalent to dt >> n
+ */
+static VALUE
+dt_lite_next_month(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_rshift(self, n);
+}
+
+/*
+ * call-seq:
+ * dt.prev_month([n=1])
+ *
+ * Equivalent to dt << n
+ */
+static VALUE
+dt_lite_prev_month(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_lshift(self, n);
+}
+
+/*
+ * call-seq:
+ * dt.next_year([n=1])
+ *
+ * Equivalent to dt >> (n * 12)
+ */
+static VALUE
+dt_lite_next_year(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_rshift(self, f_mul(n, INT2FIX(12)));
+}
+
+/*
+ * call-seq:
+ * dt.prev_year([n=1])
+ *
+ * Equivalent to dt << (n * 12)
+ */
+static VALUE
+dt_lite_prev_year(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+ if (argc < 1)
+ n = INT2FIX(1);
+ return dt_lite_lshift(self, f_mul(n, INT2FIX(12)));
}
+static VALUE
+dt_right_cmp(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_dt1(self);
+ return f_cmp(dt_lite_ajd(self), other);
+ }
+ else if (k_date_p(other)) {
+ return f_cmp(dt_lite_ajd(self), f_ajd(other));
+ }
+ return rb_num_coerce_cmp(self, other, rb_intern("<=>"));
+}
/*
* call-seq:
* dt <=> n
@@ -4092,7 +8689,20 @@ dt_lite_cmp(VALUE self, VALUE other)
{
if (k_date_p(other))
return cmp_dd(self, other);
- return iforwardop("cmp_r");
+ return c_iforwardop(cmp);
+}
+
+static VALUE
+dt_right_equal(VALUE self, VALUE other)
+{
+ if (k_numeric_p(other)) {
+ get_dt1(self);
+ return f_eqeq_p(dt_lite_jd(self), other);
+ }
+ else if (k_date_p(other)) {
+ return f_eqeq_p(dt_lite_jd(self), f_jd(other));
+ }
+ return rb_num_coerce_cmp(self, other, rb_intern("=="));
}
/*
@@ -4111,7 +8721,15 @@ dt_lite_equal(VALUE self, VALUE other)
{
if (k_date_p(other))
return equal_dd(self, other);
- return iforwardop("equal_r");
+ return c_iforwardop(equal);
+}
+
+static VALUE
+dt_right_eql_p(VALUE self, VALUE other)
+{
+ if (k_date_p(other) && f_eqeq_p(self, other))
+ return Qtrue;
+ return Qfalse;
}
/*
@@ -4127,7 +8745,15 @@ dt_lite_eql_p(VALUE self, VALUE other)
{
if (k_date_p(other))
return eql_p_dd(self, other);
- return iforwardop("eql_r?");
+ return c_iforwardop(eql_p);
+}
+
+static VALUE
+dt_right_hash(VALUE self)
+{
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+ return rb_hash(dat->r.ajd);
}
/*
@@ -4141,10 +8767,32 @@ dt_lite_hash(VALUE self)
{
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("hash_r");
+ return c_iforward0(hash);
return rb_hash(dt_lite_ajd(self));
}
+static VALUE
+dt_right_to_s(VALUE self)
+{
+ VALUE a, b, c, argv[8];
+
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+
+ argv[0] = rb_usascii_str_new2("%.4d-%02d-%02dT%02d:%02d:%02d%s");
+ a = dt_right_civil(self);
+ b = dt_right_time_wo_sf(self);
+ c = dt_right_zone(self);
+ argv[1] = RARRAY_PTR(a)[0];
+ argv[2] = RARRAY_PTR(a)[1];
+ argv[3] = RARRAY_PTR(a)[2];
+ argv[4] = RARRAY_PTR(b)[0];
+ argv[5] = RARRAY_PTR(b)[1];
+ argv[6] = RARRAY_PTR(b)[2];
+ argv[7] = c;
+ return rb_f_sprintf(8, argv);
+}
+
/*
* call-seq:
* dt.to_s
@@ -4158,7 +8806,7 @@ dt_lite_to_s(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("to_s_r");
+ return c_iforward0(to_s);
{
get_dt_civil(dat);
get_dt_time(dat);
@@ -4171,6 +8819,23 @@ dt_lite_to_s(VALUE self)
}
}
+static VALUE
+dt_right_inspect(VALUE self)
+{
+ VALUE argv[6];
+
+ get_dt1(self);
+ assert(!light_mode_p(dat));
+
+ argv[0] = rb_usascii_str_new2("#<%s[R]: %s (%s,%s,%s)>");
+ argv[1] = rb_class_name(CLASS_OF(self));
+ argv[2] = dt_right_to_s(self);
+ argv[3] = dat->r.ajd;
+ argv[4] = dat->r.of;
+ argv[5] = dat->r.sg;
+ return rb_f_sprintf(6, argv);
+}
+
/*
* call-seq:
* dt.inspect
@@ -4184,7 +8849,7 @@ dt_lite_inspect(VALUE self)
get_dt1(self);
if (!light_mode_p(dat))
- return iforward0("inspect_r");
+ return c_iforward0(inspect);
{
get_dt_civil(dat);
get_dt_time(dat);
@@ -4210,20 +8875,18 @@ dt_lite_set_tmx(VALUE self, struct tmx *tmx)
get_dt1(self);
if (!light_mode_p(dat)) {
- tmx->year = iforward0("year_r");
- tmx->yday = FIX2INT(iforward0("yday_r"));
- tmx->mon = FIX2INT(iforward0("mon_r"));
- tmx->mday = FIX2INT(iforward0("mday_r"));
- tmx->hour = FIX2INT(iforward0("hour_r"));
- tmx->min = FIX2INT(iforward0("min_r"));
- tmx->sec = FIX2INT(iforward0("sec_r"));
- tmx->wday = FIX2INT(iforward0("wday_r"));
- tmx->offset = INT2FIX(0);
- tmx->zone = RSTRING_PTR(iforward0("zone_r"));
- tmx->timev = f_mul(f_sub(dat->r.ajd,
- rb_rational_new2(INT2FIX(4881175),
- INT2FIX(2))),
- INT2FIX(86400));
+ tmx->year = dt_right_year(self);
+ tmx->yday = FIX2INT(dt_right_yday(self));
+ tmx->mon = FIX2INT(dt_right_mon(self));
+ tmx->mday = FIX2INT(dt_right_mday(self));
+ tmx->hour = FIX2INT(dt_right_hour(self));
+ tmx->min = FIX2INT(dt_right_min(self));
+ tmx->sec = FIX2INT(dt_right_sec(self));
+ tmx->wday = FIX2INT(dt_right_wday(self));
+ tmx->offset = f_mul(dat->r.of, INT2FIX(DAY_IN_SECONDS));
+ tmx->zone = RSTRING_PTR(dt_right_zone(self));
+ tmx->timev = f_mul(f_sub(dat->r.ajd, UNIX_EPOCH_IN_AJD),
+ INT2FIX(DAY_IN_SECONDS));
}
else {
get_dt_jd(dat);
@@ -4241,10 +8904,8 @@ dt_lite_set_tmx(VALUE self, struct tmx *tmx)
tmx->wday = jd_to_wday(local_jd(dat));
tmx->offset = INT2FIX(dat->l.of);
tmx->zone = RSTRING_PTR(dt_lite_zone(self));
- tmx->timev = f_mul(f_sub(dt_lite_ajd(self),
- rb_rational_new2(INT2FIX(4881175),
- INT2FIX(2))),
- INT2FIX(86400));
+ tmx->timev = f_mul(f_sub(dt_lite_ajd(self), UNIX_EPOCH_IN_AJD),
+ INT2FIX(DAY_IN_SECONDS));
}
}
@@ -4261,6 +8922,134 @@ dt_lite_strftime(int argc, VALUE *argv, VALUE self)
"%FT%T%:z", dt_lite_set_tmx);
}
+static VALUE
+dt_lite_iso8601_timediv(VALUE self, VALUE n)
+{
+ VALUE f, fmt;
+
+ if (f_lt_p(n, INT2FIX(1)))
+ f = rb_usascii_str_new2("");
+ else {
+ VALUE argv[3];
+
+ argv[0] = rb_usascii_str_new2(".%0*d");
+ argv[1] = n;
+ argv[2] = f_round(f_div(dt_lite_sec_fraction(self),
+ rb_rational_new2(INT2FIX(1),
+ f_expt(INT2FIX(10), n))));
+ f = rb_f_sprintf(3, argv);
+ }
+ fmt = f_add3(rb_usascii_str_new2("T%T"),
+ f,
+ rb_usascii_str_new2("%:z"));
+ return strftimev(RSTRING_PTR(fmt), self, dt_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * dt.asctime
+ * dt.ctime
+ *
+ * Equivalent to strftime('%c').
+ * See also asctime(3) or ctime(3).
+ */
+static VALUE
+dt_lite_asctime(VALUE self)
+{
+ return strftimev("%c", self, dt_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * dt.iso8601([n=0])
+ * dt.xmlschema([n=0])
+ *
+ * Equivalent to strftime('%FT%T').
+ * The optional argument n is length of fractional seconds.
+ */
+static VALUE
+dt_lite_iso8601(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n;
+
+ rb_scan_args(argc, argv, "01", &n);
+
+ if (argc < 1)
+ n = INT2FIX(0);
+
+ return f_add(strftimev("%F", self, dt_lite_set_tmx),
+ dt_lite_iso8601_timediv(self, n));
+}
+
+/*
+ * call-seq:
+ * dt.rfc3339([n=0])
+ *
+ * Equivalent to strftime('%FT%T').
+ * The optional argument n is length of fractional seconds.
+ */
+static VALUE
+dt_lite_rfc3339(int argc, VALUE *argv, VALUE self)
+{
+ return dt_lite_iso8601(argc, argv, self);
+}
+
+/*
+ * call-seq:
+ * dt.rfc2822
+ * dt.rfc822
+ *
+ * Equivalent to strftime('%a, %-d %b %Y %T %z').
+ */
+static VALUE
+dt_lite_rfc2822(VALUE self)
+{
+ return strftimev("%a, %-d %b %Y %T %z", self, dt_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * dt.httpdate
+ *
+ * Equivalent to strftime('%a, %d %b %Y %T GMT').
+ * See also RFC 2616.
+ */
+static VALUE
+dt_lite_httpdate(VALUE self)
+{
+ VALUE argv[1], d;
+
+ argv[0] = INT2FIX(0);
+ d = dt_lite_new_offset(1, argv, self);
+ return strftimev("%a, %d %b %Y %T GMT", d, dt_lite_set_tmx);
+}
+
+/*
+ * call-seq:
+ * dt.jisx0301
+ *
+ * Return a string as a JIS X 0301 format.
+ */
+static VALUE
+dt_lite_jisx0301(int argc, VALUE *argv, VALUE self)
+{
+ VALUE n, argv2[2];
+
+ rb_scan_args(argc, argv, "01", &n);
+
+ if (argc < 1)
+ n = INT2FIX(0);
+
+ if (!gengo(dt_lite_jd(self),
+ dt_lite_year(self),
+ argv2))
+ return f_add(strftimev("%F", self, dt_lite_set_tmx),
+ dt_lite_iso8601_timediv(self, n));
+ return f_add(f_add(rb_f_sprintf(2, argv2),
+ strftimev(".%m.%d", self, dt_lite_set_tmx)),
+ dt_lite_iso8601_timediv(self, n));
+}
+
/*
* call-seq:
* dt.marshal_dump
@@ -4313,12 +9102,12 @@ dt_lite_marshal_load(VALUE self, VALUE a)
dat->r.of = RARRAY_PTR(a)[1];
dat->r.sg = RARRAY_PTR(a)[2];
dat->r.cache = rb_hash_new();
- dat->r.flags = 0;
+ dat->r.flags = DATETIME_OBJ;
break;
case 5:
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.sf = NUM2LONG(RARRAY_PTR(a)[2]);
dat->l.of = FIX2INT(RARRAY_PTR(a)[3]);
dat->l.sg = NUM2DBL(RARRAY_PTR(a)[4]);
dat->l.year = 0;
@@ -4327,7 +9116,7 @@ dt_lite_marshal_load(VALUE self, VALUE a)
dat->l.hour = 0;
dat->l.min = 0;
dat->l.sec = 0;
- dat->l.flags = LIGHT_MODE | HAVE_JD | HAVE_DF;
+ dat->l.flags = LIGHT_MODE | HAVE_JD | HAVE_DF | DATETIME_OBJ;
break;
default:
rb_raise(rb_eTypeError, "invalid size");
@@ -4342,22 +9131,261 @@ dt_lite_marshal_load(VALUE self, VALUE a)
return self;
}
+/* conversions */
+
+#define f_getlocal(x) rb_funcall(x, rb_intern("getlocal"), 0)
+#define f_subsec(x) rb_funcall(x, rb_intern("subsec"), 0)
+#define f_utc_offset(x) rb_funcall(x, rb_intern("utc_offset"), 0)
+#define f_local3(x,y,m,d) rb_funcall(x, rb_intern("local"), 3, y, m, d)
+#define f_utc6(x,y,m,d,h,min,s) rb_funcall(x, rb_intern("utc"), 6, y, m, d, h, min, s)
+
+/*
+ * call-seq:
+ * t.to_time
+ *
+ * Return a copy of self as local mode.
+ */
+static VALUE
+time_to_time(VALUE self)
+{
+ return rb_funcall(self, rb_intern("getlocal"), 0);
+}
+
+/*
+ * call-seq:
+ * t.to_date
+ *
+ * Return a Date object which denotes self.
+ */
+static VALUE
+time_to_date(VALUE self)
+{
+ VALUE jd;
+
+ jd = rt_civil_to_jd(f_year(self), f_mon(self), f_mday(self),
+ INT2FIX(ITALY));
+ return d_switch_new_jd(cDate, jd, INT2FIX(ITALY));
+}
+
+/*
+ * call-seq:
+ * t.to_datetime
+ *
+ * Return a DateTime object which denotes self.
+ */
+static VALUE
+time_to_datetime(VALUE self)
+{
+ VALUE jd, sec, fr, of;
+
+ jd = rt_civil_to_jd(f_year(self), f_mon(self), f_mday(self),
+ INT2FIX(ITALY));
+ sec = f_sec(self);
+ if (f_gt_p(sec, INT2FIX(59)))
+ sec = INT2FIX(59);
+ fr = rt_time_to_day_fraction(f_hour(self), f_min(self), sec);
+ fr = f_add(fr, rb_Rational(f_subsec(self), INT2FIX(DAY_IN_SECONDS)));
+ of = rb_rational_new2(f_utc_offset(self), INT2FIX(DAY_IN_SECONDS));
+ return dt_switch_new_jd(cDateTime, jd, fr, of, INT2FIX(ITALY));
+}
+
+/*
+ * call-seq:
+ * d.to_time
+ *
+ * Return a Time object which denotes self.
+ */
+static VALUE
+date_to_time(VALUE self)
+{
+ return f_local3(rb_cTime,
+ d_lite_year(self),
+ d_lite_mon(self),
+ d_lite_mday(self));
+}
+
+/*
+ * call-seq:
+ * d.to_date
+ *
+ * Return self;
+ */
+static VALUE
+date_to_date(VALUE self)
+{
+ return self;
+}
+
+/*
+ * call-seq:
+ * d.to_datetime
+ *
+ * Return a DateTime object which denotes self.
+ */
+static VALUE
+date_to_datetime(VALUE self)
+{
+ return dt_switch_new_jd(cDateTime,
+ d_lite_jd(self),
+ INT2FIX(0),
+ d_lite_offset(self),
+ d_lite_start(self));
+}
+
+#ifndef NDEBUG
static VALUE
-dt_right_cache(VALUE self)
+date_to_right(VALUE self)
+{
+ get_d1(self);
+ if (!light_mode_p(dat))
+ return self;
+ return d_right_new(CLASS_OF(self),
+ d_lite_ajd(self),
+ d_lite_offset(self),
+ d_lite_start(self));
+}
+
+static VALUE
+date_to_light(VALUE self)
+{
+ get_d1(self);
+ if (light_mode_p(dat))
+ return self;
+ {
+ VALUE t, jd, df;
+
+ t = rt_ajd_to_jd(dat->r.ajd, INT2FIX(0)); /* as utc */
+ jd = RARRAY_PTR(t)[0];
+ df = RARRAY_PTR(t)[1];
+
+ if (!LIGHTABLE_JD(NUM2LONG(jd)))
+ rb_raise(rb_eRangeError, "jd too big to convert into light");
+
+ if (!f_zero_p(df))
+ rb_warning("day fraction is ignored");
+
+ if (!f_zero_p(dat->r.of))
+ rb_warning("nonzero offset is ignored");
+
+ return d_lite_new(CLASS_OF(self), jd, dat->r.sg);
+ }
+}
+#endif
+
+/*
+ * call-seq:
+ * dt.to_time
+ *
+ * Return a Time object which denotes self.
+ */
+static VALUE
+datetime_to_time(VALUE self)
+{
+ VALUE argv[1], d;
+
+ argv[0] = INT2FIX(0);
+ d = dt_lite_new_offset(1, argv, self);
+ d = f_utc6(rb_cTime,
+ dt_lite_year(d),
+ dt_lite_mon(d),
+ dt_lite_mday(d),
+ dt_lite_hour(d),
+ dt_lite_min(d),
+ f_add(dt_lite_sec(d), dt_lite_sec_fraction(d)));
+ return f_getlocal(d);
+}
+
+/*
+ * call-seq:
+ * dt.to_date
+ *
+ * Return a Date object which denotes self.
+ */
+static VALUE
+datetime_to_date(VALUE self)
+{
+ return d_switch_new_jd(cDate,
+ dt_lite_jd(self),
+ dt_lite_start(self));
+}
+
+/*
+ * call-seq:
+ * dt.to_datetime
+ *
+ * Return self.
+ */
+static VALUE
+datetime_to_datetime(VALUE self)
+{
+ return self;
+}
+
+#ifndef NDEBUG
+static VALUE
+datetime_to_right(VALUE self)
+{
+ get_dt1(self);
+ if (!light_mode_p(dat))
+ return self;
+ return dt_right_new(CLASS_OF(self),
+ dt_lite_ajd(self),
+ dt_lite_offset(self),
+ dt_lite_start(self));
+}
+
+static VALUE
+datetime_to_light(VALUE self)
{
get_dt1(self);
if (light_mode_p(dat))
- return Qnil;
- return dat->r.cache;
+ return self;
+ {
+ VALUE t, jd, df, sf, odf;
+
+ t = rt_ajd_to_jd(dat->r.ajd, INT2FIX(0)); /* as utc */
+ jd = RARRAY_PTR(t)[0];
+ df = RARRAY_PTR(t)[1];
+
+ if (!LIGHTABLE_JD(NUM2LONG(jd)))
+ rb_raise(rb_eRangeError, "jd too big to convert into light");
+
+ if (f_lt_p(dat->r.of, INT2FIX(-1)) ||
+ f_gt_p(dat->r.of, INT2FIX(1)))
+ rb_raise(rb_eRangeError, "offset too big to convert into light");
+
+ t = f_mul(df, INT2FIX(DAY_IN_SECONDS));
+ df = f_idiv(t, INT2FIX(1));
+ sf = f_mod(t, INT2FIX(1));
+
+ t = f_mul(sf, INT2FIX(SECOND_IN_NANOSECONDS));
+ sf = f_idiv(t, INT2FIX(1));
+
+ if (f_eqeq_p(t, sf))
+ rb_warning("second fraction is truncated");
+
+ t = f_mul(dat->r.of, INT2FIX(DAY_IN_SECONDS));
+ odf = f_truncate(t);
+
+ if (f_eqeq_p(t, odf))
+ rb_warning("offset is truncated");
+
+ return dt_lite_new(CLASS_OF(self),
+ jd, df, sf, odf, dat->r.sg);
+ }
}
+#endif
#ifndef NDEBUG
+/* tests */
+
static int
test_civil(long from, long to, double sg)
{
long j;
- fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+ fprintf(stderr, "test_civil: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
for (j = from; j <= to; j++) {
int y, m, d, ns;
long rj;
@@ -4397,7 +9425,8 @@ test_ordinal(long from, long to, double sg)
{
long j;
- fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+ fprintf(stderr, "test_ordinal: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
for (j = from; j <= to; j++) {
int y, d, ns;
long rj;
@@ -4437,7 +9466,8 @@ test_commercial(long from, long to, double sg)
{
long j;
- fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+ fprintf(stderr, "test_commercial: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
for (j = from; j <= to; j++) {
int y, w, d, ns;
long rj;
@@ -4477,7 +9507,8 @@ test_weeknum(long from, long to, int f, double sg)
{
long j;
- fprintf(stderr, "%ld...%ld (%ld) - %.0f\n", from, to, to - from, sg);
+ fprintf(stderr, "test_weeknum: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
for (j = from; j <= to; j++) {
int y, w, d, ns;
long rj;
@@ -4516,13 +9547,13 @@ date_s_test_weeknum(VALUE klass)
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);
+ fprintf(stderr, "test_nth_kday: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
for (j = from; j <= to; j++) {
int y, m, n, k, ns;
long rj;
@@ -4557,6 +9588,119 @@ date_s_test_nth_kday(VALUE klass)
return Qtrue;
}
+static int
+print_emesg(VALUE x, VALUE y)
+{
+ VALUE argv[3];
+ argv[0] = rb_usascii_str_new2("%s != %s\n");
+ argv[1] = x;
+ argv[2] = y;
+ return fputs(RSTRING_PTR(rb_f_sprintf(3, argv)), stderr);
+}
+
+static int
+test_d_switch_new(long from, long to, double sg)
+{
+ long j;
+
+ fprintf(stderr, "test_d_switch_new: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
+ for (j = from; j <= to; j++) {
+ VALUE jd, ajd, rd, sd;
+
+ jd = LONG2NUM(j);
+ ajd = rt_jd_to_ajd(jd, INT2FIX(0), INT2FIX(0));
+ rd = d_right_new(cDate, ajd, INT2FIX(0), DBL2NUM(sg));
+ sd = d_switch_new(cDate, ajd, INT2FIX(0), DBL2NUM(sg));
+ if (!f_eqeq_p(rd, sd)) {
+ print_emesg(rd, sd);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static VALUE
+date_s_test_d_switch_new(VALUE klass)
+{
+ if (!test_d_switch_new(MIN_JD, MIN_JD + 366, GREGORIAN))
+ return Qfalse;
+ if (!test_d_switch_new(2305814, 2598007, GREGORIAN))
+ return Qfalse;
+ if (!test_d_switch_new(MAX_JD - 366, MAX_JD, GREGORIAN))
+ return Qfalse;
+
+ if (!test_d_switch_new(MIN_JD, MIN_JD + 366, ITALY))
+ return Qfalse;
+ if (!test_d_switch_new(2305814, 2598007, ITALY))
+ return Qfalse;
+ if (!test_d_switch_new(MAX_JD - 366, MAX_JD, ITALY))
+ return Qfalse;
+
+ return Qtrue;
+}
+
+static int
+test_dt_switch_new(long from, long to, double sg)
+{
+ long j;
+
+ fprintf(stderr, "test_dt_switch_new: %ld...%ld (%ld) - %.0f\n",
+ from, to, to - from, sg);
+ for (j = from; j <= to; j++) {
+ VALUE jd, vof, ajd, rd, sd;
+ int of, df;
+ long sf;
+
+ jd = LONG2NUM(j);
+ ajd = rt_jd_to_ajd(jd, INT2FIX(0), INT2FIX(0));
+ rd = dt_right_new(cDateTime, ajd, INT2FIX(0), DBL2NUM(sg));
+ sd = dt_switch_new(cDateTime, ajd, INT2FIX(0), DBL2NUM(sg));
+ if (!f_eqeq_p(rd, sd)) {
+ print_emesg(rd, sd);
+ return 0;
+ }
+
+ of = (int)((labs(j) % (DAY_IN_SECONDS * 2)) - DAY_IN_SECONDS);
+ vof = rb_rational_new2(INT2FIX(of), INT2FIX(DAY_IN_SECONDS));
+ df = time_to_df(4, 5, 6);
+ sf = 123456789L;
+ ajd = rt_jd_to_ajd(jd,
+ f_add(rb_rational_new2(INT2FIX(df),
+ INT2FIX(DAY_IN_SECONDS)),
+ rb_rational_new2(LONG2NUM(sf),
+ day_in_nanoseconds)),
+ vof);
+ rd = dt_right_new(cDateTime, ajd, vof, DBL2NUM(sg));
+ sd = dt_switch_new(cDateTime, ajd, vof, DBL2NUM(sg));
+ if (!f_eqeq_p(rd, sd)) {
+ print_emesg(rd, sd);
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static VALUE
+date_s_test_dt_switch_new(VALUE klass)
+{
+ if (!test_dt_switch_new(MIN_JD, MIN_JD + 366, GREGORIAN))
+ return Qfalse;
+ if (!test_dt_switch_new(2305814, 2598007, GREGORIAN))
+ return Qfalse;
+ if (!test_dt_switch_new(MAX_JD - 366, MAX_JD, GREGORIAN))
+ return Qfalse;
+
+ if (!test_dt_switch_new(MIN_JD, MIN_JD + 366, ITALY))
+ return Qfalse;
+ if (!test_dt_switch_new(2305814, 2598007, ITALY))
+ return Qfalse;
+ if (!test_dt_switch_new(MAX_JD - 366, MAX_JD, ITALY))
+ return Qfalse;
+
+ return Qtrue;
+}
+
static VALUE
date_s_test_all(VALUE klass)
{
@@ -4570,10 +9714,237 @@ date_s_test_all(VALUE klass)
return Qfalse;
if (date_s_test_nth_kday(klass) == Qfalse)
return Qfalse;
+ if (date_s_test_d_switch_new(klass) == Qfalse)
+ return Qfalse;
+ if (date_s_test_dt_switch_new(klass) == Qfalse)
+ return Qfalse;
return Qtrue;
}
#endif
+static const char *monthnames[] = {
+ NULL,
+ "January", "February", "March",
+ "April", "May", "June",
+ "July", "August", "September",
+ "October", "November", "December"
+};
+
+static const char *abbr_monthnames[] = {
+ NULL,
+ "Jan", "Feb", "Mar", "Apr",
+ "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec"
+};
+
+static const char *daynames[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"
+};
+
+static const char *abbr_daynames[] = {
+ "Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"
+};
+
+static VALUE
+mk_ary_of_str(long len, const char *a[])
+{
+ VALUE o;
+ long i;
+
+ o = rb_ary_new2(len);
+ for (i = 0; i < len; i++) {
+ VALUE e;
+
+ if (!a[i])
+ e = Qnil;
+ else {
+ e = rb_str_new2(a[i]);
+ rb_obj_freeze(e);
+ }
+ rb_ary_push(o, e);
+ }
+ rb_obj_freeze(o);
+ return o;
+}
+
+/*
+ * date.rb - date and time library
+ *
+ * Author: Tadayoshi Funaba 1998-2011
+ *
+ * Initial Documentation: William Webber <william@williamwebber.com>
+ *
+ * == Overview
+ *
+ * This file provides two classes for working with
+ * dates and times.
+ *
+ * The first class, Date, represents dates.
+ * It works with years, months, weeks, and days.
+ * See the Date class documentation for more details.
+ *
+ * The second, DateTime, extends Date to include hours,
+ * minutes, seconds, and fractions of a second. It
+ * provides basic support for time zones. See the
+ * DateTime class documentation for more details.
+ *
+ * === Ways of calculating the date.
+ *
+ * In common usage, the date is reckoned in years since or
+ * before the Common Era (CE/BCE, also known as AD/BC), then
+ * as a month and day-of-the-month within the current year.
+ * This is known as the *Civil* *Date*, and abbreviated
+ * as +civil+ in the Date class.
+ *
+ * Instead of year, month-of-the-year, and day-of-the-month,
+ * the date can also be reckoned in terms of year and
+ * day-of-the-year. This is known as the *Ordinal* *Date*,
+ * and is abbreviated as +ordinal+ in the Date class. (Note
+ * that referring to this as the Julian date is incorrect.)
+ *
+ * The date can also be reckoned in terms of year, week-of-the-year,
+ * and day-of-the-week. This is known as the *Commercial*
+ * *Date*, and is abbreviated as +commercial+ in the
+ * Date class. The commercial week runs Monday (day-of-the-week
+ * 1) to Sunday (day-of-the-week 7), in contrast to the civil
+ * week which runs Sunday (day-of-the-week 0) to Saturday
+ * (day-of-the-week 6). The first week of the commercial year
+ * starts on the Monday on or before January 1, and the commercial
+ * year itself starts on this Monday, not January 1.
+ *
+ * For scientific purposes, it is convenient to refer to a date
+ * simply as a day count, counting from an arbitrary initial
+ * day. The date first chosen for this was January 1, 4713 BCE.
+ * A count of days from this date is the *Julian* *Day* *Number*
+ * or *Julian* *Date*, which is abbreviated as +jd+ in the
+ * Date class. This is in local time, and counts from midnight
+ * on the initial day. The stricter usage is in UTC, and counts
+ * from midday on the initial day. This is referred to in the
+ * Date class as the *Astronomical* *Julian* *Day* *Number*, and
+ * abbreviated as +ajd+. In the Date class, the Astronomical
+ * Julian Day Number includes fractional days.
+ *
+ * Another absolute day count is the *Modified* *Julian* *Day*
+ * *Number*, which takes November 17, 1858 as its initial day.
+ * This is abbreviated as +mjd+ in the Date class. There
+ * is also an *Astronomical* *Modified* *Julian* *Day* *Number*,
+ * which is in UTC and includes fractional days. This is
+ * abbreviated as +amjd+ in the Date class. Like the Modified
+ * Julian Day Number (and unlike the Astronomical Julian
+ * Day Number), it counts from midnight.
+ *
+ * Alternative calendars such as the Ethiopic Solar Calendar,
+ * the Islamic Lunar Calendar, or the French Revolutionary Calendar
+ * are not supported by the Date class; nor are calendars that
+ * are based on an Era different from the Common Era, such as
+ * the Japanese Era.
+ *
+ * === Calendar Reform
+ *
+ * The standard civil year is 365 days long. However, the
+ * solar year is fractionally longer than this. To account
+ * for this, a *leap* *year* is occasionally inserted. This
+ * is a year with 366 days, the extra day falling on February 29.
+ * In the early days of the civil calendar, every fourth
+ * year without exception was a leap year. This way of
+ * reckoning leap years is the *Julian* *Calendar*.
+ *
+ * However, the solar year is marginally shorter than 365 1/4
+ * days, and so the *Julian* *Calendar* gradually ran slow
+ * over the centuries. To correct this, every 100th year
+ * (but not every 400th year) was excluded as a leap year.
+ * This way of reckoning leap years, which we use today, is
+ * the *Gregorian* *Calendar*.
+ *
+ * The Gregorian Calendar was introduced at different times
+ * in different regions. The day on which it was introduced
+ * for a particular region is the *Day* *of* *Calendar*
+ * *Reform* for that region. This is abbreviated as +sg+
+ * (for Start of Gregorian calendar) in the Date class.
+ *
+ * Two such days are of particular
+ * significance. The first is October 15, 1582, which was
+ * the Day of Calendar Reform for Italy and most Catholic
+ * countries. The second is September 14, 1752, which was
+ * the Day of Calendar Reform for England and its colonies
+ * (including what is now the United States). These two
+ * dates are available as the constants Date::ITALY and
+ * Date::ENGLAND, respectively. (By comparison, Germany and
+ * Holland, less Catholic than Italy but less stubborn than
+ * England, changed over in 1698; Sweden in 1753; Russia not
+ * till 1918, after the Revolution; and Greece in 1923. Many
+ * Orthodox churches still use the Julian Calendar. A complete
+ * list of Days of Calendar Reform can be found at
+ * http://www.polysyllabic.com/GregConv.html.)
+ *
+ * Switching from the Julian to the Gregorian calendar
+ * involved skipping a number of days to make up for the
+ * accumulated lag, and the later the switch was (or is)
+ * done, the more days need to be skipped. So in 1582 in Italy,
+ * 4th October was followed by 15th October, skipping 10 days; in 1752
+ * in England, 2nd September was followed by 14th September, skipping
+ * 11 days; and if I decided to switch from Julian to Gregorian
+ * Calendar this midnight, I would go from 27th July 2003 (Julian)
+ * today to 10th August 2003 (Gregorian) tomorrow, skipping
+ * 13 days. The Date class is aware of this gap, and a supposed
+ * date that would fall in the middle of it is regarded as invalid.
+ *
+ * The Day of Calendar Reform is relevant to all date representations
+ * involving years. It is not relevant to the Julian Day Numbers,
+ * except for converting between them and year-based representations.
+ *
+ * In the Date and DateTime classes, the Day of Calendar Reform or
+ * +sg+ can be specified a number of ways. First, it can be as
+ * the Julian Day Number of the Day of Calendar Reform. Second,
+ * it can be using the constants Date::ITALY or Date::ENGLAND; these
+ * are in fact the Julian Day Numbers of the Day of Calendar Reform
+ * of the respective regions. Third, it can be as the constant
+ * Date::JULIAN, which means to always use the Julian Calendar.
+ * Finally, it can be as the constant Date::GREGORIAN, which means
+ * to always use the Gregorian Calendar.
+ *
+ * Note: in the Julian Calendar, New Years Day was March 25. The
+ * Date class does not follow this convention.
+ *
+ * === Offsets
+ *
+ * DateTime objects support a simple representation
+ * of offsets. Offsets are represented as an offset
+ * from UTC (UTC is not identical GMT; GMT is a historical term),
+ * as a fraction of a day. This offset is the
+ * how much local time is later (or earlier) than UTC.
+ * As you travel east, the offset increases until you
+ * reach the dateline in the middle of the Pacific Ocean;
+ * as you travel west, the offset decreases. This offset
+ * is abbreviated as +of+ in the Date class.
+ *
+ * This simple representation of offsets does not take
+ * into account the common practice of Daylight Savings
+ * Time or Summer Time.
+ *
+ * Most DateTime methods return the date and the
+ * time in local time. The two exceptions are
+ * #ajd() and #amjd(), which return the date and time
+ * in UTC time, including fractional days.
+ *
+ * The Date class does not support offsets, in that
+ * there is no way to create a Date object with non-utc offset.
+ *
+ * == Examples of use
+ *
+ * === Print out the date of every Sunday between two dates.
+ *
+ * def print_sundays(d1, d2)
+ * d1 += 1 until d1.sunday?
+ * d1.step(d2, 7) do |d|
+ * puts d.strftime('%B %-d')
+ * end
+ * end
+ *
+ * print_sundays(Date.new(2003, 4, 8), Date.new(2003, 5, 23))
+ */
void
Init_date_core(void)
{
@@ -4581,19 +9952,105 @@ Init_date_core(void)
rzero = rb_rational_new1(INT2FIX(0));
rhalf = rb_rational_new2(INT2FIX(1), INT2FIX(2));
- day_in_nanoseconds = DAY_IN_NANOSECONDS;
+
+#if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
+ day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS *
+ SECOND_IN_NANOSECONDS);
+#elif defined HAVE_LONG_LONG
+ day_in_nanoseconds = LL2NUM((LONG_LONG)DAY_IN_SECONDS *
+ SECOND_IN_NANOSECONDS);
+#else
+ day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS),
+ INT2FIX(SECOND_IN_NANOSECONDS));
+#endif
rb_gc_register_mark_object(rzero);
rb_gc_register_mark_object(rhalf);
rb_gc_register_mark_object(day_in_nanoseconds);
- /* date */
-
+ /*
+ * Class representing a date.
+ *
+ * See the documentation to the file date.rb for an overview.
+ *
+ * Internally, the date is represented as an Astronomical
+ * Julian Day Number, +ajd+. The Day of Calendar Reform, +sg+, is
+ * also stored, for conversions to other date formats. (There
+ * is also an +of+ field for a time zone offset, but this
+ * is only for the use of the DateTime subclass.)
+ *
+ * A new Date object is created using one of the object creation
+ * class methods named after the corresponding date format, and the
+ * arguments appropriate to that date format; for instance,
+ * Date::civil() (aliased to Date::new()) with year, month,
+ * and day-of-month, or Date::ordinal() with year and day-of-year.
+ * All of these object creation class methods also take the
+ * Day of Calendar Reform as an optional argument.
+ *
+ * Date objects are immutable once created.
+ *
+ * Once a Date has been created, date values
+ * can be retrieved for the different date formats supported
+ * using instance methods. For instance, #mon() gives the
+ * Civil month, #cwday() gives the Commercial day of the week,
+ * and #yday() gives the Ordinal day of the year. Date values
+ * can be retrieved in any format, regardless of what format
+ * was used to create the Date instance.
+ *
+ * The Date class includes the Comparable module, allowing
+ * date objects to be compared and sorted, ranges of dates
+ * to be created, and so forth.
+ */
cDate = rb_define_class("Date", rb_cObject);
+ rb_include_module(cDate, rb_mComparable);
+
+ /*
+ * Full month names, in English. Months count from 1 to 12; a
+ * month's numerical representation indexed into this array
+ * gives the name of that month (hence the first element is nil).
+ */
+ rb_define_const(cDate, "MONTHNAMES", mk_ary_of_str(13, monthnames));
+
+ /* Abbreviated month names, in English. */
+ rb_define_const(cDate, "ABBR_MONTHNAMES",
+ mk_ary_of_str(13, abbr_monthnames));
+
+ /*
+ * Full names of days of the week, in English. Days of the week
+ * count from 0 to 6 (except in the commercial week); a day's numerical
+ * representation indexed into this array gives the name of that day.
+ */
+ rb_define_const(cDate, "DAYNAMES", mk_ary_of_str(7, daynames));
+
+ /* Abbreviated day names, in English. */
+ rb_define_const(cDate, "ABBR_DAYNAMES", mk_ary_of_str(7, abbr_daynames));
+
+ /* The Julian Day Number of the Day of Calendar Reform for Italy
+ * and the Catholic countries.
+ */
+ rb_define_const(cDate, "ITALY", INT2FIX(ITALY));
+
+ /* The Julian Day Number of the Day of Calendar Reform for England
+ * and her Colonies.
+ */
+ rb_define_const(cDate, "ENGLAND", INT2FIX(ENGLAND));
+ /* A constant used to indicate that a Date should always use the
+ * Julian calendar.
+ */
+ rb_define_const(cDate, "JULIAN", DBL2NUM(JULIAN));
+ /* A constant used to indicate that a Date should always use the
+ * Gregorian calendar.
+ */
+ rb_define_const(cDate, "GREGORIAN", DBL2NUM(GREGORIAN));
+
rb_define_alloc_func(cDate, d_lite_s_alloc);
+
+#ifndef NDEBUG
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, "new!", date_s_new_bang, -1);
+#endif
#ifndef NDEBUG
rb_define_private_method(CLASS_OF(cDate), "_valid_jd?",
@@ -4606,6 +10063,10 @@ Init_date_core(void)
date_s__valid_civil_p, -1);
rb_define_private_method(CLASS_OF(cDate), "_valid_commercial?",
date_s__valid_commercial_p, -1);
+ rb_define_private_method(CLASS_OF(cDate), "_valid_weeknum?",
+ date_s__valid_weeknum_p, -1);
+ rb_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?",
+ date_s__valid_nth_kday_p, -1);
#endif
rb_define_singleton_method(cDate, "valid_jd?", date_s_valid_jd_p, -1);
@@ -4616,14 +10077,51 @@ Init_date_core(void)
rb_define_singleton_method(cDate, "valid_commercial?",
date_s_valid_commercial_p, -1);
+#ifndef NDEBUG
+ rb_define_private_method(CLASS_OF(cDate), "valid_weeknum?",
+ date_s_valid_weeknum_p, -1);
+ rb_define_private_method(CLASS_OF(cDate), "valid_nth_kday?",
+ date_s_valid_nth_kday_p, -1);
+ rb_define_private_method(CLASS_OF(cDate), "zone_to_diff",
+ date_s_zone_to_diff, 1);
+#endif
+
+ rb_define_singleton_method(cDate, "julian_leap?", date_s_julian_leap_p, 1);
+ rb_define_singleton_method(cDate, "gregorian_leap?",
+ date_s_gregorian_leap_p, 1);
+ rb_define_singleton_method(cDate, "leap?",
+ date_s_gregorian_leap_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);
+
+#ifndef NDEBUG
+ rb_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1);
+ rb_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1);
+#endif
+
rb_define_singleton_method(cDate, "today", date_s_today, -1);
rb_define_singleton_method(cDate, "_strptime", date_s__strptime, -1);
+ rb_define_singleton_method(cDate, "strptime", date_s_strptime, -1);
rb_define_singleton_method(cDate, "_parse", date_s__parse, -1);
+ rb_define_singleton_method(cDate, "parse", date_s_parse, -1);
+ rb_define_singleton_method(cDate, "_iso8601", date_s__iso8601, 1);
+ rb_define_singleton_method(cDate, "iso8601", date_s_iso8601, -1);
+ rb_define_singleton_method(cDate, "_rfc3339", date_s__rfc3339, 1);
+ rb_define_singleton_method(cDate, "rfc3339", date_s_rfc3339, -1);
+ rb_define_singleton_method(cDate, "_xmlschema", date_s__xmlschema, 1);
+ rb_define_singleton_method(cDate, "xmlschema", date_s_xmlschema, -1);
+ rb_define_singleton_method(cDate, "_rfc2822", date_s__rfc2822, 1);
+ rb_define_singleton_method(cDate, "_rfc822", date_s__rfc2822, 1);
+ rb_define_singleton_method(cDate, "rfc2822", date_s_rfc2822, -1);
+ rb_define_singleton_method(cDate, "rfc822", date_s_rfc2822, -1);
+ rb_define_singleton_method(cDate, "_httpdate", date_s__httpdate, 1);
+ rb_define_singleton_method(cDate, "httpdate", date_s_httpdate, -1);
+ rb_define_singleton_method(cDate, "_jisx0301", date_s__jisx0301, 1);
+ rb_define_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1);
rb_define_method(cDate, "ajd", d_lite_ajd, 0);
rb_define_method(cDate, "amjd", d_lite_amjd, 0);
@@ -4658,17 +10156,50 @@ Init_date_core(void)
rb_define_method(cDate, "wday", d_lite_wday, 0);
+ rb_define_method(cDate, "sunday?", d_lite_sunday_p, 0);
+ rb_define_method(cDate, "monday?", d_lite_monday_p, 0);
+ rb_define_method(cDate, "tuesday?", d_lite_tuesday_p, 0);
+ rb_define_method(cDate, "wednesday?", d_lite_wednesday_p, 0);
+ rb_define_method(cDate, "thursday?", d_lite_thursday_p, 0);
+ rb_define_method(cDate, "friday?", d_lite_friday_p, 0);
+ rb_define_method(cDate, "saturday?", d_lite_saturday_p, 0);
+
+#ifndef NDEBUG
+ rb_define_method(cDate, "nth_kday?", generic_nth_kday_p, 2);
+#endif
+
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_method(cDate, "italy", d_lite_italy, 0);
+ rb_define_method(cDate, "england", d_lite_england, 0);
+ rb_define_method(cDate, "julian", d_lite_julian, 0);
+ rb_define_method(cDate, "gregorian", d_lite_gregorian, 0);
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, "next_day", d_lite_next_day, -1);
+ rb_define_method(cDate, "prev_day", d_lite_prev_day, -1);
+ rb_define_method(cDate, "next", d_lite_next, 0);
+ rb_define_method(cDate, "succ", d_lite_next, 0);
+
+ rb_define_method(cDate, ">>", d_lite_rshift, 1);
+ rb_define_method(cDate, "<<", d_lite_lshift, 1);
+
+ rb_define_method(cDate, "next_month", d_lite_next_month, -1);
+ rb_define_method(cDate, "prev_month", d_lite_prev_month, -1);
+ rb_define_method(cDate, "next_year", d_lite_next_year, -1);
+ rb_define_method(cDate, "prev_year", d_lite_prev_year, -1);
+
+ rb_define_method(cDate, "step", generic_step, -1);
+ rb_define_method(cDate, "upto", generic_upto, 1);
+ rb_define_method(cDate, "downto", generic_downto, 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);
@@ -4678,17 +10209,30 @@ Init_date_core(void)
rb_define_method(cDate, "inspect", d_lite_inspect, 0);
rb_define_method(cDate, "strftime", d_lite_strftime, -1);
+ rb_define_method(cDate, "asctime", d_lite_asctime, 0);
+ rb_define_method(cDate, "ctime", d_lite_asctime, 0);
+ rb_define_method(cDate, "iso8601", d_lite_iso8601, 0);
+ rb_define_method(cDate, "xmlschema", d_lite_iso8601, 0);
+ rb_define_method(cDate, "rfc3339", d_lite_rfc3339, 0);
+ rb_define_method(cDate, "rfc2822", d_lite_rfc2822, 0);
+ rb_define_method(cDate, "rfc822", d_lite_rfc2822, 0);
+ rb_define_method(cDate, "httpdate", d_lite_httpdate, 0);
+ rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 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);
+
+#ifndef NDEBUG
+ rb_define_singleton_method(cDateTime, "new_r!", datetime_s_new_r_bang, -1);
rb_define_singleton_method(cDateTime, "new_l!", datetime_s_new_l_bang, -1);
+ rb_define_singleton_method(cDateTime, "new!", datetime_s_new_bang, -1);
+#endif
rb_undef_method(CLASS_OF(cDateTime), "today");
@@ -4698,9 +10242,35 @@ Init_date_core(void)
rb_define_singleton_method(cDateTime, "new", datetime_s_civil, -1);
rb_define_singleton_method(cDateTime, "commercial",
datetime_s_commercial, -1);
+
+#ifndef NDEBUG
+ rb_define_singleton_method(cDateTime, "weeknum",
+ datetime_s_weeknum, -1);
+ rb_define_singleton_method(cDateTime, "nth_kday",
+ datetime_s_nth_kday, -1);
+#endif
+
rb_define_singleton_method(cDateTime, "now", datetime_s_now, -1);
rb_define_singleton_method(cDateTime, "_strptime",
datetime_s__strptime, -1);
+ rb_define_singleton_method(cDateTime, "strptime",
+ datetime_s_strptime, -1);
+ rb_define_singleton_method(cDateTime, "parse",
+ datetime_s_parse, -1);
+ rb_define_singleton_method(cDateTime, "iso8601",
+ datetime_s_iso8601, -1);
+ rb_define_singleton_method(cDateTime, "rfc3339",
+ datetime_s_rfc3339, -1);
+ rb_define_singleton_method(cDateTime, "xmlschema",
+ datetime_s_xmlschema, -1);
+ rb_define_singleton_method(cDateTime, "rfc2822",
+ datetime_s_rfc2822, -1);
+ rb_define_singleton_method(cDateTime, "rfc822",
+ datetime_s_rfc2822, -1);
+ rb_define_singleton_method(cDateTime, "httpdate",
+ datetime_s_httpdate, -1);
+ rb_define_singleton_method(cDateTime, "jisx0301",
+ datetime_s_jisx0301, -1);
rb_define_method(cDateTime, "ajd", dt_lite_ajd, 0);
rb_define_method(cDateTime, "amjd", dt_lite_amjd, 0);
@@ -4735,17 +10305,42 @@ Init_date_core(void)
rb_define_method(cDateTime, "wday", dt_lite_wday, 0);
+ rb_define_method(cDateTime, "sunday?", dt_lite_sunday_p, 0);
+ rb_define_method(cDateTime, "monday?", dt_lite_monday_p, 0);
+ rb_define_method(cDateTime, "tuesday?", dt_lite_tuesday_p, 0);
+ rb_define_method(cDateTime, "wednesday?", dt_lite_wednesday_p, 0);
+ rb_define_method(cDateTime, "thursday?", dt_lite_thursday_p, 0);
+ rb_define_method(cDateTime, "friday?", dt_lite_friday_p, 0);
+ rb_define_method(cDateTime, "saturday?", dt_lite_saturday_p, 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, "italy", dt_lite_italy, 0);
+ rb_define_method(cDateTime, "england", dt_lite_england, 0);
+ rb_define_method(cDateTime, "julian", dt_lite_julian, 0);
+ rb_define_method(cDateTime, "gregorian", dt_lite_gregorian, 0);
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, "next_day", dt_lite_next_day, -1);
+ rb_define_method(cDateTime, "prev_day", dt_lite_prev_day, -1);
+ rb_define_method(cDateTime, "next", dt_lite_next, 0);
+ rb_define_method(cDateTime, "succ", dt_lite_next, 0);
+
+ rb_define_method(cDateTime, ">>", dt_lite_rshift, 1);
+ rb_define_method(cDateTime, "<<", dt_lite_lshift, 1);
+
+ rb_define_method(cDateTime, "next_month", dt_lite_next_month, -1);
+ rb_define_method(cDateTime, "prev_month", dt_lite_prev_month, -1);
+ rb_define_method(cDateTime, "next_year", dt_lite_next_year, -1);
+ rb_define_method(cDateTime, "prev_year", dt_lite_prev_year, -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);
@@ -4755,18 +10350,56 @@ Init_date_core(void)
rb_define_method(cDateTime, "inspect", dt_lite_inspect, 0);
rb_define_method(cDateTime, "strftime", dt_lite_strftime, -1);
+ rb_define_method(cDateTime, "asctime", dt_lite_asctime, 0);
+ rb_define_method(cDateTime, "ctime", dt_lite_asctime, 0);
+ rb_define_method(cDateTime, "iso8601", dt_lite_iso8601, -1);
+ rb_define_method(cDateTime, "xmlschema", dt_lite_iso8601, -1);
+ rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1);
+ rb_define_method(cDateTime, "rfc2822", dt_lite_rfc2822, 0);
+ rb_define_method(cDateTime, "rfc822", dt_lite_rfc2822, 0);
+ rb_define_method(cDateTime, "httpdate", dt_lite_httpdate, 0);
+ rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1);
+
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);
+ /* conversions */
+
+ rb_define_method(rb_cTime, "to_time", time_to_time, 0);
+ rb_define_method(rb_cTime, "to_date", time_to_date, 0);
+ rb_define_method(rb_cTime, "to_datetime", time_to_datetime, 0);
+
+ rb_define_method(cDate, "to_time", date_to_time, 0);
+ rb_define_method(cDate, "to_date", date_to_date, 0);
+ rb_define_method(cDate, "to_datetime", date_to_datetime, 0);
#ifndef NDEBUG
+ rb_define_method(cDate, "to_right", date_to_right, 0);
+ rb_define_method(cDate, "to_light", date_to_light, 0);
+#endif
+
+ rb_define_method(cDateTime, "to_time", datetime_to_time, 0);
+ rb_define_method(cDateTime, "to_date", datetime_to_date, 0);
+ rb_define_method(cDateTime, "to_datetime", datetime_to_datetime, 0);
+
+#ifndef NDEBUG
+ rb_define_method(cDateTime, "to_right", datetime_to_right, 0);
+ rb_define_method(cDateTime, "to_light", datetime_to_light, 0);
+#endif
+
+#ifndef NDEBUG
+ /* tests */
+
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_d_switch_new",
+ date_s_test_d_switch_new, 0);
+ rb_define_singleton_method(cDate, "test_dt_switch_new",
+ date_s_test_dt_switch_new, 0);
rb_define_singleton_method(cDate, "test_all", date_s_test_all, 0);
#endif
}
diff --git a/ext/date/date_parse.c b/ext/date/date_parse.c
index 9a84c0be83..f08e99b02b 100644
--- a/ext/date/date_parse.c
+++ b/ext/date/date_parse.c
@@ -14,6 +14,7 @@
#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 f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
#define f_mod(x,y) rb_funcall(x, '%', 1, y)
#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
@@ -33,8 +34,6 @@
#define f_aset2(o,i,j,v) rb_funcall(o, rb_intern("[]="), 3, i, j, v)
#define f_sub_bang(s,r,x) rb_funcall(s, rb_intern("sub!"), 2, r, x)
#define f_gsub_bang(s,r,x) rb_funcall(s, rb_intern("gsub!"), 2, r, x)
-#define f_split(s,p) rb_funcall(s, rb_intern("split"), 1, p)
-#define f_downcase(x) rb_funcall(x, rb_intern("downcase"), 0)
#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
@@ -213,6 +212,8 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc)
set_hash("_comp", c);
}
+#define DAYS "sunday|monday|tuesday|wednesday|thursday|friday|saturday"
+#define MONTHS "january|february|march|april|may|june|july|august|september|october|november|december"
#define ABBR_DAYS "sun|mon|tue|wed|thu|fri|sat"
#define ABBR_MONTHS "jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec"
@@ -262,6 +263,277 @@ subs(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE))
return 1;
}
+struct zone {
+ const char *name;
+ int offset;
+};
+
+static struct zone zones_source[] = {
+ {"ut", 0*3600}, {"gmt", 0*3600}, {"est", -5*3600}, {"edt", -4*3600},
+ {"cst", -6*3600}, {"cdt", -5*3600}, {"mst", -7*3600}, {"mdt", -6*3600},
+ {"pst", -8*3600}, {"pdt", -7*3600},
+ {"a", 1*3600}, {"b", 2*3600}, {"c", 3*3600}, {"d", 4*3600},
+ {"e", 5*3600}, {"f", 6*3600}, {"g", 7*3600}, {"h", 8*3600},
+ {"i", 9*3600}, {"k", 10*3600}, {"l", 11*3600}, {"m", 12*3600},
+ {"n", -1*3600}, {"o", -2*3600}, {"p", -3*3600}, {"q", -4*3600},
+ {"r", -5*3600}, {"s", -6*3600}, {"t", -7*3600}, {"u", -8*3600},
+ {"v", -9*3600}, {"w", -10*3600}, {"x", -11*3600}, {"y", -12*3600},
+ {"z", 0*3600},
+
+ {"utc", 0*3600}, {"wet", 0*3600},
+ {"at", -2*3600}, {"brst",-2*3600}, {"ndt", -(2*3600+1800)},
+ {"art", -3*3600}, {"adt", -3*3600}, {"brt", -3*3600}, {"clst",-3*3600},
+ {"nst", -(3*3600+1800)},
+ {"ast", -4*3600}, {"clt", -4*3600},
+ {"akdt",-8*3600}, {"ydt", -8*3600},
+ {"akst",-9*3600}, {"hadt",-9*3600}, {"hdt", -9*3600}, {"yst", -9*3600},
+ {"ahst",-10*3600},{"cat",-10*3600}, {"hast",-10*3600},{"hst",-10*3600},
+ {"nt", -11*3600},
+ {"idlw",-12*3600},
+ {"bst", 1*3600}, {"cet", 1*3600}, {"fwt", 1*3600}, {"met", 1*3600},
+ {"mewt", 1*3600}, {"mez", 1*3600}, {"swt", 1*3600}, {"wat", 1*3600},
+ {"west", 1*3600},
+ {"cest", 2*3600}, {"eet", 2*3600}, {"fst", 2*3600}, {"mest", 2*3600},
+ {"mesz", 2*3600}, {"sast", 2*3600}, {"sst", 2*3600},
+ {"bt", 3*3600}, {"eat", 3*3600}, {"eest", 3*3600}, {"msk", 3*3600},
+ {"msd", 4*3600}, {"zp4", 4*3600},
+ {"zp5", 5*3600}, {"ist", (5*3600+1800)},
+ {"zp6", 6*3600},
+ {"wast", 7*3600},
+ {"cct", 8*3600}, {"sgt", 8*3600}, {"wadt", 8*3600},
+ {"jst", 9*3600}, {"kst", 9*3600},
+ {"east",10*3600}, {"gst", 10*3600},
+ {"eadt",11*3600},
+ {"idle",12*3600}, {"nzst",12*3600}, {"nzt", 12*3600},
+ {"nzdt",13*3600},
+
+ {"afghanistan", 16200}, {"alaskan", -32400},
+ {"arab", 10800}, {"arabian", 14400},
+ {"arabic", 10800}, {"atlantic", -14400},
+ {"aus central", 34200}, {"aus eastern", 36000},
+ {"azores", -3600}, {"canada central", -21600},
+ {"cape verde", -3600}, {"caucasus", 14400},
+ {"cen. australia", 34200}, {"central america", -21600},
+ {"central asia", 21600}, {"central europe", 3600},
+ {"central european", 3600}, {"central pacific", 39600},
+ {"central", -21600}, {"china", 28800},
+ {"dateline", -43200}, {"e. africa", 10800},
+ {"e. australia", 36000}, {"e. europe", 7200},
+ {"e. south america", -10800}, {"eastern", -18000},
+ {"egypt", 7200}, {"ekaterinburg", 18000},
+ {"fiji", 43200}, {"fle", 7200},
+ {"greenland", -10800}, {"greenwich", 0},
+ {"gtb", 7200}, {"hawaiian", -36000},
+ {"india", 19800}, {"iran", 12600},
+ {"jerusalem", 7200}, {"korea", 32400},
+ {"mexico", -21600}, {"mid-atlantic", -7200},
+ {"mountain", -25200}, {"myanmar", 23400},
+ {"n. central asia", 21600}, {"nepal", 20700},
+ {"new zealand", 43200}, {"newfoundland", -12600},
+ {"north asia east", 28800}, {"north asia", 25200},
+ {"pacific sa", -14400}, {"pacific", -28800},
+ {"romance", 3600}, {"russian", 10800},
+ {"sa eastern", -10800}, {"sa pacific", -18000},
+ {"sa western", -14400}, {"samoa", -39600},
+ {"se asia", 25200}, {"malay peninsula", 28800},
+ {"south africa", 7200}, {"sri lanka", 21600},
+ {"taipei", 28800}, {"tasmania", 36000},
+ {"tokyo", 32400}, {"tonga", 46800},
+ {"us eastern", -18000}, {"us mountain", -25200},
+ {"vladivostok", 36000}, {"w. australia", 28800},
+ {"w. central africa", 3600}, {"w. europe", 3600},
+ {"west asia", 18000}, {"west pacific", 36000},
+ {"yakutsk", 32400}
+};
+
+VALUE
+date_zone_to_diff(VALUE str)
+{
+ VALUE offset = Qnil;
+
+ long l, i;
+ char *s, *dest, *d;
+ int sp = 1;
+
+ l = RSTRING_LEN(str);
+ s = RSTRING_PTR(str);
+
+ dest = d = ALLOC_N(char, l + 1);
+
+ for (i = 0; i < l; i++) {
+ if (isspace(s[i]) || s[i] == '\0') {
+ if (!sp)
+ *d++ = ' ';
+ sp = 1;
+ }
+ else {
+ if (isalpha(s[i]))
+ *d++ = tolower(s[i]);
+ else
+ *d++ = s[i];
+ sp = 0;
+ }
+ }
+ if (d > dest) {
+ if (*(d - 1) == ' ')
+ --d;
+ *d = '\0';
+ }
+ str = rb_str_new2(dest);
+ {
+#define STD " standard time"
+#define DST " daylight time"
+ char *ss, *ds;
+ long sl, dl;
+ int dst = 0;
+
+ sl = RSTRING_LEN(str) - (sizeof STD - 1);
+ ss = RSTRING_PTR(str) + sl;
+ dl = RSTRING_LEN(str) - (sizeof DST - 1);
+ ds = RSTRING_PTR(str) + dl;
+
+ if (strcmp(ss, STD) == 0) {
+ str = rb_str_new(RSTRING_PTR(str), sl);
+ }
+ else if (strcmp(ds, DST) == 0) {
+ str = rb_str_new(RSTRING_PTR(str), dl);
+ dst = 1;
+ }
+#undef STD
+#undef DST
+ else {
+#define DST " dst"
+ char *ds;
+ long dl;
+
+ dl = RSTRING_LEN(str) - (sizeof DST - 1);
+ ds = RSTRING_PTR(str) + dl;
+
+ if (strcmp(ds, DST) == 0) {
+ str = rb_str_new(RSTRING_PTR(str), dl);
+ dst = 1;
+ }
+#undef DST
+ }
+ {
+ static VALUE zones = Qnil;
+
+ if (NIL_P(zones)) {
+ int i;
+
+ zones = rb_hash_new();
+ rb_gc_register_mark_object(zones);
+ for (i = 0; i < (int)sizeof_array(zones_source); i++) {
+ VALUE name = rb_str_new2(zones_source[i].name);
+ VALUE offset = INT2FIX(zones_source[i].offset);
+ rb_hash_aset(zones, name, offset);
+ }
+ }
+
+ offset = f_aref(zones, str);
+ if (!NIL_P(offset)) {
+ if (dst)
+ offset = f_add(offset, INT2FIX(3600));
+ goto ok;
+ }
+ }
+ {
+ char *s, *p;
+ VALUE sign;
+ VALUE hour = Qnil, min = Qnil, sec = Qnil;
+
+ s = RSTRING_PTR(str);
+
+ if (strncmp(s, "gmt", 3) == 0 ||
+ strncmp(s, "utc", 3) == 0)
+ s += 3;
+ if (issign(*s)) {
+ sign = rb_str_new(s, 1);
+ s++;
+
+ str = rb_str_new2(s);
+
+ if (p = strchr(s, ':')) {
+ hour = rb_str_new(s, p - s);
+ s = ++p;
+ if (p = strchr(s, ':')) {
+ min = rb_str_new(s, p - s);
+ s = ++p;
+ if (p = strchr(s, ':')) {
+ sec = rb_str_new(s, p - s);
+ }
+ else
+ sec = rb_str_new2(s);
+ }
+ else
+ min = rb_str_new2(s);
+ goto num;
+ }
+ if (strpbrk(RSTRING_PTR(str), ",.")) {
+ char *a, *b;
+
+ a = ALLOC_N(char, RSTRING_LEN(str) + 1);
+ strcpy(a, RSTRING_PTR(str));
+ b = strpbrk(a, ",.");
+ *b = '\0';
+ b++;
+
+ hour = cstr2num(a);
+ min = f_mul(rb_rational_new2
+ (cstr2num(b),
+ f_expt(INT2FIX(10),
+ LONG2NUM((long)strlen(b)))),
+ INT2FIX(60));
+ goto num;
+ }
+ {
+ const char *cs = RSTRING_PTR(str);
+ long cl = RSTRING_LEN(str);
+
+ if (cl % 2) {
+ if (cl >= 1)
+ hour = rb_str_new(&cs[0], 1);
+ if (cl >= 3)
+ min = rb_str_new(&cs[1], 2);
+ if (cl >= 5)
+ min = rb_str_new(&cs[3], 2);
+ }
+ else {
+ if (cl >= 2)
+ hour = rb_str_new(&cs[0], 2);
+ if (cl >= 4)
+ min = rb_str_new(&cs[2], 2);
+ if (cl >= 6)
+ sec = rb_str_new(&cs[4], 2);
+ }
+ goto num;
+ }
+ num:
+ if (NIL_P(hour))
+ offset = INT2FIX(0);
+ else {
+ if (TYPE(hour) == T_STRING)
+ hour = str2num(hour);
+ offset = f_mul(hour, INT2FIX(3600));
+ }
+ if (!NIL_P(min)) {
+ if (TYPE(min) == T_STRING)
+ min = str2num(min);
+ offset = f_add(offset, f_mul(min, INT2FIX(60)));
+ }
+ if (!NIL_P(sec))
+ offset = f_add(offset, str2num(sec));
+ if (!NIL_P(sign) &&
+ RSTRING_LEN(sign) == 1 &&
+ *RSTRING_PTR(sign) == '-')
+ offset = f_negate(offset);
+ }
+ }
+ }
+ ok:
+ return offset;
+}
+
static int
day_num(VALUE s)
{
@@ -289,7 +561,7 @@ parse_day_cb(VALUE m, VALUE hash)
{
VALUE s;
- s = f_aref(m, INT2FIX(1));
+ s = rb_reg_nth_match(1, m);
set_hash("wday", INT2FIX(day_num(s)));
return 1;
}
@@ -309,24 +581,24 @@ parse_time2_cb(VALUE m, VALUE hash)
{
VALUE h, min, s, f, p;
- h = f_aref(m, INT2FIX(1));
+ h = rb_reg_nth_match(1, m);
h = str2num(h);
- min = f_aref(m, INT2FIX(2));
+ min = rb_reg_nth_match(2, m);
if (!NIL_P(min))
min = str2num(min);
- s = f_aref(m, INT2FIX(3));
+ s = rb_reg_nth_match(3, m);
if (!NIL_P(s))
s = str2num(s);
- f = f_aref(m, INT2FIX(4));
+ f = rb_reg_nth_match(4, m);
if (!NIL_P(f))
f = rb_rational_new2(str2num(f),
f_expt(INT2FIX(10), LONG2NUM(RSTRING_LEN(f))));
- p = f_aref(m, INT2FIX(5));
+ p = rb_reg_nth_match(5, m);
if (!NIL_P(p)) {
int ih = NUM2INT(h);
@@ -361,8 +633,8 @@ parse_time_cb(VALUE m, VALUE hash)
static VALUE pat = Qnil;
VALUE s1, s2;
- s1 = f_aref(m, INT2FIX(1));
- s2 = f_aref(m, INT2FIX(2));
+ s1 = rb_reg_nth_match(1, m);
+ s2 = rb_reg_nth_match(2, m);
if (!NIL_P(s2))
set_hash("zone", s2);
@@ -421,10 +693,10 @@ parse_eu_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d, b;
- d = f_aref(m, INT2FIX(1));
- mon = f_aref(m, INT2FIX(2));
- b = f_aref(m, INT2FIX(3));
- y = f_aref(m, INT2FIX(4));
+ d = rb_reg_nth_match(1, m);
+ mon = rb_reg_nth_match(2, m);
+ b = rb_reg_nth_match(3, m);
+ y = rb_reg_nth_match(4, m);
mon = INT2FIX(mon_num(mon));
@@ -458,10 +730,10 @@ parse_us_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d, b;
- mon = f_aref(m, INT2FIX(1));
- d = f_aref(m, INT2FIX(2));
- b = f_aref(m, INT2FIX(3));
- y = f_aref(m, INT2FIX(4));
+ mon = rb_reg_nth_match(1, m);
+ d = rb_reg_nth_match(2, m);
+ b = rb_reg_nth_match(3, m);
+ y = rb_reg_nth_match(4, m);
mon = INT2FIX(mon_num(mon));
@@ -495,9 +767,9 @@ parse_iso_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d;
- y = f_aref(m, INT2FIX(1));
- mon = f_aref(m, INT2FIX(2));
- d = f_aref(m, INT2FIX(3));
+ y = rb_reg_nth_match(1, m);
+ mon = rb_reg_nth_match(2, m);
+ d = rb_reg_nth_match(3, m);
s3e(hash, y, mon, d, 0);
return 1;
@@ -518,9 +790,9 @@ parse_iso21_cb(VALUE m, VALUE hash)
{
VALUE y, w, d;
- y = f_aref(m, INT2FIX(1));
- w = f_aref(m, INT2FIX(2));
- d = f_aref(m, INT2FIX(3));
+ y = rb_reg_nth_match(1, m);
+ w = rb_reg_nth_match(2, m);
+ d = rb_reg_nth_match(3, m);
if (!NIL_P(y))
set_hash("cwyear", str2num(y));
@@ -547,7 +819,7 @@ parse_iso22_cb(VALUE m, VALUE hash)
{
VALUE d;
- d = f_aref(m, INT2FIX(1));
+ d = rb_reg_nth_match(1, m);
set_hash("cwday", str2num(d));
return 1;
}
@@ -567,8 +839,8 @@ parse_iso23_cb(VALUE m, VALUE hash)
{
VALUE mon, d;
- mon = f_aref(m, INT2FIX(1));
- d = f_aref(m, INT2FIX(2));
+ mon = rb_reg_nth_match(1, m);
+ d = rb_reg_nth_match(2, m);
if (!NIL_P(mon))
set_hash("mon", str2num(mon));
@@ -592,8 +864,8 @@ parse_iso24_cb(VALUE m, VALUE hash)
{
VALUE mon, d;
- mon = f_aref(m, INT2FIX(1));
- d = f_aref(m, INT2FIX(2));
+ mon = rb_reg_nth_match(1, m);
+ d = rb_reg_nth_match(2, m);
set_hash("mon", str2num(mon));
if (!NIL_P(d))
@@ -617,8 +889,8 @@ parse_iso25_cb(VALUE m, VALUE hash)
{
VALUE y, d;
- y = f_aref(m, INT2FIX(1));
- d = f_aref(m, INT2FIX(2));
+ y = rb_reg_nth_match(1, m);
+ d = rb_reg_nth_match(2, m);
set_hash("year", str2num(y));
set_hash("yday", str2num(d));
@@ -647,7 +919,7 @@ parse_iso26_cb(VALUE m, VALUE hash)
{
VALUE d;
- d = f_aref(m, INT2FIX(1));
+ d = rb_reg_nth_match(1, m);
set_hash("yday", str2num(d));
return 1;
@@ -690,23 +962,32 @@ parse_iso2(VALUE str, VALUE hash)
}
static int
+gengo(int c)
+{
+ int e;
+
+ switch (c) {
+ case 'M': case 'm': e = 1867; break;
+ case 'T': case 't': e = 1911; break;
+ case 'S': case 's': e = 1925; break;
+ case 'H': case 'h': e = 1988; break;
+ default: e = 0; break;
+ }
+ return e;
+}
+
+static int
parse_jis_cb(VALUE m, VALUE hash)
{
VALUE e, y, mon, d;
int ep;
- e = f_aref(m, INT2FIX(1));
- y = f_aref(m, INT2FIX(2));
- mon = f_aref(m, INT2FIX(3));
- d = f_aref(m, INT2FIX(4));
-
- switch (*RSTRING_PTR(e)) {
- case 'M': case 'm': ep = 1867; break;
- case 'T': case 't': ep = 1911; break;
- case 'S': case 's': ep = 1925; break;
- case 'H': case 'h': ep = 1988; break;
- default: ep = 0; break;
- }
+ e = rb_reg_nth_match(1, m);
+ y = rb_reg_nth_match(2, m);
+ mon = rb_reg_nth_match(3, m);
+ d = rb_reg_nth_match(4, m);
+
+ ep = gengo(*RSTRING_PTR(e));
set_hash("year", f_add(str2num(y), INT2FIX(ep)));
set_hash("mon", str2num(mon));
@@ -730,9 +1011,9 @@ parse_vms11_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d;
- d = f_aref(m, INT2FIX(1));
- mon = f_aref(m, INT2FIX(2));
- y = f_aref(m, INT2FIX(3));
+ d = rb_reg_nth_match(1, m);
+ mon = rb_reg_nth_match(2, m);
+ y = rb_reg_nth_match(3, m);
mon = INT2FIX(mon_num(mon));
@@ -757,9 +1038,9 @@ parse_vms12_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d;
- mon = f_aref(m, INT2FIX(1));
- d = f_aref(m, INT2FIX(2));
- y = f_aref(m, INT2FIX(3));
+ mon = rb_reg_nth_match(1, m);
+ d = rb_reg_nth_match(2, m);
+ y = rb_reg_nth_match(3, m);
mon = INT2FIX(mon_num(mon));
@@ -797,9 +1078,9 @@ parse_sla_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d;
- y = f_aref(m, INT2FIX(1));
- mon = f_aref(m, INT2FIX(2));
- d = f_aref(m, INT2FIX(3));
+ y = rb_reg_nth_match(1, m);
+ mon = rb_reg_nth_match(2, m);
+ d = rb_reg_nth_match(3, m);
s3e(hash, y, mon, d, 0);
return 1;
@@ -821,9 +1102,9 @@ parse_dot_cb(VALUE m, VALUE hash)
{
VALUE y, mon, d;
- y = f_aref(m, INT2FIX(1));
- mon = f_aref(m, INT2FIX(2));
- d = f_aref(m, INT2FIX(3));
+ y = rb_reg_nth_match(1, m);
+ mon = rb_reg_nth_match(2, m);
+ d = rb_reg_nth_match(3, m);
s3e(hash, y, mon, d, 0);
return 1;
@@ -845,7 +1126,7 @@ parse_year_cb(VALUE m, VALUE hash)
{
VALUE y;
- y = f_aref(m, INT2FIX(1));
+ y = rb_reg_nth_match(1, m);
set_hash("year", str2num(y));
return 1;
}
@@ -865,7 +1146,7 @@ parse_mon_cb(VALUE m, VALUE hash)
{
VALUE mon;
- mon = f_aref(m, INT2FIX(1));
+ mon = rb_reg_nth_match(1, m);
set_hash("mon", INT2FIX(mon_num(mon)));
return 1;
}
@@ -885,7 +1166,7 @@ parse_mday_cb(VALUE m, VALUE hash)
{
VALUE d;
- d = f_aref(m, INT2FIX(1));
+ d = rb_reg_nth_match(1, m);
set_hash("mday", str2num(d));
return 1;
}
@@ -915,8 +1196,6 @@ n2i(const char *s, long f, long w)
return v;
}
-VALUE date_zone_to_diff(VALUE);
-
static int
parse_ddd_cb(VALUE m, VALUE hash)
{
@@ -924,11 +1203,11 @@ parse_ddd_cb(VALUE m, VALUE hash)
const char *cs2, *cs3, *cs5;
long l2, l3, l4, l5;
- s1 = f_aref(m, INT2FIX(1));
- s2 = f_aref(m, INT2FIX(2));
- s3 = f_aref(m, INT2FIX(3));
- s4 = f_aref(m, INT2FIX(4));
- s5 = f_aref(m, INT2FIX(5));
+ s1 = rb_reg_nth_match(1, m);
+ s2 = rb_reg_nth_match(2, m);
+ s3 = rb_reg_nth_match(3, m);
+ s4 = rb_reg_nth_match(4, m);
+ s5 = rb_reg_nth_match(5, m);
cs2 = RSTRING_PTR(s2);
l2 = RSTRING_LEN(s2);
@@ -1172,7 +1451,7 @@ parse_frag_cb(VALUE m, VALUE hash)
{
VALUE s, n;
- s = f_aref(m, INT2FIX(1));
+ s = rb_reg_nth_match(1, m);
if (!NIL_P(ref_hash("hour")) && NIL_P(ref_hash("mday"))) {
n = str2num(s);
@@ -1334,6 +1613,784 @@ date__parse(VALUE str, VALUE comp)
return hash;
}
+static VALUE
+comp_year69(VALUE y)
+{
+ if (f_ge_p(y, INT2FIX(69)))
+ return f_add(y, INT2FIX(1900));
+ return f_add(y, INT2FIX(2000));
+}
+
+static VALUE
+comp_year50(VALUE y)
+{
+ if (f_ge_p(y, INT2FIX(50)))
+ return f_add(y, INT2FIX(1900));
+ return f_add(y, INT2FIX(2000));
+}
+
+static VALUE
+sec_fraction(VALUE f)
+{
+ return rb_rational_new2(str2num(f),
+ f_expt(INT2FIX(10),
+ LONG2NUM(RSTRING_LEN(f))));
+}
+
+#define SNUM 14
+
+static int
+iso8601_ext_datetime_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1], y;
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ if (!NIL_P(s[3])) {
+ set_hash("mday", str2num(s[3]));
+ if (strcmp(RSTRING_PTR(s[1]), "-") != 0) {
+ y = str2num(s[1]);
+ if (RSTRING_LEN(s[1]) < 4)
+ y = comp_year69(y);
+ set_hash("year", y);
+ }
+ if (NIL_P(s[2])) {
+ if (strcmp(RSTRING_PTR(s[1]), "-") != 0)
+ return 0;
+ }
+ else
+ set_hash("mon", str2num(s[2]));
+ }
+ else if (!NIL_P(s[5])) {
+ set_hash("yday", str2num(s[5]));
+ if (!NIL_P(s[4])) {
+ y = str2num(s[4]);
+ if (RSTRING_LEN(s[4]) < 4)
+ y = comp_year69(y);
+ set_hash("year", y);
+ }
+ }
+ else if (!NIL_P(s[8])) {
+ set_hash("cweek", str2num(s[7]));
+ set_hash("cwday", str2num(s[8]));
+ if (!NIL_P(s[6])) {
+ y = str2num(s[6]);
+ if (RSTRING_LEN(s[6]) < 4)
+ y = comp_year69(y);
+ set_hash("cwyear", y);
+ }
+ }
+ else if (!NIL_P(s[9])) {
+ set_hash("cwday", str2num(s[9]));
+ }
+ if (!NIL_P(s[10])) {
+ set_hash("hour", str2num(s[10]));
+ set_hash("min", str2num(s[11]));
+ if (!NIL_P(s[12]))
+ set_hash("sec", str2num(s[12]));
+ }
+ if (!NIL_P(s[13])) {
+ set_hash("sec_fraction", sec_fraction(s[13]));
+ }
+ if (!NIL_P(s[14])) {
+ set_hash("zone", s[14]);
+ set_hash("offset", date_zone_to_diff(s[14]));
+ }
+
+ return 1;
+}
+
+static int
+iso8601_ext_datetime(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|"
+ "([-+]?\\d{2,})?-(\\d{3})|"
+ "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|"
+ "-w-(\\d))"
+ "(?:t"
+ "(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
+ "(z|[-+]\\d{2}(?::?\\d{2})?)?)?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, iso8601_ext_datetime_cb);
+}
+
+#undef SNUM
+#define SNUM 17
+
+static int
+iso8601_bas_datetime_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1], y;
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ if (!NIL_P(s[3])) {
+ set_hash("mday", str2num(s[3]));
+ if (strcmp(RSTRING_PTR(s[1]), "--") != 0) {
+ y = str2num(s[1]);
+ if (RSTRING_LEN(s[1]) < 4)
+ y = comp_year69(y);
+ set_hash("year", y);
+ }
+ if (*RSTRING_PTR(s[2]) == '-') {
+ if (strcmp(RSTRING_PTR(s[1]), "--") != 0)
+ return 0;
+ }
+ else
+ set_hash("mon", str2num(s[2]));
+ }
+ else if (!NIL_P(s[5])) {
+ set_hash("yday", str2num(s[5]));
+ y = str2num(s[4]);
+ if (RSTRING_LEN(s[4]) < 4)
+ y = comp_year69(y);
+ set_hash("year", y);
+ }
+ else if (!NIL_P(s[6])) {
+ set_hash("yday", str2num(s[6]));
+ }
+ else if (!NIL_P(s[9])) {
+ set_hash("cweek", str2num(s[8]));
+ set_hash("cwday", str2num(s[9]));
+ y = str2num(s[7]);
+ if (RSTRING_LEN(s[7]) < 4)
+ y = comp_year69(y);
+ set_hash("cwyear", y);
+ }
+ else if (!NIL_P(s[11])) {
+ set_hash("cweek", str2num(s[10]));
+ set_hash("cwday", str2num(s[11]));
+ }
+ else if (!NIL_P(s[12])) {
+ set_hash("cwday", str2num(s[12]));
+ }
+ if (!NIL_P(s[13])) {
+ set_hash("hour", str2num(s[13]));
+ set_hash("min", str2num(s[14]));
+ if (!NIL_P(s[15]))
+ set_hash("sec", str2num(s[15]));
+ }
+ if (!NIL_P(s[16])) {
+ set_hash("sec_fraction", sec_fraction(s[16]));
+ }
+ if (!NIL_P(s[17])) {
+ set_hash("zone", s[17]);
+ set_hash("offset", date_zone_to_diff(s[17]));
+ }
+
+ return 1;
+}
+
+static int
+iso8601_bas_datetime(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:([-+]?(?:\\d{4}|\\d{2})|--)(\\d{2}|-)(\\d{2})|"
+ "([-+]?(?:\\d{4}|\\d{2}))(\\d{3})|"
+ "-(\\d{3})|"
+ "(\\d{4}|\\d{2})w(\\d{2})(\\d)|"
+ "-w(\\d{2})(\\d)|"
+ "-w-(\\d))"
+ "(?:t?"
+ "(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
+ "(z|[-+]\\d{2}(?:\\d{2})?)?)?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, iso8601_bas_datetime_cb);
+}
+
+#undef SNUM
+#define SNUM 5
+
+static int
+iso8601_ext_time_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("hour", str2num(s[1]));
+ set_hash("min", str2num(s[2]));
+ if (!NIL_P(s[3]))
+ set_hash("sec", str2num(s[3]));
+ if (!NIL_P(s[4]))
+ set_hash("sec_fraction", sec_fraction(s[4]));
+ if (!NIL_P(s[5])) {
+ set_hash("zone", s[5]);
+ set_hash("offset", date_zone_to_diff(s[5]));
+ }
+
+ return 1;
+}
+
+#define iso8601_bas_time_cb iso8601_ext_time_cb
+
+static int
+iso8601_ext_time(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?"
+ "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, iso8601_ext_time_cb);
+}
+
+static int
+iso8601_bas_time(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?"
+ "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, iso8601_bas_time_cb);
+}
+
+VALUE
+date__iso8601(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+
+ if (iso8601_ext_datetime(str, hash))
+ goto ok;
+ if (iso8601_bas_datetime(str, hash))
+ goto ok;
+ if (iso8601_ext_time(str, hash))
+ goto ok;
+ if (iso8601_bas_time(str, hash))
+ goto ok;
+
+ ok:
+ rb_backref_set(backref);
+
+ return hash;
+}
+
+#undef SNUM
+#define SNUM 8
+
+static int
+rfc3339_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("year", str2num(s[1]));
+ set_hash("mon", str2num(s[2]));
+ set_hash("mday", str2num(s[3]));
+ set_hash("hour", str2num(s[4]));
+ set_hash("min", str2num(s[5]));
+ set_hash("sec", str2num(s[6]));
+ set_hash("zone", s[8]);
+ set_hash("offset", date_zone_to_diff(s[8]));
+ if (!NIL_P(s[7]))
+ set_hash("sec_fraction", sec_fraction(s[7]));
+
+ return 1;
+}
+
+static int
+rfc3339(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(-?\\d{4})-(\\d{2})-(\\d{2})"
+ "(?:t|\\s)"
+ "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
+ "(z|[-+]\\d{2}:\\d{2})\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, rfc3339_cb);
+}
+
+VALUE
+date__rfc3339(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+ rfc3339(str, hash);
+ rb_backref_set(backref);
+ return hash;
+}
+
+#undef SNUM
+#define SNUM 8
+
+static int
+xmlschema_datetime_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("year", str2num(s[1]));
+ if (!NIL_P(s[2]))
+ set_hash("mon", str2num(s[2]));
+ if (!NIL_P(s[3]))
+ set_hash("mday", str2num(s[3]));
+ if (!NIL_P(s[4]))
+ set_hash("hour", str2num(s[4]));
+ if (!NIL_P(s[5]))
+ set_hash("min", str2num(s[5]));
+ if (!NIL_P(s[6]))
+ set_hash("sec", str2num(s[6]));
+ if (!NIL_P(s[7]))
+ set_hash("sec_fraction", sec_fraction(s[7]));
+ if (!NIL_P(s[8])) {
+ set_hash("zone", s[8]);
+ set_hash("offset", date_zone_to_diff(s[8]));
+ }
+
+ return 1;
+}
+
+static int
+xmlschema_datetime(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(-?\\d{4,})(?:-(\\d{2})(?:-(\\d{2}))?)?"
+ "(?:t"
+ "(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?)?"
+ "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, xmlschema_datetime_cb);
+}
+
+#undef SNUM
+#define SNUM 5
+
+static int
+xmlschema_time_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("hour", str2num(s[1]));
+ set_hash("min", str2num(s[2]));
+ if (!NIL_P(s[3]))
+ set_hash("sec", str2num(s[3]));
+ if (!NIL_P(s[4]))
+ set_hash("sec_fraction", sec_fraction(s[4]));
+ if (!NIL_P(s[5])) {
+ set_hash("zone", s[5]);
+ set_hash("offset", date_zone_to_diff(s[5]));
+ }
+
+ return 1;
+}
+
+static int
+xmlschema_time(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(\\d{2}):(\\d{2}):(\\d{2})(?:\\.(\\d+))?"
+ "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, xmlschema_time_cb);
+}
+
+#undef SNUM
+#define SNUM 4
+
+static int
+xmlschema_trunc_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ if (!NIL_P(s[1]))
+ set_hash("mon", str2num(s[1]));
+ if (!NIL_P(s[2]))
+ set_hash("mday", str2num(s[2]));
+ if (!NIL_P(s[3]))
+ set_hash("mday", str2num(s[3]));
+ if (!NIL_P(s[4])) {
+ set_hash("zone", s[4]);
+ set_hash("offset", date_zone_to_diff(s[4]));
+ }
+
+ return 1;
+}
+
+static int
+xmlschema_trunc(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:--(\\d{2})(?:-(\\d{2}))?|---(\\d{2}))"
+ "(z|[-+]\\d{2}:\\d{2})?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, xmlschema_trunc_cb);
+}
+
+VALUE
+date__xmlschema(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+
+ if (xmlschema_datetime(str, hash))
+ goto ok;
+ if (xmlschema_time(str, hash))
+ goto ok;
+ if (xmlschema_trunc(str, hash))
+ goto ok;
+
+ ok:
+ rb_backref_set(backref);
+
+ return hash;
+}
+
+#undef SNUM
+#define SNUM 8
+
+static int
+rfc2822_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1], y;
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("wday", INT2FIX(day_num(s[1])));
+ set_hash("mday", str2num(s[2]));
+ set_hash("mon", INT2FIX(mon_num(s[3])));
+ y = str2num(s[4]);
+ if (RSTRING_LEN(s[4]) < 4)
+ y = comp_year50(y);
+ set_hash("year", y);
+ set_hash("hour", str2num(s[5]));
+ set_hash("min", str2num(s[6]));
+ if (!NIL_P(s[7]))
+ set_hash("sec", str2num(s[7]));
+ set_hash("zone", s[8]);
+ set_hash("offset", date_zone_to_diff(s[8]));
+
+ return 1;
+}
+
+static int
+rfc2822(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(?:(" ABBR_DAYS ")\\s*,\\s+)?"
+ "(\\d{1,2})\\s+"
+ "(" ABBR_MONTHS ")\\s+"
+ "(-?\\d{2,})\\s+"
+ "(\\d{2}):(\\d{2})(?::(\\d{2}))?\\s*"
+ "([-+]\\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, rfc2822_cb);
+}
+
+VALUE
+date__rfc2822(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+ rfc2822(str, hash);
+ rb_backref_set(backref);
+ return hash;
+}
+
+#undef SNUM
+#define SNUM 8
+
+static int
+httpdate_type1_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("wday", INT2FIX(day_num(s[1])));
+ set_hash("mday", str2num(s[2]));
+ set_hash("mon", INT2FIX(mon_num(s[3])));
+ set_hash("year", str2num(s[4]));
+ set_hash("hour", str2num(s[5]));
+ set_hash("min", str2num(s[6]));
+ set_hash("sec", str2num(s[7]));
+ set_hash("zone", s[8]);
+ set_hash("offset", INT2FIX(0));
+
+ return 1;
+}
+
+static int
+httpdate_type1(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(" ABBR_DAYS ")\\s*,\\s+"
+ "(\\d{2})\\s+"
+ "(" ABBR_MONTHS ")\\s+"
+ "(-?\\d{4})\\s+"
+ "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
+ "(gmt)\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, httpdate_type1_cb);
+}
+
+#undef SNUM
+#define SNUM 8
+
+static int
+httpdate_type2_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1], y;
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("wday", INT2FIX(day_num(s[1])));
+ set_hash("mday", str2num(s[2]));
+ set_hash("mon", INT2FIX(mon_num(s[3])));
+ y = str2num(s[4]);
+ if (f_ge_p(y, INT2FIX(0)) && f_le_p(y, INT2FIX(99)))
+ y = comp_year69(y);
+ set_hash("year", y);
+ set_hash("hour", str2num(s[5]));
+ set_hash("min", str2num(s[6]));
+ set_hash("sec", str2num(s[7]));
+ set_hash("zone", s[8]);
+ set_hash("offset", INT2FIX(0));
+
+ return 1;
+}
+
+static int
+httpdate_type2(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(" DAYS ")\\s*,\\s+"
+ "(\\d{2})\\s*-\\s*"
+ "(" ABBR_MONTHS ")\\s*-\\s*"
+ "(\\d{2})\\s+"
+ "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
+ "(gmt)\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, httpdate_type2_cb);
+}
+
+#undef SNUM
+#define SNUM 7
+
+static int
+httpdate_type3_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ set_hash("wday", INT2FIX(day_num(s[1])));
+ set_hash("mon", INT2FIX(mon_num(s[2])));
+ set_hash("mday", str2num(s[3]));
+ set_hash("hour", str2num(s[4]));
+ set_hash("min", str2num(s[5]));
+ set_hash("sec", str2num(s[6]));
+ set_hash("year", str2num(s[7]));
+
+ return 1;
+}
+
+static int
+httpdate_type3(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*(" ABBR_DAYS ")\\s+"
+ "(" ABBR_MONTHS ")\\s+"
+ "(\\d{1,2})\\s+"
+ "(\\d{2}):(\\d{2}):(\\d{2})\\s+"
+ "(\\d{4})\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, httpdate_type3_cb);
+}
+
+VALUE
+date__httpdate(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+
+ if (httpdate_type1(str, hash))
+ goto ok;
+ if (httpdate_type2(str, hash))
+ goto ok;
+ if (httpdate_type3(str, hash))
+ goto ok;
+
+ ok:
+ rb_backref_set(backref);
+
+ return hash;
+}
+
+#undef SNUM
+#define SNUM 9
+
+static int
+jisx0301_cb(VALUE m, VALUE hash)
+{
+ VALUE s[SNUM + 1];
+ int ep;
+
+ {
+ int i;
+ s[0] = Qnil;
+ for (i = 1; i <= SNUM; i++)
+ s[i] = rb_reg_nth_match(i, m);
+ }
+
+ ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1]));
+ set_hash("year", f_add(str2num(s[2]), INT2FIX(ep)));
+ set_hash("mon", str2num(s[3]));
+ set_hash("mday", str2num(s[4]));
+ if (!NIL_P(s[5])) {
+ set_hash("hour", str2num(s[5]));
+ if (!NIL_P(s[6]))
+ set_hash("min", str2num(s[6]));
+ if (!NIL_P(s[7]))
+ set_hash("sec", str2num(s[7]));
+ }
+ if (!NIL_P(s[8]))
+ set_hash("sec_fraction", sec_fraction(s[8]));
+ if (!NIL_P(s[9])) {
+ set_hash("zone", s[9]);
+ set_hash("offset", date_zone_to_diff(s[9]));
+ }
+
+ return 1;
+}
+
+static int
+jisx0301(VALUE str, VALUE hash)
+{
+ static const char pat_source[] =
+ "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})"
+ "(?:t"
+ "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?"
+ "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z";
+ static VALUE pat = Qnil;
+
+ REGCOMP_I(pat);
+ SUBS(str, pat, jisx0301_cb);
+}
+
+VALUE
+date__jisx0301(VALUE str)
+{
+ VALUE backref, hash;
+
+ backref = rb_backref_get();
+ rb_match_busy(backref);
+
+ hash = rb_hash_new();
+ if (jisx0301(str, hash))
+ goto ok;
+ hash = date__iso8601(str);
+
+ ok:
+ rb_backref_set(backref);
+ return hash;
+}
+
/*
Local variables:
c-file-style: "ruby"
diff --git a/ext/date/date_strftime.c b/ext/date/date_strftime.c
index 2b20f310f9..3596b52235 100644
--- a/ext/date/date_strftime.c
+++ b/ext/date/date_strftime.c
@@ -602,14 +602,12 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
continue;
#endif
-
#ifdef VMS_EXT
case 'v': /* date as dd-bbb-YYYY */
STRFTIME("%e-%^b-%4Y");
continue;
#endif
-
#ifdef POSIX2_DATE
case 'C':
FMTV('0', 2, "d", div(tmx->year, INT2FIX(100)));
@@ -677,7 +675,6 @@ date_strftime_with_tmx(char *s, size_t maxsize, const char *format,
#endif /* ISO_DATE_EXT */
-
case 'L':
w = 3;
goto subsec;
@@ -834,7 +831,6 @@ isleap(long year)
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
-
static void
tmx2tm_noyear(const struct tmx *tmx, struct tm *result)
{
diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c
index 897f5f8807..80b9e03278 100644
--- a/ext/date/date_strptime.c
+++ b/ext/date/date_strptime.c
@@ -40,6 +40,7 @@ static const char *extz_pats[] = {
#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 f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
#define f_mod(x,y) rb_funcall(x, '%', 1, y)
#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
@@ -559,7 +560,6 @@ date__strptime_internal(const char *str, size_t slen,
goto matched;
}
-
case 'Z':
case 'z':
{
@@ -585,7 +585,7 @@ date__strptime_internal(const char *str, size_t slen,
if (!NIL_P(m)) {
VALUE s, l, o;
- s = f_aref(m, INT2FIX(1));
+ s = rb_reg_nth_match(1, m);
l = f_end(m, INT2FIX(0));
o = date_zone_to_diff(s);
si += NUM2LONG(l);
diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb
index c6448017f7..d235d76e6f 100644
--- a/ext/date/lib/date.rb
+++ b/ext/date/lib/date.rb
@@ -1,239 +1,10 @@
-#
-# date.rb - date and time library
-#
-# Author: Tadayoshi Funaba 1998-2011
-#
-# Documentation: William Webber <william@williamwebber.com>
-#
-# == Overview
-#
-# This file provides two classes for working with
-# dates and times.
-#
-# The first class, Date, represents dates.
-# It works with years, months, weeks, and days.
-# See the Date class documentation for more details.
-#
-# The second, DateTime, extends Date to include hours,
-# minutes, seconds, and fractions of a second. It
-# provides basic support for time zones. See the
-# DateTime class documentation for more details.
-#
-# === Ways of calculating the date.
-#
-# In common usage, the date is reckoned in years since or
-# before the Common Era (CE/BCE, also known as AD/BC), then
-# as a month and day-of-the-month within the current year.
-# This is known as the *Civil* *Date*, and abbreviated
-# as +civil+ in the Date class.
-#
-# Instead of year, month-of-the-year, and day-of-the-month,
-# the date can also be reckoned in terms of year and
-# day-of-the-year. This is known as the *Ordinal* *Date*,
-# and is abbreviated as +ordinal+ in the Date class. (Note
-# that referring to this as the Julian date is incorrect.)
-#
-# The date can also be reckoned in terms of year, week-of-the-year,
-# and day-of-the-week. This is known as the *Commercial*
-# *Date*, and is abbreviated as +commercial+ in the
-# Date class. The commercial week runs Monday (day-of-the-week
-# 1) to Sunday (day-of-the-week 7), in contrast to the civil
-# week which runs Sunday (day-of-the-week 0) to Saturday
-# (day-of-the-week 6). The first week of the commercial year
-# starts on the Monday on or before January 1, and the commercial
-# year itself starts on this Monday, not January 1.
-#
-# For scientific purposes, it is convenient to refer to a date
-# simply as a day count, counting from an arbitrary initial
-# day. The date first chosen for this was January 1, 4713 BCE.
-# A count of days from this date is the *Julian* *Day* *Number*
-# or *Julian* *Date*, which is abbreviated as +jd+ in the
-# Date class. This is in local time, and counts from midnight
-# on the initial day. The stricter usage is in UTC, and counts
-# from midday on the initial day. This is referred to in the
-# Date class as the *Astronomical* *Julian* *Day* *Number*, and
-# abbreviated as +ajd+. In the Date class, the Astronomical
-# Julian Day Number includes fractional days.
-#
-# Another absolute day count is the *Modified* *Julian* *Day*
-# *Number*, which takes November 17, 1858 as its initial day.
-# This is abbreviated as +mjd+ in the Date class. There
-# is also an *Astronomical* *Modified* *Julian* *Day* *Number*,
-# which is in UTC and includes fractional days. This is
-# abbreviated as +amjd+ in the Date class. Like the Modified
-# Julian Day Number (and unlike the Astronomical Julian
-# Day Number), it counts from midnight.
-#
-# Alternative calendars such as the Ethiopic Solar Calendar,
-# the Islamic Lunar Calendar, or the French Revolutionary Calendar
-# are not supported by the Date class; nor are calendars that
-# are based on an Era different from the Common Era, such as
-# the Japanese Era.
-#
-# === Calendar Reform
-#
-# The standard civil year is 365 days long. However, the
-# solar year is fractionally longer than this. To account
-# for this, a *leap* *year* is occasionally inserted. This
-# is a year with 366 days, the extra day falling on February 29.
-# In the early days of the civil calendar, every fourth
-# year without exception was a leap year. This way of
-# reckoning leap years is the *Julian* *Calendar*.
-#
-# However, the solar year is marginally shorter than 365 1/4
-# days, and so the *Julian* *Calendar* gradually ran slow
-# over the centuries. To correct this, every 100th year
-# (but not every 400th year) was excluded as a leap year.
-# This way of reckoning leap years, which we use today, is
-# the *Gregorian* *Calendar*.
-#
-# The Gregorian Calendar was introduced at different times
-# in different regions. The day on which it was introduced
-# for a particular region is the *Day* *of* *Calendar*
-# *Reform* for that region. This is abbreviated as +sg+
-# (for Start of Gregorian calendar) in the Date class.
-#
-# Two such days are of particular
-# significance. The first is October 15, 1582, which was
-# the Day of Calendar Reform for Italy and most Catholic
-# countries. The second is September 14, 1752, which was
-# the Day of Calendar Reform for England and its colonies
-# (including what is now the United States). These two
-# dates are available as the constants Date::ITALY and
-# Date::ENGLAND, respectively. (By comparison, Germany and
-# Holland, less Catholic than Italy but less stubborn than
-# England, changed over in 1698; Sweden in 1753; Russia not
-# till 1918, after the Revolution; and Greece in 1923. Many
-# Orthodox churches still use the Julian Calendar. A complete
-# list of Days of Calendar Reform can be found at
-# http://www.polysyllabic.com/GregConv.html.)
-#
-# Switching from the Julian to the Gregorian calendar
-# involved skipping a number of days to make up for the
-# accumulated lag, and the later the switch was (or is)
-# done, the more days need to be skipped. So in 1582 in Italy,
-# 4th October was followed by 15th October, skipping 10 days; in 1752
-# in England, 2nd September was followed by 14th September, skipping
-# 11 days; and if I decided to switch from Julian to Gregorian
-# Calendar this midnight, I would go from 27th July 2003 (Julian)
-# today to 10th August 2003 (Gregorian) tomorrow, skipping
-# 13 days. The Date class is aware of this gap, and a supposed
-# date that would fall in the middle of it is regarded as invalid.
-#
-# The Day of Calendar Reform is relevant to all date representations
-# involving years. It is not relevant to the Julian Day Numbers,
-# except for converting between them and year-based representations.
-#
-# In the Date and DateTime classes, the Day of Calendar Reform or
-# +sg+ can be specified a number of ways. First, it can be as
-# the Julian Day Number of the Day of Calendar Reform. Second,
-# it can be using the constants Date::ITALY or Date::ENGLAND; these
-# are in fact the Julian Day Numbers of the Day of Calendar Reform
-# of the respective regions. Third, it can be as the constant
-# Date::JULIAN, which means to always use the Julian Calendar.
-# Finally, it can be as the constant Date::GREGORIAN, which means
-# to always use the Gregorian Calendar.
-#
-# Note: in the Julian Calendar, New Years Day was March 25. The
-# Date class does not follow this convention.
-#
-# === Offsets
-#
-# DateTime objects support a simple representation
-# of offsets. Offsets are represented as an offset
-# from UTC (UTC is not identical GMT; GMT is a historical term),
-# as a fraction of a day. This offset is the
-# how much local time is later (or earlier) than UTC.
-# As you travel east, the offset increases until you
-# reach the dateline in the middle of the Pacific Ocean;
-# as you travel west, the offset decreases. This offset
-# is abbreviated as +of+ in the Date class.
-#
-# This simple representation of offsets does not take
-# into account the common practice of Daylight Savings
-# Time or Summer Time.
-#
-# Most DateTime methods return the date and the
-# time in local time. The two exceptions are
-# #ajd() and #amjd(), which return the date and time
-# in UTC time, including fractional days.
-#
-# The Date class does not support offsets, in that
-# there is no way to create a Date object with non-utc offset.
-#
-# == Examples of use
-#
-# === Print out the date of every Sunday between two dates.
-#
-# def print_sundays(d1, d2)
-# d1 += 1 until d1.sunday?
-# d1.step(d2, 7) do |d|
-# puts d.strftime('%B %-d')
-# end
-# end
-#
-# print_sundays(Date.new(2003, 4, 8), Date.new(2003, 5, 23))
+# date.rb: Written by Tadayoshi Funaba 1998-2011
+require 'date_core'
require 'date/format'
-# Class representing a date.
-#
-# See the documentation to the file date.rb for an overview.
-#
-# Internally, the date is represented as an Astronomical
-# Julian Day Number, +ajd+. The Day of Calendar Reform, +sg+, is
-# also stored, for conversions to other date formats. (There
-# is also an +of+ field for a time zone offset, but this
-# is only for the use of the DateTime subclass.)
-#
-# A new Date object is created using one of the object creation
-# class methods named after the corresponding date format, and the
-# arguments appropriate to that date format; for instance,
-# Date::civil() (aliased to Date::new()) with year, month,
-# and day-of-month, or Date::ordinal() with year and day-of-year.
-# All of these object creation class methods also take the
-# Day of Calendar Reform as an optional argument.
-#
-# Date objects are immutable once created.
-#
-# Once a Date has been created, date values
-# can be retrieved for the different date formats supported
-# using instance methods. For instance, #mon() gives the
-# Civil month, #cwday() gives the Commercial day of the week,
-# and #yday() gives the Ordinal day of the year. Date values
-# can be retrieved in any format, regardless of what format
-# was used to create the Date instance.
-#
-# The Date class includes the Comparable module, allowing
-# date objects to be compared and sorted, ranges of dates
-# to be created, and so forth.
class Date
- include Comparable
-
- # Full month names, in English. Months count from 1 to 12; a
- # month's numerical representation indexed into this array
- # gives the name of that month (hence the first element is nil).
- MONTHNAMES = [nil] + %w(January February March April May June July
- August September October November December)
-
- # Full names of days of the week, in English. Days of the week
- # count from 0 to 6 (except in the commercial week); a day's numerical
- # representation indexed into this array gives the name of that day.
- DAYNAMES = %w(Sunday Monday Tuesday Wednesday Thursday Friday Saturday)
-
- # Abbreviated month names, in English.
- ABBR_MONTHNAMES = [nil] + %w(Jan Feb Mar Apr May Jun
- Jul Aug Sep Oct Nov Dec)
-
- # Abbreviated day names, in English.
- ABBR_DAYNAMES = %w(Sun Mon Tue Wed Thu Fri Sat)
-
- [MONTHNAMES, DAYNAMES, ABBR_MONTHNAMES, ABBR_DAYNAMES].each do |xs|
- xs.each{|x| x.freeze unless x.nil?}.freeze
- end
-
- # now only for marshal dumped
class Infinity < Numeric # :nodoc:
include Comparable
@@ -287,1361 +58,4 @@ class Date
end
- # The Julian Day Number of the Day of Calendar Reform for Italy
- # and the Catholic countries.
- ITALY = 2299161 # 1582-10-15
-
- # The Julian Day Number of the Day of Calendar Reform for England
- # and her Colonies.
- ENGLAND = 2361222 # 1752-09-14
-
- # A constant used to indicate that a Date should always use the
- # Julian calendar.
- JULIAN = Float::INFINITY
-
- # A constant used to indicate that a Date should always use the
- # Gregorian calendar.
- GREGORIAN = -Float::INFINITY
-
- HALF_DAYS_IN_DAY = Rational(1, 2) # :nodoc:
- HOURS_IN_DAY = Rational(1, 24) # :nodoc:
- MINUTES_IN_DAY = Rational(1, 1440) # :nodoc:
- SECONDS_IN_DAY = Rational(1, 86400) # :nodoc:
- MILLISECONDS_IN_DAY = Rational(1, 86400*10**3) # :nodoc:
- NANOSECONDS_IN_DAY = Rational(1, 86400*10**9) # :nodoc:
- MILLISECONDS_IN_SECOND = Rational(1, 10**3) # :nodoc:
- NANOSECONDS_IN_SECOND = Rational(1, 10**9) # :nodoc:
-
- MJD_EPOCH_IN_AJD = Rational(4800001, 2) # 1858-11-17 # :nodoc:
- UNIX_EPOCH_IN_AJD = Rational(4881175, 2) # 1970-01-01 # :nodoc:
- MJD_EPOCH_IN_CJD = 2400001 # :nodoc:
- UNIX_EPOCH_IN_CJD = 2440588 # :nodoc:
- LD_EPOCH_IN_CJD = 2299160 # :nodoc:
-
- t = Module.new do
-
- private
-
- def find_fdoy(y, sg) # :nodoc:
- j = nil
- 1.upto(31) do |d|
- break if j = _valid_civil_r?(y, 1, d, sg)
- end
- j
- end
-
- def find_ldoy(y, sg) # :nodoc:
- j = nil
- 31.downto(1) do |d|
- break if j = _valid_civil_r?(y, 12, d, sg)
- end
- j
- end
-
- def find_fdom(y, m, sg) # :nodoc:
- j = nil
- 1.upto(31) do |d|
- break if j = _valid_civil_r?(y, m, d, sg)
- end
- j
- end
-
- def find_ldom(y, m, sg) # :nodoc:
- j = nil
- 31.downto(1) do |d|
- break if j = _valid_civil_r?(y, m, d, sg)
- end
- j
- end
-
- # Convert an Ordinal Date to a Julian Day Number.
- #
- # +y+ and +d+ are the year and day-of-year to convert.
- # +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Julian Day Number.
- def ordinal_to_jd(y, d, sg=GREGORIAN) # :nodoc:
- find_fdoy(y, sg) + d - 1
- end
-
- # Convert a Julian Day Number to an Ordinal Date.
- #
- # +jd+ is the Julian Day Number to convert.
- # +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Ordinal Date as
- # [year, day_of_year]
- def jd_to_ordinal(jd, sg=GREGORIAN) # :nodoc:
- y = jd_to_civil(jd, sg)[0]
- j = find_fdoy(y, sg)
- doy = jd - j + 1
- return y, doy
- end
-
- # Convert a Civil Date to a Julian Day Number.
- # +y+, +m+, and +d+ are the year, month, and day of the
- # month. +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Julian Day Number.
- def civil_to_jd(y, m, d, sg=GREGORIAN) # :nodoc:
- if m <= 2
- y -= 1
- m += 12
- end
- a = (y / 100.0).floor
- b = 2 - a + (a / 4.0).floor
- jd = (365.25 * (y + 4716)).floor +
- (30.6001 * (m + 1)).floor +
- d + b - 1524
- if jd < sg
- jd -= b
- end
- jd
- end
-
- # Convert a Julian Day Number to a Civil Date. +jd+ is
- # the Julian Day Number. +sg+ specifies the Day of
- # Calendar Reform.
- #
- # Returns the corresponding [year, month, day_of_month]
- # as a three-element array.
- def jd_to_civil(jd, sg=GREGORIAN) # :nodoc:
- if jd < sg
- a = jd
- else
- x = ((jd - 1867216.25) / 36524.25).floor
- a = jd + 1 + x - (x / 4.0).floor
- end
- b = a + 1524
- c = ((b - 122.1) / 365.25).floor
- d = (365.25 * c).floor
- e = ((b - d) / 30.6001).floor
- dom = b - d - (30.6001 * e).floor
- if e <= 13
- m = e - 1
- y = c - 4716
- else
- m = e - 13
- y = c - 4715
- end
- return y, m, dom
- end
-
- # Convert a Commercial Date to a Julian Day Number.
- #
- # +y+, +w+, and +d+ are the (commercial) year, week of the year,
- # and day of the week of the Commercial Date to convert.
- # +sg+ specifies the Day of Calendar Reform.
- def commercial_to_jd(y, w, d, sg=GREGORIAN) # :nodoc:
- j = find_fdoy(y, sg) + 3
- (j - (((j - 1) + 1) % 7)) +
- 7 * (w - 1) +
- (d - 1)
- end
-
- # Convert a Julian Day Number to a Commercial Date
- #
- # +jd+ is the Julian Day Number to convert.
- # +sg+ specifies the Day of Calendar Reform.
- #
- # Returns the corresponding Commercial Date as
- # [commercial_year, week_of_year, day_of_week]
- def jd_to_commercial(jd, sg=GREGORIAN) # :nodoc:
- a = jd_to_civil(jd - 3, sg)[0]
- 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
- end
-
- def weeknum_to_jd(y, w, d, f=0, sg=GREGORIAN) # :nodoc:
- a = find_fdoy(y, sg) + 6
- (a - ((a - f) + 1) % 7 - 7) + 7 * w + d
- end
-
- def jd_to_weeknum(jd, f=0, sg=GREGORIAN) # :nodoc:
- y, _, d = jd_to_civil(jd, sg)
- a = find_fdoy(y, sg) + 6
- w, d = (jd - (a - ((a - f) + 1) % 7) + 7).divmod(7)
- return y, w, d
- end
-
- def nth_kday_to_jd(y, m, n, k, sg=GREGORIAN) # :nodoc:
- j = if n > 0
- find_fdom(y, m, sg) - 1
- else
- find_ldom(y, m, sg) + 7
- end
- (j - (((j - k) + 1) % 7)) + 7 * n
- end
-
- def jd_to_nth_kday(jd, sg=GREGORIAN) # :nodoc:
- y, m, = jd_to_civil(jd, sg)
- j = find_fdom(y, m, sg)
- return y, m, ((jd - j) / 7).floor + 1, jd_to_wday(jd)
- end
-
- # Convert an Astronomical Julian Day Number to a (civil) Julian
- # Day Number.
- #
- # +ajd+ is the Astronomical Julian Day Number to convert.
- # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
- #
- # Returns the (civil) Julian Day Number as [day_number,
- # fraction] where +fraction+ is always 1/2.
- def ajd_to_jd(ajd, of=0) (ajd + of + HALF_DAYS_IN_DAY).divmod(1) end # :nodoc:
-
- # Convert a (civil) Julian Day Number to an Astronomical Julian
- # Day Number.
- #
- # +jd+ is the Julian Day Number to convert, and +fr+ is a
- # fractional day.
- # +of+ is the offset from UTC as a fraction of a day (defaults to 0).
- #
- # Returns the Astronomical Julian Day Number as a single
- # numeric value.
- def jd_to_ajd(jd, fr, of=0) jd + fr - of - HALF_DAYS_IN_DAY end # :nodoc:
-
- # Convert a fractional day +fr+ to [hours, minutes, seconds,
- # fraction_of_a_second]
- def day_fraction_to_time(fr) # :nodoc:
- ss, fr = fr.divmod(SECONDS_IN_DAY) # 4p
- h, ss = ss.divmod(3600)
- min, s = ss.divmod(60)
- return h, min, s, fr * 86400
- end
-
- def day_fraction_to_time_wo_sf(fr) # :nodoc:
- ss = fr.div(SECONDS_IN_DAY) # 4p
- h, ss = ss.divmod(3600)
- min, s = ss.divmod(60)
- return h, min, s
- end
-
- # Convert an +h+ hour, +min+ minutes, +s+ seconds period
- # to a fractional day.
- begin
- Rational(Rational(1, 2), 2) # a challenge
-
- def time_to_day_fraction(h, min, s)
- Rational(h * 3600 + min * 60 + s, 86400) # 4p
- end
- rescue
- def time_to_day_fraction(h, min, s)
- if Integer === h && Integer === min && Integer === s
- Rational(h * 3600 + min * 60 + s, 86400) # 4p
- else
- (h * 3600 + min * 60 + s).to_r/86400 # 4p
- end
- end
- end
-
- # Convert an Astronomical Modified Julian Day Number to an
- # Astronomical Julian Day Number.
- def amjd_to_ajd(amjd) amjd + MJD_EPOCH_IN_AJD end # :nodoc:
-
- # Convert an Astronomical Julian Day Number to an
- # Astronomical Modified Julian Day Number.
- def ajd_to_amjd(ajd) ajd - MJD_EPOCH_IN_AJD end # :nodoc:
-
- # Convert a Modified Julian Day Number to a Julian
- # Day Number.
- def mjd_to_jd(mjd) mjd + MJD_EPOCH_IN_CJD end # :nodoc:
-
- # Convert a Julian Day Number to a Modified Julian Day
- # Number.
- def jd_to_mjd(jd) jd - MJD_EPOCH_IN_CJD end # :nodoc:
-
- # Convert a count of the number of days since the adoption
- # of the Gregorian Calendar (in Italy) to a Julian Day Number.
- def ld_to_jd(ld) ld + LD_EPOCH_IN_CJD end # :nodoc:
-
- # Convert a Julian Day Number to the number of days since
- # the adoption of the Gregorian Calendar (in Italy).
- def jd_to_ld(jd) jd - LD_EPOCH_IN_CJD end # :nodoc:
-
- # Convert a Julian Day Number to the day of the week.
- #
- # Sunday is day-of-week 0; Saturday is day-of-week 6.
- def jd_to_wday(jd) (jd + 1) % 7 end # :nodoc:
-
- # Is +jd+ a valid Julian Day Number?
- #
- # If it is, returns it. In fact, any value is treated as a valid
- # Julian Day Number.
- def _valid_jd_r? (jd, sg=GREGORIAN) jd end # :nodoc:
-
- # Do the year +y+ and day-of-year +d+ make a valid Ordinal Date?
- # Returns the corresponding Julian Day Number if they do, or
- # nil if they don't.
- #
- # +d+ can be a negative number, in which case it counts backwards
- # from the end of the year (-1 being the last day of the year).
- # No year wraparound is performed, however, so valid values of
- # +d+ are -365 .. -1, 1 .. 365 on a non-leap-year,
- # -366 .. -1, 1 .. 366 on a leap year.
- # A date falling in the period skipped in the Day of Calendar Reform
- # adjustment is not valid.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def _valid_ordinal_r? (y, d, sg=GREGORIAN) # :nodoc:
- if d < 0
- return unless j = find_ldoy(y, sg)
- ny, nd = jd_to_ordinal(j + d + 1, sg)
- return unless ny == y
- d = nd
- end
- jd = ordinal_to_jd(y, d, sg)
- return unless [y, d] == jd_to_ordinal(jd, sg)
- jd
- end
-
- # Do year +y+, month +m+, and day-of-month +d+ make a
- # valid Civil Date? Returns the corresponding Julian
- # Day Number if they do, nil if they don't.
- #
- # +m+ and +d+ can be negative, in which case they count
- # backwards from the end of the year and the end of the
- # month respectively. No wraparound is performed, however,
- # and invalid values cause an ArgumentError to be raised.
- # A date falling in the period skipped in the Day of Calendar
- # Reform adjustment is not valid.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def _valid_civil_r? (y, m, d, sg=GREGORIAN) # :nodoc:
- if m < 0
- m += 13
- end
- if d < 0
- return unless j = find_ldom(y, m, sg)
- ny, nm, nd = jd_to_civil(j + d + 1, sg)
- return unless [ny, nm] == [y, m]
- d = nd
- end
- jd = civil_to_jd(y, m, d, sg)
- return unless [y, m, d] == jd_to_civil(jd, sg)
- jd
- end
-
- # Do year +y+, week-of-year +w+, and day-of-week +d+ make a
- # valid Commercial Date? Returns the corresponding Julian
- # Day Number if they do, nil if they don't.
- #
- # Monday is day-of-week 1; Sunday is day-of-week 7.
- #
- # +w+ and +d+ can be negative, in which case they count
- # backwards from the end of the year and the end of the
- # week respectively. No wraparound is performed, however,
- # and invalid values cause an ArgumentError to be raised.
- # A date falling in the period skipped in the Day of Calendar
- # Reform adjustment is not valid.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def _valid_commercial_r? (y, w, d, sg=GREGORIAN) # :nodoc:
- if d < 0
- d += 8
- end
- if w < 0
- ny, nw, =
- jd_to_commercial(commercial_to_jd(y + 1, 1, 1, sg) + w * 7, sg)
- return unless ny == y
- w = nw
- end
- jd = commercial_to_jd(y, w, d, sg)
- return unless [y, w, d] == jd_to_commercial(jd, sg)
- jd
- end
-
- def _valid_weeknum_r? (y, w, d, f, sg=GREGORIAN) # :nodoc:
- if d < 0
- d += 7
- end
- if w < 0
- ny, nw, =
- jd_to_weeknum(weeknum_to_jd(y + 1, 1, f, f, sg) + w * 7, f, sg)
- return unless ny == y
- w = nw
- end
- jd = weeknum_to_jd(y, w, d, f, sg)
- return unless [y, w, d] == jd_to_weeknum(jd, f, sg)
- jd
- end
-
- def _valid_nth_kday_r? (y, m, n, k, sg=GREGORIAN) # :nodoc:
- if k < 0
- k += 7
- end
- if n < 0
- ny, nm = (y * 12 + m).divmod(12)
- nm, = (nm + 1) .divmod(1)
- ny, nm, nn, =
- jd_to_nth_kday(nth_kday_to_jd(ny, nm, 1, k, sg) + n * 7, sg)
- return unless [ny, nm] == [y, m]
- n = nn
- end
- jd = nth_kday_to_jd(y, m, n, k, sg)
- return unless [y, m, n, k] == jd_to_nth_kday(jd, sg)
- jd
- end
-
- # Do hour +h+, minute +min+, and second +s+ constitute a valid time?
- #
- # If they do, returns their value as a fraction of a day. If not,
- # returns nil.
- #
- # The 24-hour clock is used. Negative values of +h+, +min+, and
- # +sec+ are treating as counting backwards from the end of the
- # next larger unit (e.g. a +min+ of -2 is treated as 58). No
- # wraparound is performed.
- def _valid_time_r? (h, min, s) # :nodoc:
- h += 24 if h < 0
- min += 60 if min < 0
- s += 60 if s < 0
- return unless ((0...24) === h &&
- (0...60) === min &&
- (0...60) === s) ||
- (24 == h &&
- 0 == min &&
- 0 == s)
- time_to_day_fraction(h, min, s)
- end
-
- end
-
- extend t
- include t
-
- # Is a year a leap year in the Julian calendar?
- #
- # All years divisible by 4 are leap years in the Julian calendar.
- def self.julian_leap? (y) y % 4 == 0 end
-
- # Is a year a leap year in the Gregorian calendar?
- #
- # All years divisible by 4 are leap years in the Gregorian calendar,
- # except for years divisible by 100 and not by 400.
- def self.gregorian_leap? (y) y % 4 == 0 && y % 100 != 0 || y % 400 == 0 end
-
- class << self; alias_method :leap?, :gregorian_leap? end
-
- 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
-
- def self.jd_r(jd=0, sg=ITALY) # :nodoc:
- jd = _valid_jd_r?(jd, sg)
- new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :jd_r
-
- def self.ordinal_r(y=-4712, d=1, sg=ITALY) # :nodoc:
- unless jd = _valid_ordinal_r?(y, d, sg)
- raise ArgumentError, 'invalid date'
- end
- new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :ordinal_r
-
- def self.civil_r(y=-4712, m=1, d=1, sg=ITALY) # :nodoc:
- unless jd = _valid_civil_r?(y, m, d, sg)
- raise ArgumentError, 'invalid date'
- end
- new_r!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :civil_r
-
- def self.commercial_r(y=-4712, w=1, d=1, sg=ITALY) # :nodoc:
- unless jd = _valid_commercial_r?(y, w, d, sg)
- raise ArgumentError, 'invalid date'
- end
- 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_r?(y, w, d, f, sg)
- raise ArgumentError, 'invalid date'
- end
- new!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :weeknum
-
- def self.nth_kday(y=-4712, m=1, n=1, k=1, sg=ITALY)
- unless jd = _valid_nth_kday_r?(y, m, n, k, sg)
- raise ArgumentError, 'invalid date'
- end
- new!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :nth_kday
-
- def self.rewrite_frags(elem) # :nodoc:
- elem ||= {}
- if seconds = elem[:seconds]
- d, fr = seconds.divmod(86400)
- h, fr = fr.divmod(3600)
- min, fr = fr.divmod(60)
- s, fr = fr.divmod(1)
- elem[:jd] = UNIX_EPOCH_IN_CJD + d
- elem[:hour] = h
- elem[:min] = min
- elem[:sec] = s
- elem[:sec_fraction] = fr
- elem.delete(:seconds)
- elem.delete(:offset)
- end
- elem
- end
-
- private_class_method :rewrite_frags
-
- def self.complete_frags(elem) # :nodoc:
- i = 0
- g = [[:time, [:hour, :min, :sec]],
- [nil, [:jd]],
- [:ordinal, [:year, :yday, :hour, :min, :sec]],
- [:civil, [:year, :mon, :mday, :hour, :min, :sec]],
- [:commercial, [:cwyear, :cweek, :cwday, :hour, :min, :sec]],
- [:wday, [:wday, :hour, :min, :sec]],
- [:wnum0, [:year, :wnum0, :wday, :hour, :min, :sec]],
- [:wnum1, [:year, :wnum1, :wday, :hour, :min, :sec]],
- [nil, [:cwyear, :cweek, :wday, :hour, :min, :sec]],
- [nil, [:year, :wnum0, :cwday, :hour, :min, :sec]],
- [nil, [:year, :wnum1, :cwday, :hour, :min, :sec]]].
- collect{|k, a| e = elem.values_at(*a).compact; [k, a, e]}.
- select{|k, a, e| e.size > 0}.
- sort_by{|k, a, e| [e.size, i -= 1]}.last
-
- d = nil
-
- if g && g[0] && (g[1].size - g[2].size) != 0
- d ||= Date.today
-
- case g[0]
- when :ordinal
- elem[:year] ||= d.year
- elem[:yday] ||= 1
- when :civil
- g[1].each do |e|
- break if elem[e]
- elem[e] = d.__send__(e)
- end
- elem[:mon] ||= 1
- elem[:mday] ||= 1
- when :commercial
- g[1].each do |e|
- break if elem[e]
- elem[e] = d.__send__(e)
- end
- elem[:cweek] ||= 1
- elem[:cwday] ||= 1
- when :wday
- elem[:jd] ||= (d - d.wday + elem[:wday]).jd
- when :wnum0
- g[1].each do |e|
- break if elem[e]
- elem[e] = d.__send__(e)
- end
- elem[:wnum0] ||= 0
- elem[:wday] ||= 0
- when :wnum1
- g[1].each do |e|
- break if elem[e]
- elem[e] = d.__send__(e)
- end
- elem[:wnum1] ||= 0
- elem[:wday] ||= 1
- end
- end
-
- if g && g[0] == :time
- if self <= DateTime
- d ||= Date.today
- elem[:jd] ||= d.jd
- end
- end
-
- elem[:hour] ||= 0
- elem[:min] ||= 0
- elem[:sec] ||= 0
- elem[:sec] = [elem[:sec], 59].min
-
- elem
- end
-
- private_class_method :complete_frags
-
- def self.valid_date_frags?(elem, sg) # :nodoc:
- catch :jd do
- a = elem.values_at(:jd)
- if a.all?
- if jd = _valid_jd_r?(*(a << sg))
- throw :jd, jd
- end
- end
-
- a = elem.values_at(:year, :yday)
- if a.all?
- if jd = _valid_ordinal_r?(*(a << sg))
- throw :jd, jd
- end
- end
-
- a = elem.values_at(:year, :mon, :mday)
- if a.all?
- if jd = _valid_civil_r?(*(a << sg))
- throw :jd, jd
- end
- end
-
- a = elem.values_at(:cwyear, :cweek, :cwday)
- if a[2].nil? && elem[:wday]
- a[2] = elem[:wday].nonzero? || 7
- end
- if a.all?
- if jd = _valid_commercial_r?(*(a << sg))
- throw :jd, jd
- end
- end
-
- a = elem.values_at(:year, :wnum0, :wday)
- if a[2].nil? && elem[:cwday]
- a[2] = elem[:cwday] % 7
- end
- if a.all?
- if jd = _valid_weeknum_r?(*(a << 0 << sg))
- throw :jd, jd
- end
- end
-
- a = elem.values_at(:year, :wnum1, :wday)
- if a[2]
- a[2] = (a[2] - 1) % 7
- end
- if a[2].nil? && elem[:cwday]
- a[2] = (elem[:cwday] - 1) % 7
- end
- if a.all?
- if jd = _valid_weeknum_r?(*(a << 1 << sg))
- throw :jd, jd
- end
- end
- end
- end
-
- private_class_method :valid_date_frags?
-
- def self.valid_time_frags? (elem) # :nodoc:
- h, min, s = elem.values_at(:hour, :min, :sec)
- _valid_time_r?(h, min, s)
- end
-
- private_class_method :valid_time_frags?
-
- def self.new_by_frags(elem, sg) # :nodoc:
- elem = rewrite_frags(elem)
- elem = complete_frags(elem)
- unless jd = valid_date_frags?(elem, sg)
- raise ArgumentError, 'invalid date'
- end
- new!(jd_to_ajd(jd, 0, 0), 0, sg)
- end
-
- private_class_method :new_by_frags
-
- # Create a new Date object by parsing from a String
- # according to a specified format.
- #
- # +str+ is a String holding a date representation.
- # +fmt+ is the format that the date is in. See
- # date/format.rb for details on supported formats.
- #
- # The default +str+ is '-4712-01-01', and the default
- # +fmt+ is '%F', which means Year-Month-Day_of_Month.
- # This gives Julian Day Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- #
- # An ArgumentError will be raised if +str+ cannot be
- # parsed.
- def self.strptime(str='-4712-01-01', fmt='%F', sg=ITALY)
- elem = _strptime(str, fmt)
- new_by_frags(elem, sg)
- end
-
- # Create a new Date object by parsing from a String,
- # without specifying the format.
- #
- # +str+ is a String holding a date representation.
- # +comp+ specifies whether to interpret 2-digit years
- # as 19XX (>= 69) or 20XX (< 69); the default is to.
- # The method will attempt to parse a date from the String
- # using various heuristics; see #_parse in date/format.rb
- # for more details. If parsing fails, an ArgumentError
- # will be raised.
- #
- # The default +str+ is '-4712-01-01'; this is Julian
- # Day Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def self.parse(str='-4712-01-01', comp=true, sg=ITALY)
- elem = _parse(str, comp)
- new_by_frags(elem, sg)
- end
-
- def self.iso8601(str='-4712-01-01', sg=ITALY) # :nodoc:
- elem = _iso8601(str)
- new_by_frags(elem, sg)
- end
-
- def self.rfc3339(str='-4712-01-01T00:00:00+00:00', sg=ITALY) # :nodoc:
- elem = _rfc3339(str)
- new_by_frags(elem, sg)
- end
-
- def self.xmlschema(str='-4712-01-01', sg=ITALY) # :nodoc:
- elem = _xmlschema(str)
- new_by_frags(elem, sg)
- end
-
- def self.rfc2822(str='Mon, 1 Jan -4712 00:00:00 +0000', sg=ITALY) # :nodoc:
- elem = _rfc2822(str)
- new_by_frags(elem, sg)
- end
-
- class << self; alias_method :rfc822, :rfc2822 end
-
- def self.httpdate(str='Mon, 01 Jan -4712 00:00:00 GMT', sg=ITALY) # :nodoc:
- elem = _httpdate(str)
- new_by_frags(elem, sg)
- end
-
- def self.jisx0301(str='-4712-01-01', sg=ITALY) # :nodoc:
- elem = _jisx0301(str)
- new_by_frags(elem, sg)
- end
-
- class << self
-
- def once(*ids) # :nodoc: -- restricted
- for id in ids
- module_eval <<-"end;"
- 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)
- end
- end;
- end
- end # <<dummy
-
- private :once
-
- end
-
- def amjd_r() ajd_to_amjd(ajd) end
-
- once :amjd_r
-
- def daynum() ajd_to_jd(ajd, offset) end
-
- once :daynum
- private :daynum
-
- def jd_r() daynum[0] end # :nodoc:
- def day_fraction_r() daynum[1] end # :nodoc:
- def mjd_r() jd_to_mjd(jd) end # :nodoc:
- def ld_r() jd_to_ld(jd) end # :nodoc:
-
- once :jd_r, :day_fraction_r, :mjd_r, :ld_r
- private :jd_r, :day_fraction_r, :mjd_r, :ld_r
-
- def civil() jd_to_civil(jd, start) end # :nodoc:
- def ordinal() jd_to_ordinal(jd, start) end # :nodoc:
- def commercial() jd_to_commercial(jd, start) 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
-
- def year_r() civil[0] end # :nodoc:
- def yday_r() ordinal[1] end # :nodoc:
- def mon_r() civil[1] end # :nodoc:
- def mday_r() civil[2] end # :nodoc:
-
- private :year_r, :yday_r, :mon_r, :mday_r
-
- def wnum0_r() weeknum0[1] end # :nodoc:
- def wnum1_r() weeknum1[1] end # :nodoc:
-
- private :wnum0_r, :wnum1_r
-
- def time() day_fraction_to_time(day_fraction) end # :nodoc:
- def time_wo_sf() day_fraction_to_time_wo_sf(day_fraction) end # :nodoc:
- def time_sf() day_fraction % SECONDS_IN_DAY * 86400 end # :nodoc:
-
- once :time, :time_wo_sf, :time_sf
- private :time, :time_wo_sf, :time_sf
-
- def hour_r() time_wo_sf[0] end # :nodoc: # 4p
- def min_r() time_wo_sf[1] end # :nodoc: # 4p
- def sec_r() time_wo_sf[2] end # :nodoc: # 4p
- def sec_fraction_r() time_sf end # 4p
-
- private :hour_r, :min_r, :sec_r, :sec_fraction_r
-
- def zone_r # :nodoc: # 4p - strftime('%:z')
- sign = if offset < 0 then '-' else '+' end
- fr = offset.abs
- ss = fr.div(SECONDS_IN_DAY)
- hh, ss = ss.divmod(3600)
- mm = ss.div(60)
- format('%s%02d:%02d', sign, hh, mm)
- end
-
- private :zone_r
-
- def cwyear_r() commercial[0] end # :nodoc:
- def cweek_r() commercial[1] end # :nodoc:
- def cwday_r() commercial[2] end # :nodoc:
-
- private :cwyear_r, :cweek_r, :cwday_r
-
- def wday_r() jd_to_wday(jd) end # :nodoc:
-
- once :wday_r
- private :wday_r
-
-=begin
- MONTHNAMES.each_with_index do |n, i|
- if n
- define_method(n.downcase + '?'){mon == i}
- end
- end
-=end
-
- DAYNAMES.each_with_index do |n, i|
- define_method(n.downcase + '?'){wday == i}
- end
-
- def nth_kday? (n, k) # :nodoc:
- k == wday && jd === nth_kday_to_jd(year, mon, n, k, start)
- end
-
- private :nth_kday?
-
- def julian_r? () jd < start end # :nodoc:
- def gregorian_r? () !julian? end # :nodoc:
-
- once :julian_r?, :gregorian_r?
- private :julian_r?, :gregorian_r?
-
- def fix_style # :nodoc:
- if julian?
- then self.class::JULIAN
- else self.class::GREGORIAN end
- end
-
- private :fix_style
-
- def leap_r? # :nodoc:
- jd_to_civil(civil_to_jd(year, 3, 1, fix_style) - 1,
- fix_style)[-1] == 29
- end
-
- once :leap_r?
- private :leap_r?
-
- def new_start_r(sg=self.class::ITALY) self.class.new_r!(ajd, offset, sg) end # :nodoc:
-
- private :new_start_r
-
- # Create a copy of this Date object that uses the Italian/Catholic
- # Day of Calendar Reform.
- def italy() new_start(self.class::ITALY) end
-
- # Create a copy of this Date object that uses the English/Colonial
- # Day of Calendar Reform.
- def england() new_start(self.class::ENGLAND) end
-
- # Create a copy of this Date object that always uses the Julian
- # Calendar.
- def julian() new_start(self.class::JULIAN) end
-
- # Create a copy of this Date object that always uses the Gregorian
- # Calendar.
- def gregorian() new_start(self.class::GREGORIAN) end
-
- 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_r!(ajd, of, start)
- end
-
- private :new_offset_r
-
- def plus_r (n) # :nodoc:
- case n
- 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
-
- def minus_r (x) # :nodoc:
- case x
- 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
-
- def cmp_r (other) # :nodoc:
- case other
- when Numeric; return ajd <=> other
- when Date; return ajd <=> other.ajd
- else
- begin
- l, r = other.coerce(self)
- return l <=> r
- rescue NoMethodError
- end
- end
- nil
- end
-
- private :cmp_r
-
- def equal_r (other) # :nodoc:
- case other
- when Numeric; return jd == other
- when Date; return jd == other.jd
- else
- begin
- l, r = other.coerce(self)
- return l === r
- rescue NoMethodError
- end
- end
- false
- end
-
- private :equal_r
-
- def next_day(n=1) self + n end
- def prev_day(n=1) self - n end
-
- # Return a new Date one day after this one.
- def next() next_day end
-
- alias_method :succ, :next
-
- # Return a new Date object that is +n+ months later than
- # the current one.
- #
- # If the day-of-the-month of the current Date is greater
- # than the last day of the target month, the day-of-the-month
- # of the returned Date will be the last day of the target month.
- def >> (n)
- y, m = (year * 12 + (mon - 1) + n).divmod(12)
- m, = (m + 1) .divmod(1)
- d = mday
- until jd2 = _valid_civil_r?(y, m, d, start)
- d -= 1
- raise ArgumentError, 'invalid date' unless d > 0
- end
- self + (jd2 - jd)
- end
-
- # Return a new Date object that is +n+ months earlier than
- # the current one.
- #
- # If the day-of-the-month of the current Date is greater
- # than the last day of the target month, the day-of-the-month
- # of the returned Date will be the last day of the target month.
- def << (n) self >> -n end
-
- def next_month(n=1) self >> n end
- def prev_month(n=1) self << n end
-
- def next_year(n=1) self >> n * 12 end
- def prev_year(n=1) self << n * 12 end
-
- require 'enumerator'
-
- # Step the current date forward +step+ days at a
- # time (or backward, if +step+ is negative) until
- # we reach +limit+ (inclusive), yielding the resultant
- # date at each step.
- def step(limit, step=1) # :yield: date
-=begin
- if step.zero?
- raise ArgumentError, "step can't be 0"
- end
-=end
- unless block_given?
- return to_enum(:step, limit, step)
- end
- da = self
- op = %w(- <= >=)[step <=> 0]
- while da.__send__(op, limit)
- yield da
- da += step
- end
- self
- end
-
- # Step forward one day at a time until we reach +max+
- # (inclusive), yielding each date as we go.
- def upto(max, &block) # :yield: date
- step(max, +1, &block)
- end
-
- # Step backward one day at a time until we reach +min+
- # (inclusive), yielding each date as we go.
- def downto(min, &block) # :yield: date
- step(min, -1, &block)
- end
-
- def eql_r? (other) Date === other && self == other end # :nodoc:
-
- private :eql_r?
-
- def hash_r() ajd.hash end # :nodoc:
-
- private :hash_r
-
- def inspect_r # :nodoc:
- format('#<%s[R]: %s (%s,%s,%s)>', self.class, to_s_r, ajd, offset, start)
- end
-
- private :inspect_r
-
- def to_s_r() format('%.4d-%02d-%02d', year, mon, mday) end # :nodoc: # 4p
-
- private :to_s_r
-
end
-
-# Class representing a date and time.
-#
-# See the documentation to the file date.rb for an overview.
-#
-# DateTime objects are immutable once created.
-#
-# == Other methods.
-#
-# The following methods are defined in Date, but declared private
-# there. They are made public in DateTime. They are documented
-# here.
-#
-# === hour()
-#
-# Get the hour-of-the-day of the time. This is given
-# using the 24-hour clock, counting from midnight. The first
-# hour after midnight is hour 0; the last hour of the day is
-# hour 23.
-#
-# === min()
-#
-# Get the minute-of-the-hour of the time.
-#
-# === sec()
-#
-# Get the second-of-the-minute of the time.
-#
-# === sec_fraction()
-#
-# Get the fraction of a second of the time. This is returned as
-# a +Rational+.
-#
-# === zone()
-#
-# Get the time zone as a String. This is representation of the
-# time offset such as "+10:00".
-#
-# === offset()
-#
-# Get the time zone offset as a fraction of a day. This is returned
-# as a +Rational+.
-#
-# === new_offset(of=0)
-#
-# Create a new DateTime object, identical to the current one, except
-# with a new time zone offset of +of+. +of+ is the new offset from
-# UTC as a fraction of a day.
-#
-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
-
- def self.jd_r(jd=0, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
- unless (jd = _valid_jd_r?(jd, sg)) &&
- (fr = _valid_time_r?(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_r!(jd_to_ajd(jd, fr, of), of, sg)
- end
-
- private_class_method :jd_r
-
- def self.ordinal_r(y=-4712, d=1, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
- unless (jd = _valid_ordinal_r?(y, d, sg)) &&
- (fr = _valid_time_r?(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_r!(jd_to_ajd(jd, fr, of), of, sg)
- end
-
- private_class_method :ordinal_r
-
- 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_r?(y, m, d, sg)) &&
- (fr = _valid_time_r?(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_r!(jd_to_ajd(jd, fr, of), of, sg)
- end
-
- private_class_method :civil_r
-
- 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_r?(y, w, d, sg)) &&
- (fr = _valid_time_r?(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_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_r?(y, w, d, f, sg)) &&
- (fr = _valid_time_r?(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)
- end
-
- private_class_method :weeknum
-
- def self.nth_kday(y=-4712, m=1, n=1, k=1, h=0, min=0, s=0, of=0, sg=ITALY) # :nodoc:
- unless (jd = _valid_nth_kday_r?(y, m, n, k, sg)) &&
- (fr = _valid_time_r?(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)
- end
-
- private_class_method :nth_kday
-
- def self.new_by_frags(elem, sg) # :nodoc:
- elem = rewrite_frags(elem)
- elem = complete_frags(elem)
- unless (jd = valid_date_frags?(elem, sg)) &&
- (fr = valid_time_frags?(elem))
- raise ArgumentError, 'invalid date'
- end
- fr += (elem[:sec_fraction] || 0) / 86400
- of = Rational(elem[:offset] || 0, 86400)
- new!(jd_to_ajd(jd, fr, of), of, sg)
- end
-
- private_class_method :new_by_frags
-
- # Create a new DateTime object by parsing from a String
- # according to a specified format.
- #
- # +str+ is a String holding a date-time representation.
- # +fmt+ is the format that the date-time is in. See
- # date/format.rb for details on supported formats.
- #
- # The default +str+ is '-4712-01-01T00:00:00+00:00', and the default
- # +fmt+ is '%FT%T%z'. This gives midnight on Julian Day Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- #
- # An ArgumentError will be raised if +str+ cannot be
- # parsed.
- def self.strptime(str='-4712-01-01T00:00:00+00:00', fmt='%FT%T%z', sg=ITALY)
- elem = _strptime(str, fmt)
- new_by_frags(elem, sg)
- end
-
- # Create a new DateTime object by parsing from a String,
- # without specifying the format.
- #
- # +str+ is a String holding a date-time representation.
- # +comp+ specifies whether to interpret 2-digit years
- # as 19XX (>= 69) or 20XX (< 69); the default is to.
- # The method will attempt to parse a date-time from the String
- # using various heuristics; see #_parse in date/format.rb
- # for more details. If parsing fails, an ArgumentError
- # will be raised.
- #
- # The default +str+ is '-4712-01-01T00:00:00+00:00'; this is Julian
- # Day Number day 0.
- #
- # +sg+ specifies the Day of Calendar Reform.
- def self.parse(str='-4712-01-01T00:00:00+00:00', comp=true, sg=ITALY)
- elem = _parse(str, comp)
- new_by_frags(elem, sg)
- end
-
- def self.iso8601(str='-4712-01-01T00:00:00+00:00', sg=ITALY) # :nodoc:
- elem = _iso8601(str)
- new_by_frags(elem, sg)
- end
-
- def self.xmlschema(str='-4712-01-01T00:00:00+00:00', sg=ITALY) # :nodoc:
- elem = _xmlschema(str)
- new_by_frags(elem, sg)
- end
-
- def self.rfc2822(str='Mon, 1 Jan -4712 00:00:00 +0000', sg=ITALY) # :nodoc:
- elem = _rfc2822(str)
- new_by_frags(elem, sg)
- end
-
- class << self; alias_method :rfc822, :rfc2822 end
-
- def self.httpdate(str='Mon, 01 Jan -4712 00:00:00 GMT', sg=ITALY) # :nodoc:
- elem = _httpdate(str)
- new_by_frags(elem, sg)
- end
-
- def self.jisx0301(str='-4712-01-01T00:00:00+00:00', sg=ITALY) # :nodoc:
- elem = _jisx0301(str)
- new_by_frags(elem, sg)
- end
-
- 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
-
- def to_time() getlocal end
-
- def to_date
- jd = Date.__send__(:civil_to_jd, year, mon, mday, Date::ITALY)
- Date.new!(Date.__send__(:jd_to_ajd, jd, 0, 0), 0, Date::ITALY)
- end
-
- def to_datetime
- jd = DateTime.__send__(:civil_to_jd, year, mon, mday, DateTime::ITALY)
- fr = DateTime.__send__(:time_to_day_fraction, hour, min, [sec, 59].min) +
- Rational(subsec, 86400)
- of = Rational(utc_offset, 86400)
- DateTime.new!(DateTime.__send__(:jd_to_ajd, jd, fr, of),
- of, DateTime::ITALY)
- end
-
-end
-
-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), offset, start) end
-
-end
-
-class DateTime < Date
-
- def to_time
- d = new_offset(0)
- d.instance_eval do
- Time.utc(year, mon, mday, hour, min, sec +
- sec_fraction)
- end.
- getlocal
- end
-
- def to_date() Date.new!(jd_to_ajd(jd, 0, 0), 0, start) end
- def to_datetime() self end
-
-end
-
-require 'date_core'
diff --git a/ext/date/lib/date/format.rb b/ext/date/lib/date/format.rb
index 3da4c40f51..892e7aacaa 100644
--- a/ext/date/lib/date/format.rb
+++ b/ext/date/lib/date/format.rb
@@ -1,584 +1 @@
-#--
# format.rb: Written by Tadayoshi Funaba 1999-2011
-#++
-
-class Date
-
- module Format # :nodoc:
-
- MONTHS = {
- 'january' => 1, 'february' => 2, 'march' => 3, 'april' => 4,
- 'may' => 5, 'june' => 6, 'july' => 7, 'august' => 8,
- 'september'=> 9, 'october' =>10, 'november' =>11, 'december' =>12
- }
-
- DAYS = {
- 'sunday' => 0, 'monday' => 1, 'tuesday' => 2, 'wednesday'=> 3,
- 'thursday' => 4, 'friday' => 5, 'saturday' => 6
- }
-
- ABBR_MONTHS = {
- 'jan' => 1, 'feb' => 2, 'mar' => 3, 'apr' => 4,
- 'may' => 5, 'jun' => 6, 'jul' => 7, 'aug' => 8,
- 'sep' => 9, 'oct' =>10, 'nov' =>11, 'dec' =>12
- }
-
- ABBR_DAYS = {
- 'sun' => 0, 'mon' => 1, 'tue' => 2, 'wed' => 3,
- 'thu' => 4, 'fri' => 5, 'sat' => 6
- }
-
- ZONES = {
- 'ut' => 0*3600, 'gmt' => 0*3600, 'est' => -5*3600, 'edt' => -4*3600,
- 'cst' => -6*3600, 'cdt' => -5*3600, 'mst' => -7*3600, 'mdt' => -6*3600,
- 'pst' => -8*3600, 'pdt' => -7*3600,
- 'a' => 1*3600, 'b' => 2*3600, 'c' => 3*3600, 'd' => 4*3600,
- 'e' => 5*3600, 'f' => 6*3600, 'g' => 7*3600, 'h' => 8*3600,
- 'i' => 9*3600, 'k' => 10*3600, 'l' => 11*3600, 'm' => 12*3600,
- 'n' => -1*3600, 'o' => -2*3600, 'p' => -3*3600, 'q' => -4*3600,
- 'r' => -5*3600, 's' => -6*3600, 't' => -7*3600, 'u' => -8*3600,
- 'v' => -9*3600, 'w' =>-10*3600, 'x' =>-11*3600, 'y' =>-12*3600,
- 'z' => 0*3600,
-
- 'utc' => 0*3600, 'wet' => 0*3600,
- 'at' => -2*3600, 'brst'=> -2*3600, 'ndt' => -(2*3600+1800),
- 'art' => -3*3600, 'adt' => -3*3600, 'brt' => -3*3600, 'clst'=> -3*3600,
- 'nst' => -(3*3600+1800),
- 'ast' => -4*3600, 'clt' => -4*3600,
- 'akdt'=> -8*3600, 'ydt' => -8*3600,
- 'akst'=> -9*3600, 'hadt'=> -9*3600, 'hdt' => -9*3600, 'yst' => -9*3600,
- 'ahst'=>-10*3600, 'cat' =>-10*3600, 'hast'=>-10*3600, 'hst' =>-10*3600,
- 'nt' =>-11*3600,
- 'idlw'=>-12*3600,
- 'bst' => 1*3600, 'cet' => 1*3600, 'fwt' => 1*3600, 'met' => 1*3600,
- 'mewt'=> 1*3600, 'mez' => 1*3600, 'swt' => 1*3600, 'wat' => 1*3600,
- 'west'=> 1*3600,
- 'cest'=> 2*3600, 'eet' => 2*3600, 'fst' => 2*3600, 'mest'=> 2*3600,
- 'mesz'=> 2*3600, 'sast'=> 2*3600, 'sst' => 2*3600,
- 'bt' => 3*3600, 'eat' => 3*3600, 'eest'=> 3*3600, 'msk' => 3*3600,
- 'msd' => 4*3600, 'zp4' => 4*3600,
- 'zp5' => 5*3600, 'ist' => (5*3600+1800),
- 'zp6' => 6*3600,
- 'wast'=> 7*3600,
- 'cct' => 8*3600, 'sgt' => 8*3600, 'wadt'=> 8*3600,
- 'jst' => 9*3600, 'kst' => 9*3600,
- 'east'=> 10*3600, 'gst' => 10*3600,
- 'eadt'=> 11*3600,
- 'idle'=> 12*3600, 'nzst'=> 12*3600, 'nzt' => 12*3600,
- 'nzdt'=> 13*3600,
-
- 'afghanistan' => 16200, 'alaskan' => -32400,
- 'arab' => 10800, 'arabian' => 14400,
- 'arabic' => 10800, 'atlantic' => -14400,
- 'aus central' => 34200, 'aus eastern' => 36000,
- 'azores' => -3600, 'canada central' => -21600,
- 'cape verde' => -3600, 'caucasus' => 14400,
- 'cen. australia' => 34200, 'central america' => -21600,
- 'central asia' => 21600, 'central europe' => 3600,
- 'central european' => 3600, 'central pacific' => 39600,
- 'central' => -21600, 'china' => 28800,
- 'dateline' => -43200, 'e. africa' => 10800,
- 'e. australia' => 36000, 'e. europe' => 7200,
- 'e. south america' => -10800, 'eastern' => -18000,
- 'egypt' => 7200, 'ekaterinburg' => 18000,
- 'fiji' => 43200, 'fle' => 7200,
- 'greenland' => -10800, 'greenwich' => 0,
- 'gtb' => 7200, 'hawaiian' => -36000,
- 'india' => 19800, 'iran' => 12600,
- 'jerusalem' => 7200, 'korea' => 32400,
- 'mexico' => -21600, 'mid-atlantic' => -7200,
- 'mountain' => -25200, 'myanmar' => 23400,
- 'n. central asia' => 21600, 'nepal' => 20700,
- 'new zealand' => 43200, 'newfoundland' => -12600,
- 'north asia east' => 28800, 'north asia' => 25200,
- 'pacific sa' => -14400, 'pacific' => -28800,
- 'romance' => 3600, 'russian' => 10800,
- 'sa eastern' => -10800, 'sa pacific' => -18000,
- 'sa western' => -14400, 'samoa' => -39600,
- 'se asia' => 25200, 'malay peninsula' => 28800,
- 'south africa' => 7200, 'sri lanka' => 21600,
- 'taipei' => 28800, 'tasmania' => 36000,
- 'tokyo' => 32400, 'tonga' => 46800,
- 'us eastern' => -18000, 'us mountain' => -25200,
- 'vladivostok' => 36000, 'w. australia' => 28800,
- 'w. central africa' => 3600, 'w. europe' => 3600,
- 'west asia' => 18000, 'west pacific' => 36000,
- 'yakutsk' => 32400
- }
-
- [MONTHS, DAYS, ABBR_MONTHS, ABBR_DAYS, ZONES].each do |x|
- x.freeze
- end
-
- end
-
- # Returns a String representing this Date in the form:
- # Sun Sep 30 00:00:00 1977.
- def asctime() strftime('%c') end
-
- alias_method :ctime, :asctime
-
- # Returns a String representing this Date in the form:
- # 1977-09-30.
- #
- # This form is in accordance with
- # ISO8601[http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/date_and_time_format.htm].
- def iso8601() strftime('%F') end
-
- # Returns a String representing this Date in the form:
- # 1977-09-30T00:00:00+00:00
- #
- # This form is in accordance with the format for a timestamp in
- # RFC3339[http://www.ietf.org/rfc/rfc3339.txt].
- def rfc3339() strftime('%FT%T%:z') end
-
- # Synonym for Date.iso8601.
- def xmlschema() iso8601 end # :nodoc:
-
- # Returns a String representing this Date in the form:
- # Fri, 30 Sep 1977 00:00:00 +0000
- #
- # This form is in accordance with the format for a full
- # date and time specification in
- # RFC2822[http://www.ietf.org/rfc/rfc2822.txt].
- def rfc2822() strftime('%a, %-d %b %Y %T %z') end
-
- alias_method :rfc822, :rfc2822
-
- def httpdate() new_offset(0).strftime('%a, %d %b %Y %T GMT') end # :nodoc:
-
- # Returns a String representing this Date in a form
- # that is in accordance with the Japanese specification
- # JIS X 0301.
- def jisx0301
- if jd < 2405160
- strftime('%F')
- else
- case jd
- when 2405160...2419614
- g = 'M%02d' % (year - 1867)
- when 2419614...2424875
- g = 'T%02d' % (year - 1911)
- when 2424875...2447535
- g = 'S%02d' % (year - 1925)
- else
- g = 'H%02d' % (year - 1988)
- end
- g + strftime('.%m.%d')
- end
- end
-
- def self._iso8601(str) # :nodoc:
- if /\A\s*(?:([-+]?\d{2,}|-)-(\d{2})?-(\d{2})|
- ([-+]?\d{2,})?-(\d{3})|
- (\d{4}|\d{2})?-w(\d{2})-(\d)|
- -w-(\d))
- (?:t
- (\d{2}):(\d{2})(?::(\d{2})(?:[,.](\d+))?)?
- (z|[-+]\d{2}(?::?\d{2})?)?)?\s*\z/ix =~ str
- if $3
- e = {
- :mday => $3.to_i
- }
- if $1 != '-'
- y = $1.to_i
- if $1.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:year] = y
- end
- if $2.nil?
- return if $1 != '-'
- else
- e[:mon] = $2.to_i
- end
- elsif $5
- e = {
- :yday => $5.to_i
- }
- if $4
- y = $4.to_i
- if $4.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:year] = y
- end
- elsif $8
- e = {
- :cweek => $7.to_i,
- :cwday => $8.to_i
- }
- if $6
- y = $6.to_i
- if $6.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:cwyear] = y
- end
- elsif $9
- e = {
- :cwday => $9.to_i
- }
- end
- if $10
- e[:hour] = $10.to_i
- e[:min] = $11.to_i
- e[:sec] = $12.to_i if $12
- end
- if $13
- e[:sec_fraction] = Rational($13.to_i, 10**$13.size)
- end
- if $14
- e[:zone] = $14
- e[:offset] = zone_to_diff($14)
- end
- e
- elsif /\A\s*(?:([-+]?(?:\d{4}|\d{2})|--)(\d{2}|-)(\d{2})|
- ([-+]?(?:\d{4}|\d{2}))(\d{3})|
- -(\d{3})|
- (\d{4}|\d{2})w(\d{2})(\d)|
- -w(\d{2})(\d)|
- -w-(\d))
- (?:t?
- (\d{2})(\d{2})(?:(\d{2})(?:[,.](\d+))?)?
- (z|[-+]\d{2}(?:\d{2})?)?)?\s*\z/ix =~ str
- if $3
- e = {
- :mday => $3.to_i
- }
- if $1 != '--'
- y = $1.to_i
- if $1.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:year] = y
- end
- if $2 == '-'
- return if $1 != '--'
- else
- e[:mon] = $2.to_i
- end
- elsif $5
- e = {
- :yday => $5.to_i
- }
- y = $4.to_i
- if $4.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:year] = y
- elsif $6
- e = {
- :yday => $6.to_i
- }
- elsif $9
- e = {
- :cweek => $8.to_i,
- :cwday => $9.to_i
- }
- y = $7.to_i
- if $7.size < 4
- y += if y >= 69 then 1900 else 2000 end
- end
- e[:cwyear] = y
- elsif $11
- e = {
- :cweek => $10.to_i,
- :cwday => $11.to_i
- }
- elsif $12
- e = {
- :cwday => $12.to_i
- }
- end
- if $13
- e[:hour] = $13.to_i
- e[:min] = $14.to_i
- e[:sec] = $15.to_i if $15
- end
- if $16
- e[:sec_fraction] = Rational($16.to_i, 10**$16.size)
- end
- if $17
- e[:zone] = $17
- e[:offset] = zone_to_diff($17)
- end
- e
- elsif /\A\s*(?:(\d{2}):(\d{2})(?::(\d{2})(?:[,.](\d+))?)?
- (z|[-+]\d{2}(:?\d{2})?)?)?\s*\z/ix =~ str
- e = {}
- e[:hour] = $1.to_i if $1
- e[:min] = $2.to_i if $2
- e[:sec] = $3.to_i if $3
- if $4
- e[:sec_fraction] = Rational($4.to_i, 10**$4.size)
- end
- if $5
- e[:zone] = $5
- e[:offset] = zone_to_diff($5)
- end
- e
- elsif /\A\s*(?:(\d{2})(\d{2})(?:(\d{2})(?:[,.](\d+))?)?
- (z|[-+]\d{2}(\d{2})?)?)?\s*\z/ix =~ str
- e = {}
- e[:hour] = $1.to_i if $1
- e[:min] = $2.to_i if $2
- e[:sec] = $3.to_i if $3
- if $4
- e[:sec_fraction] = Rational($4.to_i, 10**$4.size)
- end
- if $5
- e[:zone] = $5
- e[:offset] = zone_to_diff($5)
- end
- e
- end
- end
-
- def self._rfc3339(str) # :nodoc:
- if /\A\s*(-?\d{4})-(\d{2})-(\d{2}) # allow minus, anyway
- (?:t|\s)
- (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
- (z|[-+]\d{2}:\d{2})\s*\z/ix =~ str
- e = {
- :year => $1.to_i,
- :mon => $2.to_i,
- :mday => $3.to_i,
- :hour => $4.to_i,
- :min => $5.to_i,
- :sec => $6.to_i,
- :zone => $8,
- :offset => zone_to_diff($8)
- }
- e[:sec_fraction] = Rational($7.to_i, 10**$7.size) if $7
- e
- end
- end
-
- def self._xmlschema(str) # :nodoc:
- if /\A\s*(-?\d{4,})(?:-(\d{2})(?:-(\d{2}))?)?
- (?:t
- (\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?)?
- (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
- e = {}
- e[:year] = $1.to_i
- e[:mon] = $2.to_i if $2
- e[:mday] = $3.to_i if $3
- e[:hour] = $4.to_i if $4
- e[:min] = $5.to_i if $5
- e[:sec] = $6.to_i if $6
- e[:sec_fraction] = Rational($7.to_i, 10**$7.size) if $7
- if $8
- e[:zone] = $8
- e[:offset] = zone_to_diff($8)
- end
- e
- elsif /\A\s*(\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?
- (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
- e = {}
- e[:hour] = $1.to_i if $1
- e[:min] = $2.to_i if $2
- e[:sec] = $3.to_i if $3
- e[:sec_fraction] = Rational($4.to_i, 10**$4.size) if $4
- if $5
- e[:zone] = $5
- e[:offset] = zone_to_diff($5)
- end
- e
- elsif /\A\s*(?:--(\d{2})(?:-(\d{2}))?|---(\d{2}))
- (z|[-+]\d{2}:\d{2})?\s*\z/ix =~ str
- e = {}
- e[:mon] = $1.to_i if $1
- e[:mday] = $2.to_i if $2
- e[:mday] = $3.to_i if $3
- if $4
- e[:zone] = $4
- e[:offset] = zone_to_diff($4)
- end
- e
- end
- end
-
- def self._rfc2822(str) # :nodoc:
- if /\A\s*(?:(#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+)?
- (\d{1,2})\s+
- (#{Format::ABBR_MONTHS.keys.join('|')})\s+
- (-?\d{2,})\s+ # allow minus, anyway
- (\d{2}):(\d{2})(?::(\d{2}))?\s*
- ([-+]\d{4}|ut|gmt|e[sd]t|c[sd]t|m[sd]t|p[sd]t|[a-ik-z])\s*\z/iox =~ str
- y = $4.to_i
- if $4.size < 4
- y += if y >= 50 then 1900 else 2000 end
- end
- e = {
- :wday => Format::ABBR_DAYS[$1.downcase],
- :mday => $2.to_i,
- :mon => Format::ABBR_MONTHS[$3.downcase],
- :year => y,
- :hour => $5.to_i,
- :min => $6.to_i,
- :zone => $8,
- :offset => zone_to_diff($8)
- }
- e[:sec] = $7.to_i if $7
- e
- end
- end
-
- class << self; alias_method :_rfc822, :_rfc2822 end
-
- def self._httpdate(str) # :nodoc:
- if /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s*,\s+
- (\d{2})\s+
- (#{Format::ABBR_MONTHS.keys.join('|')})\s+
- (-?\d{4})\s+ # allow minus, anyway
- (\d{2}):(\d{2}):(\d{2})\s+
- (gmt)\s*\z/iox =~ str
- {
- :wday => Format::ABBR_DAYS[$1.downcase],
- :mday => $2.to_i,
- :mon => Format::ABBR_MONTHS[$3.downcase],
- :year => $4.to_i,
- :hour => $5.to_i,
- :min => $6.to_i,
- :sec => $7.to_i,
- :zone => $8,
- :offset => 0
- }
- elsif /\A\s*(#{Format::DAYS.keys.join('|')})\s*,\s+
- (\d{2})\s*-\s*
- (#{Format::ABBR_MONTHS.keys.join('|')})\s*-\s*
- (\d{2})\s+
- (\d{2}):(\d{2}):(\d{2})\s+
- (gmt)\s*\z/iox =~ str
- y = $4.to_i
- if y >= 0 && y <= 99
- y += if y >= 69 then 1900 else 2000 end
- end
- {
- :wday => Format::DAYS[$1.downcase],
- :mday => $2.to_i,
- :mon => Format::ABBR_MONTHS[$3.downcase],
- :year => y,
- :hour => $5.to_i,
- :min => $6.to_i,
- :sec => $7.to_i,
- :zone => $8,
- :offset => 0
- }
- elsif /\A\s*(#{Format::ABBR_DAYS.keys.join('|')})\s+
- (#{Format::ABBR_MONTHS.keys.join('|')})\s+
- (\d{1,2})\s+
- (\d{2}):(\d{2}):(\d{2})\s+
- (\d{4})\s*\z/iox =~ str
- {
- :wday => Format::ABBR_DAYS[$1.downcase],
- :mon => Format::ABBR_MONTHS[$2.downcase],
- :mday => $3.to_i,
- :hour => $4.to_i,
- :min => $5.to_i,
- :sec => $6.to_i,
- :year => $7.to_i
- }
- end
- end
-
- def self._jisx0301(str) # :nodoc:
- if /\A\s*([mtsh])?(\d{2})\.(\d{2})\.(\d{2})
- (?:t
- (?:(\d{2}):(\d{2})(?::(\d{2})(?:[,.](\d*))?)?
- (z|[-+]\d{2}(?::?\d{2})?)?)?)?\s*\z/ix =~ str
- era = {
- 'm'=>1867,
- 't'=>1911,
- 's'=>1925,
- 'h'=>1988
- }[$1 ? $1.downcase : 'h']
- e = {
- :year => $2.to_i + era,
- :mon => $3.to_i,
- :mday => $4.to_i
- }
- if $5
- e[:hour] = $5.to_i
- e[:min] = $6.to_i if $6
- e[:sec] = $7.to_i if $7
- end
- if $8
- e[:sec_fraction] = Rational($8.to_i, 10**$8.size)
- end
- if $9
- e[:zone] = $9
- e[:offset] = zone_to_diff($9)
- end
- e
- else
- _iso8601(str)
- end
- end
-
- def self.zone_to_diff(zone) # :nodoc:
- zone = zone.downcase
- if zone.sub!(/\s+(standard|daylight)\s+time\z/, '')
- dst = $1 == 'daylight'
- else
- dst = zone.sub!(/\s+dst\z/, '')
- end
- if Format::ZONES.include?(zone)
- offset = Format::ZONES[zone]
- offset += 3600 if dst
- elsif zone.sub!(/\A(?:gmt|utc?)?([-+])/, '')
- sign = $1
- if zone.include?(':')
- hour, min, sec, = zone.split(':')
- elsif zone.include?(',') || zone.include?('.')
- hour, fr, = zone.split(/[,.]/)
- min = Rational(fr.to_i, 10**fr.size) * 60
- else
- if (zone.size % 2) == 1
- hour = zone[0,1]
- min = zone[1,2]
- sec = zone[3,2]
- else
- hour = zone[0,2]
- min = zone[2,2]
- sec = zone[4,2]
- end
- end
- offset = hour.to_i * 3600 + min.to_i * 60 + sec.to_i
- offset *= -1 if sign == '-'
- end
- offset
- end
-
- private_class_method :zone_to_diff
-
-end
-
-class DateTime < Date
-
- def iso8601_timediv(n) # :nodoc:
- strftime('T%T' +
- if n < 1
- ''
- else
- '.%0*d' % [n, (sec_fraction / Rational(1, 10**n)).round]
- end +
- '%:z')
- end
-
- private :iso8601_timediv
-
- def iso8601(n=0)
- super() + iso8601_timediv(n)
- end
-
- def rfc3339(n=0) iso8601(n) end
-
- def xmlschema(n=0) iso8601(n) end # :nodoc:
-
- def jisx0301(n=0)
- super() + iso8601_timediv(n)
- end
-
-end