diff options
Diffstat (limited to 'ext/date')
| -rw-r--r-- | ext/date/date.gemspec | 36 | ||||
| -rw-r--r-- | ext/date/date_core.c | 4286 | ||||
| -rw-r--r-- | ext/date/date_parse.c | 1327 | ||||
| -rw-r--r-- | ext/date/date_strftime.c | 1699 | ||||
| -rw-r--r-- | ext/date/date_strptime.c | 222 | ||||
| -rw-r--r-- | ext/date/date_tmx.h | 4 | ||||
| -rw-r--r-- | ext/date/depend | 690 | ||||
| -rw-r--r-- | ext/date/extconf.rb | 11 | ||||
| -rw-r--r-- | ext/date/lib/date.rb | 45 | ||||
| -rw-r--r-- | ext/date/lib/date/format.rb | 1 | ||||
| -rw-r--r-- | ext/date/prereq.mk | 19 | ||||
| -rw-r--r-- | ext/date/update-abbr | 52 | ||||
| -rw-r--r-- | ext/date/zonetab.h | 1564 | ||||
| -rw-r--r-- | ext/date/zonetab.list | 330 |
14 files changed, 6815 insertions, 3471 deletions
diff --git a/ext/date/date.gemspec b/ext/date/date.gemspec new file mode 100644 index 0000000000..cb439bd0a5 --- /dev/null +++ b/ext/date/date.gemspec @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +version = File.foreach(File.expand_path("../lib/date.rb", __FILE__)).find do |line| + /^\s*VERSION\s*=\s*["'](.*)["']/ =~ line and break $1 +end + +Gem::Specification.new do |s| + s.name = "date" + s.version = version + s.summary = "The official date library for Ruby." + s.description = "The official date library for Ruby." + + if Gem::Platform === s.platform and s.platform =~ 'java' or RUBY_ENGINE == 'jruby' + s.platform = 'java' + # No files shipped, no require path, no-op for now on JRuby + else + s.require_path = %w{lib} + + s.files = [ + "README.md", "COPYING", "BSDL", + "lib/date.rb", "ext/date/date_core.c", "ext/date/date_parse.c", "ext/date/date_strftime.c", + "ext/date/date_strptime.c", "ext/date/date_tmx.h", "ext/date/extconf.rb", "ext/date/prereq.mk", + "ext/date/zonetab.h", "ext/date/zonetab.list" + ] + s.extensions = "ext/date/extconf.rb" + end + + s.required_ruby_version = ">= 2.6.0" + + s.authors = ["Tadayoshi Funaba"] + s.email = [nil] + s.homepage = "https://github.com/ruby/date" + s.licenses = ["Ruby", "BSD-2-Clause"] + + s.metadata["changelog_uri"] = s.homepage + "/releases" +end diff --git a/ext/date/date_core.c b/ext/date/date_core.c index c22a9d496c..72d697c8ea 100644 --- a/ext/date/date_core.c +++ b/ext/date/date_core.c @@ -1,12 +1,17 @@ /* - date_core.c: Coded by Tadayoshi Funaba 2010, 2011 + date_core.c: Coded by Tadayoshi Funaba 2010-2014 */ #include "ruby.h" #include "ruby/encoding.h" +#include "ruby/util.h" #include <math.h> #include <time.h> +#if defined(HAVE_SYS_TIME_H) +#include <sys/time.h> +#endif +#undef NDEBUG #define NDEBUG #include <assert.h> @@ -18,9 +23,14 @@ static ID id_cmp, id_le_p, id_ge_p, id_eqeq_p; static VALUE cDate, cDateTime; +static VALUE eDateError; static VALUE half_days_in_day, day_in_nanoseconds; static double positive_inf, negative_inf; +/* used by deconstruct_keys */ +static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday; +static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone; + #define f_boolcast(x) ((x) ? Qtrue : Qfalse) #define f_abs(x) rb_funcall(x, rb_intern("abs"), 0) @@ -47,18 +57,32 @@ static double positive_inf, negative_inf; #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) -inline static VALUE +#define f_frozen_ary(...) rb_ary_freeze(rb_ary_new3(__VA_ARGS__)) + +static VALUE date_initialize(int argc, VALUE *argv, VALUE self); +static VALUE datetime_initialize(int argc, VALUE *argv, VALUE self); + +#define RETURN_FALSE_UNLESS_NUMERIC(obj) if(!RTEST(rb_obj_is_kind_of((obj), rb_cNumeric))) return Qfalse +inline static void +check_numeric(VALUE obj, const char* field) +{ + if(!RTEST(rb_obj_is_kind_of(obj, rb_cNumeric))) { + rb_raise(rb_eTypeError, "invalid %s (not numeric)", field); + } +} + +inline static int f_cmp(VALUE x, VALUE y) { if (FIXNUM_P(x) && FIXNUM_P(y)) { long c = FIX2LONG(x) - FIX2LONG(y); if (c > 0) - c = 1; + return 1; else if (c < 0) - c = -1; - return INT2FIX(c); + return -1; + return 0; } - return rb_funcall(x, id_cmp, 1, y); + return rb_cmpint(rb_funcallv(x, id_cmp, 1, &y), x, y); } inline static VALUE @@ -90,7 +114,7 @@ f_ge_p(VALUE x, VALUE y) { if (FIXNUM_P(x) && FIXNUM_P(y)) return f_boolcast(FIX2LONG(x) >= FIX2LONG(y)); - return rb_funcall(x, rb_intern(">="), 1, y); + return rb_funcall(x, id_ge_p, 1, y); } inline static VALUE @@ -98,7 +122,7 @@ f_eqeq_p(VALUE x, VALUE y) { if (FIXNUM_P(x) && FIXNUM_P(y)) return f_boolcast(FIX2LONG(x) == FIX2LONG(y)); - return rb_funcall(x, rb_intern("=="), 1, y); + return rb_funcall(x, id_eqeq_p, 1, y); } inline static VALUE @@ -111,7 +135,7 @@ f_zero_p(VALUE x) return Qfalse; case T_RATIONAL: { - VALUE num = RRATIONAL(x)->num; + VALUE num = rb_rational_num(x); return f_boolcast(FIXNUM_P(num) && FIX2LONG(num) == 0); } } @@ -218,15 +242,17 @@ f_negative_p(VALUE x) #include <float.h> #endif -#if defined(FLT_RADIX) && defined(FLT_MANT_DIG) -#if FLT_RADIX == 2 && FLT_MANT_DIG > 22 -#define USE_FLOAT -#define sg_cast float +#if defined(FLT_RADIX) && defined(FLT_MANT_DIG) && FLT_RADIX == 2 && FLT_MANT_DIG > 22 +#define date_sg_t float #else -#define sg_cast double -#endif +#define date_sg_t double #endif +#define JULIAN_EPOCH_DATE "-4712-01-01" +#define JULIAN_EPOCH_DATETIME JULIAN_EPOCH_DATE "T00:00:00+00:00" +#define JULIAN_EPOCH_DATETIME_RFC3339 "Mon, 1 Jan -4712 00:00:00 +0000" +#define JULIAN_EPOCH_DATETIME_HTTPDATE "Mon, 01 Jan -4712 00:00:00 GMT" + /* A set of nth, jd, df and sf denote ajd + 1/2. Each ajd begin at * noon of GMT (assume equal to UTC). However, this begins at * midnight. @@ -235,16 +261,9 @@ f_negative_p(VALUE x) struct SimpleDateData { unsigned flags; - VALUE nth; /* not always canonicalized */ int jd; /* as utc */ - /* df is zero */ - /* sf is zero */ - /* of is zero */ -#ifndef USE_FLOAT - double sg; /* 2298874..2426355 or -/+oo */ -#else - float sg; /* at most 22 bits */ -#endif + VALUE nth; /* not always canonicalized */ + date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ /* decoded as utc=local */ int year; /* truncated */ #ifndef USE_PACK @@ -262,16 +281,9 @@ struct SimpleDateData struct ComplexDateData { unsigned flags; - VALUE nth; /* not always canonicalized */ int jd; /* as utc */ - int df; /* as utc, in secs */ - VALUE sf; /* in nano secs */ - int of; /* in secs */ -#ifndef USE_FLOAT - double sg; /* 2298874..2426355 or -/+oo */ -#else - float sg; /* at most 22 bits */ -#endif + VALUE nth; /* not always canonicalized */ + date_sg_t sg; /* 2298874..2426355 or -/+oo -- at most 22 bits */ /* decoded as local */ int year; /* truncated */ #ifndef USE_PACK @@ -284,6 +296,9 @@ struct ComplexDateData /* packed civil */ unsigned pc; #endif + int df; /* as utc, in secs */ + int of; /* in secs */ + VALUE sf; /* in nano secs */ }; union DateData { @@ -294,98 +309,98 @@ union DateData { #define get_d1(x)\ union DateData *dat;\ - Data_Get_Struct(x, union DateData, dat); + TypedData_Get_Struct(x, union DateData, &d_lite_type, dat); #define get_d1a(x)\ union DateData *adat;\ - Data_Get_Struct(x, union DateData, adat); + TypedData_Get_Struct(x, union DateData, &d_lite_type, adat); #define get_d1b(x)\ union DateData *bdat;\ - Data_Get_Struct(x, union DateData, bdat); + TypedData_Get_Struct(x, union DateData, &d_lite_type, bdat); #define get_d2(x,y)\ union DateData *adat, *bdat;\ - Data_Get_Struct(x, union DateData, adat);\ - Data_Get_Struct(y, union DateData, bdat); + TypedData_Get_Struct(x, union DateData, &d_lite_type, adat);\ + TypedData_Get_Struct(y, union DateData, &d_lite_type, bdat); inline static VALUE canon(VALUE x) { - if (TYPE(x) == T_RATIONAL) { - VALUE den = RRATIONAL(x)->den; + if (RB_TYPE_P(x, T_RATIONAL)) { + VALUE den = rb_rational_den(x); if (FIXNUM_P(den) && FIX2LONG(den) == 1) - return RRATIONAL(x)->num; + return rb_rational_num(x); } return x; } #ifndef USE_PACK -#define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ -{\ - (x)->nth = canon(_nth);\ +#define set_to_simple(obj, x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth)); \ (x)->jd = _jd;\ - (x)->sg = (sg_cast)(_sg);\ + (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->mon = _mon;\ (x)->mday = _mday;\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) & ~COMPLEX_DAT;\ +} while (0) #else -#define set_to_simple(x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ -{\ - (x)->nth = canon(_nth);\ +#define set_to_simple(obj, x, _nth, _jd ,_sg, _year, _mon, _mday, _flags) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth)); \ (x)->jd = _jd;\ - (x)->sg = (sg_cast)(_sg);\ + (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->pc = PACK2(_mon, _mday);\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) & ~COMPLEX_DAT;\ +} while (0) #endif #ifndef USE_PACK -#define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\ +#define set_to_complex(obj, x, _nth, _jd ,_df, _sf, _of, _sg,\ _year, _mon, _mday, _hour, _min, _sec, _flags) \ -{\ - (x)->nth = canon(_nth);\ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth));\ (x)->jd = _jd;\ (x)->df = _df;\ - (x)->sf = canon(_sf);\ + RB_OBJ_WRITE((obj), &(x)->sf, canon(_sf));\ (x)->of = _of;\ - (x)->sg = (sg_cast)(_sg);\ + (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->mon = _mon;\ (x)->mday = _mday;\ (x)->hour = _hour;\ (x)->min = _min;\ (x)->sec = _sec;\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) | COMPLEX_DAT;\ +} while (0) #else -#define set_to_complex(x, _nth, _jd ,_df, _sf, _of, _sg,\ +#define set_to_complex(obj, x, _nth, _jd ,_df, _sf, _of, _sg,\ _year, _mon, _mday, _hour, _min, _sec, _flags) \ -{\ - (x)->nth = canon(_nth);\ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, canon(_nth));\ (x)->jd = _jd;\ (x)->df = _df;\ - (x)->sf = canon(_sf);\ + RB_OBJ_WRITE((obj), &(x)->sf, canon(_sf));\ (x)->of = _of;\ - (x)->sg = (sg_cast)(_sg);\ + (x)->sg = (date_sg_t)(_sg);\ (x)->year = _year;\ (x)->pc = PACK5(_mon, _mday, _hour, _min, _sec);\ - (x)->flags = _flags;\ -} + (x)->flags = (_flags) | COMPLEX_DAT;\ +} while (0) #endif #ifndef USE_PACK -#define copy_simple_to_complex(x, y) \ -{\ - (x)->nth = (y)->nth;\ +#define copy_simple_to_complex(obj, x, y) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->df = 0;\ (x)->sf = INT2FIX(0);\ (x)->of = 0;\ - (x)->sg = (sg_cast)((y)->sg);\ + (x)->sg = (date_sg_t)((y)->sg);\ (x)->year = (y)->year;\ (x)->mon = (y)->mon;\ (x)->mday = (y)->mday;\ @@ -393,43 +408,43 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ (x)->min = 0;\ (x)->sec = 0;\ (x)->flags = (y)->flags;\ -} +} while (0) #else -#define copy_simple_to_complex(x, y) \ -{\ - (x)->nth = (y)->nth;\ +#define copy_simple_to_complex(obj, x, y) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ (x)->df = 0;\ - (x)->sf = INT2FIX(0);\ + RB_OBJ_WRITE((obj), &(x)->sf, INT2FIX(0));\ (x)->of = 0;\ - (x)->sg = (sg_cast)((y)->sg);\ + (x)->sg = (date_sg_t)((y)->sg);\ (x)->year = (y)->year;\ (x)->pc = PACK5(EX_MON((y)->pc), EX_MDAY((y)->pc), 0, 0, 0);\ (x)->flags = (y)->flags;\ -} +} while (0) #endif #ifndef USE_PACK -#define copy_complex_to_simple(x, y) \ -{\ - (x)->nth = (y)->nth;\ +#define copy_complex_to_simple(obj, x, y) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ - (x)->sg = (sg_cast)((y)->sg);\ + (x)->sg = (date_sg_t)((y)->sg);\ (x)->year = (y)->year;\ (x)->mon = (y)->mon;\ (x)->mday = (y)->mday;\ (x)->flags = (y)->flags;\ -} +} while (0) #else -#define copy_complex_to_simple(x, y) \ -{\ - (x)->nth = (y)->nth;\ +#define copy_complex_to_simple(obj, x, y) \ +do {\ + RB_OBJ_WRITE((obj), &(x)->nth, (y)->nth);\ (x)->jd = (y)->jd;\ - (x)->sg = (sg_cast)((y)->sg);\ + (x)->sg = (date_sg_t)((y)->sg);\ (x)->year = (y)->year;\ (x)->pc = PACK2(EX_MON((y)->pc), EX_MDAY((y)->pc));\ (x)->flags = (y)->flags;\ -} +} while (0) #endif /* base */ @@ -437,11 +452,43 @@ _year, _mon, _mday, _hour, _min, _sec, _flags) \ static int c_valid_civil_p(int, int, int, double, int *, int *, int *, int *); +/* Check if using pure Gregorian calendar (sg == -Infinity) */ +#define c_gregorian_only_p(sg) (isinf(sg) && (sg) < 0) + +/* + * Fast path macros for pure Gregorian calendar. + * Sets *rjd to the JD value, *ns to 1 (new style), and returns. + */ +#define GREGORIAN_JD_FAST_PATH_RET(sg, jd_expr, rjd, ns) \ + if (c_gregorian_only_p(sg)) { \ + *(rjd) = (jd_expr); \ + *(ns) = 1; \ + return 1; \ + } + +#define GREGORIAN_JD_FAST_PATH(sg, jd_expr, rjd, ns) \ + if (c_gregorian_only_p(sg)) { \ + *(rjd) = (jd_expr); \ + *(ns) = 1; \ + return; \ + } + +/* Forward declarations for Neri-Schneider optimized functions */ +static int c_gregorian_civil_to_jd(int y, int m, int d); +static void c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd); +static int c_gregorian_fdoy(int y); +static int c_gregorian_ldoy(int y); +static int c_gregorian_ldom_jd(int y, int m); +static int ns_jd_in_range(int jd); + static int c_find_fdoy(int y, double sg, int *rjd, int *ns) { int d, rm, rd; + GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_fdoy(y), rjd, ns); + + /* Keep existing loop for Julian/reform period */ for (d = 1; d < 31; d++) if (c_valid_civil_p(y, 1, d, sg, &rm, &rd, rjd, ns)) return 1; @@ -453,6 +500,9 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns) { int i, rm, rd; + GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldoy(y), rjd, ns); + + /* Keep existing loop for Julian/reform period */ for (i = 0; i < 30; i++) if (c_valid_civil_p(y, 12, 31 - i, sg, &rm, &rd, rjd, ns)) return 1; @@ -460,6 +510,7 @@ c_find_ldoy(int y, double sg, int *rjd, int *ns) } #ifndef NDEBUG +/* :nodoc: */ static int c_find_fdom(int y, int m, double sg, int *rjd, int *ns) { @@ -477,6 +528,9 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns) { int i, rm, rd; + GREGORIAN_JD_FAST_PATH_RET(sg, c_gregorian_ldom_jd(y, m), rjd, ns); + + /* Keep existing loop for Julian/reform period */ for (i = 0; i < 30; i++) if (c_valid_civil_p(y, m, 31 - i, sg, &rm, &rd, rjd, ns)) return 1; @@ -486,55 +540,69 @@ c_find_ldom(int y, int m, double sg, int *rjd, int *ns) static void c_civil_to_jd(int y, int m, int d, double sg, int *rjd, int *ns) { - double a, b, jd; + int jd; + + GREGORIAN_JD_FAST_PATH(sg, c_gregorian_civil_to_jd(y, m, d), rjd, ns); + + /* Calculate Gregorian JD using optimized algorithm */ + jd = c_gregorian_civil_to_jd(y, m, d); - if (m <= 2) { - y -= 1; - m += 12; - } - a = floor(y / 100.0); - b = 2 - a + floor(a / 4.0); - jd = floor(365.25 * (y + 4716)) + - floor(30.6001 * (m + 1)) + - d + b - 1524; if (jd < sg) { - jd -= b; + /* Before Gregorian switchover - use Julian calendar */ + int y2 = y, m2 = m; + if (m2 <= 2) { + y2 -= 1; + m2 += 12; + } + jd = (int)(floor(365.25 * (y2 + 4716)) + + floor(30.6001 * (m2 + 1)) + + d - 1524); *ns = 0; } - else + else { *ns = 1; + } - *rjd = (int)jd; + *rjd = jd; } static void c_jd_to_civil(int jd, double sg, int *ry, int *rm, int *rdom) { - double x, a, b, c, d, e, y, m, dom; - - if (jd < sg) - a = jd; - else { - x = floor((jd - 1867216.25) / 36524.25); - a = jd + 1 + x - floor(x / 4.0); - } - b = a + 1524; - c = floor((b - 122.1) / 365.25); - d = floor(365.25 * c); - e = floor((b - d) / 30.6001); - dom = b - d - floor(30.6001 * e); - if (e <= 13) { - m = e - 1; - y = c - 4716; - } - else { - m = e - 13; - y = c - 4715; + /* Fast path: pure Gregorian or date after switchover, within safe range */ + if ((c_gregorian_only_p(sg) || jd >= sg) && ns_jd_in_range(jd)) { + c_gregorian_jd_to_civil(jd, ry, rm, rdom); + return; } - *ry = (int)y; - *rm = (int)m; - *rdom = (int)dom; + /* Original algorithm for Julian calendar or extreme dates */ + { + double x, a, b, c, d, e, y, m, dom; + + if (jd < sg) + a = jd; + else { + x = floor((jd - 1867216.25) / 36524.25); + a = jd + 1 + x - floor(x / 4.0); + } + b = a + 1524; + c = floor((b - 122.1) / 365.25); + d = floor(365.25 * c); + e = floor((b - d) / 30.6001); + dom = b - d - floor(30.6001 * e); + if (e <= 13) { + m = e - 1; + y = c - 4716; + } + else { + m = e - 13; + y = c - 4715; + } + + *ry = (int)y; + *rm = (int)m; + *rdom = (int)dom; + } } static void @@ -616,6 +684,7 @@ c_jd_to_weeknum(int jd, int f, double sg, int *ry, int *rw, int *rd) } #ifndef NDEBUG +/* :nodoc: */ static void c_nth_kday_to_jd(int y, int m, int n, int k, double sg, int *rjd, int *ns) { @@ -641,6 +710,7 @@ c_jd_to_wday(int jd) } #ifndef NDEBUG +/* :nodoc: */ static void c_jd_to_nth_kday(int jd, double sg, int *ry, int *rm, int *rn, int *rk) { @@ -690,7 +760,7 @@ c_julian_leap_p(int y) inline static int c_gregorian_leap_p(int y) { - return MOD(y, 4) == 0 && y % 100 != 0 || MOD(y, 400) == 0; + return (MOD(y, 4) == 0 && y % 100 != 0) || MOD(y, 400) == 0; } static int @@ -707,6 +777,147 @@ c_gregorian_last_day_of_month(int y, int m) return monthtab[c_gregorian_leap_p(y) ? 1 : 0][m]; } +/* + * Neri-Schneider algorithm for optimized Gregorian date conversion. + * Reference: Neri & Schneider, "Euclidean Affine Functions and Applications + * to Calendar Algorithms", Software: Practice and Experience, 2023. + * https://arxiv.org/abs/2102.06959 + * + * This algorithm provides ~2-3x speedup over traditional floating-point + * implementations by using pure integer arithmetic with multiplication + * and bit-shifts instead of expensive division operations. + */ + +/* JDN of March 1, Year 0 in proleptic Gregorian calendar */ +#define NS_EPOCH 1721120 + +/* Days in a 4-year cycle (3 normal years + 1 leap year) */ +#define NS_DAYS_IN_4_YEARS 1461 + +/* Days in a 400-year Gregorian cycle (97 leap years in 400 years) */ +#define NS_DAYS_IN_400_YEARS 146097 + +/* Years per century */ +#define NS_YEARS_PER_CENTURY 100 + +/* + * Multiplier for extracting year within century using fixed-point arithmetic. + * This is ceil(2^32 / NS_DAYS_IN_4_YEARS) for the Euclidean affine function. + */ +#define NS_YEAR_MULTIPLIER 2939745 + +/* + * Coefficients for month calculation from day-of-year. + * Maps day-of-year to month using: month = (NS_MONTH_COEFF * doy + NS_MONTH_OFFSET) >> 16 + */ +#define NS_MONTH_COEFF 2141 +#define NS_MONTH_OFFSET 197913 + +/* + * Coefficients for civil date to JDN month contribution. + * Maps month to accumulated days: days = (NS_CIVIL_MONTH_COEFF * m - NS_CIVIL_MONTH_OFFSET) / 32 + */ +#define NS_CIVIL_MONTH_COEFF 979 +#define NS_CIVIL_MONTH_OFFSET 2919 +#define NS_CIVIL_MONTH_DIVISOR 32 + +/* Days from March 1 to December 31 (for Jan/Feb year adjustment) */ +#define NS_DAYS_BEFORE_NEW_YEAR 306 + +/* + * Safe bounds for Neri-Schneider algorithm to avoid integer overflow. + * These correspond to approximately years -1,000,000 to +1,000,000. + */ +#define NS_JD_MIN -364000000 +#define NS_JD_MAX 538000000 + +inline static int +ns_jd_in_range(int jd) +{ + return jd >= NS_JD_MIN && jd <= NS_JD_MAX; +} + +/* Optimized: Gregorian date -> Julian Day Number */ +static int +c_gregorian_civil_to_jd(int y, int m, int d) +{ + /* Shift epoch to March 1 of year 0 (Jan/Feb belong to previous year) */ + int j = (m < 3) ? 1 : 0; + int y0 = y - j; + int m0 = j ? m + 12 : m; + int d0 = d - 1; + + /* Calculate year contribution with leap year correction */ + int q1 = DIV(y0, NS_YEARS_PER_CENTURY); + int yc = DIV(NS_DAYS_IN_4_YEARS * y0, 4) - q1 + DIV(q1, 4); + + /* Calculate month contribution using integer arithmetic */ + int mc = (NS_CIVIL_MONTH_COEFF * m0 - NS_CIVIL_MONTH_OFFSET) / NS_CIVIL_MONTH_DIVISOR; + + /* Combine and add epoch offset to get JDN */ + return yc + mc + d0 + NS_EPOCH; +} + +/* Optimized: Julian Day Number -> Gregorian date */ +static void +c_gregorian_jd_to_civil(int jd, int *ry, int *rm, int *rd) +{ + int r0, n1, q1, r1, n2, q2, r2, n3, q3, r3, y0, j; + uint64_t u2; + + /* Convert JDN to rata die (March 1, Year 0 epoch) */ + r0 = jd - NS_EPOCH; + + /* Extract century and day within 400-year cycle */ + /* Use Euclidean (floor) division for negative values */ + n1 = 4 * r0 + 3; + q1 = DIV(n1, NS_DAYS_IN_400_YEARS); + r1 = MOD(n1, NS_DAYS_IN_400_YEARS) / 4; + + /* Calculate year within century and day of year */ + n2 = 4 * r1 + 3; + /* Use 64-bit arithmetic to avoid overflow */ + u2 = (uint64_t)NS_YEAR_MULTIPLIER * (uint64_t)n2; + q2 = (int)(u2 >> 32); + r2 = (int)((uint32_t)u2 / NS_YEAR_MULTIPLIER / 4); + + /* Calculate month and day using integer arithmetic */ + n3 = NS_MONTH_COEFF * r2 + NS_MONTH_OFFSET; + q3 = n3 >> 16; + r3 = (n3 & 0xFFFF) / NS_MONTH_COEFF; + + /* Combine century and year */ + y0 = NS_YEARS_PER_CENTURY * q1 + q2; + + /* Adjust for January/February (shift from fiscal year) */ + j = (r2 >= NS_DAYS_BEFORE_NEW_YEAR) ? 1 : 0; + + *ry = y0 + j; + *rm = j ? q3 - 12 : q3; + *rd = r3 + 1; +} + +/* O(1) first day of year for Gregorian calendar */ +inline static int +c_gregorian_fdoy(int y) +{ + return c_gregorian_civil_to_jd(y, 1, 1); +} + +/* O(1) last day of year for Gregorian calendar */ +inline static int +c_gregorian_ldoy(int y) +{ + return c_gregorian_civil_to_jd(y, 12, 31); +} + +/* O(1) last day of month (JDN) for Gregorian calendar */ +inline static int +c_gregorian_ldom_jd(int y, int m) +{ + return c_gregorian_civil_to_jd(y, m, c_gregorian_last_day_of_month(y, m)); +} + static int c_valid_julian_p(int y, int m, int d, int *rm, int *rd) { @@ -753,6 +964,8 @@ c_valid_civil_p(int y, int m, int d, double sg, if (m < 0) m += 13; + if (m < 1 || m > 12) + return 0; if (d < 0) { if (!c_find_ldom(y, m, sg, rjd, ns)) return 0; @@ -817,6 +1030,7 @@ c_valid_weeknum_p(int y, int w, int d, int f, double sg, } #ifndef NDEBUG +/* :nodoc: */ static int c_valid_nth_kday_p(int y, int m, int n, int k, double sg, int *rm, int *rn, int *rk, int *rjd, int *ns) @@ -958,6 +1172,7 @@ ns_to_day(VALUE n) } #ifndef NDEBUG +/* :nodoc: */ static VALUE ms_to_sec(VALUE m) { @@ -976,6 +1191,7 @@ ns_to_sec(VALUE n) } #ifndef NDEBUG +/* :nodoc: */ inline static VALUE ins_to_day(int n) { @@ -991,8 +1207,14 @@ safe_mul_p(VALUE x, long m) if (!FIXNUM_P(x)) return 0; ix = FIX2LONG(x); - if (ix >= (FIXNUM_MAX / m)) - return 0; + if (ix < 0) { + if (ix <= (FIXNUM_MIN / m)) + return 0; + } + else { + if (ix >= (FIXNUM_MAX / m)) + return 0; + } return 1; } @@ -1005,6 +1227,7 @@ day_to_sec(VALUE d) } #ifndef NDEBUG +/* :nodoc: */ static VALUE day_to_ns(VALUE d) { @@ -1029,6 +1252,7 @@ sec_to_ns(VALUE s) } #ifndef NDEBUG +/* :nodoc: */ static VALUE isec_to_ns(int s) { @@ -1055,6 +1279,7 @@ div_df(VALUE d, VALUE *f) } #ifndef NDEBUG +/* :nodoc: */ static VALUE div_sf(VALUE s, VALUE *f) { @@ -1109,6 +1334,30 @@ m_virtual_sg(union DateData *x) return c_virtual_sg(x); } +#define canonicalize_jd(_nth, _jd) \ +do {\ + if (_jd < 0) {\ + _nth = f_sub(_nth, INT2FIX(1));\ + _jd += CM_PERIOD;\ + }\ + if (_jd >= CM_PERIOD) {\ + _nth = f_add(_nth, INT2FIX(1));\ + _jd -= CM_PERIOD;\ + }\ +} while (0) + +inline static void +canonicalize_s_jd(VALUE obj, union DateData *x) +{ + int j = x->s.jd; + VALUE nth = x->s.nth; + assert(have_jd_p(x)); + canonicalize_jd(nth, x->s.jd); + RB_OBJ_WRITE(obj, &x->s.nth, nth); + if (x->s.jd != j) + x->flags &= ~HAVE_CIVIL; +} + inline static void get_s_jd(union DateData *x) { @@ -1194,6 +1443,18 @@ get_c_time(union DateData *x) } inline static void +canonicalize_c_jd(VALUE obj, union DateData *x) +{ + int j = x->c.jd; + VALUE nth = x->c.nth; + assert(have_jd_p(x)); + canonicalize_jd(nth, x->c.jd); + RB_OBJ_WRITE(obj, &x->c.nth, nth); + if (x->c.jd != j) + x->flags &= ~HAVE_CIVIL; +} + +inline static void get_c_jd(union DateData *x) { assert(complex_dat_p(x)); @@ -1325,10 +1586,8 @@ encode_year(VALUE nth, int y, double style, static void decode_jd(VALUE jd, VALUE *nth, int *rjd) { - assert(FIXNUM_P(jd) || RB_TYPE_P(jd, T_BIGNUM)); *nth = f_idiv(jd, INT2FIX(CM_PERIOD)); if (f_zero_p(*nth)) { - assert(FIXNUM_P(jd)); *rjd = FIX2INT(jd); return; } @@ -1366,6 +1625,19 @@ guess_style(VALUE y, double sg) /* -/+oo or zero */ return style; } +inline static void +m_canonicalize_jd(VALUE obj, union DateData *x) +{ + if (simple_dat_p(x)) { + get_s_jd(x); + canonicalize_s_jd(obj, x); + } + else { + get_c_jd(x); + canonicalize_c_jd(obj, x); + } +} + inline static VALUE m_nth(union DateData *x) { @@ -1442,6 +1714,7 @@ m_df(union DateData *x) } #ifndef NDEBUG +/* :nodoc: */ static VALUE m_df_in_day(union DateData *x) { @@ -1519,7 +1792,7 @@ m_ajd(union DateData *x) if (simple_dat_p(x)) { r = m_real_jd(x); - if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2)) { + if (FIXNUM_P(r) && FIX2LONG(r) <= (FIXNUM_MAX / 2) && FIX2LONG(r) >= (FIXNUM_MIN + 1) / 2) { long ir = FIX2LONG(r); ir = ir * 2 - 1; return rb_rational_new2(LONG2FIX(ir), INT2FIX(2)); @@ -1680,23 +1953,6 @@ m_real_year(union DateData *x) return ry; } - -#ifdef USE_PACK -inline static int -m_pc(union DateData *x) -{ - if (simple_dat_p(x)) { - get_s_civil(x); - return x->s.pc; - } - else { - get_c_civil(x); - get_c_time(x); - return x->c.pc; - } -} -#endif - inline static int m_mon(union DateData *x) { @@ -1899,13 +2155,13 @@ m_sec(union DateData *x) } #define decode_offset(of,s,h,m)\ -{\ +do {\ int a;\ s = (of < 0) ? '-' : '+';\ a = (of < 0) ? -of : of;\ h = a / HOUR_IN_SECONDS;\ m = a % HOUR_IN_SECONDS / MINUTE_IN_SECONDS;\ -} +} while (0) static VALUE of2str(int of) @@ -1937,12 +2193,6 @@ k_date_p(VALUE x) } inline static VALUE -k_datetime_p(VALUE x) -{ - return f_kind_of_p(x, cDateTime); -} - -inline static VALUE k_numeric_p(VALUE x) { return f_kind_of_p(x, rb_cNumeric); @@ -1954,7 +2204,15 @@ k_rational_p(VALUE x) return f_kind_of_p(x, rb_cRational); } +static inline void +expect_numeric(VALUE x) +{ + if (!k_numeric_p(x)) + rb_raise(rb_eTypeError, "expected numeric"); +} + #ifndef NDEBUG +/* :nodoc: */ static void civil_to_jd(VALUE y, int m, int d, double sg, VALUE *nth, int *ry, @@ -1972,7 +2230,7 @@ civil_to_jd(VALUE y, int m, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2007,7 +2265,7 @@ ordinal_to_jd(VALUE y, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2042,7 +2300,7 @@ commercial_to_jd(VALUE y, int w, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2077,7 +2335,7 @@ weeknum_to_jd(VALUE y, int w, int d, int f, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2112,7 +2370,7 @@ nth_kday_to_jd(VALUE y, int m, int n, int k, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2151,7 +2409,7 @@ valid_ordinal_p(VALUE y, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2190,7 +2448,7 @@ valid_civil_p(VALUE y, int m, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2226,7 +2484,7 @@ valid_commercial_p(VALUE y, int w, int d, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2256,7 +2514,7 @@ valid_weeknum_p(VALUE y, int w, int d, int f, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2267,6 +2525,7 @@ valid_weeknum_p(VALUE y, int w, int d, int f, double sg, } #ifndef NDEBUG +/* :nodoc: */ static int valid_nth_kday_p(VALUE y, int m, int n, int k, double sg, VALUE *nth, int *ry, @@ -2287,7 +2546,7 @@ valid_nth_kday_p(VALUE y, int m, int n, int k, double sg, *ry = FIX2INT(y); else { VALUE nth2; - decode_year(y, ns ? -1 : +1, &nth2, ry); + decode_year(y, *ns ? -1 : +1, &nth2, ry); } } else { @@ -2303,6 +2562,9 @@ VALUE date_zone_to_diff(VALUE); static int offset_to_sec(VALUE vof, int *rof) { + int try_rational = 1; + + again: switch (TYPE(vof)) { case T_FIXNUM: { @@ -2327,13 +2589,13 @@ offset_to_sec(VALUE vof, int *rof) return 1; } default: - if (!k_numeric_p(vof)) - rb_raise(rb_eTypeError, "expected numeric"); + expect_numeric(vof); vof = f_to_r(vof); -#ifdef CANONICALIZATION_FOR_MATHN - if (!k_rational_p(vof)) - return offset_to_sec(vof, rof); -#endif + if (!k_rational_p(vof)) { + if (!try_rational) Check_Type(vof, T_RATIONAL); + try_rational = 0; + goto again; + } /* fall through */ case T_RATIONAL: { @@ -2342,19 +2604,12 @@ offset_to_sec(VALUE vof, int *rof) vs = day_to_sec(vof); -#ifdef CANONICALIZATION_FOR_MATHN if (!k_rational_p(vs)) { - if (!FIXNUM_P(vs)) - return 0; - n = FIX2LONG(vs); - if (n < -DAY_IN_SECONDS || n > DAY_IN_SECONDS) - return 0; - *rof = (int)n; - return 1; + vn = vs; + goto rounded; } -#endif - vn = RRATIONAL(vs)->num; - vd = RRATIONAL(vs)->den; + vn = rb_rational_num(vs); + vd = rb_rational_den(vs); if (FIXNUM_P(vn) && FIXNUM_P(vd) && (FIX2LONG(vd) == 1)) n = FIX2LONG(vn); @@ -2362,6 +2617,7 @@ offset_to_sec(VALUE vof, int *rof) vn = f_round(vs); if (!f_eqeq_p(vn, vs)) rb_warning("fraction of offset is ignored"); + rounded: if (!FIXNUM_P(vn)) return 0; n = FIX2LONG(vn); @@ -2391,12 +2647,12 @@ offset_to_sec(VALUE vof, int *rof) /* date */ #define valid_sg(sg) \ -{\ +do {\ if (!c_valid_start_p(sg)) {\ sg = 0;\ rb_warning("invalid start is ignored");\ }\ -} +} while (0) static VALUE valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd) @@ -2407,6 +2663,7 @@ valid_jd_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass) { @@ -2427,15 +2684,16 @@ date_s__valid_jd_p(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.valid_jd?(jd[, start=Date::ITALY]) -> bool + * Date.valid_jd?(jd, start = Date::ITALY) -> true * - * Just returns true. It's nonsense, but is for symmetry. + * Implemented for compatibility; + * returns +true+ unless +jd+ is invalid (i.e., not a Numeric). * - * For example: + * Date.valid_jd?(2451944) # => true * - * Date.valid_jd?(2451944) #=> true + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * See also jd. + * Related: Date.jd. */ static VALUE date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass) @@ -2445,6 +2703,7 @@ date_s_valid_jd_p(int argc, VALUE *argv, VALUE klass) rb_scan_args(argc, argv, "11", &vjd, &vsg); + RETURN_FALSE_UNLESS_NUMERIC(vjd); argv2[0] = vjd; if (argc < 2) argv2[1] = INT2FIX(DEFAULT_SG); @@ -2494,6 +2753,7 @@ valid_civil_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass) { @@ -2516,17 +2776,18 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.valid_civil?(year, month, mday[, start=Date::ITALY]) -> bool - * Date.valid_date?(year, month, mday[, start=Date::ITALY]) -> bool + * Date.valid_civil?(year, month, mday, start = Date::ITALY) -> true or false * - * Returns true if the given calendar date is valid, and false if not. + * Returns +true+ if the arguments define a valid ordinal date, + * +false+ otherwise: * - * For example: + * Date.valid_date?(2001, 2, 3) # => true + * Date.valid_date?(2001, 2, 29) # => false + * Date.valid_date?(2001, 2, -1) # => true * - * Date.valid_date?(2001,2,3) #=> true - * Date.valid_date?(2001,2,29) #=> false + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * See also jd and civil. + * Related: Date.jd, Date.new. */ static VALUE date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass) @@ -2536,6 +2797,9 @@ date_s_valid_civil_p(int argc, VALUE *argv, VALUE klass) rb_scan_args(argc, argv, "31", &vy, &vm, &vd, &vsg); + RETURN_FALSE_UNLESS_NUMERIC(vy); + RETURN_FALSE_UNLESS_NUMERIC(vm); + RETURN_FALSE_UNLESS_NUMERIC(vd); argv2[0] = vy; argv2[1] = vm; argv2[2] = vd; @@ -2579,6 +2843,7 @@ valid_ordinal_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass) { @@ -2600,16 +2865,17 @@ date_s__valid_ordinal_p(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.valid_ordinal?(year, yday[, start=Date::ITALY]) -> bool + * Date.valid_ordinal?(year, yday, start = Date::ITALY) -> true or false * - * Returns true if the given ordinal date is valid, and false if not. + * Returns +true+ if the arguments define a valid ordinal date, + * +false+ otherwise: * - * For example: + * Date.valid_ordinal?(2001, 34) # => true + * Date.valid_ordinal?(2001, 366) # => false * - * Date.valid_ordinal?(2001,34) #=> true - * Date.valid_ordinal?(2001,366) #=> false + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * See also jd and ordinal. + * Related: Date.jd, Date.ordinal. */ static VALUE date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass) @@ -2619,6 +2885,8 @@ date_s_valid_ordinal_p(int argc, VALUE *argv, VALUE klass) rb_scan_args(argc, argv, "21", &vy, &vd, &vsg); + RETURN_FALSE_UNLESS_NUMERIC(vy); + RETURN_FALSE_UNLESS_NUMERIC(vd); argv2[0] = vy; argv2[1] = vd; if (argc < 3) @@ -2662,6 +2930,7 @@ valid_commercial_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass) { @@ -2684,16 +2953,19 @@ date_s__valid_commercial_p(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.valid_commercial?(cwyear, cweek, cwday[, start=Date::ITALY]) -> bool + * Date.valid_commercial?(cwyear, cweek, cwday, start = Date::ITALY) -> true or false * - * Returns true if the given week date is valid, and false if not. + * Returns +true+ if the arguments define a valid commercial date, + * +false+ otherwise: * - * For example: + * Date.valid_commercial?(2001, 5, 6) # => true + * Date.valid_commercial?(2001, 5, 8) # => false * - * Date.valid_commercial?(2001,5,6) #=> true - * Date.valid_commercial?(2001,5,8) #=> false + * See Date.commercial. * - * See also jd and commercial. + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * + * Related: Date.jd, Date.commercial. */ static VALUE date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) @@ -2703,6 +2975,9 @@ date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) rb_scan_args(argc, argv, "31", &vy, &vw, &vd, &vsg); + RETURN_FALSE_UNLESS_NUMERIC(vy); + RETURN_FALSE_UNLESS_NUMERIC(vw); + RETURN_FALSE_UNLESS_NUMERIC(vd); argv2[0] = vy; argv2[1] = vw; argv2[2] = vd; @@ -2717,6 +2992,7 @@ date_s_valid_commercial_p(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd) { @@ -2748,6 +3024,7 @@ valid_weeknum_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } } +/* :nodoc: */ static VALUE date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass) { @@ -2768,6 +3045,7 @@ date_s__valid_weeknum_p(int argc, VALUE *argv, VALUE klass) return valid_weeknum_sub(5, argv2, klass, 1); } +/* :nodoc: */ static VALUE date_s_valid_weeknum_p(int argc, VALUE *argv, VALUE klass) { @@ -2819,6 +3097,7 @@ valid_nth_kday_sub(int argc, VALUE *argv, VALUE klass, int need_jd) } } +/* :nodoc: */ static VALUE date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) { @@ -2839,6 +3118,7 @@ date_s__valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) return valid_nth_kday_sub(5, argv2, klass, 1); } +/* :nodoc: */ static VALUE date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) { @@ -2861,6 +3141,7 @@ date_s_valid_nth_kday_p(int argc, VALUE *argv, VALUE klass) return Qtrue; } +/* :nodoc: */ static VALUE date_s_zone_to_diff(VALUE klass, VALUE str) { @@ -2870,15 +3151,15 @@ date_s_zone_to_diff(VALUE klass, VALUE str) /* * call-seq: - * Date.julian_leap?(year) -> bool + * Date.julian_leap?(year) -> true or false * - * Returns true if the given year is a leap year of the proleptic - * Julian calendar. + * Returns +true+ if the given year is a leap year + * in the {proleptic Julian calendar}[https://en.wikipedia.org/wiki/Proleptic_Julian_calendar], +false+ otherwise: * - * For example: + * Date.julian_leap?(1900) # => true + * Date.julian_leap?(1901) # => false * - * Date.julian_leap?(1900) #=> true - * Date.julian_leap?(1901) #=> false + * Related: Date.gregorian_leap?. */ static VALUE date_s_julian_leap_p(VALUE klass, VALUE y) @@ -2886,22 +3167,22 @@ date_s_julian_leap_p(VALUE klass, VALUE y) VALUE nth; int ry; + check_numeric(y, "year"); decode_year(y, +1, &nth, &ry); return f_boolcast(c_julian_leap_p(ry)); } /* * call-seq: - * Date.gregorian_leap?(year) -> bool - * Date.leap?(year) -> bool + * Date.gregorian_leap?(year) -> true or false * - * Returns true if the given year is a leap year of the proleptic - * Gregorian calendar. + * Returns +true+ if the given year is a leap year + * in the {proleptic Gregorian calendar}[https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar], +false+ otherwise: * - * For example: + * Date.gregorian_leap?(2000) # => true + * Date.gregorian_leap?(2001) # => false * - * Date.gregorian_leap?(1900) #=> false - * Date.gregorian_leap?(2000) #=> true + * Related: Date.julian_leap?. */ static VALUE date_s_gregorian_leap_p(VALUE klass, VALUE y) @@ -2909,22 +3190,41 @@ date_s_gregorian_leap_p(VALUE klass, VALUE y) VALUE nth; int ry; + check_numeric(y, "year"); decode_year(y, -1, &nth, &ry); return f_boolcast(c_gregorian_leap_p(ry)); } static void -d_lite_gc_mark(union DateData *dat) +d_lite_gc_mark(void *ptr) { + union DateData *dat = ptr; if (simple_dat_p(dat)) rb_gc_mark(dat->s.nth); else { rb_gc_mark(dat->c.nth); rb_gc_mark(dat->c.sf); - } } +static size_t +d_lite_memsize(const void *ptr) +{ + const union DateData *dat = ptr; + return complex_dat_p(dat) ? sizeof(struct ComplexDateData) : sizeof(struct SimpleDateData); +} + +#ifndef HAVE_RB_EXT_RACTOR_SAFE +# define RUBY_TYPED_FROZEN_SHAREABLE 0 +#endif + +static const rb_data_type_t d_lite_type = { + "Date", + {d_lite_gc_mark, RUBY_TYPED_DEFAULT_FREE, d_lite_memsize,}, + 0, 0, + RUBY_TYPED_FREE_IMMEDIATELY|RUBY_TYPED_WB_PROTECTED|RUBY_TYPED_FROZEN_SHAREABLE, +}; + inline static VALUE d_simple_new_internal(VALUE klass, VALUE nth, int jd, @@ -2935,9 +3235,9 @@ d_simple_new_internal(VALUE klass, struct SimpleDateData *dat; VALUE obj; - obj = Data_Make_Struct(klass, struct SimpleDateData, - d_lite_gc_mark, -1, dat); - set_to_simple(dat, nth, jd, sg, y, m, d, flags & ~COMPLEX_DAT); + obj = TypedData_Make_Struct(klass, struct SimpleDateData, + &d_lite_type, dat); + set_to_simple(obj, dat, nth, jd, sg, y, m, d, flags); assert(have_jd_p(dat) || have_civil_p(dat)); @@ -2956,10 +3256,10 @@ d_complex_new_internal(VALUE klass, struct ComplexDateData *dat; VALUE obj; - obj = Data_Make_Struct(klass, struct ComplexDateData, - d_lite_gc_mark, -1, dat); - set_to_complex(dat, nth, jd, df, sf, of, sg, - y, m, d, h, min, s, flags | COMPLEX_DAT); + obj = TypedData_Make_Struct(klass, struct ComplexDateData, + &d_lite_type, dat); + set_to_complex(obj, dat, nth, jd, df, sf, of, sg, + y, m, d, h, min, s, flags); assert(have_jd_p(dat) || have_civil_p(dat)); assert(have_df_p(dat) || have_time_p(dat)); @@ -3018,7 +3318,7 @@ old_to_new(VALUE ajd, VALUE of, VALUE sg, *rsg = NUM2DBL(sg); if (*rdf < 0 || *rdf >= DAY_IN_SECONDS) - rb_raise(rb_eArgError, "invalid day fraction"); + rb_raise(eDateError, "invalid day fraction"); if (f_lt_p(*rsf, INT2FIX(0)) || f_ge_p(*rsf, INT2FIX(SECOND_IN_NANOSECONDS))) @@ -3035,6 +3335,7 @@ old_to_new(VALUE ajd, VALUE of, VALUE sg, } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s_new_bang(int argc, VALUE *argv, VALUE klass) { @@ -3089,7 +3390,7 @@ wholenum_p(VALUE x) break; case T_RATIONAL: { - VALUE den = RRATIONAL(x)->den; + VALUE den = rb_rational_den(x); return FIXNUM_P(den) && FIX2LONG(den) == 1; } break; @@ -3100,7 +3401,7 @@ wholenum_p(VALUE x) inline static VALUE to_integer(VALUE x) { - if (FIXNUM_P(x) || RB_TYPE_P(x, T_BIGNUM)) + if (RB_INTEGER_TYPE_P(x)) return x; return f_to_i(x); } @@ -3176,64 +3477,75 @@ s_trunc(VALUE s, VALUE *fr) } #define num2num_with_frac(s,n) \ -{\ +do {\ s = s##_trunc(v##s, &fr);\ if (f_nonzero_p(fr)) {\ if (argc > n)\ - rb_raise(rb_eArgError, "invalid fraction");\ + rb_raise(eDateError, "invalid fraction");\ fr2 = fr;\ }\ -} +} while (0) #define num2int_with_frac(s,n) \ -{\ +do {\ s = NUM2INT(s##_trunc(v##s, &fr));\ if (f_nonzero_p(fr)) {\ if (argc > n)\ - rb_raise(rb_eArgError, "invalid fraction");\ + rb_raise(eDateError, "invalid fraction");\ fr2 = fr;\ }\ -} +} while (0) #define canon24oc() \ -{\ +do {\ if (rh == 24) {\ rh = 0;\ fr2 = f_add(fr2, INT2FIX(1));\ }\ -} +} while (0) #define add_frac() \ -{\ +do {\ if (f_nonzero_p(fr2))\ ret = d_lite_plus(ret, fr2);\ -} +} while (0) #define val2sg(vsg,dsg) \ -{\ +do {\ dsg = NUM2DBL(vsg);\ if (!c_valid_start_p(dsg)) {\ dsg = DEFAULT_SG;\ rb_warning("invalid start is ignored");\ }\ -} +} while (0) static VALUE d_lite_plus(VALUE, VALUE); /* * call-seq: - * Date.jd([jd=0[, start=Date::ITALY]]) -> date + * Date.jd(jd = 0, start = Date::ITALY) -> date + * + * Returns a new \Date object formed from the arguments: + * + * Date.jd(2451944).to_s # => "2001-02-03" + * Date.jd(2451945).to_s # => "2001-02-04" + * Date.jd(0).to_s # => "-4712-01-01" + * + * The returned date is: * - * Creates a date object denoting the given chronological Julian day - * number. + * - Gregorian, if the argument is greater than or equal to +start+: * - * For example: + * Date::ITALY # => 2299161 + * Date.jd(Date::ITALY).gregorian? # => true + * Date.jd(Date::ITALY + 1).gregorian? # => true * - * Date.jd(2451944) #=> #<Date: 2001-02-03 ...> - * Date.jd(2451945) #=> #<Date: 2001-02-04 ...> - * Date.jd(0) #=> #<Date: -4712-01-01 ...> + * - Julian, otherwise * - * See also new. + * Date.jd(Date::ITALY - 1).julian? # => true + * + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * + * Related: Date.new. */ static VALUE date_s_jd(int argc, VALUE *argv, VALUE klass) @@ -3251,6 +3563,7 @@ date_s_jd(int argc, VALUE *argv, VALUE klass) case 2: val2sg(vsg, sg); case 1: + check_numeric(vjd, "jd"); num2num_with_frac(jd, positive_inf); } @@ -3271,21 +3584,33 @@ date_s_jd(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.ordinal([year=-4712[, yday=1[, start=Date::ITALY]]]) -> date + * Date.ordinal(year = -4712, yday = 1, start = Date::ITALY) -> date + * + * Returns a new \Date object formed fom the arguments. + * + * With no arguments, returns the date for January 1, -4712: + * + * Date.ordinal.to_s # => "-4712-01-01" + * + * With argument +year+, returns the date for January 1 of that year: + * + * Date.ordinal(2001).to_s # => "2001-01-01" + * Date.ordinal(-2001).to_s # => "-2001-01-01" * - * Creates a date object denoting the given ordinal date. + * With positive argument +yday+ == +n+, + * returns the date for the +nth+ day of the given year: * - * The day of year should be a negative or a positive number (as a - * relative day from the end of year when negative). It should not be - * zero. + * Date.ordinal(2001, 14).to_s # => "2001-01-14" * - * For example: + * With negative argument +yday+, counts backward from the end of the year: * - * Date.ordinal(2001) #=> #<Date: 2001-01-01 ...> - * Date.ordinal(2001,34) #=> #<Date: 2001-02-03 ...> - * Date.ordinal(2001,-1) #=> #<Date: 2001-12-31 ...> + * Date.ordinal(2001, -14).to_s # => "2001-12-18" * - * See also jd and new. + * Raises an exception if +yday+ is zero or out of range. + * + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * + * Related: Date.jd, Date.new. */ static VALUE date_s_ordinal(int argc, VALUE *argv, VALUE klass) @@ -3305,8 +3630,10 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass) case 3: val2sg(vsg, sg); case 2: + check_numeric(vd, "yday"); num2int_with_frac(d, positive_inf); case 1: + check_numeric(vy, "year"); y = vy; } @@ -3318,7 +3645,7 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); ret = d_simple_new_internal(klass, nth, rjd, @@ -3331,38 +3658,48 @@ date_s_ordinal(int argc, VALUE *argv, VALUE klass) } /* + * Same as Date.new. + */ +static VALUE +date_s_civil(int argc, VALUE *argv, VALUE klass) +{ + return date_initialize(argc, argv, d_lite_s_alloc_simple(klass)); +} + +/* * call-seq: - * Date.civil([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]]) -> date - * Date.new([year=-4712[, month=1[, mday=1[, start=Date::ITALY]]]]) -> date + * Date.new(year = -4712, month = 1, mday = 1, start = Date::ITALY) -> date + * + * Returns a new \Date object constructed from the given arguments: * - * Creates a date object denoting the given calendar date. + * Date.new(2022).to_s # => "2022-01-01" + * Date.new(2022, 2).to_s # => "2022-02-01" + * Date.new(2022, 2, 4).to_s # => "2022-02-04" * - * In this class, BCE years are counted astronomically. Thus, the - * year before the year 1 is the year zero, and the year preceding the - * year zero is the year -1. The month and the day of month should be - * a negative or a positive number (as a relative month/day from the - * end of year/month when negative). They should not be zero. + * Argument +month+ should be in range (1..12) or range (-12..-1); + * when the argument is negative, counts backward from the end of the year: * - * The last argument should be a Julian day number which denotes the - * day of calendar reform. Date::ITALY (2299161=1582-10-15), - * Date::ENGLAND (2361222=1752-09-14), Date::GREGORIAN (the proleptic - * Gregorian calendar) and Date::JULIAN (the proleptic Julian - * calendar) can be specified as a day of calendar reform. + * Date.new(2022, -11, 4).to_s # => "2022-02-04" * - * For example: + * Argument +mday+ should be in range (1..n) or range (-n..-1) + * where +n+ is the number of days in the month; + * when the argument is negative, counts backward from the end of the month. * - * Date.new(2001) #=> #<Date: 2001-01-01 ...> - * Date.new(2001,2,3) #=> #<Date: 2001-02-03 ...> - * Date.new(2001,2,-1) #=> #<Date: 2001-02-28 ...> + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * See also jd. + * Related: Date.jd. */ static VALUE -date_s_civil(int argc, VALUE *argv, VALUE klass) +date_initialize(int argc, VALUE *argv, VALUE self) { VALUE vy, vm, vd, vsg, y, fr, fr2, ret; int m, d; double sg; + struct SimpleDateData *dat = rb_check_typeddata(self, &d_lite_type); + + if (!simple_dat_p(dat)) { + rb_raise(rb_eTypeError, "Date expected"); + } rb_scan_args(argc, argv, "04", &vy, &vm, &vd, &vsg); @@ -3376,10 +3713,13 @@ date_s_civil(int argc, VALUE *argv, VALUE klass) case 4: val2sg(vsg, sg); case 3: + check_numeric(vd, "day"); num2int_with_frac(d, positive_inf); case 2: + check_numeric(vm, "month"); m = NUM2INT(vm); case 1: + check_numeric(vy, "year"); y = vy; } @@ -3390,13 +3730,9 @@ date_s_civil(int argc, VALUE *argv, VALUE klass) if (!valid_gregorian_p(y, m, d, &nth, &ry, &rm, &rd)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); - ret = d_simple_new_internal(klass, - nth, 0, - sg, - ry, rm, rd, - HAVE_CIVIL); + set_to_simple(self, dat, nth, 0, sg, ry, rm, rd, HAVE_CIVIL); } else { VALUE nth; @@ -3406,35 +3742,58 @@ date_s_civil(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rm, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); - ret = d_simple_new_internal(klass, - nth, rjd, - sg, - ry, rm, rd, - HAVE_JD | HAVE_CIVIL); + set_to_simple(self, dat, nth, rjd, sg, ry, rm, rd, HAVE_JD | HAVE_CIVIL); } + ret = self; add_frac(); return ret; } /* * call-seq: - * Date.commercial([cwyear=-4712[, cweek=1[, cwday=1[, start=Date::ITALY]]]]) -> date + * Date.commercial(cwyear = -4712, cweek = 1, cwday = 1, start = Date::ITALY) -> date + * + * Returns a new \Date object constructed from the arguments. * - * Creates a date object denoting the given week date. + * Argument +cwyear+ gives the year, and should be an integer. * - * The week and the day of week should be a negative or a positive - * number (as a relative week/day from the end of year/week when - * negative). They should not be zero. + * Argument +cweek+ gives the index of the week within the year, + * and should be in range (1..53) or (-53..-1); + * in some years, 53 or -53 will be out-of-range; + * if negative, counts backward from the end of the year: * - * For example: + * Date.commercial(2022, 1, 1).to_s # => "2022-01-03" + * Date.commercial(2022, 52, 1).to_s # => "2022-12-26" * - * Date.commercial(2001) #=> #<Date: 2001-01-01 ...> - * Date.commercial(2002) #=> #<Date: 2001-12-31 ...> - * Date.commercial(2001,5,6) #=> #<Date: 2001-02-03 ...> + * Argument +cwday+ gives the indes of the weekday within the week, + * and should be in range (1..7) or (-7..-1); + * 1 or -7 is Monday; + * if negative, counts backward from the end of the week: * - * See also jd and new. + * Date.commercial(2022, 1, 1).to_s # => "2022-01-03" + * Date.commercial(2022, 1, -7).to_s # => "2022-01-03" + * + * When +cweek+ is 1: + * + * - If January 1 is a Friday, Saturday, or Sunday, + * the first week begins in the week after: + * + * Date::ABBR_DAYNAMES[Date.new(2023, 1, 1).wday] # => "Sun" + * Date.commercial(2023, 1, 1).to_s # => "2023-01-02" + Date.commercial(2023, 1, 7).to_s # => "2023-01-08" + * + * - Otherwise, the first week is the week of January 1, + * which may mean some of the days fall on the year before: + * + * Date::ABBR_DAYNAMES[Date.new(2020, 1, 1).wday] # => "Wed" + * Date.commercial(2020, 1, 1).to_s # => "2019-12-30" + Date.commercial(2020, 1, 7).to_s # => "2020-01-05" + * + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * + * Related: Date.jd, Date.new, Date.ordinal. */ static VALUE date_s_commercial(int argc, VALUE *argv, VALUE klass) @@ -3455,10 +3814,13 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass) case 4: val2sg(vsg, sg); case 3: + check_numeric(vd, "cwday"); num2int_with_frac(d, positive_inf); case 2: + check_numeric(vw, "cweek"); w = NUM2INT(vw); case 1: + check_numeric(vy, "year"); y = vy; } @@ -3470,7 +3832,7 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rw, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); ret = d_simple_new_internal(klass, nth, rjd, @@ -3483,6 +3845,7 @@ date_s_commercial(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE date_s_weeknum(int argc, VALUE *argv, VALUE klass) { @@ -3520,7 +3883,7 @@ date_s_weeknum(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rw, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); ret = d_simple_new_internal(klass, nth, rjd, @@ -3532,6 +3895,7 @@ date_s_weeknum(int argc, VALUE *argv, VALUE klass) return ret; } +/* :nodoc: */ static VALUE date_s_nth_kday(int argc, VALUE *argv, VALUE klass) { @@ -3569,7 +3933,7 @@ date_s_nth_kday(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rm, &rn, &rk, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); ret = d_simple_new_internal(klass, nth, rjd, @@ -3606,13 +3970,14 @@ static void set_sg(union DateData *, double); /* * call-seq: - * Date.today([start=Date::ITALY]) -> date + * Date.today(start = Date::ITALY) -> date + * + * Returns a new \Date object constructed from the present date: * - * For example: + * Date.today.to_s # => "2022-07-06" * - * Date.today #=> #<Date: 2011-06-11 ..> + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * Creates a date object denoting the present day. */ static VALUE date_s_today(int argc, VALUE *argv, VALUE klass) @@ -3658,18 +4023,24 @@ date_s_today(int argc, VALUE *argv, VALUE klass) #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))) +#define sym(x) ID2SYM(rb_intern(x"")) + +#define set_hash(k,v) set_hash0(sym(k), v) +#define ref_hash(k) ref_hash0(sym(k)) +#define del_hash(k) del_hash0(sym(k)) static VALUE rt_rewrite_frags(VALUE hash) { VALUE seconds; - seconds = ref_hash("seconds"); + seconds = del_hash("seconds"); if (!NIL_P(seconds)) { - VALUE d, h, min, s, fr; + VALUE offset, d, h, min, s, fr; + + offset = ref_hash("offset"); + if (!NIL_P(offset)) + seconds = f_add(seconds, offset); d = f_idiv(seconds, INT2FIX(DAY_IN_SECONDS)); fr = f_mod(seconds, INT2FIX(DAY_IN_SECONDS)); @@ -3688,14 +4059,10 @@ rt_rewrite_frags(VALUE hash) 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 d_lite_year(VALUE); static VALUE d_lite_wday(VALUE); static VALUE d_lite_jd(VALUE); @@ -3704,93 +4071,93 @@ static VALUE rt_complete_frags(VALUE klass, VALUE hash) { static VALUE tab = Qnil; - int g, e; + long e; VALUE k, a, d; if (NIL_P(tab)) { - tab = rb_ary_new3(11, - rb_ary_new3(2, + tab = f_frozen_ary(11, + f_frozen_ary(2, sym("time"), - rb_ary_new3(3, + f_frozen_ary(3, sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, Qnil, - rb_ary_new3(1, + f_frozen_ary(1, sym("jd"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("ordinal"), - rb_ary_new3(5, + f_frozen_ary(5, sym("year"), sym("yday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("civil"), - rb_ary_new3(6, + f_frozen_ary(6, sym("year"), sym("mon"), sym("mday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("commercial"), - rb_ary_new3(6, + f_frozen_ary(6, sym("cwyear"), sym("cweek"), sym("cwday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("wday"), - rb_ary_new3(4, + f_frozen_ary(4, sym("wday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("wnum0"), - rb_ary_new3(6, + f_frozen_ary(6, sym("year"), sym("wnum0"), sym("wday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, sym("wnum1"), - rb_ary_new3(6, + f_frozen_ary(6, sym("year"), sym("wnum1"), sym("wday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, Qnil, - rb_ary_new3(6, + f_frozen_ary(6, sym("cwyear"), sym("cweek"), sym("wday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, Qnil, - rb_ary_new3(6, + f_frozen_ary(6, sym("year"), sym("wnum0"), sym("cwday"), sym("hour"), sym("min"), sym("sec"))), - rb_ary_new3(2, + f_frozen_ary(2, Qnil, - rb_ary_new3(6, + f_frozen_ary(6, sym("year"), sym("wnum1"), sym("cwday"), @@ -3800,40 +4167,41 @@ rt_complete_frags(VALUE klass, VALUE hash) rb_gc_register_mark_object(tab); } + k = a = Qnil; + { - int i, eno = 0, idx = 0; + long i, eno = 0; + VALUE t = Qnil; - for (i = 0; i < RARRAY_LENINT(tab); i++) { + e = 0; + for (i = 0; i < RARRAY_LEN(tab); i++) { VALUE x, a; - x = RARRAY_PTR(tab)[i]; - a = RARRAY_PTR(x)[1]; + x = RARRAY_AREF(tab, i); + a = RARRAY_AREF(x, 1); { - int j, n = 0; + long j, n = 0; - for (j = 0; j < RARRAY_LENINT(a); j++) - if (!NIL_P(ref_hash0(RARRAY_PTR(a)[j]))) + for (j = 0; j < RARRAY_LEN(a); j++) + if (!NIL_P(ref_hash0(RARRAY_AREF(a, j)))) n++; if (n > eno) { eno = n; - idx = i; + t = x; } } } - if (eno == 0) - g = 0; - else { - g = 1; - k = RARRAY_PTR(RARRAY_PTR(tab)[idx])[0]; - a = RARRAY_PTR(RARRAY_PTR(tab)[idx])[1]; - e = eno; + if (eno > 0) { + k = RARRAY_AREF(t, 0); + a = RARRAY_AREF(t, 1); } + e = eno; } d = Qnil; - if (g && !NIL_P(k) && (RARRAY_LENINT(a) - e)) { + if (!NIL_P(k) && (RARRAY_LEN(a) > e)) { if (k == sym("ordinal")) { if (NIL_P(ref_hash("year"))) { if (NIL_P(d)) @@ -3844,10 +4212,10 @@ rt_complete_frags(VALUE klass, VALUE hash) set_hash("yday", INT2FIX(1)); } else if (k == sym("civil")) { - int i; + long i; - for (i = 0; i < RARRAY_LENINT(a); i++) { - VALUE e = RARRAY_PTR(a)[i]; + for (i = 0; i < RARRAY_LEN(a); i++) { + VALUE e = RARRAY_AREF(a, i); if (!NIL_P(ref_hash0(e))) break; @@ -3861,10 +4229,10 @@ rt_complete_frags(VALUE klass, VALUE hash) set_hash("mday", INT2FIX(1)); } else if (k == sym("commercial")) { - int i; + long i; - for (i = 0; i < RARRAY_LENINT(a); i++) { - VALUE e = RARRAY_PTR(a)[i]; + for (i = 0; i < RARRAY_LEN(a); i++) { + VALUE e = RARRAY_AREF(a, i); if (!NIL_P(ref_hash0(e))) break; @@ -3885,10 +4253,10 @@ rt_complete_frags(VALUE klass, VALUE hash) ref_hash("wday")))); } else if (k == sym("wnum0")) { - int i; + long i; - for (i = 0; i < RARRAY_LENINT(a); i++) { - VALUE e = RARRAY_PTR(a)[i]; + for (i = 0; i < RARRAY_LEN(a); i++) { + VALUE e = RARRAY_AREF(a, i); if (!NIL_P(ref_hash0(e))) break; @@ -3902,10 +4270,10 @@ rt_complete_frags(VALUE klass, VALUE hash) set_hash("wday", INT2FIX(0)); } else if (k == sym("wnum1")) { - int i; + long i; - for (i = 0; i < RARRAY_LENINT(a); i++) { - VALUE e = RARRAY_PTR(a)[i]; + for (i = 0; i < RARRAY_LEN(a); i++) { + VALUE e = RARRAY_AREF(a, i); if (!NIL_P(ref_hash0(e))) break; @@ -3920,7 +4288,7 @@ rt_complete_frags(VALUE klass, VALUE hash) } } - if (g && k == sym("time")) { + if (k == sym("time")) { if (f_le_p(klass, cDateTime)) { if (NIL_P(d)) d = date_s_today(0, (VALUE *)0, cDate); @@ -4115,7 +4483,7 @@ d_new_by_frags(VALUE klass, VALUE hash, VALUE sg) } if (NIL_P(hash)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (NIL_P(ref_hash("jd")) && NIL_P(ref_hash("yday")) && @@ -4132,7 +4500,7 @@ d_new_by_frags(VALUE klass, VALUE hash, VALUE sg) } if (NIL_P(jd)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); { VALUE nth; int rjd; @@ -4160,6 +4528,7 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, rb_scan_args(argc, argv, "11", &vstr, &vfmt); StringValue(vstr); + if (argc > 1) StringValue(vfmt); if (!rb_enc_str_asciicompat_p(vstr)) rb_raise(rb_eArgError, "string should have ASCII compatible encoding"); @@ -4170,7 +4539,6 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, flen = strlen(default_fmt); } else { - StringValue(vfmt); if (!rb_enc_str_asciicompat_p(vfmt)) rb_raise(rb_eArgError, "format should have ASCII compatible encoding"); @@ -4187,12 +4555,10 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, if (!NIL_P(zone)) { rb_enc_copy(zone, vstr); - OBJ_INFECT(zone, vstr); set_hash("zone", zone); } if (!NIL_P(left)) { rb_enc_copy(left, vstr); - OBJ_INFECT(left, vstr); set_hash("leftover", left); } } @@ -4202,17 +4568,20 @@ date_s__strptime_internal(int argc, VALUE *argv, VALUE klass, /* * call-seq: - * Date._strptime(string[, format='%F']) -> hash + * Date._strptime(string, format = '%F') -> hash * - * Parses the given representation of date and time with the given - * template, and returns a hash of parsed elements. + * Returns a hash of values parsed from +string+ + * according to the given +format+: * - * For example: + * Date._strptime('2001-02-03', '%Y-%m-%d') # => {:year=>2001, :mon=>2, :mday=>3} * - * Date._strptime('2001-02-03', '%Y-%m-%d') - * #=> {:year=>2001, :mon=>2, :mday=>3} + * For other formats, see + * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]. + * (Unlike Date.strftime, does not support flags and width.) * - * See also strptime(3) and strftime. + * See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html]. + * + * Related: Date.strptime (returns a \Date object). */ static VALUE date_s__strptime(int argc, VALUE *argv, VALUE klass) @@ -4222,22 +4591,28 @@ date_s__strptime(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.strptime([string='-4712-01-01'[, format='%F'[, start=ITALY]]]) -> date + * Date.strptime(string = '-4712-01-01', format = '%F', start = Date::ITALY) -> date * - * Parses the given representation of date and time with the given - * template, and creates a date object. + * Returns a new \Date object with values parsed from +string+, + * according to the given +format+: + * + * Date.strptime('2001-02-03', '%Y-%m-%d') # => #<Date: 2001-02-03> + * Date.strptime('03-02-2001', '%d-%m-%Y') # => #<Date: 2001-02-03> + * Date.strptime('2001-034', '%Y-%j') # => #<Date: 2001-02-03> + * Date.strptime('2001-W05-6', '%G-W%V-%u') # => #<Date: 2001-02-03> + * Date.strptime('2001 04 6', '%Y %U %w') # => #<Date: 2001-02-03> + * Date.strptime('2001 05 6', '%Y %W %u') # => #<Date: 2001-02-03> + * Date.strptime('sat3feb01', '%a%d%b%y') # => #<Date: 2001-02-03> * - * For example: + * For other formats, see + * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]. + * (Unlike Date.strftime, does not support flags and width.) * - * Date.strptime('2001-02-03', '%Y-%m-%d') #=> #<Date: 2001-02-03 ...> - * Date.strptime('03-02-2001', '%d-%m-%Y') #=> #<Date: 2001-02-03 ...> - * Date.strptime('2001-034', '%Y-%j') #=> #<Date: 2001-02-03 ...> - * Date.strptime('2001-W05-6', '%G-W%V-%u') #=> #<Date: 2001-02-03 ...> - * Date.strptime('2001 04 6', '%Y %U %w') #=> #<Date: 2001-02-03 ...> - * Date.strptime('2001 05 6', '%Y %W %u') #=> #<Date: 2001-02-03 ...> - * Date.strptime('sat3feb01', '%a%d%b%y') #=> #<Date: 2001-02-03 ...> + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * See also strptime(3) and strftime. + * See also {strptime(3)}[https://man7.org/linux/man-pages/man3/strptime.3.html]. + * + * Related: Date._strptime (returns a hash). */ static VALUE date_s_strptime(int argc, VALUE *argv, VALUE klass) @@ -4248,7 +4623,7 @@ date_s_strptime(int argc, VALUE *argv, VALUE klass) switch (argc) { case 0: - str = rb_str_new2("-4712-01-01"); + str = rb_str_new2(JULIAN_EPOCH_DATE); case 1: fmt = rb_str_new2("%F"); case 2: @@ -4267,13 +4642,42 @@ date_s_strptime(int argc, VALUE *argv, VALUE klass) VALUE date__parse(VALUE str, VALUE comp); +static size_t +get_limit(VALUE opt) +{ + if (!NIL_P(opt)) { + VALUE limit = rb_hash_aref(opt, ID2SYM(rb_intern("limit"))); + if (NIL_P(limit)) return SIZE_MAX; + return NUM2SIZET(limit); + } + return 128; +} + +#ifndef HAVE_RB_CATEGORY_WARN +#define rb_category_warn(category, fmt) rb_warn(fmt) +#endif + +static VALUE +check_limit(VALUE str, VALUE opt) +{ + size_t slen, limit; + StringValue(str); + slen = RSTRING_LEN(str); + limit = get_limit(opt); + if (slen > limit) { + rb_raise(rb_eArgError, + "string length (%"PRI_SIZE_PREFIX"u) exceeds the limit %"PRI_SIZE_PREFIX"u", slen, limit); + } + return str; +} + static VALUE date_s__parse_internal(int argc, VALUE *argv, VALUE klass) { - VALUE vstr, vcomp, hash; + VALUE vstr, vcomp, hash, opt; - rb_scan_args(argc, argv, "11", &vstr, &vcomp); - StringValue(vstr); + argc = rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt); + vstr = check_limit(vstr, opt); if (!rb_enc_str_asciicompat_p(vstr)) rb_raise(rb_eArgError, "string should have ASCII compatible encoding"); @@ -4282,33 +4686,37 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass) hash = date__parse(vstr, vcomp); - { - VALUE zone = ref_hash("zone"); - - if (!NIL_P(zone)) { - rb_enc_copy(zone, vstr); - OBJ_INFECT(zone, vstr); - set_hash("zone", zone); - } - } - return hash; } /* * call-seq: - * Date._parse(string[, comp=true]) -> hash + * Date._parse(string, comp = true, limit: 128) -> hash * - * Parses the given representation of date and time, and returns a - * hash of parsed elements. + * <b>Note</b>: + * This method recognizes many forms in +string+, + * but it is not a validator. + * For formats, see + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings] * - * If the optional second argument is true and the detected year is in - * the range "00" to "99", considers the year a 2-digit form and makes - * it full. + * If +string+ does not specify a valid date, + * the result is unpredictable; + * consider using Date._strptime instead. + * + * Returns a hash of values parsed from +string+: * - * For example: + * Date._parse('2001-02-03') # => {:year=>2001, :mon=>2, :mday=>3} * - * Date._parse('2001-02-03') #=> {:year=>2001, :mon=>2, :mday=>3} + * If +comp+ is +true+ and the given year is in the range <tt>(0..99)</tt>, + * the current century is supplied; + * otherwise, the year is taken as given: + * + * Date._parse('01-02-03', true) # => {:year=>2001, :mon=>2, :mday=>3} + * Date._parse('01-02-03', false) # => {:year=>1, :mon=>2, :mday=>3} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.parse(returns a \Date object). */ static VALUE date_s__parse(int argc, VALUE *argv, VALUE klass) @@ -4318,31 +4726,47 @@ date_s__parse(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * Date.parse(string='-4712-01-01'[, comp=true[, start=ITALY]]) -> date + * Date.parse(string = '-4712-01-01', comp = true, start = Date::ITALY, limit: 128) -> date * - * Parses the given representation of date and time, and creates a - * date object. + * <b>Note</b>: + * This method recognizes many forms in +string+, + * but it is not a validator. + * For formats, see + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings] + * If +string+ does not specify a valid date, + * the result is unpredictable; + * consider using Date._strptime instead. * - * If the optional second argument is true and the detected year is in - * the range "00" to "99", considers the year a 2-digit form and makes - * it full. + * Returns a new \Date object with values parsed from +string+: + * + * Date.parse('2001-02-03') # => #<Date: 2001-02-03> + * Date.parse('20010203') # => #<Date: 2001-02-03> + * Date.parse('3rd Feb 2001') # => #<Date: 2001-02-03> * - * For example: + * If +comp+ is +true+ and the given year is in the range <tt>(0..99)</tt>, + * the current century is supplied; + * otherwise, the year is taken as given: * - * Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...> - * Date.parse('20010203') #=> #<Date: 2001-02-03 ...> - * Date.parse('3rd Feb 2001') #=> #<Date: 2001-02-03 ...> + * Date.parse('01-02-03', true) # => #<Date: 2001-02-03> + * Date.parse('01-02-03', false) # => #<Date: 0001-02-03> + * + * See: + * + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._parse (returns a hash). */ static VALUE date_s_parse(int argc, VALUE *argv, VALUE klass) { - VALUE str, comp, sg; + VALUE str, comp, sg, opt; - rb_scan_args(argc, argv, "03", &str, &comp, &sg); + argc = rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01"); + str = rb_str_new2(JULIAN_EPOCH_DATE); case 1: comp = Qtrue; case 2: @@ -4350,11 +4774,12 @@ date_s_parse(int argc, VALUE *argv, VALUE klass) } { - VALUE argv2[2], hash; - - argv2[0] = str; - argv2[1] = comp; - hash = date_s__parse(2, argv2, klass); + int argc2 = 2; + VALUE argv2[3], hash; + argv2[0] = str; + argv2[1] = comp; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__parse(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } @@ -4368,265 +4793,417 @@ VALUE date__jisx0301(VALUE); /* * call-seq: - * Date._iso8601(string) -> hash + * Date._iso8601(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should contain + * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]: * - * Returns a hash of parsed elements. + * d = Date.new(2001, 2, 3) + * s = d.iso8601 # => "2001-02-03" + * Date._iso8601(s) # => {:mday=>3, :year=>2001, :mon=>2} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.iso8601 (returns a \Date object). */ static VALUE -date_s__iso8601(VALUE klass, VALUE str) +date_s__iso8601(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__iso8601(str); } /* * call-seq: - * Date.iso8601(string='-4712-01-01'[, start=ITALY]) -> date + * Date.iso8601(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical ISO 8601 formats. + * Returns a new \Date object with values parsed from +string+, + * which should contain + * an {ISO 8601 formatted date}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications]: + * + * d = Date.new(2001, 2, 3) + * s = d.iso8601 # => "2001-02-03" + * Date.iso8601(s) # => #<Date: 2001-02-03> * - * For example: + * See: * - * Date.iso8601('2001-02-03') #=> #<Date: 2001-02-03 ...> - * Date.iso8601('20010203') #=> #<Date: 2001-02-03 ...> - * Date.iso8601('2001-W05-6') #=> #<Date: 2001-02-03 ...> + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._iso8601 (returns a hash). */ static VALUE date_s_iso8601(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01"); + str = rb_str_new2(JULIAN_EPOCH_DATE); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__iso8601(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__iso8601(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._rfc3339(string) -> hash + * Date._rfc3339(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should be a valid + * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]: + * + * d = Date.new(2001, 2, 3) + * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" + * Date._rfc3339(s) + * # => {:year=>2001, :mon=>2, :mday=>3, :hour=>0, :min=>0, :sec=>0, :zone=>"+00:00", :offset=>0} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. * - * Returns a hash of parsed elements. + * Related: Date.rfc3339 (returns a \Date object). */ static VALUE -date_s__rfc3339(VALUE klass, VALUE str) +date_s__rfc3339(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__rfc3339(str); } /* * call-seq: - * Date.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> date + * Date.rfc3339(string = '-4712-01-01T00:00:00+00:00', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical RFC 3339 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {RFC 3339 format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+3339+Format]: * - * For example: + * d = Date.new(2001, 2, 3) + * s = d.rfc3339 # => "2001-02-03T00:00:00+00:00" + * Date.rfc3339(s) # => #<Date: 2001-02-03> * - * Date.rfc3339('2001-02-03T04:05:06+07:00') #=> #<Date: 2001-02-03 ...> + * See: + * + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._rfc3339 (returns a hash). */ static VALUE date_s_rfc3339(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__rfc3339(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__rfc3339(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._xmlschema(string) -> hash + * Date._xmlschema(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should be a valid + * XML date format: + * + * d = Date.new(2001, 2, 3) + * s = d.xmlschema # => "2001-02-03" + * Date._xmlschema(s) # => {:year=>2001, :mon=>2, :mday=>3} * - * Returns a hash of parsed elements. + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.xmlschema (returns a \Date object). */ static VALUE -date_s__xmlschema(VALUE klass, VALUE str) +date_s__xmlschema(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__xmlschema(str); } /* * call-seq: - * Date.xmlschema(string='-4712-01-01'[, start=ITALY]) -> date + * Date.xmlschema(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical XML Schema formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid XML date format: + * + * d = Date.new(2001, 2, 3) + * s = d.xmlschema # => "2001-02-03" + * Date.xmlschema(s) # => #<Date: 2001-02-03> * - * For example: + * See: * - * Date.xmlschema('2001-02-03') #=> #<Date: 2001-02-03 ...> + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._xmlschema (returns a hash). */ static VALUE date_s_xmlschema(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01"); + str = rb_str_new2(JULIAN_EPOCH_DATE); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__xmlschema(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__xmlschema(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._rfc2822(string) -> hash - * Date._rfc822(string) -> hash + * Date._rfc2822(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should be a valid + * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]: * - * Returns a hash of parsed elements. + * d = Date.new(2001, 2, 3) + * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" + * Date._rfc2822(s) + * # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"+0000", :offset=>0} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date.rfc2822 (returns a \Date object). */ static VALUE -date_s__rfc2822(VALUE klass, VALUE str) +date_s__rfc2822(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__rfc2822(str); } /* * call-seq: - * Date.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> date - * Date.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> date + * Date.rfc2822(string = 'Mon, 1 Jan -4712 00:00:00 +0000', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical RFC 2822 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {RFC 2822 date format}[rdoc-ref:language/strftime_formatting.rdoc@RFC+2822+Format]: + * + * d = Date.new(2001, 2, 3) + * s = d.rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" + * Date.rfc2822(s) # => #<Date: 2001-02-03> * - * For example: + * See: * - * Date.rfc2822('Sat, 3 Feb 2001 00:00:00 +0000') - * #=> #<Date: 2001-02-03 ...> + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._rfc2822 (returns a hash). */ static VALUE date_s_rfc2822(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__rfc2822(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__rfc2822(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._httpdate(string) -> hash + * Date._httpdate(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should be a valid + * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]: + * + * d = Date.new(2001, 2, 3) + * s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" + * Date._httpdate(s) + * # => {:wday=>6, :mday=>3, :mon=>2, :year=>2001, :hour=>0, :min=>0, :sec=>0, :zone=>"GMT", :offset=>0} * - * Returns a hash of parsed elements. + * Related: Date.httpdate (returns a \Date object). */ static VALUE -date_s__httpdate(VALUE klass, VALUE str) +date_s__httpdate(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__httpdate(str); } /* * call-seq: - * Date.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY]) -> date + * Date.httpdate(string = 'Mon, 01 Jan -4712 00:00:00 GMT', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some RFC 2616 format. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid + * {HTTP date format}[rdoc-ref:language/strftime_formatting.rdoc@HTTP+Format]: + * + * d = Date.new(2001, 2, 3) + s = d.httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" + Date.httpdate(s) # => #<Date: 2001-02-03> * - * For example: + * See: * - * Date.httpdate('Sat, 03 Feb 2001 00:00:00 GMT') - * #=> #<Date: 2001-02-03 ...> + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. * + * Related: Date._httpdate (returns a hash). */ static VALUE date_s_httpdate(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME_HTTPDATE); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__httpdate(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__httpdate(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } /* * call-seq: - * Date._jisx0301(string) -> hash + * Date._jisx0301(string, limit: 128) -> hash + * + * Returns a hash of values parsed from +string+, which should be a valid + * {JIS X 0301 date format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]: + * + * d = Date.new(2001, 2, 3) + * s = d.jisx0301 # => "H13.02.03" + * Date._jisx0301(s) # => {:year=>2001, :mon=>2, :mday=>3} + * + * See argument {limit}[rdoc-ref:Date@Argument+limit]. * - * Returns a hash of parsed elements. + * Related: Date.jisx0301 (returns a \Date object). */ static VALUE -date_s__jisx0301(VALUE klass, VALUE str) +date_s__jisx0301(int argc, VALUE *argv, VALUE klass) { + VALUE str, opt; + + rb_scan_args(argc, argv, "1:", &str, &opt); + if (!NIL_P(str)) str = check_limit(str, opt); + return date__jisx0301(str); } /* * call-seq: - * Date.jisx0301(string='-4712-01-01'[, start=ITALY]) -> date + * Date.jisx0301(string = '-4712-01-01', start = Date::ITALY, limit: 128) -> date * - * Creates a new Date object by parsing from a string according to - * some typical JIS X 0301 formats. + * Returns a new \Date object with values parsed from +string+, + * which should be a valid {JIS X 0301 format}[rdoc-ref:language/strftime_formatting.rdoc@JIS+X+0301+Format]: + * + * d = Date.new(2001, 2, 3) + * s = d.jisx0301 # => "H13.02.03" + * Date.jisx0301(s) # => #<Date: 2001-02-03> + * + * For no-era year, legacy format, Heisei is assumed. + * + * Date.jisx0301('13.02.03') # => #<Date: 2001-02-03> * - * For example: + * See: * - * Date.jisx0301('H13.02.03') #=> #<Date: 2001-02-03 ...> + * - Argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. + * - Argument {limit}[rdoc-ref:Date@Argument+limit]. + * + * Related: Date._jisx0301 (returns a hash). */ static VALUE date_s_jisx0301(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01"); + str = rb_str_new2(JULIAN_EPOCH_DATE); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__jisx0301(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + if (!NIL_P(opt)) argv2[argc2++] = opt; + hash = date_s__jisx0301(argc2, argv2, klass); return d_new_by_frags(klass, hash, sg); } } @@ -4641,6 +5218,7 @@ dup_obj(VALUE self) { get_d1b(new); bdat->s = adat->s; + RB_OBJ_WRITTEN(new, Qundef, bdat->s.nth); return new; } } @@ -4649,6 +5227,8 @@ dup_obj(VALUE self) { get_d1b(new); bdat->c = adat->c; + RB_OBJ_WRITTEN(new, Qundef, bdat->c.nth); + RB_OBJ_WRITTEN(new, Qundef, bdat->c.sf); return new; } } @@ -4663,7 +5243,7 @@ dup_obj_as_complex(VALUE self) VALUE new = d_lite_s_alloc_complex(rb_obj_class(self)); { get_d1b(new); - copy_simple_to_complex(&bdat->c, &adat->s); + copy_simple_to_complex(new, &bdat->c, &adat->s); bdat->c.flags |= HAVE_DF | COMPLEX_DAT; return new; } @@ -4673,20 +5253,22 @@ dup_obj_as_complex(VALUE self) { get_d1b(new); bdat->c = adat->c; + RB_OBJ_WRITTEN(new, Qundef, bdat->c.nth); + RB_OBJ_WRITTEN(new, Qundef, bdat->c.sf); return new; } } } #define val2off(vof,iof) \ -{\ +do {\ if (!offset_to_sec(vof, &iof)) {\ iof = 0;\ rb_warning("invalid offset is ignored");\ }\ -} +} while (0) -#ifndef NDEBUG +#if 0 static VALUE d_lite_initialize(int argc, VALUE *argv, VALUE self) { @@ -4694,6 +5276,8 @@ d_lite_initialize(int argc, VALUE *argv, VALUE self) int df, of; double sg; + rb_check_frozen(self); + rb_scan_args(argc, argv, "05", &vjd, &vdf, &vsf, &vof, &vsg); jd = INT2FIX(0); @@ -4711,11 +5295,11 @@ d_lite_initialize(int argc, VALUE *argv, VALUE self) sf = vsf; if (f_lt_p(sf, INT2FIX(0)) || f_ge_p(sf, INT2FIX(SECOND_IN_NANOSECONDS))) - rb_raise(rb_eArgError, "invalid second fraction"); + rb_raise(eDateError, "invalid second fraction"); case 2: df = NUM2INT(vdf); if (df < 0 || df >= DAY_IN_SECONDS) - rb_raise(rb_eArgError, "invalid day fraction"); + rb_raise(eDateError, "invalid day fraction"); case 1: jd = vjd; } @@ -4728,15 +5312,15 @@ d_lite_initialize(int argc, VALUE *argv, VALUE self) decode_jd(jd, &nth, &rjd); if (!df && f_zero_p(sf) && !of) { - set_to_simple(&dat->s, nth, rjd, sg, 0, 0, 0, HAVE_JD); + set_to_simple(self, &dat->s, nth, rjd, sg, 0, 0, 0, HAVE_JD); } else { if (!complex_dat_p(dat)) rb_raise(rb_eArgError, "cannot load complex into simple"); - set_to_complex(&dat->c, nth, rjd, df, sf, of, sg, - 0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF | COMPLEX_DAT); + set_to_complex(self, &dat->c, nth, rjd, df, sf, of, sg, + 0, 0, 0, 0, 0, 0, HAVE_JD | HAVE_DF); } } return self; @@ -4747,13 +5331,35 @@ d_lite_initialize(int argc, VALUE *argv, VALUE self) static VALUE d_lite_initialize_copy(VALUE copy, VALUE date) { + rb_check_frozen(copy); + if (copy == date) return copy; { get_d2(copy, date); if (simple_dat_p(bdat)) { - adat->s = bdat->s; - adat->s.flags &= ~COMPLEX_DAT; + if (simple_dat_p(adat)) { + adat->s = bdat->s; + } + else { + adat->c.flags = bdat->s.flags | COMPLEX_DAT; + adat->c.nth = bdat->s.nth; + adat->c.jd = bdat->s.jd; + adat->c.df = 0; + adat->c.sf = INT2FIX(0); + adat->c.of = 0; + adat->c.sg = bdat->s.sg; + adat->c.year = bdat->s.year; +#ifndef USE_PACK + adat->c.mon = bdat->s.mon; + adat->c.mday = bdat->s.mday; + adat->c.hour = bdat->s.hour; + adat->c.min = bdat->s.min; + adat->c.sec = bdat->s.sec; +#else + adat->c.pc = bdat->s.pc; +#endif + } } else { if (!complex_dat_p(adat)) @@ -4761,13 +5367,13 @@ d_lite_initialize_copy(VALUE copy, VALUE date) "cannot load complex into simple"); adat->c = bdat->c; - adat->c.flags |= COMPLEX_DAT; } } return copy; } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_fill(VALUE self) { @@ -4794,8 +5400,6 @@ d_lite_fill(VALUE self) * Returns the astronomical Julian day number. This is a fractional * number, which is not adjusted by the offset. * - * For example: - * * DateTime.new(2001,2,3,4,5,6,'+7').ajd #=> (11769328217/4800) * DateTime.new(2001,2,2,14,5,6,'-7').ajd #=> (11769328217/4800) */ @@ -4813,8 +5417,6 @@ d_lite_ajd(VALUE self) * Returns the astronomical modified Julian day number. This is * a fractional number, which is not adjusted by the offset. * - * For example: - * * DateTime.new(2001,2,3,4,5,6,'+7').amjd #=> (249325817/4800) * DateTime.new(2001,2,2,14,5,6,'-7').amjd #=> (249325817/4800) */ @@ -4832,8 +5434,6 @@ d_lite_amjd(VALUE self) * Returns the Julian day number. This is a whole number, which is * adjusted by the offset as the local time. * - * For example: - * * DateTime.new(2001,2,3,4,5,6,'+7').jd #=> 2451944 * DateTime.new(2001,2,3,4,5,6,'-7').jd #=> 2451944 */ @@ -4851,8 +5451,6 @@ d_lite_jd(VALUE self) * Returns the modified Julian day number. This is a whole number, * which is adjusted by the offset as the local time. * - * For example: - * * DateTime.new(2001,2,3,4,5,6,'+7').mjd #=> 51943 * DateTime.new(2001,2,3,4,5,6,'-7').mjd #=> 51943 */ @@ -4865,14 +5463,15 @@ d_lite_mjd(VALUE self) /* * call-seq: - * d.ld -> integer + * ld -> integer * - * Returns the Lilian day number. This is a whole number, which is - * adjusted by the offset as the local time. + * Returns the + * {Lilian day number}[https://en.wikipedia.org/wiki/Lilian_date], + * which is the number of days since the beginning of the Gregorian + * calendar, October 15, 1582. * - * For example: + * Date.new(2001, 2, 3).ld # => 152784 * - * Date.new(2001,2,3).ld #=> 152784 */ static VALUE d_lite_ld(VALUE self) @@ -4883,14 +5482,13 @@ d_lite_ld(VALUE self) /* * call-seq: - * d.year -> integer + * year -> integer * - * Returns the year. + * Returns the year: * - * For example: + * Date.new(2001, 2, 3).year # => 2001 + * (Date.new(1, 1, 1) - 1).year # => 0 * - * Date.new(2001,2,3).year #=> 2001 - * (Date.new(1,1,1) - 1).year #=> 0 */ static VALUE d_lite_year(VALUE self) @@ -4901,13 +5499,12 @@ d_lite_year(VALUE self) /* * call-seq: - * d.yday -> fixnum + * yday -> integer * - * Returns the day of the year (1-366). + * Returns the day of the year, in range (1..366): * - * For example: + * Date.new(2001, 2, 3).yday # => 34 * - * Date.new(2001,2,3).yday #=> 34 */ static VALUE d_lite_yday(VALUE self) @@ -4918,14 +5515,12 @@ d_lite_yday(VALUE self) /* * call-seq: - * d.mon -> fixnum - * d.month -> fixnum + * mon -> integer * - * Returns the month (1-12). + * Returns the month in range (1..12): * - * For example: + * Date.new(2001, 2, 3).mon # => 2 * - * Date.new(2001,2,3).mon #=> 2 */ static VALUE d_lite_mon(VALUE self) @@ -4936,14 +5531,12 @@ d_lite_mon(VALUE self) /* * call-seq: - * d.mday -> fixnum - * d.day -> fixnum + * mday -> integer * - * Returns the day of the month (1-31). + * Returns the day of the month in range (1..31): * - * For example: + * Date.new(2001, 2, 3).mday # => 3 * - * Date.new(2001,2,3).mday #=> 3 */ static VALUE d_lite_mday(VALUE self) @@ -4954,13 +5547,12 @@ d_lite_mday(VALUE self) /* * call-seq: - * d.day_fraction -> rational + * day_fraction -> rational * - * Returns the fractional part of the day. + * Returns the fractional part of the day in range (Rational(0, 1)...Rational(1, 1)): * - * For example: + * DateTime.new(2001,2,3,12).day_fraction # => (1/2) * - * DateTime.new(2001,2,3,12).day_fraction #=> (1/2) */ static VALUE d_lite_day_fraction(VALUE self) @@ -4973,14 +5565,14 @@ d_lite_day_fraction(VALUE self) /* * call-seq: - * d.cwyear -> integer + * cwyear -> integer * - * Returns the calendar week based year. + * Returns commercial-date year for +self+ + * (see Date.commercial): * - * For example: + * Date.new(2001, 2, 3).cwyear # => 2001 + * Date.new(2000, 1, 1).cwyear # => 1999 * - * Date.new(2001,2,3).cwyear #=> 2001 - * Date.new(2000,1,1).cwyear #=> 1999 */ static VALUE d_lite_cwyear(VALUE self) @@ -4991,13 +5583,13 @@ d_lite_cwyear(VALUE self) /* * call-seq: - * d.cweek -> fixnum + * cweek -> integer * - * Returns the calendar week number (1-53). + * Returns commercial-date week index for +self+ + * (see Date.commercial): * - * For example: + * Date.new(2001, 2, 3).cweek # => 5 * - * Date.new(2001,2,3).cweek #=> 5 */ static VALUE d_lite_cweek(VALUE self) @@ -5008,13 +5600,14 @@ d_lite_cweek(VALUE self) /* * call-seq: - * d.cwday -> fixnum + * cwday -> integer * - * Returns the day of calendar week (1-7, Monday is 1). + * Returns the commercial-date weekday index for +self+ + * (see Date.commercial); + * 1 is Monday: * - * For example: + * Date.new(2001, 2, 3).cwday # => 6 * - * Date.new(2001,2,3).cwday #=> 6 */ static VALUE d_lite_cwday(VALUE self) @@ -5024,6 +5617,7 @@ d_lite_cwday(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_wnum0(VALUE self) { @@ -5031,6 +5625,7 @@ d_lite_wnum0(VALUE self) return INT2FIX(m_wnum0(dat)); } +/* :nodoc: */ static VALUE d_lite_wnum1(VALUE self) { @@ -5041,13 +5636,12 @@ d_lite_wnum1(VALUE self) /* * call-seq: - * d.wday -> fixnum + * wday -> integer * - * Returns the day of week (0-6, Sunday is zero). + * Returns the day of week in range (0..6); Sunday is 0: * - * For example: + * Date.new(2001, 2, 3).wday # => 6 * - * Date.new(2001,2,3).wday #=> 6 */ static VALUE d_lite_wday(VALUE self) @@ -5058,9 +5652,9 @@ d_lite_wday(VALUE self) /* * call-seq: - * d.sunday? -> bool + * sunday? -> true or false * - * Returns true if the date is Sunday. + * Returns +true+ if +self+ is a Sunday, +false+ otherwise. */ static VALUE d_lite_sunday_p(VALUE self) @@ -5071,9 +5665,9 @@ d_lite_sunday_p(VALUE self) /* * call-seq: - * d.monday? -> bool + * monday? -> true or false * - * Returns true if the date is Monday. + * Returns +true+ if +self+ is a Monday, +false+ otherwise. */ static VALUE d_lite_monday_p(VALUE self) @@ -5084,9 +5678,9 @@ d_lite_monday_p(VALUE self) /* * call-seq: - * d.tuesday? -> bool + * tuesday? -> true or false * - * Returns true if the date is Tuesday. + * Returns +true+ if +self+ is a Tuesday, +false+ otherwise. */ static VALUE d_lite_tuesday_p(VALUE self) @@ -5097,9 +5691,9 @@ d_lite_tuesday_p(VALUE self) /* * call-seq: - * d.wednesday? -> bool + * wednesday? -> true or false * - * Returns true if the date is Wednesday. + * Returns +true+ if +self+ is a Wednesday, +false+ otherwise. */ static VALUE d_lite_wednesday_p(VALUE self) @@ -5110,9 +5704,9 @@ d_lite_wednesday_p(VALUE self) /* * call-seq: - * d.thursday? -> bool + * thursday? -> true or false * - * Returns true if the date is Thursday. + * Returns +true+ if +self+ is a Thursday, +false+ otherwise. */ static VALUE d_lite_thursday_p(VALUE self) @@ -5123,9 +5717,9 @@ d_lite_thursday_p(VALUE self) /* * call-seq: - * d.friday? -> bool + * friday? -> true or false * - * Returns true if the date is Friday. + * Returns +true+ if +self+ is a Friday, +false+ otherwise. */ static VALUE d_lite_friday_p(VALUE self) @@ -5136,9 +5730,9 @@ d_lite_friday_p(VALUE self) /* * call-seq: - * d.saturday? -> bool + * saturday? -> true or false * - * Returns true if the date is Saturday. + * Returns +true+ if +self+ is a Saturday, +false+ otherwise. */ static VALUE d_lite_saturday_p(VALUE self) @@ -5148,6 +5742,7 @@ d_lite_saturday_p(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_nth_kday_p(VALUE self, VALUE n, VALUE k) { @@ -5169,13 +5764,12 @@ d_lite_nth_kday_p(VALUE self, VALUE n, VALUE k) /* * call-seq: - * d.hour -> fixnum + * hour -> integer * - * Returns the hour (0-23). + * Returns the hour in range (0..23): * - * For example: + * DateTime.new(2001, 2, 3, 4, 5, 6).hour # => 4 * - * DateTime.new(2001,2,3,4,5,6).hour #=> 4 */ static VALUE d_lite_hour(VALUE self) @@ -5186,14 +5780,12 @@ d_lite_hour(VALUE self) /* * call-seq: - * d.min -> fixnum - * d.minute -> fixnum + * min -> integer * - * Returns the minute (0-59). + * Returns the minute in range (0..59): * - * For example: + * DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5 * - * DateTime.new(2001,2,3,4,5,6).min #=> 5 */ static VALUE d_lite_min(VALUE self) @@ -5204,14 +5796,12 @@ d_lite_min(VALUE self) /* * call-seq: - * d.sec -> fixnum - * d.second -> fixnum + * sec -> integer * - * Returns the second (0-59). + * Returns the second in range (0..59): * - * For example: + * DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6 * - * DateTime.new(2001,2,3,4,5,6).sec #=> 6 */ static VALUE d_lite_sec(VALUE self) @@ -5222,14 +5812,13 @@ d_lite_sec(VALUE self) /* * call-seq: - * d.sec_fraction -> rational - * d.second_fraction -> rational + * sec_fraction -> rational * - * Returns the fractional part of the second. + * Returns the fractional part of the second in range + * (Rational(0, 1)...Rational(1, 1)): * - * For example: + * DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2) * - * DateTime.new(2001,2,3,4,5,6.5).sec_fraction #=> (1/2) */ static VALUE d_lite_sec_fraction(VALUE self) @@ -5244,8 +5833,6 @@ d_lite_sec_fraction(VALUE self) * * Returns the offset. * - * For example: - * * DateTime.parse('04pm+0730').offset #=> (5/16) */ static VALUE @@ -5261,8 +5848,6 @@ d_lite_offset(VALUE self) * * Returns the timezone. * - * For example: - * * DateTime.parse('04pm+0730').zone #=> "+07:30" */ static VALUE @@ -5274,14 +5859,14 @@ d_lite_zone(VALUE self) /* * call-seq: - * d.julian? -> bool + * d.julian? -> true or false * - * Retruns true if the date is before the day of calendar reform. + * Returns +true+ if the date is before the date of calendar reform, + * +false+ otherwise: * - * For example: + * (Date.new(1582, 10, 15) - 1).julian? # => true + * Date.new(1582, 10, 15).julian? # => false * - * Date.new(1582,10,15).julian? #=> false - * (Date.new(1582,10,15) - 1).julian? #=> true */ static VALUE d_lite_julian_p(VALUE self) @@ -5292,14 +5877,14 @@ d_lite_julian_p(VALUE self) /* * call-seq: - * d.gregorian? -> bool + * gregorian? -> true or false * - * Retunrs true if the date is on or after the day of calendar reform. + * Returns +true+ if the date is on or after + * the date of calendar reform, +false+ otherwise: * - * For example: + * Date.new(1582, 10, 15).gregorian? # => true + * (Date.new(1582, 10, 15) - 1).gregorian? # => false * - * Date.new(1582,10,15).gregorian? #=> true - * (Date.new(1582,10,15) - 1).gregorian? #=> false */ static VALUE d_lite_gregorian_p(VALUE self) @@ -5310,14 +5895,13 @@ d_lite_gregorian_p(VALUE self) /* * call-seq: - * d.leap? -> bool + * leap? -> true or false * - * Returns true if the year is a leap year. + * Returns +true+ if the year is a leap year, +false+ otherwise: * - * For example: + * Date.new(2000).leap? # => true + * Date.new(2001).leap? # => false * - * Date.new(2000).leap? #=> true - * Date.new(2001).leap? #=> false */ static VALUE d_lite_leap_p(VALUE self) @@ -5336,14 +5920,25 @@ d_lite_leap_p(VALUE self) /* * call-seq: - * d.start -> float + * start -> float + * + * Returns the Julian start date for calendar reform; + * if not an infinity, the returned value is suitable + * for passing to Date#jd: * - * Returns the Julian day number denoting the day of calendar reform. + * d = Date.new(2001, 2, 3, Date::ITALY) + * s = d.start # => 2299161.0 + * Date.jd(s).to_s # => "1582-10-15" * - * For example: + * d = Date.new(2001, 2, 3, Date::ENGLAND) + * s = d.start # => 2361222.0 + * Date.jd(s).to_s # => "1752-09-14" + * + * Date.new(2001, 2, 3, Date::GREGORIAN).start # => -Infinity + * Date.new(2001, 2, 3, Date::JULIAN).start # => Infinity + * + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * Date.new(2001,2,3).start #=> 2299161.0 - * Date.new(2001,2,3,Date::GREGORIAN).start #=> -Infinity */ static VALUE d_lite_start(VALUE self) @@ -5386,12 +5981,12 @@ set_sg(union DateData *x, double sg) if (simple_dat_p(x)) { get_s_jd(x); clear_civil(x); - x->s.sg = (sg_cast)sg; + x->s.sg = (date_sg_t)sg; } else { get_c_jd(x); get_c_df(x); clear_civil(x); - x->c.sg = (sg_cast)sg; + x->c.sg = (date_sg_t)sg; } } @@ -5408,14 +6003,17 @@ dup_obj_with_new_start(VALUE obj, double sg) /* * call-seq: - * d.new_start([start=Date::ITALY]) -> date + * new_start(start = Date::ITALY) -> new_date + * + * Returns a copy of +self+ with the given +start+ value: * - * Duplicates self and resets its the day of calendar reform. + * d0 = Date.new(2000, 2, 3) + * d0.julian? # => false + * d1 = d0.new_start(Date::JULIAN) + * d1.julian? # => true * - * For example: + * See argument {start}[rdoc-ref:language/calendars.rdoc@Argument+start]. * - * d = Date.new(1582,10,15) - * d.new_start(Date::JULIAN) #=> #<Date: 1582-10-05 ...> */ static VALUE d_lite_new_start(int argc, VALUE *argv, VALUE self) @@ -5434,9 +6032,10 @@ d_lite_new_start(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.italy -> date + * italy -> new_date + * + * Equivalent to Date#new_start with argument Date::ITALY. * - * This method is equivalent to new_start(Date::ITALY). */ static VALUE d_lite_italy(VALUE self) @@ -5446,9 +6045,9 @@ d_lite_italy(VALUE self) /* * call-seq: - * d.england -> date + * england -> new_date * - * This method is equivalent to new_start(Date::ENGLAND). + * Equivalent to Date#new_start with argument Date::ENGLAND. */ static VALUE d_lite_england(VALUE self) @@ -5458,9 +6057,9 @@ d_lite_england(VALUE self) /* * call-seq: - * d.julian -> date + * julian -> new_date * - * This method is equivalent to new_start(Date::JULIAN). + * Equivalent to Date#new_start with argument Date::JULIAN. */ static VALUE d_lite_julian(VALUE self) @@ -5470,9 +6069,9 @@ d_lite_julian(VALUE self) /* * call-seq: - * d.gregorian -> date + * gregorian -> new_date * - * This method is equivalent to new_start(Date::GREGORIAN). + * Equivalent to Date#new_start with argument Date::GREGORIAN. */ static VALUE d_lite_gregorian(VALUE self) @@ -5507,8 +6106,6 @@ dup_obj_with_new_offset(VALUE obj, int of) * * Duplicates self and resets its offset. * - * For example: - * * d = DateTime.new(2001,2,3,4,5,6,'-02:00') * #=> #<DateTime: 2001-02-03T04:05:06-02:00 ...> * d.new_offset('+09:00') #=> #<DateTime: 2001-02-03T15:05:06+09:00 ...> @@ -5532,11 +6129,9 @@ d_lite_new_offset(int argc, VALUE *argv, VALUE self) * call-seq: * d + other -> date * - * Returns a date object pointing other days after self. The other - * should be a numeric value. If the other is flonum, assumes its - * precision is at most nanosecond. - * - * For example: + * Returns a date object pointing +other+ days after self. The other + * should be a numeric value. If the other is a fractional number, + * assumes its precision is at most nanosecond. * * Date.new(2001,2,3) + 1 #=> #<Date: 2001-02-04 ...> * DateTime.new(2001,2,3) + Rational(1,2) @@ -5549,8 +6144,10 @@ d_lite_new_offset(int argc, VALUE *argv, VALUE self) static VALUE d_lite_plus(VALUE self, VALUE other) { + int try_rational = 1; get_d1(self); + again: switch (TYPE(other)) { case T_FIXNUM: { @@ -5569,15 +6166,7 @@ d_lite_plus(VALUE self, VALUE other) jd = m_jd(dat); else { jd = m_jd(dat) + (int)t; - - if (jd < 0) { - nth = f_sub(nth, INT2FIX(1)); - jd += CM_PERIOD; - } - else if (jd >= CM_PERIOD) { - nth = f_add(nth, INT2FIX(1)); - jd -= CM_PERIOD; - } + canonicalize_jd(nth, jd); } if (simple_dat_p(dat)) @@ -5630,14 +6219,7 @@ d_lite_plus(VALUE self, VALUE other) jd = m_jd(dat); else { jd = m_jd(dat) + jd; - if (jd < 0) { - nth = f_sub(nth, INT2FIX(1)); - jd += CM_PERIOD; - } - else if (jd >= CM_PERIOD) { - nth = f_add(nth, INT2FIX(1)); - jd -= CM_PERIOD; - } + canonicalize_jd(nth, jd); } if (f_zero_p(nth)) @@ -5744,14 +6326,7 @@ d_lite_plus(VALUE self, VALUE other) jd = m_jd(dat); else { jd = m_jd(dat) + jd; - if (jd < 0) { - nth = f_sub(nth, INT2FIX(1)); - jd += CM_PERIOD; - } - else if (jd >= CM_PERIOD) { - nth = f_add(nth, INT2FIX(1)); - jd -= CM_PERIOD; - } + canonicalize_jd(nth, jd); } if (f_zero_p(nth)) @@ -5780,21 +6355,23 @@ d_lite_plus(VALUE self, VALUE other) } break; default: - if (!k_numeric_p(other)) - rb_raise(rb_eTypeError, "expected numeric"); + expect_numeric(other); other = f_to_r(other); -#ifdef CANONICALIZATION_FOR_MATHN - if (!k_rational_p(other)) - return d_lite_plus(self, other); -#endif + if (!k_rational_p(other)) { + if (!try_rational) Check_Type(other, T_RATIONAL); + try_rational = 0; + goto again; + } /* fall through */ case T_RATIONAL: { VALUE nth, sf, t; int jd, df, s; - if (wholenum_p(other)) - return d_lite_plus(self, RRATIONAL(other)->num); + if (wholenum_p(other)) { + other = rb_rational_num(other); + goto again; + } if (f_positive_p(other)) s = +1; @@ -5854,14 +6431,7 @@ d_lite_plus(VALUE self, VALUE other) jd = m_jd(dat); else { jd = m_jd(dat) + jd; - if (jd < 0) { - nth = f_sub(nth, INT2FIX(1)); - jd += CM_PERIOD; - } - else if (jd >= CM_PERIOD) { - nth = f_add(nth, INT2FIX(1)); - jd -= CM_PERIOD; - } + canonicalize_jd(nth, jd); } if (f_zero_p(nth)) @@ -5905,15 +6475,7 @@ minus_dd(VALUE self, VALUE other) d = m_jd(adat) - m_jd(bdat); df = m_df(adat) - m_df(bdat); sf = f_sub(m_sf(adat), m_sf(bdat)); - - if (d < 0) { - n = f_sub(n, INT2FIX(1)); - d += CM_PERIOD; - } - else if (d >= CM_PERIOD) { - n = f_add(n, INT2FIX(1)); - d -= CM_PERIOD; - } + canonicalize_jd(n, d); if (df < 0) { d -= 1; @@ -5945,7 +6507,7 @@ minus_dd(VALUE self, VALUE other) if (f_nonzero_p(sf)) r = f_add(r, ns_to_day(sf)); - if (TYPE(r) == T_RATIONAL) + if (RB_TYPE_P(r, T_RATIONAL)) return r; return rb_rational_new1(r); } @@ -5955,12 +6517,12 @@ minus_dd(VALUE self, VALUE other) * call-seq: * d - other -> date or rational * - * Returns the difference between the two dates if the other is a date - * object. If the other is a numeric value, returns a date object - * pointing other days before self. If the other is flonum, assumes - * its precision is at most nanosecond. - * - * For example: + * If the other is a date object, returns a Rational + * whose value is the difference between the two dates in days. + * If the other is a numeric value, returns a date object + * pointing +other+ days before self. + * If the other is a fractional number, + * assumes its precision is at most nanosecond. * * Date.new(2001,2,3) - 1 #=> #<Date: 2001-02-02 ...> * DateTime.new(2001,2,3) - Rational(1,2) @@ -5982,8 +6544,7 @@ d_lite_minus(VALUE self, VALUE other) case T_FLOAT: return d_lite_plus(self, DBL2NUM(-RFLOAT_VALUE(other))); default: - if (!k_numeric_p(other)) - rb_raise(rb_eTypeError, "expected numeric"); + expect_numeric(other); /* fall through */ case T_BIGNUM: case T_RATIONAL: @@ -5993,9 +6554,9 @@ d_lite_minus(VALUE self, VALUE other) /* * call-seq: - * d.next_day([n=1]) -> date + * next_day(n = 1) -> new_date * - * This method is equivalent to d + n. + * Equivalent to Date#+ with argument +n+. */ static VALUE d_lite_next_day(int argc, VALUE *argv, VALUE self) @@ -6010,9 +6571,9 @@ d_lite_next_day(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.prev_day([n=1]) -> date + * prev_day(n = 1) -> new_date * - * This method is equivalent to d - n. + * Equivalent to Date#- with argument +n+. */ static VALUE d_lite_prev_day(int argc, VALUE *argv, VALUE self) @@ -6027,9 +6588,14 @@ d_lite_prev_day(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.next -> date + * d.next -> new_date + * + * Returns a new \Date object representing the following day: + * + * d = Date.new(2001, 2, 3) + * d.to_s # => "2001-02-03" + * d.next.to_s # => "2001-02-04" * - * Returns a date object denoting the following day. */ static VALUE d_lite_next(VALUE self) @@ -6039,16 +6605,30 @@ d_lite_next(VALUE self) /* * call-seq: - * d >> n -> date + * d >> n -> new_date + * + * Returns a new \Date object representing the date + * +n+ months later; +n+ should be a numeric: + * + * (Date.new(2001, 2, 3) >> 1).to_s # => "2001-03-03" + * (Date.new(2001, 2, 3) >> -2).to_s # => "2000-12-03" + * + * When the same day does not exist for the new month, + * the last day of that month is used instead: + * + * (Date.new(2001, 1, 31) >> 1).to_s # => "2001-02-28" + * (Date.new(2001, 1, 31) >> -4).to_s # => "2000-09-30" + * + * This results in the following, possibly unexpected, behaviors: * - * Returns a date object pointing n months after self. The n should - * be a numeric value. + * d0 = Date.new(2001, 1, 31) + * d1 = d0 >> 1 # => #<Date: 2001-02-28> + * d2 = d1 >> 1 # => #<Date: 2001-03-28> * - * For example: + * d0 = Date.new(2001, 1, 31) + * d1 = d0 >> 1 # => #<Date: 2001-02-28> + * d2 = d1 >> -1 # => #<Date: 2001-01-28> * - * Date.new(2001,2,3) >> 1 #=> #<Date: 2001-03-03 ...> - * Date.new(2001,1,31) >> 1 #=> #<Date: 2001-02-28 ...> - * Date.new(2001,2,3) >> -2 #=> #<Date: 2000-12-03 ...> */ static VALUE d_lite_rshift(VALUE self, VALUE other) @@ -6083,7 +6663,7 @@ d_lite_rshift(VALUE self, VALUE other) &rm, &rd, &rjd, &ns)) break; if (--d < 1) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); } encode_jd(nth, rjd, &rjd2); return d_lite_plus(self, f_sub(rjd2, m_real_local_jd(dat))); @@ -6093,26 +6673,41 @@ d_lite_rshift(VALUE self, VALUE other) * call-seq: * d << n -> date * - * Returns a date object pointing n months before self. The n should - * be a numeric value. + * Returns a new \Date object representing the date + * +n+ months earlier; +n+ should be a numeric: * - * For example: + * (Date.new(2001, 2, 3) << 1).to_s # => "2001-01-03" + * (Date.new(2001, 2, 3) << -2).to_s # => "2001-04-03" + * + * When the same day does not exist for the new month, + * the last day of that month is used instead: + * + * (Date.new(2001, 3, 31) << 1).to_s # => "2001-02-28" + * (Date.new(2001, 3, 31) << -6).to_s # => "2001-09-30" + * + * This results in the following, possibly unexpected, behaviors: + * + * d0 = Date.new(2001, 3, 31) + * d0 << 2 # => #<Date: 2001-01-31> + * d0 << 1 << 1 # => #<Date: 2001-01-28> + * + * d0 = Date.new(2001, 3, 31) + * d1 = d0 << 1 # => #<Date: 2001-02-28> + * d2 = d1 << -1 # => #<Date: 2001-03-28> * - * Date.new(2001,2,3) << 1 #=> #<Date: 2001-01-03 ...> - * Date.new(2001,1,31) << 11 #=> #<Date: 2000-02-29 ...> - * Date.new(2001,2,3) << -1 #=> #<Date: 2001-03-03 ...> */ static VALUE d_lite_lshift(VALUE self, VALUE other) { + expect_numeric(other); return d_lite_rshift(self, f_negate(other)); } /* * call-seq: - * d.next_month([n=1]) -> date + * next_month(n = 1) -> new_date * - * This method is equivalent to d >> n + * Equivalent to #>> with argument +n+. */ static VALUE d_lite_next_month(int argc, VALUE *argv, VALUE self) @@ -6127,9 +6722,9 @@ d_lite_next_month(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.prev_month([n=1]) -> date + * prev_month(n = 1) -> new_date * - * This method is equivalent to d << n + * Equivalent to #<< with argument +n+. */ static VALUE d_lite_prev_month(int argc, VALUE *argv, VALUE self) @@ -6144,9 +6739,9 @@ d_lite_prev_month(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.next_year([n=1]) -> date + * next_year(n = 1) -> new_date * - * This method is equivalent to d >> (n * 12) + * Equivalent to #>> with argument <tt>n * 12</tt>. */ static VALUE d_lite_next_year(int argc, VALUE *argv, VALUE self) @@ -6161,9 +6756,9 @@ d_lite_next_year(int argc, VALUE *argv, VALUE self) /* * call-seq: - * d.prev_year([n=1]) -> date + * prev_year(n = 1) -> new_date * - * This method is equivalent to d << (n * 12) + * Equivalent to #<< with argument <tt>n * 12</tt>. */ static VALUE d_lite_prev_year(int argc, VALUE *argv, VALUE self) @@ -6180,21 +6775,39 @@ static VALUE d_lite_cmp(VALUE, VALUE); /* * call-seq: - * d.step(limit[, step=1]) -> enumerator - * d.step(limit[, step=1]){|date| ...} -> self + * step(limit, step = 1){|date| ... } -> self + * + * Calls the block with specified dates; + * returns +self+. + * + * - The first +date+ is +self+. + * - Each successive +date+ is <tt>date + step</tt>, + * where +step+ is the numeric step size in days. + * - The last date is the last one that is before or equal to +limit+, + * which should be a \Date object. * - * Iterates evaluation of the given block, which takes a date object. - * The limit should be a date object. + * Example: * - * For example: + * limit = Date.new(2001, 12, 31) + * Date.new(2001).step(limit){|date| p date.to_s if date.mday == 31 } * - * Date.new(2001).step(Date.new(2001,-1,-1)).select{|d| d.sunday?}.size - * #=> 52 + * Output: + * + * "2001-01-31" + * "2001-03-31" + * "2001-05-31" + * "2001-07-31" + * "2001-08-31" + * "2001-10-31" + * "2001-12-31" + * + * Returns an Enumerator if no block is given. */ static VALUE d_lite_step(int argc, VALUE *argv, VALUE self) { VALUE limit, step, date; + int c; rb_scan_args(argc, argv, "11", &limit, &step); @@ -6209,35 +6822,31 @@ d_lite_step(int argc, VALUE *argv, VALUE self) RETURN_ENUMERATOR(self, argc, argv); date = self; - switch (FIX2INT(f_cmp(step, INT2FIX(0)))) { - case -1: + c = f_cmp(step, INT2FIX(0)); + if (c < 0) { while (FIX2INT(d_lite_cmp(date, limit)) >= 0) { rb_yield(date); date = d_lite_plus(date, step); } - break; - case 0: + } + else if (c == 0) { while (1) rb_yield(date); - break; - case 1: + } + else /* if (c > 0) */ { while (FIX2INT(d_lite_cmp(date, limit)) <= 0) { rb_yield(date); date = d_lite_plus(date, step); } - break; - default: - abort(); } return self; } /* * call-seq: - * d.upto(max) -> enumerator - * d.upto(max){|date| ...} -> self + * upto(max){|date| ... } -> self * - * This method is equivalent to step(max, 1){|date| ...}. + * Equivalent to #step with arguments +max+ and +1+. */ static VALUE d_lite_upto(VALUE self, VALUE max) @@ -6256,10 +6865,9 @@ d_lite_upto(VALUE self, VALUE max) /* * call-seq: - * d.downto(min) -> enumerator - * d.downto(min){|date| ...} -> self + * downto(min){|date| ... } -> self * - * This method is equivalent to step(min, -1){|date| ...}. + * Equivalent to #step with arguments +min+ and <tt>-1</tt>. */ static VALUE d_lite_downto(VALUE self, VALUE min) @@ -6282,10 +6890,10 @@ cmp_gen(VALUE self, VALUE other) get_d1(self); if (k_numeric_p(other)) - return f_cmp(m_ajd(dat), other); + return INT2FIX(f_cmp(m_ajd(dat), other)); else if (k_date_p(other)) - return f_cmp(m_ajd(dat), f_ajd(other)); - return rb_num_coerce_cmp(self, other, rb_intern("<=>")); + return INT2FIX(f_cmp(m_ajd(dat), f_ajd(other))); + return rb_num_coerce_cmp(self, other, id_cmp); } static VALUE @@ -6299,6 +6907,8 @@ cmp_dd(VALUE self, VALUE other) int a_jd, b_jd, a_df, b_df; + m_canonicalize_jd(self, adat); + m_canonicalize_jd(other, bdat); a_nth = m_nth(adat); b_nth = m_nth(bdat); if (f_eqeq_p(a_nth, b_nth)) { @@ -6345,21 +6955,43 @@ cmp_dd(VALUE self, VALUE other) /* * call-seq: - * d <=> other -> -1, 0, +1 or nil + * self <=> other -> -1, 0, 1 or nil + * + * Compares +self+ and +other+, returning: + * + * - <tt>-1</tt> if +other+ is larger. + * - <tt>0</tt> if the two are equal. + * - <tt>1</tt> if +other+ is smaller. + * - +nil+ if the two are incomparable. + * + * Argument +other+ may be: * - * Compares the two dates and returns -1, zero, 1 or nil. The other - * should be a date object or a numeric value as an astronomical - * Julian day number. + * - Another \Date object: * - * For example: + * d = Date.new(2022, 7, 27) # => #<Date: 2022-07-27 ((2459788j,0s,0n),+0s,2299161j)> + * prev_date = d.prev_day # => #<Date: 2022-07-26 ((2459787j,0s,0n),+0s,2299161j)> + * next_date = d.next_day # => #<Date: 2022-07-28 ((2459789j,0s,0n),+0s,2299161j)> + * d <=> next_date # => -1 + * d <=> d # => 0 + * d <=> prev_date # => 1 * - * Date.new(2001,2,3) <=> Date.new(2001,2,4) #=> -1 - * Date.new(2001,2,3) <=> Date.new(2001,2,3) #=> 0 - * Date.new(2001,2,3) <=> Date.new(2001,2,2) #=> 1 - * Date.new(2001,2,3) <=> Object.new #=> nil - * Date.new(2001,2,3) <=> Rational(4903887,2)#=> 0 + * - A DateTime object: + * + * d <=> DateTime.new(2022, 7, 26) # => 1 + * d <=> DateTime.new(2022, 7, 27) # => 0 + * d <=> DateTime.new(2022, 7, 28) # => -1 + * + * - A numeric (compares <tt>self.ajd</tt> to +other+): + * + * d <=> 2459788 # => -1 + * d <=> 2459787 # => 1 + * d <=> 2459786 # => 1 + * d <=> d.ajd # => 0 + * + * - Any other object: + * + * d <=> Object.new # => nil * - * See also Comparable. */ static VALUE d_lite_cmp(VALUE self, VALUE other) @@ -6374,11 +7006,12 @@ d_lite_cmp(VALUE self, VALUE other) m_gregorian_p(adat) == m_gregorian_p(bdat))) return cmp_dd(self, other); - if (have_jd_p(adat) && - have_jd_p(bdat)) { + { VALUE a_nth, b_nth; int a_jd, b_jd; + m_canonicalize_jd(self, adat); + m_canonicalize_jd(other, bdat); a_nth = m_nth(adat); b_nth = m_nth(bdat); if (f_eqeq_p(a_nth, b_nth)) { @@ -6394,74 +7027,6 @@ d_lite_cmp(VALUE self, VALUE other) return INT2FIX(1); } } - else if (a_nth < b_nth) { - return INT2FIX(-1); - } - else { - return INT2FIX(1); - } - } - else { -#ifndef USE_PACK - VALUE a_nth, b_nth; - int a_year, b_year, - a_mon, b_mon, - a_mday, b_mday; -#else - VALUE a_nth, b_nth; - int a_year, b_year, - a_pd, b_pd; -#endif - - a_nth = m_nth(adat); - b_nth = m_nth(bdat); - if (f_eqeq_p(a_nth, b_nth)) { - a_year = m_year(adat); - b_year = m_year(bdat); - if (a_year == b_year) { -#ifndef USE_PACK - a_mon = m_mon(adat); - b_mon = m_mon(bdat); - if (a_mon == b_mon) { - a_mday = m_mday(adat); - b_mday = m_mday(bdat); - if (a_mday == b_mday) { - return INT2FIX(0); - } - else if (a_mday < b_mday) { - return INT2FIX(-1); - } - else { - return INT2FIX(1); - } - } - else if (a_mon < b_mon) { - return INT2FIX(-1); - } - else { - return INT2FIX(1); - } -#else - a_pd = m_pc(adat); - b_pd = m_pc(bdat); - if (a_pd == b_pd) { - return INT2FIX(0); - } - else if (a_pd < b_pd) { - return INT2FIX(-1); - } - else { - return INT2FIX(1); - } -#endif - } - else if (a_year < b_year) { - return INT2FIX(-1); - } - else { - return INT2FIX(1); - } - } else if (f_lt_p(a_nth, b_nth)) { return INT2FIX(-1); } @@ -6481,27 +7046,44 @@ equal_gen(VALUE self, VALUE other) return f_eqeq_p(m_real_local_jd(dat), other); else if (k_date_p(other)) return f_eqeq_p(m_real_local_jd(dat), f_jd(other)); - return rb_num_coerce_cmp(self, other, rb_intern("==")); + return rb_num_coerce_cmp(self, other, id_eqeq_p); } /* * call-seq: - * d === other -> bool - * - * Returns true if they are the same day. - * - * For example: - * - * Date.new(2001,2,3) === Date.new(2001,2,3) - * #=> true - * Date.new(2001,2,3) === Date.new(2001,2,4) - * #=> false - * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,12) - * #=> true - * DateTime.new(2001,2,3) === DateTime.new(2001,2,3,0,0,0,'+24:00') - * #=> true - * DateTime.new(2001,2,3) === DateTime.new(2001,2,4,0,0,0,'+24:00') - * #=> false + * self === other -> true, false, or nil. + * + * Returns +true+ if +self+ and +other+ represent the same date, + * +false+ if not, +nil+ if the two are not comparable. + * + * Argument +other+ may be: + * + * - Another \Date object: + * + * d = Date.new(2022, 7, 27) # => #<Date: 2022-07-27 ((2459788j,0s,0n),+0s,2299161j)> + * prev_date = d.prev_day # => #<Date: 2022-07-26 ((2459787j,0s,0n),+0s,2299161j)> + * next_date = d.next_day # => #<Date: 2022-07-28 ((2459789j,0s,0n),+0s,2299161j)> + * d === prev_date # => false + * d === d # => true + * d === next_date # => false + * + * - A DateTime object: + * + * d === DateTime.new(2022, 7, 26) # => false + * d === DateTime.new(2022, 7, 27) # => true + * d === DateTime.new(2022, 7, 28) # => false + * + * - A numeric (compares <tt>self.jd</tt> to +other+): + * + * d === 2459788 # => true + * d === 2459787 # => false + * d === 2459786 # => false + * d === d.jd # => true + * + * - An object not comparable: + * + * d === Object.new # => nil + * */ static VALUE d_lite_equal(VALUE self, VALUE other) @@ -6515,11 +7097,12 @@ d_lite_equal(VALUE self, VALUE other) if (!(m_gregorian_p(adat) == m_gregorian_p(bdat))) return equal_gen(self, other); - if (have_jd_p(adat) && - have_jd_p(bdat)) { + { VALUE a_nth, b_nth; int a_jd, b_jd; + m_canonicalize_jd(self, adat); + m_canonicalize_jd(other, bdat); a_nth = m_nth(adat); b_nth = m_nth(bdat); a_jd = m_local_jd(adat); @@ -6529,45 +7112,6 @@ d_lite_equal(VALUE self, VALUE other) return Qtrue; return Qfalse; } - else { -#ifndef USE_PACK - VALUE a_nth, b_nth; - int a_year, b_year, - a_mon, b_mon, - a_mday, b_mday; -#else - VALUE a_nth, b_nth; - int a_year, b_year, - a_pd, b_pd; -#endif - - a_nth = m_nth(adat); - b_nth = m_nth(bdat); - if (f_eqeq_p(a_nth, b_nth)) { - a_year = m_year(adat); - b_year = m_year(bdat); - if (a_year == b_year) { -#ifndef USE_PACK - a_mon = m_mon(adat); - b_mon = m_mon(bdat); - if (a_mon == b_mon) { - a_mday = m_mday(adat); - b_mday = m_mday(bdat); - if (a_mday == b_mday) - return Qtrue; - } -#else - /* mon and mday only */ - a_pd = (m_pc(adat) >> MDAY_SHIFT); - b_pd = (m_pc(bdat) >> MDAY_SHIFT); - if (a_pd == b_pd) { - return Qtrue; - } -#endif - } - } - return Qfalse; - } } } @@ -6584,15 +7128,26 @@ d_lite_eql_p(VALUE self, VALUE other) static VALUE d_lite_hash(VALUE self) { - st_index_t v, h[4]; + st_index_t v, h[5]; + VALUE nth; get_d1(self); - h[0] = m_nth(dat); - h[1] = m_jd(dat); - h[2] = m_df(dat); - h[3] = m_sf(dat); + nth = m_nth(dat); + + if (FIXNUM_P(nth)) { + h[0] = 0; + h[1] = (st_index_t)nth; + } else { + h[0] = 1; + h[1] = (st_index_t)FIX2LONG(rb_hash(nth)); + } + + h[2] = m_jd(dat); + h[3] = m_df(dat); + h[4] = m_sf(dat); + v = rb_memhash(h, sizeof(h)); - return LONG2FIX(v); + return ST2FIX(v); } #include "date_tmx.h" @@ -6602,14 +7157,14 @@ static VALUE strftimev(const char *, VALUE, /* * call-seq: - * d.to_s -> string + * to_s -> string * - * Returns a string in an ISO 8601 format (This method doesn't use the - * expanded representations). + * Returns a string representation of the date in +self+ + * in {ISO 8601 extended date format}[rdoc-ref:language/strftime_formatting.rdoc@ISO+8601+Format+Specifications] + * (<tt>'%Y-%m-%d'</tt>): * - * For example: + * Date.new(2001, 2, 3).to_s # => "2001-02-03" * - * Date.new(2001,2,3).to_s #=> "2001-02-03" */ static VALUE d_lite_to_s(VALUE self) @@ -6618,55 +7173,42 @@ d_lite_to_s(VALUE self) } #ifndef NDEBUG +/* :nodoc: */ static VALUE -mk_inspect_flags(union DateData *x) -{ - return rb_enc_sprintf(rb_usascii_encoding(), - "%c%c%c%c%c", - (x->flags & COMPLEX_DAT) ? 'C' : 'S', - (x->flags & HAVE_JD) ? 'j' : '-', - (x->flags & HAVE_DF) ? 'd' : '-', - (x->flags & HAVE_CIVIL) ? 'c' : '-', - (x->flags & HAVE_TIME) ? 't' : '-'); -} - -static VALUE -mk_inspect_raw(union DateData *x, const char *klass) +mk_inspect_raw(union DateData *x, VALUE klass) { - if (simple_dat_p(x)) { - VALUE nth, flags; + char flags[6]; - RB_GC_GUARD(nth) = f_inspect(x->s.nth); - RB_GC_GUARD(flags) = mk_inspect_flags(x); + flags[0] = (x->flags & COMPLEX_DAT) ? 'C' : 'S'; + flags[1] = (x->flags & HAVE_JD) ? 'j' : '-'; + flags[2] = (x->flags & HAVE_DF) ? 'd' : '-'; + flags[3] = (x->flags & HAVE_CIVIL) ? 'c' : '-'; + flags[4] = (x->flags & HAVE_TIME) ? 't' : '-'; + flags[5] = '\0'; + if (simple_dat_p(x)) { return rb_enc_sprintf(rb_usascii_encoding(), - "#<%s: " - "(%sth,%dj),+0s,%.0fj; " + "#<%"PRIsVALUE": " + "(%+"PRIsVALUE"th,%dj),+0s,%.0fj; " "%dy%dm%dd; %s>", - klass ? klass : "?", - RSTRING_PTR(nth), x->s.jd, x->s.sg, + klass, + x->s.nth, x->s.jd, x->s.sg, #ifndef USE_PACK x->s.year, x->s.mon, x->s.mday, #else x->s.year, EX_MON(x->s.pc), EX_MDAY(x->s.pc), #endif - RSTRING_PTR(flags)); + flags); } else { - VALUE nth, sf, flags; - - RB_GC_GUARD(nth) = f_inspect(x->c.nth); - RB_GC_GUARD(sf) = f_inspect(x->c.sf); - RB_GC_GUARD(flags) = mk_inspect_flags(x); - return rb_enc_sprintf(rb_usascii_encoding(), - "#<%s: " - "(%sth,%dj,%ds,%sn),%+ds,%.0fj; " + "#<%"PRIsVALUE": " + "(%+"PRIsVALUE"th,%dj,%ds,%+"PRIsVALUE"n)," + "%+ds,%.0fj; " "%dy%dm%dd %dh%dm%ds; %s>", - klass ? klass : "?", - RSTRING_PTR(nth), x->c.jd, x->c.df, - RSTRING_PTR(sf), + klass, + x->c.nth, x->c.jd, x->c.df, x->c.sf, x->c.of, x->c.sg, #ifndef USE_PACK x->c.year, x->c.mon, x->c.mday, @@ -6677,58 +7219,45 @@ mk_inspect_raw(union DateData *x, const char *klass) EX_HOUR(x->c.pc), EX_MIN(x->c.pc), EX_SEC(x->c.pc), #endif - RSTRING_PTR(flags)); + flags); } } +/* :nodoc: */ static VALUE d_lite_inspect_raw(VALUE self) { get_d1(self); - return mk_inspect_raw(dat, rb_obj_classname(self)); + return mk_inspect_raw(dat, rb_obj_class(self)); } #endif static VALUE -mk_inspect(union DateData *x, const char *klass, const char *to_s) +mk_inspect(union DateData *x, VALUE klass, VALUE to_s) { - VALUE jd, sf; - - RB_GC_GUARD(jd) = f_inspect(m_real_jd(x)); - RB_GC_GUARD(sf) = f_inspect(m_sf(x)); - return rb_enc_sprintf(rb_usascii_encoding(), - "#<%s: %s ((%sj,%ds,%sn),%+ds,%.0fj)>", - klass ? klass : "?", - to_s ? to_s : "?", - RSTRING_PTR(jd), m_df(x), RSTRING_PTR(sf), + "#<%"PRIsVALUE": %"PRIsVALUE" " + "((%+"PRIsVALUE"j,%ds,%+"PRIsVALUE"n),%+ds,%.0fj)>", + klass, to_s, + m_real_jd(x), m_df(x), m_sf(x), m_of(x), m_sg(x)); } /* * call-seq: - * d.inspect -> string - * - * Returns the value as a string for inspection. + * inspect -> string * - * For example: + * Returns a string representation of +self+: * - * Date.new(2001,2,3).inspect - * #=> "#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>" - * DateTime.new(2001,2,3,4,5,6,'-7').inspect - * #=> "#<DateTime: 2001-02-03T04:05:06-07:00 ((2451944j,39906s,0n),-25200s,2299161j)>" + * Date.new(2001, 2, 3).inspect + * # => "#<Date: 2001-02-03 ((2451944j,0s,0n),+0s,2299161j)>" * */ static VALUE d_lite_inspect(VALUE self) { get_d1(self); - { - VALUE to_s; - - RB_GC_GUARD(to_s) = f_to_s(self); - return mk_inspect(dat, rb_obj_classname(self), RSTRING_PTR(to_s)); - } + return mk_inspect(dat, rb_obj_class(self), self); } #include <errno.h> @@ -6805,19 +7334,21 @@ tmx_m_msecs(union DateData *x) return s; } -static VALUE +static int tmx_m_of(union DateData *x) { - return INT2FIX(m_of(x)); + return m_of(x); } static char * tmx_m_zone(union DateData *x) { - return RSTRING_PTR(m_zone(x)); + VALUE zone = m_zone(x); + /* TODO: fix potential dangling pointer */ + return RSTRING_PTR(zone); } -static struct tmx_funcs tmx_funcs = { +static const struct tmx_funcs tmx_funcs = { (VALUE (*)(void *))m_real_year, (int (*)(void *))m_yday, (int (*)(void *))m_mon, @@ -6834,7 +7365,7 @@ static struct tmx_funcs tmx_funcs = { (VALUE (*)(void *))m_sf_in_sec, (VALUE (*)(void *))tmx_m_secs, (VALUE (*)(void *))tmx_m_msecs, - (VALUE (*)(void *))tmx_m_of, + (int (*)(void *))tmx_m_of, (char *(*)(void *))tmx_m_zone }; @@ -6889,7 +7420,6 @@ date_strftime_internal(int argc, VALUE *argv, VALUE self, if (p > fmt) rb_str_cat(str, fmt, p - fmt); } rb_enc_copy(str, vfmt); - OBJ_INFECT(str, vfmt); return str; } else @@ -6898,186 +7428,21 @@ 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; } /* * call-seq: - * d.strftime([format='%F']) -> string - * - * Formats date according to the directives in the given format - * string. - * The directives begins with a percent (%) character. - * Any text not listed as a directive will be passed through to the - * output string. - * - * The directive consists of a percent (%) character, - * zero or more flags, optional minimum field width, - * optional modifier and a conversion specifier - * as follows. - * - * %<flags><width><modifier><conversion> - * - * Flags: - * - don't pad a numerical output. - * _ use spaces for padding. - * 0 use zeros for padding. - * ^ upcase the result string. - * # change case. - * : use colons for %z. - * - * The minimum field width specifies the minimum width. - * - * The modifier is "E" and "O". - * They are ignored. - * - * Format directives: - * - * Date (Year, Month, Day): - * %Y - Year with century (can be negative, 4 digits at least) - * -0001, 0000, 1995, 2009, 14292, etc. - * %C - year / 100 (round down. 20 in 2009) - * %y - year % 100 (00..99) - * - * %m - Month of the year, zero-padded (01..12) - * %_m blank-padded ( 1..12) - * %-m no-padded (1..12) - * %B - The full month name (``January'') - * %^B uppercased (``JANUARY'') - * %b - The abbreviated month name (``Jan'') - * %^b uppercased (``JAN'') - * %h - Equivalent to %b - * - * %d - Day of the month, zero-padded (01..31) - * %-d no-padded (1..31) - * %e - Day of the month, blank-padded ( 1..31) - * - * %j - Day of the year (001..366) - * - * Time (Hour, Minute, Second, Subsecond): - * %H - Hour of the day, 24-hour clock, zero-padded (00..23) - * %k - Hour of the day, 24-hour clock, blank-padded ( 0..23) - * %I - Hour of the day, 12-hour clock, zero-padded (01..12) - * %l - Hour of the day, 12-hour clock, blank-padded ( 1..12) - * %P - Meridian indicator, lowercase (``am'' or ``pm'') - * %p - Meridian indicator, uppercase (``AM'' or ``PM'') - * - * %M - Minute of the hour (00..59) - * - * %S - Second of the minute (00..59) - * - * %L - Millisecond of the second (000..999) - * %N - Fractional seconds digits, default is 9 digits (nanosecond) - * %3N millisecond (3 digits) - * %6N microsecond (6 digits) - * %9N nanosecond (9 digits) - * %12N picosecond (12 digits) - * - * Time zone: - * %z - Time zone as hour and minute offset from UTC (e.g. +0900) - * %:z - hour and minute offset from UTC with a colon (e.g. +09:00) - * %::z - hour, minute and second offset from UTC (e.g. +09:00:00) - * %:::z - hour, minute and second offset from UTC - * (e.g. +09, +09:30, +09:30:30) - * %Z - Time zone abbreviation name - * - * Weekday: - * %A - The full weekday name (``Sunday'') - * %^A uppercased (``SUNDAY'') - * %a - The abbreviated name (``Sun'') - * %^a uppercased (``SUN'') - * %u - Day of the week (Monday is 1, 1..7) - * %w - Day of the week (Sunday is 0, 0..6) - * - * ISO 8601 week-based year and week number: - * The week 1 of YYYY starts with a Monday and includes YYYY-01-04. - * The days in the year before the first week are in the last week of - * the previous year. - * %G - The week-based year - * %g - The last 2 digits of the week-based year (00..99) - * %V - Week number of the week-based year (01..53) - * - * Week number: - * The week 1 of YYYY starts with a Sunday or Monday (according to %U - * or %W). The days in the year before the first week are in week 0. - * %U - Week number of the year. The week starts with Sunday. (00..53) - * %W - Week number of the year. The week starts with Monday. (00..53) - * - * Seconds since the Unix Epoch: - * %s - Number of seconds since 1970-01-01 00:00:00 UTC. - * %Q - Number of microseconds since 1970-01-01 00:00:00 UTC. - * - * Literal string: - * %n - Newline character (\n) - * %t - Tab character (\t) - * %% - Literal ``%'' character - * - * Combination: - * %c - date and time (%a %b %e %T %Y) - * %D - Date (%m/%d/%y) - * %F - The ISO 8601 date format (%Y-%m-%d) - * %v - VMS date (%e-%b-%Y) - * %x - Same as %D - * %X - Same as %T - * %r - 12-hour time (%I:%M:%S %p) - * %R - 24-hour time (%H:%M) - * %T - 24-hour time (%H:%M:%S) - * %+ - date(1) (%a %b %e %H:%M:%S %Z %Y) - * - * This method is similar to strftime() function defined in ISO C and POSIX. - * Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z) - * are locale dependent in the function. - * However this method is locale independent. - * So, the result may differ even if a same format string is used in other - * systems such as C. - * It is good practice to avoid %x and %X because there are corresponding - * locale independent representations, %D and %T. - * - * Examples: - * - * d = DateTime.new(2007,11,19,8,37,48,"-06:00") - * #=> #<DateTime: 2007-11-19T08:37:48-0600 ...> - * d.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007" - * d.strftime("at %I:%M%p") #=> "at 08:37AM" - * - * Various ISO 8601 formats: - * %Y%m%d => 20071119 Calendar date (basic) - * %F => 2007-11-19 Calendar date (extended) - * %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month - * %Y => 2007 Calendar date, reduced accuracy, specific year - * %C => 20 Calendar date, reduced accuracy, specific century - * %Y%j => 2007323 Ordinal date (basic) - * %Y-%j => 2007-323 Ordinal date (extended) - * %GW%V%u => 2007W471 Week date (basic) - * %G-W%V-%u => 2007-W47-1 Week date (extended) - * %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic) - * %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended) - * %H%M%S => 083748 Local time (basic) - * %T => 08:37:48 Local time (extended) - * %H%M => 0837 Local time, reduced accuracy, specific minute (basic) - * %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended) - * %H => 08 Local time, reduced accuracy, specific hour - * %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic) - * %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended) - * %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic) - * %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended) - * %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic) - * %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended) - * %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic) - * %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended) - * %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic) - * %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended) - * %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic) - * %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended) - * %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic) - * %FT%R => 2007-11-19T08:37 Calendar date and local time (extended) - * %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic) - * %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended) - * %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic) - * %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended) - * - * See also strftime(3) and strptime. + * strftime(format = '%F') -> string + * + * Returns a string representation of the date in +self+, + * formatted according the given +format+: + * + * Date.new(2001, 2, 3).strftime # => "2001-02-03" + * + * For other formats, see + * {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]. + * */ static VALUE d_lite_strftime(int argc, VALUE *argv, VALUE self) @@ -7097,6 +7462,7 @@ strftimev(const char *fmt, VALUE self, (*func)(self, &tmx); len = date_strftime_alloc(&buf, fmt, &tmx); + RB_GC_GUARD(self); str = rb_usascii_str_new(buf, len); if (buf != buffer) xfree(buf); return str; @@ -7104,13 +7470,16 @@ strftimev(const char *fmt, VALUE self, /* * call-seq: - * d.asctime -> string - * d.ctime -> string + * asctime -> string + * + * Equivalent to #strftime with argument <tt>'%a %b %e %T %Y'</tt> + * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers] + * <tt>'%c'</tt>): * - * Returns a string in asctime(3) format (but without "\n\0" at the - * end). This method is equivalent to strftime('%c'). + * Date.new(2001, 2, 3).asctime # => "Sat Feb 3 00:00:00 2001" + * + * See {asctime}[https://man7.org/linux/man-pages/man3/asctime.3p.html]. * - * See also asctime(3) or ctime(3). */ static VALUE d_lite_asctime(VALUE self) @@ -7120,10 +7489,14 @@ d_lite_asctime(VALUE self) /* * call-seq: - * d.iso8601 -> string - * d.xmlschema -> string + * iso8601 -> string + * + * Equivalent to #strftime with argument <tt>'%Y-%m-%d'</tt> + * (or its {shorthand form}[rdoc-ref:language/strftime_formatting.rdoc@Shorthand+Conversion+Specifiers] + * <tt>'%F'</tt>); + * + * Date.new(2001, 2, 3).iso8601 # => "2001-02-03" * - * This method is equivalent to strftime('%F'). */ static VALUE d_lite_iso8601(VALUE self) @@ -7133,9 +7506,13 @@ d_lite_iso8601(VALUE self) /* * call-seq: - * d.rfc3339 -> string + * rfc3339 -> string + * + * Equivalent to #strftime with argument <tt>'%FT%T%:z'</tt>; + * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]: + * + * Date.new(2001, 2, 3).rfc3339 # => "2001-02-03T00:00:00+00:00" * - * This method is equivalent to strftime('%FT%T%:z'). */ static VALUE d_lite_rfc3339(VALUE self) @@ -7145,10 +7522,13 @@ d_lite_rfc3339(VALUE self) /* * call-seq: - * d.rfc2822 -> string - * d.rfc822 -> string + * rfc2822 -> string + * + * Equivalent to #strftime with argument <tt>'%a, %-d %b %Y %T %z'</tt>; + * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]: + * + * Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000" * - * This method is equivalent to strftime('%a, %-d %b %Y %T %z'). */ static VALUE d_lite_rfc2822(VALUE self) @@ -7158,10 +7538,13 @@ d_lite_rfc2822(VALUE self) /* * call-seq: - * d.httpdate -> string + * httpdate -> string + * + * Equivalent to #strftime with argument <tt>'%a, %d %b %Y %T GMT'</tt>; + * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]: + * + * Date.new(2001, 2, 3).httpdate # => "Sat, 03 Feb 2001 00:00:00 GMT" * - * This method is equivalent to strftime('%a, %d %b %Y %T GMT'). - * See also RFC 2616. */ static VALUE d_lite_httpdate(VALUE self) @@ -7170,54 +7553,161 @@ d_lite_httpdate(VALUE self) return strftimev("%a, %d %b %Y %T GMT", dup, set_tmx); } -static VALUE -jisx0301_date(VALUE jd, VALUE y) -{ - VALUE a[2]; +enum { + DECIMAL_SIZE_OF_LONG = DECIMAL_SIZE_OF_BITS(CHAR_BIT*sizeof(long)), + JISX0301_DATE_SIZE = DECIMAL_SIZE_OF_LONG+8 +}; - if (f_lt_p(jd, INT2FIX(2405160))) - return rb_usascii_str_new2("%Y-%m-%d"); - if (f_lt_p(jd, INT2FIX(2419614))) { - a[0] = rb_usascii_str_new2("M%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1867)); - } - else if (f_lt_p(jd, INT2FIX(2424875))) { - a[0] = rb_usascii_str_new2("T%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1911)); - } - else if (f_lt_p(jd, INT2FIX(2447535))) { - a[0] = rb_usascii_str_new2("S%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1925)); - } - else { - a[0] = rb_usascii_str_new2("H%02d" ".%%m.%%d"); - a[1] = f_sub(y, INT2FIX(1988)); +static const char * +jisx0301_date_format(char *fmt, size_t size, VALUE jd, VALUE y) +{ + if (FIXNUM_P(jd)) { + long d = FIX2INT(jd); + long s; + char c; + if (d < 2405160) + return "%Y-%m-%d"; + if (d < 2419614) { + c = 'M'; + s = 1867; + } + else if (d < 2424875) { + c = 'T'; + s = 1911; + } + else if (d < 2447535) { + c = 'S'; + s = 1925; + } + else if (d < 2458605) { + c = 'H'; + s = 1988; + } + else { + c = 'R'; + s = 2018; + } + snprintf(fmt, size, "%c%02ld" ".%%m.%%d", c, FIX2INT(y) - s); + return fmt; } - return rb_f_sprintf(2, a); + return "%Y-%m-%d"; } /* * call-seq: - * d.jisx0301 -> string + * jisx0301 -> string * - * Returns a string in a JIS X 0301 format. + * Returns a string representation of the date in +self+ + * in JIS X 0301 format. * - * For example: + * Date.new(2001, 2, 3).jisx0301 # => "H13.02.03" * - * Date.new(2001,2,3).jisx0301 #=> "H13.02.03" */ static VALUE d_lite_jisx0301(VALUE self) { - VALUE s; + char fmtbuf[JISX0301_DATE_SIZE]; + const char *fmt; + + get_d1(self); + fmt = jisx0301_date_format(fmtbuf, sizeof(fmtbuf), + m_real_local_jd(dat), + m_real_year(dat)); + return strftimev(fmt, self, set_tmx); +} + +static VALUE +deconstruct_keys(VALUE self, VALUE keys, int is_datetime) +{ + VALUE h = rb_hash_new(); + long i; get_d1(self); - s = jisx0301_date(m_real_local_jd(dat), - m_real_year(dat)); - return strftimev(RSTRING_PTR(s), self, set_tmx); + + if (NIL_P(keys)) { + rb_hash_aset(h, sym_year, m_real_year(dat)); + rb_hash_aset(h, sym_month, INT2FIX(m_mon(dat))); + rb_hash_aset(h, sym_day, INT2FIX(m_mday(dat))); + rb_hash_aset(h, sym_yday, INT2FIX(m_yday(dat))); + rb_hash_aset(h, sym_wday, INT2FIX(m_wday(dat))); + if (is_datetime) { + rb_hash_aset(h, sym_hour, INT2FIX(m_hour(dat))); + rb_hash_aset(h, sym_min, INT2FIX(m_min(dat))); + rb_hash_aset(h, sym_sec, INT2FIX(m_sec(dat))); + rb_hash_aset(h, sym_sec_fraction, m_sf_in_sec(dat)); + rb_hash_aset(h, sym_zone, m_zone(dat)); + } + + return h; + } + if (!RB_TYPE_P(keys, T_ARRAY)) { + rb_raise(rb_eTypeError, + "wrong argument type %"PRIsVALUE" (expected Array or nil)", + rb_obj_class(keys)); + + } + + for (i=0; i<RARRAY_LEN(keys); i++) { + VALUE key = RARRAY_AREF(keys, i); + + if (sym_year == key) rb_hash_aset(h, key, m_real_year(dat)); + if (sym_month == key) rb_hash_aset(h, key, INT2FIX(m_mon(dat))); + if (sym_day == key) rb_hash_aset(h, key, INT2FIX(m_mday(dat))); + if (sym_yday == key) rb_hash_aset(h, key, INT2FIX(m_yday(dat))); + if (sym_wday == key) rb_hash_aset(h, key, INT2FIX(m_wday(dat))); + if (is_datetime) { + if (sym_hour == key) rb_hash_aset(h, key, INT2FIX(m_hour(dat))); + if (sym_min == key) rb_hash_aset(h, key, INT2FIX(m_min(dat))); + if (sym_sec == key) rb_hash_aset(h, key, INT2FIX(m_sec(dat))); + if (sym_sec_fraction == key) rb_hash_aset(h, key, m_sf_in_sec(dat)); + if (sym_zone == key) rb_hash_aset(h, key, m_zone(dat)); + } + } + return h; +} + +/* + * call-seq: + * deconstruct_keys(array_of_names_or_nil) -> hash + * + * Returns a hash of the name/value pairs, to use in pattern matching. + * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, + * <tt>:wday</tt>, <tt>:yday</tt>. + * + * Possible usages: + * + * d = Date.new(2022, 10, 5) + * + * if d in wday: 3, day: ..7 # uses deconstruct_keys underneath + * puts "first Wednesday of the month" + * end + * #=> prints "first Wednesday of the month" + * + * case d + * in year: ...2022 + * puts "too old" + * in month: ..9 + * puts "quarter 1-3" + * in wday: 1..5, month: + * puts "working day in month #{month}" + * end + * #=> prints "working day in month 10" + * + * Note that deconstruction by pattern can also be combined with class check: + * + * if d in Date(wday: 3, day: ..7) + * puts "first Wednesday of the month" + * end + * + */ +static VALUE +d_lite_deconstruct_keys(VALUE self, VALUE keys) +{ + return deconstruct_keys(self, keys, /* is_datetime=false */ 0); } #ifndef NDEBUG +/* :nodoc: */ static VALUE d_lite_marshal_dump_old(VALUE self) { @@ -7230,10 +7720,7 @@ d_lite_marshal_dump_old(VALUE self) m_of_in_day(dat), DBL2NUM(m_sg(dat))); - if (FL_TEST(self, FL_EXIVAR)) { - rb_copy_generic_ivar(a, self); - FL_SET(a, FL_EXIVAR); - } + rb_copy_generic_ivar(a, self); return a; } @@ -7255,10 +7742,8 @@ d_lite_marshal_dump(VALUE self) INT2FIX(m_of(dat)), DBL2NUM(m_sg(dat))); - if (FL_TEST(self, FL_EXIVAR)) { - rb_copy_generic_ivar(a, self); - FL_SET(a, FL_EXIVAR); - } + + rb_copy_generic_ivar(a, self); return a; } @@ -7267,61 +7752,48 @@ d_lite_marshal_dump(VALUE self) static VALUE d_lite_marshal_load(VALUE self, VALUE a) { + VALUE nth, sf; + int jd, df, of; + double sg; + get_d1(self); - if (TYPE(a) != T_ARRAY) + rb_check_frozen(self); + + if (!RB_TYPE_P(a, T_ARRAY)) rb_raise(rb_eTypeError, "expected an array"); switch (RARRAY_LEN(a)) { - case 3: + case 2: /* 1.6.x */ + case 3: /* 1.8.x, 1.9.2 */ { - VALUE ajd, of, sg, nth, sf; - int jd, df, rof; - double rsg; - - ajd = RARRAY_PTR(a)[0]; - of = RARRAY_PTR(a)[1]; - sg = RARRAY_PTR(a)[2]; - - old_to_new(ajd, of, sg, - &nth, &jd, &df, &sf, &rof, &rsg); - - if (!df && f_zero_p(sf) && !rof) { - set_to_simple(&dat->s, nth, jd, rsg, 0, 0, 0, HAVE_JD); - } else { - if (!complex_dat_p(dat)) - rb_raise(rb_eArgError, - "cannot load complex into simple"); - - set_to_complex(&dat->c, nth, jd, df, sf, rof, rsg, - 0, 0, 0, 0, 0, 0, - HAVE_JD | HAVE_DF | COMPLEX_DAT); + VALUE ajd, vof, vsg; + + if (RARRAY_LEN(a) == 2) { + ajd = f_sub(RARRAY_AREF(a, 0), half_days_in_day); + vof = INT2FIX(0); + vsg = RARRAY_AREF(a, 1); + if (!k_numeric_p(vsg)) + vsg = DBL2NUM(RTEST(vsg) ? GREGORIAN : JULIAN); } + else { + ajd = RARRAY_AREF(a, 0); + vof = RARRAY_AREF(a, 1); + vsg = RARRAY_AREF(a, 2); + } + + old_to_new(ajd, vof, vsg, + &nth, &jd, &df, &sf, &of, &sg); } break; case 6: { - VALUE nth, sf; - int jd, df, of; - double sg; - - nth = RARRAY_PTR(a)[0]; - jd = NUM2INT(RARRAY_PTR(a)[1]); - df = NUM2INT(RARRAY_PTR(a)[2]); - sf = RARRAY_PTR(a)[3]; - of = NUM2INT(RARRAY_PTR(a)[4]); - sg = NUM2DBL(RARRAY_PTR(a)[5]); - if (!df && f_zero_p(sf) && !of) { - set_to_simple(&dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD); - } else { - if (!complex_dat_p(dat)) - rb_raise(rb_eArgError, - "cannot load complex into simple"); - - set_to_complex(&dat->c, nth, jd, df, sf, of, sg, - 0, 0, 0, 0, 0, 0, - HAVE_JD | HAVE_DF | COMPLEX_DAT); - } + nth = RARRAY_AREF(a, 0); + jd = NUM2INT(RARRAY_AREF(a, 1)); + df = NUM2INT(RARRAY_AREF(a, 2)); + sf = RARRAY_AREF(a, 3); + of = NUM2INT(RARRAY_AREF(a, 4)); + sg = NUM2DBL(RARRAY_AREF(a, 5)); } break; default: @@ -7329,14 +7801,36 @@ d_lite_marshal_load(VALUE self, VALUE a) break; } - if (FL_TEST(a, FL_EXIVAR)) { - rb_copy_generic_ivar(self, a); - FL_SET(self, FL_EXIVAR); + if (simple_dat_p(dat)) { + if (df || !f_zero_p(sf) || of) { + /* loading a fractional date; promote to complex */ + dat = ruby_xrealloc(dat, sizeof(struct ComplexDateData)); + RTYPEDDATA(self)->data = dat; + goto complex_data; + } + set_to_simple(self, &dat->s, nth, jd, sg, 0, 0, 0, HAVE_JD); + } else { + complex_data: + set_to_complex(self, &dat->c, nth, jd, df, sf, of, sg, + 0, 0, 0, 0, 0, 0, + HAVE_JD | HAVE_DF); } + rb_copy_generic_ivar(self, a); + return self; } +/* :nodoc: */ +static VALUE +date_s__load(VALUE klass, VALUE s) +{ + VALUE a, obj; + + a = rb_marshal_load(s); + obj = d_lite_s_alloc(klass); + return d_lite_marshal_load(obj, a); +} /* datetime */ @@ -7344,11 +7838,9 @@ d_lite_marshal_load(VALUE self, VALUE a) * call-seq: * DateTime.jd([jd=0[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]) -> datetime * - * Creates a datetime object denoting the given chronological Julian + * Creates a DateTime object denoting the given chronological Julian * day number. * - * For example: - * * DateTime.jd(2451944) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> * DateTime.jd(2451945) #=> #<DateTime: 2001-02-04T00:00:00+00:00 ...> * DateTime.jd(Rational('0.5')) @@ -7376,12 +7868,16 @@ datetime_s_jd(int argc, VALUE *argv, VALUE klass) case 5: val2off(vof, rof); case 4: + check_numeric(vs, "second"); num2int_with_frac(s, positive_inf); case 3: + check_numeric(vmin, "minute"); num2int_with_frac(min, 3); case 2: + check_numeric(vh, "hour"); num2int_with_frac(h, 2); case 1: + check_numeric(vjd, "jd"); num2num_with_frac(jd, 1); } @@ -7390,7 +7886,7 @@ datetime_s_jd(int argc, VALUE *argv, VALUE klass) int rh, rmin, rs, rjd, rjd2; if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); decode_jd(jd, &nth, &rjd); @@ -7414,9 +7910,7 @@ datetime_s_jd(int argc, VALUE *argv, VALUE klass) * call-seq: * DateTime.ordinal([year=-4712[, yday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]) -> datetime * - * Creates a date-time object denoting the given ordinal date. - * - * For example: + * Creates a DateTime object denoting the given ordinal date. * * DateTime.ordinal(2001,34) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> * DateTime.ordinal(2001,34,4,5,6,'+7') @@ -7447,14 +7941,19 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) case 6: val2off(vof, rof); case 5: + check_numeric(vs, "second"); num2int_with_frac(s, positive_inf); case 4: + check_numeric(vmin, "minute"); num2int_with_frac(min, 4); case 3: + check_numeric(vh, "hour"); num2int_with_frac(h, 3); case 2: + check_numeric(vd, "yday"); num2int_with_frac(d, 2); case 1: + check_numeric(vy, "year"); y = vy; } @@ -7466,9 +7965,9 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); rjd2 = jd_local_to_utc(rjd, @@ -7488,26 +7987,25 @@ datetime_s_ordinal(int argc, VALUE *argv, VALUE klass) } /* - * call-seq: - * DateTime.civil([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime - * DateTime.new([year=-4712[, month=1[, mday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime - * - * Creates a date-time object denoting the given calendar date. - * - * For example: - * - * DateTime.new(2001,2,3) #=> #<DateTime: 2001-02-03T00:00:00+00:00 ...> - * DateTime.new(2001,2,3,4,5,6,'+7') - * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> - * DateTime.new(2001,-11,-26,-20,-55,-54,'+7') - * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * Same as DateTime.new. */ static VALUE datetime_s_civil(int argc, VALUE *argv, VALUE klass) { + return datetime_initialize(argc, argv, d_lite_s_alloc_complex(klass)); +} + +static VALUE +datetime_initialize(int argc, VALUE *argv, VALUE self) +{ VALUE vy, vm, vd, vh, vmin, vs, vof, vsg, y, fr, fr2, ret; int m, d, h, min, s, rof; double sg; + struct ComplexDateData *dat = rb_check_typeddata(self, &d_lite_type); + + if (!complex_dat_p(dat)) { + rb_raise(rb_eTypeError, "DateTime expected"); + } rb_scan_args(argc, argv, "08", &vy, &vm, &vd, &vh, &vmin, &vs, &vof, &vsg); @@ -7526,16 +8024,22 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) case 7: val2off(vof, rof); case 6: + check_numeric(vs, "second"); num2int_with_frac(s, positive_inf); case 5: + check_numeric(vmin, "minute"); num2int_with_frac(min, 5); case 4: + check_numeric(vh, "hour"); num2int_with_frac(h, 4); case 3: + check_numeric(vd, "day"); num2int_with_frac(d, 3); case 2: + check_numeric(vm, "month"); m = NUM2INT(vm); case 1: + check_numeric(vy, "year"); y = vy; } @@ -7546,18 +8050,18 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) if (!valid_gregorian_p(y, m, d, &nth, &ry, &rm, &rd)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); - ret = d_complex_new_internal(klass, - nth, 0, - 0, INT2FIX(0), - rof, sg, - ry, rm, rd, - rh, rmin, rs, - HAVE_CIVIL | HAVE_TIME); + set_to_complex(self, dat, + nth, 0, + 0, INT2FIX(0), + rof, sg, + ry, rm, rd, + rh, rmin, rs, + HAVE_CIVIL | HAVE_TIME); } else { VALUE nth; @@ -7567,23 +8071,24 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rm, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); rjd2 = jd_local_to_utc(rjd, time_to_df(rh, rmin, rs), rof); - ret = d_complex_new_internal(klass, - nth, rjd2, - 0, INT2FIX(0), - rof, sg, - ry, rm, rd, - rh, rmin, rs, - HAVE_JD | HAVE_CIVIL | HAVE_TIME); + set_to_complex(self, dat, + nth, rjd2, + 0, INT2FIX(0), + rof, sg, + ry, rm, rd, + rh, rmin, rs, + HAVE_JD | HAVE_CIVIL | HAVE_TIME); } + ret = self; add_frac(); return ret; } @@ -7592,9 +8097,7 @@ datetime_s_civil(int argc, VALUE *argv, VALUE klass) * call-seq: * DateTime.commercial([cwyear=-4712[, cweek=1[, cwday=1[, hour=0[, minute=0[, second=0[, offset=0[, start=Date::ITALY]]]]]]]]) -> datetime * - * Creates a date-time object denoting the given week date. - * - * For example: + * Creates a DateTime object denoting the given week date. * * DateTime.commercial(2001) #=> #<DateTime: 2001-01-01T00:00:00+00:00 ...> * DateTime.commercial(2002) #=> #<DateTime: 2001-12-31T00:00:00+00:00 ...> @@ -7625,16 +8128,22 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass) case 7: val2off(vof, rof); case 6: + check_numeric(vs, "second"); num2int_with_frac(s, positive_inf); case 5: + check_numeric(vmin, "minute"); num2int_with_frac(min, 5); case 4: + check_numeric(vh, "hour"); num2int_with_frac(h, 4); case 3: + check_numeric(vd, "cwday"); num2int_with_frac(d, 3); case 2: + check_numeric(vw, "cweek"); w = NUM2INT(vw); case 1: + check_numeric(vy, "year"); y = vy; } @@ -7646,9 +8155,9 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rw, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); rjd2 = jd_local_to_utc(rjd, @@ -7668,6 +8177,7 @@ datetime_s_commercial(int argc, VALUE *argv, VALUE klass) } #ifndef NDEBUG +/* :nodoc: */ static VALUE datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) { @@ -7717,9 +8227,9 @@ datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rw, &rd, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); rjd2 = jd_local_to_utc(rjd, @@ -7737,6 +8247,7 @@ datetime_s_weeknum(int argc, VALUE *argv, VALUE klass) return ret; } +/* :nodoc: */ static VALUE datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass) { @@ -7786,9 +8297,9 @@ datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass) &nth, &ry, &rm, &rn, &rk, &rjd, &ns)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (!c_valid_time_p(h, min, s, &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); canon24oc(); rjd2 = jd_local_to_utc(rjd, @@ -7811,9 +8322,7 @@ datetime_s_nth_kday(int argc, VALUE *argv, VALUE klass) * call-seq: * DateTime.now([start=Date::ITALY]) -> datetime * - * Creates a date-time object denoting the present time. - * - * For example: + * Creates a DateTime object denoting the present time. * * DateTime.now #=> #<DateTime: 2011-06-11T21:20:44+09:00 ...> */ @@ -7862,9 +8371,9 @@ datetime_s_now(int argc, VALUE *argv, VALUE klass) s = 59; #ifdef HAVE_STRUCT_TM_TM_GMTOFF of = tm.tm_gmtoff; -#elif defined(HAVE_VAR_TIMEZONE) -#ifdef HAVE_VAR_ALTZONE - of = (long)((tm.tm_isdst > 0) ? altzone : timezone); +#elif defined(HAVE_TIMEZONE) +#if defined(HAVE_ALTZONE) && !defined(_AIX) + of = (long)-((tm.tm_isdst > 0) ? altzone : timezone); #else of = (long)-timezone; if (tm.tm_isdst) { @@ -7933,7 +8442,7 @@ dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) } if (NIL_P(hash)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); if (NIL_P(ref_hash("jd")) && NIL_P(ref_hash("yday")) && @@ -7950,7 +8459,7 @@ dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) 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))) + else if (f_eqeq_p(ref_hash("sec"), INT2FIX(60))) set_hash("sec", INT2FIX(59)); } else { @@ -7960,7 +8469,7 @@ dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) } if (NIL_P(jd)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); { int rh, rmin, rs; @@ -7969,7 +8478,7 @@ dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) NUM2INT(ref_hash("min")), NUM2INT(ref_hash("sec")), &rh, &rmin, &rs)) - rb_raise(rb_eArgError, "invalid date"); + rb_raise(eDateError, "invalid date"); df = time_to_df(rh, rmin, rs); } @@ -8013,9 +8522,10 @@ dt_new_by_frags(VALUE klass, VALUE hash, VALUE sg) * DateTime._strptime(string[, format='%FT%T%z']) -> hash * * Parses the given representation of date and time with the given - * template, and returns a hash of parsed elements. + * template, and returns a hash of parsed elements. _strptime does + * not support specification of flags and width unlike strftime. * - * See also strptime(3) and strftime. + * See also strptime(3) and #strftime. */ static VALUE datetime_s__strptime(int argc, VALUE *argv, VALUE klass) @@ -8025,12 +8535,11 @@ 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]]]) -> datetime + * DateTime.strptime([string='-4712-01-01T00:00:00+00:00'[, format='%FT%T%z'[ ,start=Date::ITALY]]]) -> datetime * * Parses the given representation of date and time with the given - * template, and creates a date object. - * - * For example: + * template, and creates a DateTime object. strptime does not support + * specification of flags and width unlike strftime. * * DateTime.strptime('2001-02-03T04:05:06+07:00', '%Y-%m-%dT%H:%M:%S%z') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> @@ -8049,7 +8558,7 @@ datetime_s__strptime(int argc, VALUE *argv, VALUE klass) * DateTime.strptime('sat3feb014pm+7', '%a%d%b%y%H%p%z') * #=> #<DateTime: 2001-02-03T16:00:00+07:00 ...> * - * See also strptime(3) and strftime. + * See also strptime(3) and #strftime. */ static VALUE datetime_s_strptime(int argc, VALUE *argv, VALUE klass) @@ -8060,7 +8569,7 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: fmt = rb_str_new2("%FT%T%z"); case 2: @@ -8079,33 +8588,40 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass) /* * call-seq: - * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=ITALY]]) -> datetime + * DateTime.parse(string='-4712-01-01T00:00:00+00:00'[, comp=true[, start=Date::ITALY]], limit: 128) -> datetime * * Parses the given representation of date and time, and creates a - * date object. + * DateTime object. + * + * This method *does* *not* function as a validator. If the input + * string does not match valid formats strictly, you may get a cryptic + * result. Should consider to use DateTime.strptime instead of this + * method as possible. * * If the optional second argument is true and the detected year is in * the range "00" to "99", makes it full. * - * For example: - * * DateTime.parse('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.parse('20010203T040506+0700') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.parse('3rd Feb 2001 04:05:06 PM') * #=> #<DateTime: 2001-02-03T16:05:06+00:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_parse(int argc, VALUE *argv, VALUE klass) { - VALUE str, comp, sg; + VALUE str, comp, sg, opt; - rb_scan_args(argc, argv, "03", &str, &comp, &sg); + argc = rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: comp = Qtrue; case 2: @@ -8113,208 +8629,257 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass) } { - VALUE argv2[2], hash; - - argv2[0] = str; - argv2[1] = comp; - hash = date_s__parse(2, argv2, klass); + int argc2 = 2; + VALUE argv2[3], hash; + argv2[0] = str; + argv2[1] = comp; + argv2[2] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__parse(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime + * DateTime.iso8601(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some typical ISO 8601 formats. * - * For example: - * * DateTime.iso8601('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.iso8601('20010203T040506+0700') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> * DateTime.iso8601('2001-W05-6T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_iso8601(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__iso8601(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__iso8601(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime + * DateTime.rfc3339(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some typical RFC 3339 formats. * - * For example: - * * DateTime.rfc3339('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__rfc3339(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__rfc3339(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime + * DateTime.xmlschema(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some typical XML Schema formats. * - * For example: - * * DateTime.xmlschema('2001-02-03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__xmlschema(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__xmlschema(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> datetime - * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=ITALY]) -> datetime + * DateTime.rfc2822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime + * DateTime.rfc822(string='Mon, 1 Jan -4712 00:00:00 +0000'[, start=Date::ITALY], limit: 128) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some typical RFC 2822 formats. * - * For example: - * * DateTime.rfc2822('Sat, 3 Feb 2001 04:05:06 +0700') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__rfc2822(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__rfc2822(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=ITALY]) -> datetime + * DateTime.httpdate(string='Mon, 01 Jan -4712 00:00:00 GMT'[, start=Date::ITALY]) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some RFC 2616 format. * - * For example: - * * DateTime.httpdate('Sat, 03 Feb 2001 04:05:06 GMT') * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_httpdate(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME_HTTPDATE); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__httpdate(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__httpdate(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } /* * call-seq: - * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=ITALY]) -> datetime + * DateTime.jisx0301(string='-4712-01-01T00:00:00+00:00'[, start=Date::ITALY], limit: 128) -> datetime * - * Creates a new Date object by parsing from a string according to + * Creates a new DateTime object by parsing from a string according to * some typical JIS X 0301 formats. * - * For example: - * * DateTime.jisx0301('H13.02.03T04:05:06+07:00') * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * For no-era year, legacy format, Heisei is assumed. + * + * DateTime.jisx0301('13.02.03T04:05:06+07:00') + * #=> #<DateTime: 2001-02-03T04:05:06+07:00 ...> + * + * Raise an ArgumentError when the string length is longer than _limit_. + * You can stop this check by passing <code>limit: nil</code>, but note + * that it may take a long time to parse. */ static VALUE datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) { - VALUE str, sg; + VALUE str, sg, opt; - rb_scan_args(argc, argv, "02", &str, &sg); + argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt); switch (argc) { case 0: - str = rb_str_new2("-4712-01-01T00:00:00+00:00"); + str = rb_str_new2(JULIAN_EPOCH_DATETIME); case 1: sg = INT2FIX(DEFAULT_SG); } { - VALUE hash = date_s__jisx0301(klass, str); + int argc2 = 1; + VALUE argv2[2], hash; + argv2[0] = str; + argv2[1] = opt; + if (!NIL_P(opt)) argc2++; + hash = date_s__jisx0301(argc2, argv2, klass); return dt_new_by_frags(klass, hash, sg); } } @@ -8323,10 +8888,8 @@ datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass) * call-seq: * dt.to_s -> string * - * Returns a string in an ISO 8601 format (This method doesn't use the - * expanded representations). - * - * For example: + * Returns a string in an ISO 8601 format. (This method doesn't use the + * expanded representations.) * * DateTime.new(2001,2,3,4,5,6,'-7').to_s * #=> "2001-02-03T04:05:06-07:00" @@ -8339,180 +8902,16 @@ dt_lite_to_s(VALUE self) /* * call-seq: - * dt.strftime([format='%FT%T%:z']) -> string - * - * Formats date according to the directives in the given format - * string. - * The directives begins with a percent (%) character. - * Any text not listed as a directive will be passed through to the - * output string. - * - * The directive consists of a percent (%) character, - * zero or more flags, optional minimum field width, - * optional modifier and a conversion specifier - * as follows. - * - * %<flags><width><modifier><conversion> - * - * Flags: - * - don't pad a numerical output. - * _ use spaces for padding. - * 0 use zeros for padding. - * ^ upcase the result string. - * # change case. - * : use colons for %z. - * - * The minimum field width specifies the minimum width. - * - * The modifier is "E" and "O". - * They are ignored. - * - * Format directives: - * - * Date (Year, Month, Day): - * %Y - Year with century (can be negative, 4 digits at least) - * -0001, 0000, 1995, 2009, 14292, etc. - * %C - year / 100 (round down. 20 in 2009) - * %y - year % 100 (00..99) - * - * %m - Month of the year, zero-padded (01..12) - * %_m blank-padded ( 1..12) - * %-m no-padded (1..12) - * %B - The full month name (``January'') - * %^B uppercased (``JANUARY'') - * %b - The abbreviated month name (``Jan'') - * %^b uppercased (``JAN'') - * %h - Equivalent to %b - * - * %d - Day of the month, zero-padded (01..31) - * %-d no-padded (1..31) - * %e - Day of the month, blank-padded ( 1..31) - * - * %j - Day of the year (001..366) - * - * Time (Hour, Minute, Second, Subsecond): - * %H - Hour of the day, 24-hour clock, zero-padded (00..23) - * %k - Hour of the day, 24-hour clock, blank-padded ( 0..23) - * %I - Hour of the day, 12-hour clock, zero-padded (01..12) - * %l - Hour of the day, 12-hour clock, blank-padded ( 1..12) - * %P - Meridian indicator, lowercase (``am'' or ``pm'') - * %p - Meridian indicator, uppercase (``AM'' or ``PM'') - * - * %M - Minute of the hour (00..59) - * - * %S - Second of the minute (00..59) - * - * %L - Millisecond of the second (000..999) - * %N - Fractional seconds digits, default is 9 digits (nanosecond) - * %3N millisecond (3 digits) - * %6N microsecond (6 digits) - * %9N nanosecond (9 digits) - * %12N picosecond (12 digits) - * - * Time zone: - * %z - Time zone as hour and minute offset from UTC (e.g. +0900) - * %:z - hour and minute offset from UTC with a colon (e.g. +09:00) - * %::z - hour, minute and second offset from UTC (e.g. +09:00:00) - * %:::z - hour, minute and second offset from UTC - * (e.g. +09, +09:30, +09:30:30) - * %Z - Time zone abbreviation name - * - * Weekday: - * %A - The full weekday name (``Sunday'') - * %^A uppercased (``SUNDAY'') - * %a - The abbreviated name (``Sun'') - * %^a uppercased (``SUN'') - * %u - Day of the week (Monday is 1, 1..7) - * %w - Day of the week (Sunday is 0, 0..6) - * - * ISO 8601 week-based year and week number: - * The week 1 of YYYY starts with a Monday and includes YYYY-01-04. - * The days in the year before the first week are in the last week of - * the previous year. - * %G - The week-based year - * %g - The last 2 digits of the week-based year (00..99) - * %V - Week number of the week-based year (01..53) - * - * Week number: - * The week 1 of YYYY starts with a Sunday or Monday (according to %U - * or %W). The days in the year before the first week are in week 0. - * %U - Week number of the year. The week starts with Sunday. (00..53) - * %W - Week number of the year. The week starts with Monday. (00..53) - * - * Seconds since the Unix Epoch: - * %s - Number of seconds since 1970-01-01 00:00:00 UTC. - * %Q - Number of microseconds since 1970-01-01 00:00:00 UTC. - * - * Literal string: - * %n - Newline character (\n) - * %t - Tab character (\t) - * %% - Literal ``%'' character - * - * Combination: - * %c - date and time (%a %b %e %T %Y) - * %D - Date (%m/%d/%y) - * %F - The ISO 8601 date format (%Y-%m-%d) - * %v - VMS date (%e-%b-%Y) - * %x - Same as %D - * %X - Same as %T - * %r - 12-hour time (%I:%M:%S %p) - * %R - 24-hour time (%H:%M) - * %T - 24-hour time (%H:%M:%S) - * %+ - date(1) (%a %b %e %H:%M:%S %Z %Y) - * - * This method is similar to strftime() function defined in ISO C and POSIX. - * Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z) - * are locale dependent in the function. - * However this method is locale independent. - * So, the result may differ even if a same format string is used in other - * systems such as C. - * It is good practice to avoid %x and %X because there are corresponding - * locale independent representations, %D and %T. - * - * Examples: - * - * d = DateTime.new(2007,11,19,8,37,48,"-06:00") - * #=> #<DateTime: 2007-11-19T08:37:48-0600 ...> - * d.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007" - * d.strftime("at %I:%M%p") #=> "at 08:37AM" - * - * Various ISO 8601 formats: - * %Y%m%d => 20071119 Calendar date (basic) - * %F => 2007-11-19 Calendar date (extended) - * %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month - * %Y => 2007 Calendar date, reduced accuracy, specific year - * %C => 20 Calendar date, reduced accuracy, specific century - * %Y%j => 2007323 Ordinal date (basic) - * %Y-%j => 2007-323 Ordinal date (extended) - * %GW%V%u => 2007W471 Week date (basic) - * %G-W%V-%u => 2007-W47-1 Week date (extended) - * %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic) - * %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended) - * %H%M%S => 083748 Local time (basic) - * %T => 08:37:48 Local time (extended) - * %H%M => 0837 Local time, reduced accuracy, specific minute (basic) - * %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended) - * %H => 08 Local time, reduced accuracy, specific hour - * %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic) - * %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended) - * %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic) - * %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended) - * %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic) - * %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended) - * %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic) - * %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended) - * %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic) - * %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended) - * %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic) - * %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended) - * %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic) - * %FT%R => 2007-11-19T08:37 Calendar date and local time (extended) - * %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic) - * %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended) - * %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic) - * %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended) - * - * See also strftime(3) and strptime. + * strftime(format = '%FT%T%:z') -> string + * + * Returns a string representation of +self+, + * formatted according the given +format: + * + * DateTime.now.strftime # => "2022-07-01T11:03:19-05:00" + * + * For other formats, + * see {Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc]: + * */ static VALUE dt_lite_strftime(int argc, VALUE *argv, VALUE self) @@ -8522,25 +8921,19 @@ dt_lite_strftime(int argc, VALUE *argv, VALUE self) } static VALUE -iso8601_timediv(VALUE self, VALUE n) +iso8601_timediv(VALUE self, long n) { - VALUE fmt; - - fmt = rb_usascii_str_new2("T%H:%M:%S"); - if (f_gt_p(n, INT2FIX(0))) { - VALUE argv[3]; + static const char timefmt[] = "T%H:%M:%S"; + static const char zone[] = "%:z"; + char fmt[sizeof(timefmt) + sizeof(zone) + rb_strlen_lit(".%N") + + DECIMAL_SIZE_OF_LONG]; + char *p = fmt; - get_d1(self); - - argv[0] = rb_usascii_str_new2(".%0*d"); - argv[1] = n; - argv[2] = f_round(f_quo(m_sf_in_sec(dat), - f_quo(INT2FIX(1), - f_expt(INT2FIX(10), n)))); - rb_str_append(fmt, rb_f_sprintf(3, argv)); - } - rb_str_append(fmt, rb_usascii_str_new2("%:z")); - return strftimev(RSTRING_PTR(fmt), self, set_tmx); + memcpy(p, timefmt, sizeof(timefmt)-1); + p += sizeof(timefmt)-1; + if (n > 0) p += snprintf(p, fmt+sizeof(fmt)-p, ".%%%ldN", n); + memcpy(p, zone, sizeof(zone)); + return strftimev(fmt, self, set_tmx); } /* @@ -8548,10 +8941,8 @@ iso8601_timediv(VALUE self, VALUE n) * dt.iso8601([n=0]) -> string * dt.xmlschema([n=0]) -> string * - * This method is equivalent to strftime('%FT%T'). The optional - * argument n is length of fractional seconds. - * - * For example: + * This method is equivalent to strftime('%FT%T%:z'). + * The optional argument +n+ is the number of digits for fractional seconds. * * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').iso8601(9) * #=> "2001-02-03T04:05:06.123456789+07:00" @@ -8559,25 +8950,22 @@ iso8601_timediv(VALUE self, VALUE n) static VALUE dt_lite_iso8601(int argc, VALUE *argv, VALUE self) { - VALUE n; - - rb_scan_args(argc, argv, "01", &n); + long n = 0; - if (argc < 1) - n = INT2FIX(0); + rb_check_arity(argc, 0, 1); + if (argc >= 1) + n = NUM2LONG(argv[0]); - return f_add(strftimev("%Y-%m-%d", self, set_tmx), - iso8601_timediv(self, n)); + return rb_str_append(strftimev("%Y-%m-%d", self, set_tmx), + iso8601_timediv(self, n)); } /* * call-seq: * dt.rfc3339([n=0]) -> string * - * This method is equivalent to strftime('%FT%T'). The optional - * argument n is length of fractional seconds. - * - * For example: + * This method is equivalent to strftime('%FT%T%:z'). + * The optional argument +n+ is the number of digits for fractional seconds. * * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').rfc3339(9) * #=> "2001-02-03T04:05:06.123456789+07:00" @@ -8592,10 +8980,8 @@ dt_lite_rfc3339(int argc, VALUE *argv, VALUE self) * call-seq: * dt.jisx0301([n=0]) -> string * - * Returns a string in a JIS X 0301 format. The optional argument n - * is length of fractional seconds. - * - * For example: + * Returns a string in a JIS X 0301 format. + * The optional argument +n+ is the number of digits for fractional seconds. * * DateTime.parse('2001-02-03T04:05:06.123456789+07:00').jisx0301(9) * #=> "H13.02.03T04:05:06.123456789+07:00" @@ -8603,41 +8989,73 @@ dt_lite_rfc3339(int argc, VALUE *argv, VALUE self) static VALUE dt_lite_jisx0301(int argc, VALUE *argv, VALUE self) { - VALUE n, s; + long n = 0; - rb_scan_args(argc, argv, "01", &n); + rb_check_arity(argc, 0, 1); + if (argc >= 1) + n = NUM2LONG(argv[0]); - if (argc < 1) - n = INT2FIX(0); + return rb_str_append(d_lite_jisx0301(self), + iso8601_timediv(self, n)); +} - { - get_d1(self); - s = jisx0301_date(m_real_local_jd(dat), - m_real_year(dat)); - return rb_str_append(strftimev(RSTRING_PTR(s), self, set_tmx), - iso8601_timediv(self, n)); - } +/* + * call-seq: + * deconstruct_keys(array_of_names_or_nil) -> hash + * + * Returns a hash of the name/value pairs, to use in pattern matching. + * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, + * <tt>:wday</tt>, <tt>:yday</tt>, <tt>:hour</tt>, <tt>:min</tt>, + * <tt>:sec</tt>, <tt>:sec_fraction</tt>, <tt>:zone</tt>. + * + * Possible usages: + * + * dt = DateTime.new(2022, 10, 5, 13, 30) + * + * if d in wday: 1..5, hour: 10..18 # uses deconstruct_keys underneath + * puts "Working time" + * end + * #=> prints "Working time" + * + * case dt + * in year: ...2022 + * puts "too old" + * in month: ..9 + * puts "quarter 1-3" + * in wday: 1..5, month: + * puts "working day in month #{month}" + * end + * #=> prints "working day in month 10" + * + * Note that deconstruction by pattern can also be combined with class check: + * + * if d in DateTime(wday: 1..5, hour: 10..18, day: ..7) + * puts "Working time, first week of the month" + * end + * + */ +static VALUE +dt_lite_deconstruct_keys(VALUE self, VALUE keys) +{ + return deconstruct_keys(self, keys, /* is_datetime=true */ 1); } /* 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 -> time * - * Returns a copy of self as local mode. + * Returns self. */ static VALUE time_to_time(VALUE self) { - return rb_funcall(self, rb_intern("getlocal"), 0); + return self; } /* @@ -8700,7 +9118,7 @@ time_to_datetime(VALUE self) ret = d_complex_new_internal(cDateTime, nth, 0, 0, sf, - of, DEFAULT_SG, + of, GREGORIAN, ry, m, d, h, min, s, HAVE_CIVIL | HAVE_TIME); @@ -8713,26 +9131,43 @@ time_to_datetime(VALUE self) /* * call-seq: - * d.to_time -> time + * to_time -> time + * + * Returns a new Time object with the same value as +self+; + * if +self+ is a Julian date, derives its Gregorian date + * for conversion to the \Time object: + * + * Date.new(2001, 2, 3).to_time # => 2001-02-03 00:00:00 -0600 + * Date.new(2001, 2, 3, Date::JULIAN).to_time # => 2001-02-16 00:00:00 -0600 * - * Returns a Time object which denotes self. */ static VALUE date_to_time(VALUE self) { - get_d1(self); + VALUE t; - return f_local3(rb_cTime, - m_real_year(dat), - INT2FIX(m_mon(dat)), - INT2FIX(m_mday(dat))); + get_d1a(self); + + if (m_julian_p(adat)) { + VALUE g = d_lite_gregorian(self); + get_d1b(g); + adat = bdat; + self = g; + } + + t = f_local3(rb_cTime, + m_real_year(adat), + INT2FIX(m_mon(adat)), + INT2FIX(m_mday(adat))); + RB_GC_GUARD(self); /* may be the converted gregorian */ + return t; } /* * call-seq: - * d.to_date -> self + * to_date -> self * - * Returns self; + * Returns +self+. */ static VALUE date_to_date(VALUE self) @@ -8744,7 +9179,10 @@ date_to_date(VALUE self) * call-seq: * d.to_datetime -> datetime * - * Returns a DateTime object which denotes self. + * Returns a DateTime whose value is the same as +self+: + * + * Date.new(2001, 2, 3).to_datetime # => #<DateTime: 2001-02-03T00:00:00+00:00> + * */ static VALUE date_to_datetime(VALUE self) @@ -8765,7 +9203,7 @@ date_to_datetime(VALUE self) get_d1b(new); bdat->c = adat->c; bdat->c.df = 0; - bdat->c.sf = INT2FIX(0); + RB_OBJ_WRITE(new, &bdat->c.sf, INT2FIX(0)); #ifndef USE_PACK bdat->c.hour = 0; bdat->c.min = 0; @@ -8789,21 +9227,31 @@ date_to_datetime(VALUE self) static VALUE datetime_to_time(VALUE self) { - volatile VALUE dup = dup_obj_with_new_offset(self, 0); + get_d1(self); + + if (m_julian_p(dat)) { + VALUE g = d_lite_gregorian(self); + get_d1a(g); + dat = adat; + self = g; + } + { VALUE t; - get_d1(dup); - - t = f_utc6(rb_cTime, + t = rb_funcall(rb_cTime, + rb_intern("new"), + 7, m_real_year(dat), INT2FIX(m_mon(dat)), INT2FIX(m_mday(dat)), INT2FIX(m_hour(dat)), INT2FIX(m_min(dat)), f_add(INT2FIX(m_sec(dat)), - m_sf_in_sec(dat))); - return f_getlocal(t); + m_sf_in_sec(dat)), + INT2FIX(m_of(dat))); + RB_GC_GUARD(self); /* may be the converted gregorian */ + return t; } } @@ -8831,7 +9279,7 @@ datetime_to_date(VALUE self) VALUE new = d_lite_s_alloc_simple(cDate); { get_d1b(new); - copy_complex_to_simple(&bdat->s, &adat->c) + copy_complex_to_simple(new, &bdat->s, &adat->c); bdat->s.jd = m_local_jd(adat); bdat->s.flags &= ~(HAVE_DF | HAVE_TIME | COMPLEX_DAT); return new; @@ -8859,6 +9307,7 @@ datetime_to_datetime(VALUE self) #define MIN_JD -327 #define MAX_JD 366963925 +/* :nodoc: */ static int test_civil(int from, int to, double sg) { @@ -8879,6 +9328,7 @@ test_civil(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_civil(VALUE klass) { @@ -8899,6 +9349,7 @@ date_s_test_civil(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_ordinal(int from, int to, double sg) { @@ -8919,6 +9370,7 @@ test_ordinal(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_ordinal(VALUE klass) { @@ -8939,6 +9391,7 @@ date_s_test_ordinal(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_commercial(int from, int to, double sg) { @@ -8959,6 +9412,7 @@ test_commercial(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_commercial(VALUE klass) { @@ -8979,6 +9433,7 @@ date_s_test_commercial(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_weeknum(int from, int to, int f, double sg) { @@ -8999,6 +9454,7 @@ test_weeknum(int from, int to, int f, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_weeknum(VALUE klass) { @@ -9023,6 +9479,7 @@ date_s_test_weeknum(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_nth_kday(int from, int to, double sg) { @@ -9043,6 +9500,7 @@ test_nth_kday(int from, int to, double sg) return 1; } +/* :nodoc: */ static VALUE date_s_test_nth_kday(VALUE klass) { @@ -9063,6 +9521,7 @@ date_s_test_nth_kday(VALUE klass) return Qtrue; } +/* :nodoc: */ static int test_unit_v2v(VALUE i, VALUE (* conv1)(VALUE), @@ -9074,6 +9533,7 @@ test_unit_v2v(VALUE i, return f_eqeq_p(o, i); } +/* :nodoc: */ static int test_unit_v2v_iter2(VALUE (* conv1)(VALUE), VALUE (* conv2)(VALUE)) @@ -9105,6 +9565,7 @@ test_unit_v2v_iter2(VALUE (* conv1)(VALUE), return 1; } +/* :nodoc: */ static int test_unit_v2v_iter(VALUE (* conv1)(VALUE), VALUE (* conv2)(VALUE)) @@ -9116,6 +9577,7 @@ test_unit_v2v_iter(VALUE (* conv1)(VALUE), return 1; } +/* :nodoc: */ static VALUE date_s_test_unit_conv(VALUE klass) { @@ -9130,6 +9592,7 @@ date_s_test_unit_conv(VALUE klass) return Qtrue; } +/* :nodoc: */ static VALUE date_s_test_all(VALUE klass) { @@ -9192,24 +9655,41 @@ mk_ary_of_str(long len, const char *a[]) } rb_ary_push(o, e); } - rb_obj_freeze(o); + rb_ary_freeze(o); return o; } +/* :nodoc: */ +static VALUE +d_lite_zero(VALUE x) +{ + return INT2FIX(0); +} + void Init_date_core(void) { -#undef rb_intern -#define rb_intern(str) rb_intern_const(str) - - assert(fprintf(stderr, "assert() is now active\n")); - - id_cmp = rb_intern("<=>"); - id_le_p = rb_intern("<="); - id_ge_p = rb_intern(">="); - id_eqeq_p = rb_intern("=="); + #ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(true); + #endif + id_cmp = rb_intern_const("<=>"); + id_le_p = rb_intern_const("<="); + id_ge_p = rb_intern_const(">="); + id_eqeq_p = rb_intern_const("=="); + + sym_year = ID2SYM(rb_intern_const("year")); + sym_month = ID2SYM(rb_intern_const("month")); + sym_yday = ID2SYM(rb_intern_const("yday")); + sym_wday = ID2SYM(rb_intern_const("wday")); + sym_day = ID2SYM(rb_intern_const("day")); + sym_hour = ID2SYM(rb_intern_const("hour")); + sym_min = ID2SYM(rb_intern_const("min")); + sym_sec = ID2SYM(rb_intern_const("sec")); + sym_sec_fraction = ID2SYM(rb_intern_const("sec_fraction")); + sym_zone = ID2SYM(rb_intern_const("zone")); half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2)); + rb_gc_register_mark_object(half_days_in_day); #if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS day_in_nanoseconds = LONG2NUM((long)DAY_IN_SECONDS * @@ -9221,234 +9701,108 @@ Init_date_core(void) day_in_nanoseconds = f_mul(INT2FIX(DAY_IN_SECONDS), INT2FIX(SECOND_IN_NANOSECONDS)); #endif - - rb_gc_register_mark_object(half_days_in_day); rb_gc_register_mark_object(day_in_nanoseconds); positive_inf = +INFINITY; negative_inf = -INFINITY; /* - * date and datetime class - Tadayoshi Funaba 1998-2011 - * - * 'date' provides two classes Date and DateTime. + * \Class \Date provides methods for storing and manipulating + * calendar dates. * - * == Terms and definitions + * Consider using + * {class Time}[rdoc-ref:Time] + * instead of class \Date if: * - * Some terms and definitions are based on ISO 8601 and JIS X 0301. + * - You need both dates and times; \Date handles only dates. + * - You need only Gregorian dates (and not Julian dates); + * see {Julian and Gregorian Calendars}[rdoc-ref:language/calendars.rdoc]. * - * === calendar date + * A \Date object, once created, is immutable, and cannot be modified. * - * The calendar date is a particular day of a calendar year, - * identified by its ordinal number within a calendar month within - * that year. + * == Creating a \Date * - * In those classes, this is so-called "civil". + * You can create a date for the current date, using Date.today: * - * === ordinal date + * Date.today # => #<Date: 1999-12-31> * - * The ordinal date is a particular day of a calendar year identified - * by its ordinal number within the year. + * You can create a specific date from various combinations of arguments: * - * In those classes, this is so-called "ordinal". + * - Date.new takes integer year, month, and day-of-month: * - * === week date + * Date.new(1999, 12, 31) # => #<Date: 1999-12-31> * - * The week date is a date identified by calendar week and day numbers. + * - Date.ordinal takes integer year and day-of-year: * - * The calendar week is a seven day period within a calendar year, - * starting on a Monday and identified by its ordinal number within - * the year; the first calendar week of the year is the one that - * includes the first Thursday of that year. In the Gregorian - * calendar, this is equivalent to the week which includes January 4. + * Date.ordinal(1999, 365) # => #<Date: 1999-12-31> * - * In those classes, this so-called "commercial". + * - Date.jd takes integer Julian day: * - * === julian day number + * Date.jd(2451544) # => #<Date: 1999-12-31> * - * The Julian day number is in elapsed days since noon (Greenwich mean - * time) on January 1, 4713 BCE (in the Julian calendar). + * - Date.commercial takes integer commercial data (year, week, day-of-week): * - * In this document, the astronomical Julian day number is same as the - * original Julian day number. And the chronological Julian day - * number is a variation of the Julian day number. Its days begin at - * midnight on local time. + * Date.commercial(1999, 52, 5) # => #<Date: 1999-12-31> * - * In this document, when the term "Julian day number" simply appears, - * it just refers to "chronological Julian day number", not the - * original. + * - Date.parse takes a string, which it parses heuristically: * - * In those classes, those are so-called "ajd" and "jd". + * Date.parse('1999-12-31') # => #<Date: 1999-12-31> + * Date.parse('31-12-1999') # => #<Date: 1999-12-31> + * Date.parse('1999-365') # => #<Date: 1999-12-31> + * Date.parse('1999-W52-5') # => #<Date: 1999-12-31> * - * === modified julian day number + * - Date.strptime takes a date string and a format string, + * then parses the date string according to the format string: * - * The modified Julian day number is in elapsed days since midnight - * (Coordinated universal time) on November 17, 1858 CE (in the - * Gregorian calendar). + * Date.strptime('1999-12-31', '%Y-%m-%d') # => #<Date: 1999-12-31> + * Date.strptime('31-12-1999', '%d-%m-%Y') # => #<Date: 1999-12-31> + * Date.strptime('1999-365', '%Y-%j') # => #<Date: 1999-12-31> + * Date.strptime('1999-W52-5', '%G-W%V-%u') # => #<Date: 1999-12-31> + * Date.strptime('1999 52 5', '%Y %U %w') # => #<Date: 1999-12-31> + * Date.strptime('1999 52 5', '%Y %W %u') # => #<Date: 1999-12-31> + * Date.strptime('fri31dec99', '%a%d%b%y') # => #<Date: 1999-12-31> * - * In this document, the astronomical modified Julian day number is - * same as the original modified Julian day number. And the - * chronological modified Julian day number is a variation of the - * modified Julian day number. Its days begin at midnight on local - * time. + * See also the specialized methods in + * {"Specialized Format Strings" in Formats for Dates and Times}[rdoc-ref:language/strftime_formatting.rdoc@Specialized+Format+Strings] * - * In this document, when the term "modified Julian day number" simply - * appears, it just refers to "chronological modified Julian day - * number", not the original. - * - * In those classes, this is so-called "mjd". - * - * - * == Date - * - * A subclass of Object includes Comparable module, easily handles - * date. - * - * Date object is created with Date::new, Date::jd, Date::ordinal, - * Date::commercial, Date::parse, Date::strptime, Date::today, - * Time#to_date or etc. - * - * require 'date' + * == Argument +limit+ * - * Date.new(2001,2,3) #=> #<Date: 2001-02-03 ...> - * Date.jd(2451944) #=> #<Date: 2001-02-03 ...> - * Date.ordinal(2001,34) #=> #<Date: 2001-02-03 ...> - * Date.commercial(2001,5,6) #=> #<Date: 2001-02-03 ...> - * Date.parse('2001-02-03') #=> #<Date: 2001-02-03 ...> - * Date.strptime('03-02-2001', '%d-%m-%Y') - * #=> #<Date: 2001-02-03 ...> - * Time.new(2001,2,3).to_date #=> #<Date: 2001-02-03 ...> + * Certain singleton methods in \Date that parse string arguments + * also take optional keyword argument +limit+, + * which can limit the length of the string argument. * - * All date objects are immutable; hence cannot modify themselves. + * When +limit+ is: * - * The concept of this date object can be represented as a tuple - * of the day count, the offset and the day of calendar reform. - * - * The day count denotes the absolute position of a temporal - * dimension. The offset is relative adjustment, which determines - * decoded local time with the day count. The day of calendar - * reform denotes the start day of the new style. The old style - * of the West is the Julian calendar which was adopted by - * Caersar. The new style is the Gregorian calendar, which is the - * current civil calendar of many countries. - * - * The day count is virtually the astronomical Julian day number. - * The offset in this class is usually zero, and cannot be - * specified directly. - * - * An optional argument the day of calendar reform (start) as a - * Julian day number, which should be 2298874 to 2426355 or -/+oo. - * The default value is Date::ITALY (2299161=1582-10-15). See - * also sample/cal.rb. - * - * $ ruby sample/cal.rb -c it 10 1582 - * October 1582 - * S M Tu W Th F S - * 1 2 3 4 15 16 - * 17 18 19 20 21 22 23 - * 24 25 26 27 28 29 30 - * 31 - * - * $ ruby sample/cal.rb -c gb 9 1752 - * September 1752 - * S M Tu W Th F S - * 1 2 14 15 16 - * 17 18 19 20 21 22 23 - * 24 25 26 27 28 29 30 - * - * Date object has various methods. See each reference. - * - * d = Date.parse('3rd Feb 2001') - * #=> #<Date: 2001-02-03 ...> - * d.year #=> 2001 - * d.mon #=> 2 - * d.mday #=> 3 - * d.wday #=> 6 - * d += 1 #=> #<Date: 2001-02-04 ...> - * d.strftime('%a %d %b %Y') #=> "Sun 04 Feb 2001" - * - * - * == DateTime - * - * A subclass of Date easily handles date, hour, minute, second and - * offset. - * - * DateTime does not consider any leapseconds, does not track - * any summer time rules. + * - Non-negative: + * raises ArgumentError if the string length is greater than _limit_. + * - Other numeric or +nil+: ignores +limit+. + * - Other non-numeric: raises TypeError. * - * DateTime object is created with DateTime::new, DateTime::jd, - * DateTime::ordinal, DateTime::commercial, DateTime::parse, - * DateTime::strptime, DateTime::now, Time#to_datetime or etc. - * - * require 'date' - * - * DateTime.new(2001,2,3,4,5,6) - * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> - * - * The last element of day, hour, minute or senond can be - * fractional number. The fractional number's precision is assumed - * at most nanosecond. - * - * DateTime.new(2001,2,3.5) - * #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...> - * - * An optional argument the offset indicates the difference - * between the local time and UTC. For example, Rational(3,24) - * represents ahead of 3 hours of UTC, Rational(-5,24) represents - * behind of 5 hours of UTC. The offset should be -1 to +1, and - * its precision is assumed at most second. The default value is - * zero (equals to UTC). - * - * DateTime.new(2001,2,3,4,5,6,Rational(3,24)) - * #=> #<DateTime: 2001-02-03T03:04:05+03:00 ...> - * also accepts string form. - * - * DateTime.new(2001,2,3,4,5,6,'+03:00') - * #=> #<DateTime: 2001-02-03T03:04:05+03:00 ...> - * - * An optional argument the day of calendar reform (start) denotes - * a Julian day number, which should be 2298874 to 2426355 or - * -/+oo. The default value is Date::ITALY (2299161=1582-10-15). - * - * DateTime object has various methods. See each reference. - * - * d = DateTime.parse('3rd Feb 2001 04:05:06+03:30') - * #=> #<DateTime: 2001-02-03T04:05:06+03:30 ...> - * d.hour #=> 4 - * d.min #=> 5 - * d.sec #=> 6 - * d.offset #=> (7/48) - * d.zone #=> "+03:30" - * d += Rational('1.5') - * #=> #<DateTime: 2001-02-04%16:05:06+03:30 ...> - * d = d.new_offset('+09:00') - * #=> #<DateTime: 2001-02-04%21:35:06+09:00 ...> - * d.strftime('%I:%M:%S %p') - * #=> "09:35:06 PM" - * d > DateTime.new(1999) - * #=> true */ cDate = rb_define_class("Date", rb_cObject); + /* Exception for invalid date/time */ + eDateError = rb_define_class_under(cDate, "Error", rb_eArgError); + rb_include_module(cDate, rb_mComparable); - /* An array of stirng of full month name in English. The first + /* An array of strings of full month names in English. The first * element is nil. */ rb_define_const(cDate, "MONTHNAMES", mk_ary_of_str(13, monthnames)); - /* An array of string of abbreviated month name in English. The + /* An array of strings of abbreviated month names in English. The * first element is nil. */ rb_define_const(cDate, "ABBR_MONTHNAMES", mk_ary_of_str(13, abbr_monthnames)); - /* An array of string of full name of days of the week in English. + /* An array of strings of the full names of days of the week in English. * The first is "Sunday". */ rb_define_const(cDate, "DAYNAMES", mk_ary_of_str(7, daynames)); - /* An array of string of abbreviated day name in English. The + /* An array of strings of abbreviated day names in English. The * first is "Sun". */ rb_define_const(cDate, "ABBR_DAYNAMES", mk_ary_of_str(7, abbr_daynames)); @@ -9464,32 +9818,31 @@ Init_date_core(void) rb_define_const(cDate, "ENGLAND", INT2FIX(ENGLAND)); /* The Julian day number of the day of calendar reform for the - * proleptic Julian calendar + * proleptic Julian calendar. */ rb_define_const(cDate, "JULIAN", DBL2NUM(JULIAN)); /* The Julian day number of the day of calendar reform for the - * proleptic Gregorian calendar + * proleptic Gregorian calendar. */ rb_define_const(cDate, "GREGORIAN", DBL2NUM(GREGORIAN)); - rb_define_alloc_func(cDate, d_lite_s_alloc); + rb_define_alloc_func(cDate, d_lite_s_alloc_simple); #ifndef NDEBUG -#define de_define_private_method rb_define_private_method - de_define_private_method(CLASS_OF(cDate), "_valid_jd?", + rb_define_private_method(CLASS_OF(cDate), "_valid_jd?", date_s__valid_jd_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_ordinal?", + rb_define_private_method(CLASS_OF(cDate), "_valid_ordinal?", date_s__valid_ordinal_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_civil?", + rb_define_private_method(CLASS_OF(cDate), "_valid_civil?", date_s__valid_civil_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_date?", + rb_define_private_method(CLASS_OF(cDate), "_valid_date?", date_s__valid_civil_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_commercial?", + rb_define_private_method(CLASS_OF(cDate), "_valid_commercial?", date_s__valid_commercial_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_weeknum?", + rb_define_private_method(CLASS_OF(cDate), "_valid_weeknum?", date_s__valid_weeknum_p, -1); - de_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?", + rb_define_private_method(CLASS_OF(cDate), "_valid_nth_kday?", date_s__valid_nth_kday_p, -1); #endif @@ -9502,11 +9855,11 @@ Init_date_core(void) date_s_valid_commercial_p, -1); #ifndef NDEBUG - de_define_private_method(CLASS_OF(cDate), "valid_weeknum?", + rb_define_private_method(CLASS_OF(cDate), "valid_weeknum?", date_s_valid_weeknum_p, -1); - de_define_private_method(CLASS_OF(cDate), "valid_nth_kday?", + rb_define_private_method(CLASS_OF(cDate), "valid_nth_kday?", date_s_valid_nth_kday_p, -1); - de_define_private_method(CLASS_OF(cDate), "zone_to_diff", + rb_define_private_method(CLASS_OF(cDate), "zone_to_diff", date_s_zone_to_diff, 1); #endif @@ -9517,21 +9870,18 @@ Init_date_core(void) date_s_gregorian_leap_p, 1); #ifndef NDEBUG -#define de_define_singleton_method rb_define_singleton_method -#define de_define_alias rb_define_alias - de_define_singleton_method(cDate, "new!", date_s_new_bang, -1); - de_define_alias(rb_singleton_class(cDate), "new_l!", "new"); + rb_define_singleton_method(cDate, "new!", date_s_new_bang, -1); + rb_define_alias(rb_singleton_class(cDate), "new_l!", "new"); #endif 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 - de_define_singleton_method(cDate, "weeknum", date_s_weeknum, -1); - de_define_singleton_method(cDate, "nth_kday", date_s_nth_kday, -1); + 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); @@ -9539,29 +9889,26 @@ Init_date_core(void) 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, "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, "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, "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, "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, "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_singleton_method(cDate, "jisx0301", date_s_jisx0301, -1); -#ifndef NDEBUG -#define de_define_method rb_define_method - de_define_method(cDate, "initialize", d_lite_initialize, -1); -#endif + rb_define_method(cDate, "initialize", date_initialize, -1); rb_define_method(cDate, "initialize_copy", d_lite_initialize_copy, 1); #ifndef NDEBUG - de_define_method(cDate, "fill", d_lite_fill, 0); + rb_define_method(cDate, "fill", d_lite_fill, 0); #endif rb_define_method(cDate, "ajd", d_lite_ajd, 0); @@ -9583,8 +9930,8 @@ Init_date_core(void) rb_define_method(cDate, "cwday", d_lite_cwday, 0); #ifndef NDEBUG - de_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); - de_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); + rb_define_private_method(cDate, "wnum0", d_lite_wnum0, 0); + rb_define_private_method(cDate, "wnum1", d_lite_wnum1, 0); #endif rb_define_method(cDate, "wday", d_lite_wday, 0); @@ -9598,18 +9945,14 @@ Init_date_core(void) rb_define_method(cDate, "saturday?", d_lite_saturday_p, 0); #ifndef NDEBUG - de_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2); + rb_define_method(cDate, "nth_kday?", d_lite_nth_kday_p, 2); #endif - rb_define_private_method(cDate, "hour", d_lite_hour, 0); - rb_define_private_method(cDate, "min", d_lite_min, 0); - rb_define_private_method(cDate, "minute", d_lite_min, 0); - rb_define_private_method(cDate, "sec", d_lite_sec, 0); - rb_define_private_method(cDate, "second", d_lite_sec, 0); - rb_define_private_method(cDate, "sec_fraction", d_lite_sec_fraction, 0); - rb_define_private_method(cDate, "second_fraction", d_lite_sec_fraction, 0); - rb_define_private_method(cDate, "offset", d_lite_offset, 0); - rb_define_private_method(cDate, "zone", d_lite_zone, 0); + rb_define_private_method(cDate, "hour", d_lite_zero, 0); + rb_define_private_method(cDate, "min", d_lite_zero, 0); + rb_define_private_method(cDate, "minute", d_lite_zero, 0); + rb_define_private_method(cDate, "sec", d_lite_zero, 0); + rb_define_private_method(cDate, "second", d_lite_zero, 0); rb_define_method(cDate, "julian?", d_lite_julian_p, 0); rb_define_method(cDate, "gregorian?", d_lite_gregorian_p, 0); @@ -9622,8 +9965,6 @@ Init_date_core(void) 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); @@ -9651,7 +9992,7 @@ Init_date_core(void) rb_define_method(cDate, "to_s", d_lite_to_s, 0); #ifndef NDEBUG - de_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0); + rb_define_method(cDate, "inspect_raw", d_lite_inspect_raw, 0); #endif rb_define_method(cDate, "inspect", d_lite_inspect, 0); @@ -9667,15 +10008,159 @@ Init_date_core(void) rb_define_method(cDate, "httpdate", d_lite_httpdate, 0); rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0); + rb_define_method(cDate, "deconstruct_keys", d_lite_deconstruct_keys, 1); + #ifndef NDEBUG - de_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0); + rb_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0); #endif rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0); rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1); + rb_define_singleton_method(cDate, "_load", date_s__load, 1); - /* datetime */ + /* + * == DateTime + * + * A subclass of Date that easily handles date, hour, minute, second, + * and offset. + * + * DateTime class is considered deprecated. Use Time class. + * + * DateTime does not consider any leap seconds, does not track + * any summer time rules. + * + * A DateTime object is created with DateTime::new, DateTime::jd, + * DateTime::ordinal, DateTime::commercial, DateTime::parse, + * DateTime::strptime, DateTime::now, Time#to_datetime, etc. + * + * require 'date' + * + * DateTime.new(2001,2,3,4,5,6) + * #=> #<DateTime: 2001-02-03T04:05:06+00:00 ...> + * + * The last element of day, hour, minute, or second can be a + * fractional number. The fractional number's precision is assumed + * at most nanosecond. + * + * DateTime.new(2001,2,3.5) + * #=> #<DateTime: 2001-02-03T12:00:00+00:00 ...> + * + * An optional argument, the offset, indicates the difference + * between the local time and UTC. For example, <tt>Rational(3,24)</tt> + * represents ahead of 3 hours of UTC, <tt>Rational(-5,24)</tt> represents + * behind of 5 hours of UTC. The offset should be -1 to +1, and + * its precision is assumed at most second. The default value is + * zero (equals to UTC). + * + * DateTime.new(2001,2,3,4,5,6,Rational(3,24)) + * #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...> + * + * The offset also accepts string form: + * + * DateTime.new(2001,2,3,4,5,6,'+03:00') + * #=> #<DateTime: 2001-02-03T04:05:06+03:00 ...> + * + * An optional argument, the day of calendar reform (+start+), denotes + * a Julian day number, which should be 2298874 to 2426355 or + * negative/positive infinity. + * The default value is +Date::ITALY+ (2299161=1582-10-15). + * + * A DateTime object has various methods. See each reference. + * + * d = DateTime.parse('3rd Feb 2001 04:05:06+03:30') + * #=> #<DateTime: 2001-02-03T04:05:06+03:30 ...> + * d.hour #=> 4 + * d.min #=> 5 + * d.sec #=> 6 + * d.offset #=> (7/48) + * d.zone #=> "+03:30" + * d += Rational('1.5') + * #=> #<DateTime: 2001-02-04%16:05:06+03:30 ...> + * d = d.new_offset('+09:00') + * #=> #<DateTime: 2001-02-04%21:35:06+09:00 ...> + * d.strftime('%I:%M:%S %p') + * #=> "09:35:06 PM" + * d > DateTime.new(1999) + * #=> true + * + * === When should you use DateTime and when should you use Time? + * + * It's a common misconception that + * {William Shakespeare}[https://en.wikipedia.org/wiki/William_Shakespeare] + * and + * {Miguel de Cervantes}[https://en.wikipedia.org/wiki/Miguel_de_Cervantes] + * died on the same day in history - + * so much so that UNESCO named April 23 as + * {World Book Day because of this fact}[https://en.wikipedia.org/wiki/World_Book_Day]. + * However, because England hadn't yet adopted the + * {Gregorian Calendar Reform}[https://en.wikipedia.org/wiki/Gregorian_calendar#Gregorian_reform] + * (and wouldn't until {1752}[https://en.wikipedia.org/wiki/Calendar_(New_Style)_Act_1750]) + * their deaths are actually 10 days apart. + * Since Ruby's Time class implements a + * {proleptic Gregorian calendar}[https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar] + * and has no concept of calendar reform there's no way + * to express this with Time objects. This is where DateTime steps in: + * + * shakespeare = DateTime.iso8601('1616-04-23', Date::ENGLAND) + * #=> Tue, 23 Apr 1616 00:00:00 +0000 + * cervantes = DateTime.iso8601('1616-04-23', Date::ITALY) + * #=> Sat, 23 Apr 1616 00:00:00 +0000 + * + * Already you can see something is weird - the days of the week + * are different. Taking this further: + * + * cervantes == shakespeare + * #=> false + * (shakespeare - cervantes).to_i + * #=> 10 + * + * This shows that in fact they died 10 days apart (in reality + * 11 days since Cervantes died a day earlier but was buried on + * the 23rd). We can see the actual date of Shakespeare's death by + * using the #gregorian method to convert it: + * + * shakespeare.gregorian + * #=> Tue, 03 May 1616 00:00:00 +0000 + * + * So there's an argument that all the celebrations that take + * place on the 23rd April in Stratford-upon-Avon are actually + * the wrong date since England is now using the Gregorian calendar. + * You can see why when we transition across the reform + * date boundary: + * + * # start off with the anniversary of Shakespeare's birth in 1751 + * shakespeare = DateTime.iso8601('1751-04-23', Date::ENGLAND) + * #=> Tue, 23 Apr 1751 00:00:00 +0000 + * + * # add 366 days since 1752 is a leap year and April 23 is after February 29 + * shakespeare + 366 + * #=> Thu, 23 Apr 1752 00:00:00 +0000 + * + * # add another 365 days to take us to the anniversary in 1753 + * shakespeare + 366 + 365 + * #=> Fri, 04 May 1753 00:00:00 +0000 + * + * As you can see, if we're accurately tracking the number of + * {solar years}[https://en.wikipedia.org/wiki/Tropical_year] + * since Shakespeare's birthday then the correct anniversary date + * would be the 4th May and not the 23rd April. + * + * So when should you use DateTime in Ruby and when should + * you use Time? Almost certainly you'll want to use Time + * since your app is probably dealing with current dates and + * times. However, if you need to deal with dates and times in a + * historical context you'll want to use DateTime to avoid + * making the same mistakes as UNESCO. If you also have to deal + * with timezones then best of luck - just bear in mind that + * you'll probably be dealing with + * {local solar times}[https://en.wikipedia.org/wiki/Solar_time], + * since it wasn't until the 19th century that the introduction + * of the railways necessitated the need for + * {Standard Time}[https://en.wikipedia.org/wiki/Standard_time#Great_Britain] + * and eventually timezones. + */ cDateTime = rb_define_class("DateTime", cDate); + rb_define_alloc_func(cDateTime, d_lite_s_alloc_complex); rb_define_singleton_method(cDateTime, "jd", datetime_s_jd, -1); rb_define_singleton_method(cDateTime, "ordinal", datetime_s_ordinal, -1); @@ -9685,9 +10170,9 @@ Init_date_core(void) datetime_s_commercial, -1); #ifndef NDEBUG - de_define_singleton_method(cDateTime, "weeknum", + rb_define_singleton_method(cDateTime, "weeknum", datetime_s_weeknum, -1); - de_define_singleton_method(cDateTime, "nth_kday", + rb_define_singleton_method(cDateTime, "nth_kday", datetime_s_nth_kday, -1); #endif @@ -9715,19 +10200,16 @@ Init_date_core(void) rb_define_singleton_method(cDateTime, "jisx0301", datetime_s_jisx0301, -1); -#define f_public(m,s) rb_funcall(m, rb_intern("public"), 1,\ - ID2SYM(rb_intern(s))) - - f_public(cDateTime, "hour"); - f_public(cDateTime, "min"); - f_public(cDateTime, "minute"); - f_public(cDateTime, "sec"); - f_public(cDateTime, "second"); - f_public(cDateTime, "sec_fraction"); - f_public(cDateTime, "second_fraction"); - f_public(cDateTime, "offset"); - f_public(cDateTime, "zone"); - f_public(cDateTime, "new_offset"); + rb_define_method(cDateTime, "hour", d_lite_hour, 0); + rb_define_method(cDateTime, "min", d_lite_min, 0); + rb_define_method(cDateTime, "minute", d_lite_min, 0); + rb_define_method(cDateTime, "sec", d_lite_sec, 0); + rb_define_method(cDateTime, "second", d_lite_sec, 0); + rb_define_method(cDateTime, "sec_fraction", d_lite_sec_fraction, 0); + rb_define_method(cDateTime, "second_fraction", d_lite_sec_fraction, 0); + rb_define_method(cDateTime, "offset", d_lite_offset, 0); + rb_define_method(cDateTime, "zone", d_lite_zone, 0); + rb_define_method(cDateTime, "new_offset", d_lite_new_offset, -1); rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0); @@ -9738,6 +10220,8 @@ Init_date_core(void) rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1); rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1); + rb_define_method(cDateTime, "deconstruct_keys", dt_lite_deconstruct_keys, 1); + /* conversions */ rb_define_method(rb_cTime, "to_time", time_to_time, 0); @@ -9755,15 +10239,15 @@ Init_date_core(void) #ifndef NDEBUG /* tests */ - de_define_singleton_method(cDate, "test_civil", date_s_test_civil, 0); - de_define_singleton_method(cDate, "test_ordinal", date_s_test_ordinal, 0); - de_define_singleton_method(cDate, "test_commercial", + 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); - de_define_singleton_method(cDate, "test_weeknum", date_s_test_weeknum, 0); - de_define_singleton_method(cDate, "test_nth_kday", date_s_test_nth_kday, 0); - de_define_singleton_method(cDate, "test_unit_conv", + 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_unit_conv", date_s_test_unit_conv, 0); - de_define_singleton_method(cDate, "test_all", date_s_test_all, 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 903163003c..a1600e4708 100644 --- a/ext/date/date_parse.c +++ b/ext/date/date_parse.c @@ -7,6 +7,14 @@ #include "ruby/re.h" #include <ctype.h> +#undef strncasecmp +#define strncasecmp STRNCASECMP + +RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); +RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow); + +/* #define TIGHT_PARSER */ + #define sizeof_array(o) (sizeof o / sizeof o[0]) #define f_negate(x) rb_funcall(x, rb_intern("-@"), 0) @@ -35,32 +43,47 @@ #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 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))) +#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""))) #define cstr2num(s) rb_cstr_to_inum(s, 10, 0) #define str2num(s) rb_str_to_inum(s, 10, 0) -static const char *abbr_days[] = { +static const char abbr_days[][4] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; -static const char *abbr_months[] = { +static const char abbr_months[][4] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; #define issign(c) ((c) == '-' || (c) == '+') #define asp_string() rb_str_new(" ", 1) +#ifdef TIGHT_PARSER +#define asuba_string() rb_str_new("\001", 1) +#define asubb_string() rb_str_new("\002", 1) +#define asubw_string() rb_str_new("\027", 1) +#define asubt_string() rb_str_new("\024", 1) +#endif + +static size_t +digit_span(const char *s, const char *e) +{ + size_t i = 0; + while (s + i < e && isdigit((unsigned char)s[i])) i++; + return i; +} static void s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) { + VALUE vbuf = 0; VALUE c = Qnil; - if (TYPE(m) != T_STRING) + if (!RB_TYPE_P(m, T_STRING)) m = f_to_s(m); if (!NIL_P(y) && !NIL_P(m) && NIL_P(d)) { @@ -78,7 +101,7 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) y = d; d = Qnil; } - if (!NIL_P(d) && *RSTRING_PTR(d) == '\'') { + if (!NIL_P(d) && RSTRING_LEN(d) > 0 && *RSTRING_PTR(d) == '\'') { y = d; d = Qnil; } @@ -89,17 +112,20 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) size_t l; s = RSTRING_PTR(y); - while (!issign(*s) && !isdigit(*s)) + ep = RSTRING_END(y); + while (s < ep && !issign(*s) && !isdigit((unsigned char)*s)) s++; + if (s >= ep) goto no_date; bp = s; - if (issign(*s)) + if (issign((unsigned char)*s)) s++; - l = strspn(s, "0123456789"); + l = digit_span(s, ep); ep = s + l; if (*ep) { y = d; d = rb_str_new(bp, ep - bp); } + no_date:; } if (!NIL_P(m)) { @@ -138,8 +164,10 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) VALUE iy; s = RSTRING_PTR(y); - while (!issign(*s) && !isdigit(*s)) + ep = RSTRING_END(y); + while (s < ep && !issign(*s) && !isdigit((unsigned char)*s)) s++; + if (s >= ep) goto no_year; bp = s; if (issign(*s)) { s++; @@ -147,43 +175,50 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) } if (sign) c = Qfalse; - l = strspn(s, "0123456789"); + l = digit_span(s, ep); ep = s + l; if (l > 2) c = Qfalse; { char *buf; - buf = ALLOCA_N(char, ep - bp + 1); + buf = ALLOCV_N(char, vbuf, ep - bp + 1); memcpy(buf, bp, ep - bp); buf[ep - bp] = '\0'; iy = cstr2num(buf); + ALLOCV_END(vbuf); } - if (bc) - iy = f_add(f_negate(iy), INT2FIX(1)); set_hash("year", iy); + no_year:; } + if (bc) + set_hash("_bc", Qtrue); + if (!NIL_P(m)) { const char *s, *bp, *ep; size_t l; VALUE im; s = RSTRING_PTR(m); - while (!isdigit(*s)) + ep = RSTRING_END(m); + while (s < ep && !isdigit((unsigned char)*s)) s++; + if (s >= ep) goto no_month; bp = s; - l = strspn(s, "0123456789"); + l = digit_span(s, ep); ep = s + l; { char *buf; - buf = ALLOCA_N(char, ep - bp + 1); + buf = ALLOCV_N(char, vbuf, ep - bp + 1); memcpy(buf, bp, ep - bp); buf[ep - bp] = '\0'; im = cstr2num(buf); + ALLOCV_END(vbuf); } set_hash("mon", im); + no_month:; } if (!NIL_P(d)) { @@ -192,20 +227,24 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) VALUE id; s = RSTRING_PTR(d); - while (!isdigit(*s)) + ep = RSTRING_END(d); + while (s < ep && !isdigit((unsigned char)*s)) s++; + if (s >= ep) goto no_mday; bp = s; - l = strspn(s, "0123456789"); + l = digit_span(s, ep); ep = s + l; { char *buf; - buf = ALLOCA_N(char, ep - bp + 1); + buf = ALLOCV_N(char, vbuf, ep - bp + 1); memcpy(buf, bp, ep - bp); buf[ep - bp] = '\0'; id = cstr2num(buf); + ALLOCV_END(vbuf); } set_hash("mday", id); + no_mday:; } if (!NIL_P(c)) @@ -217,29 +256,49 @@ s3e(VALUE hash, VALUE y, VALUE m, VALUE d, int bc) #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" +#define NUMBER "(?<!\\d)\\d" + +#ifdef TIGHT_PARSER +#define VALID_DAYS "(?:" DAYS ")" "|(?:tues|wednes|thurs|thur|" ABBR_DAYS ")\\.?" +#define VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")\\.?" +#define DOTLESS_VALID_MONTHS "(?:" MONTHS ")" "|(?:sept|" ABBR_MONTHS ")" +#define BOS "\\A\\s*" +#define FPA "\\001" +#define FPB "\\002" +#define FPW "\\027" +#define FPT "\\024" +#define FPW_COM "\\s*(?:" FPW "\\s*,?)?\\s*" +#define FPT_COM "\\s*(?:" FPT "\\s*,?)?\\s*" +#define COM_FPW "\\s*(?:,?\\s*" FPW ")?\\s*" +#define COM_FPT "\\s*(?:,?\\s*(?:@|\\b[aA][tT]\\b)?\\s*" FPT ")?\\s*" +#define TEE_FPT "\\s*(?:[tT]?" FPT ")?" +#define EOS "\\s*\\z" +#endif + static VALUE regcomp(const char *source, long len, int opt) { VALUE pat; pat = rb_reg_new(source, len, opt); + rb_obj_freeze(pat); rb_gc_register_mark_object(pat); return pat; } #define REGCOMP(pat,opt) \ -{ \ +do { \ if (NIL_P(pat)) \ pat = regcomp(pat##_source, sizeof pat##_source - 1, opt); \ -} +} while (0) #define REGCOMP_0(pat) REGCOMP(pat, 0) #define REGCOMP_I(pat) REGCOMP(pat, ONIG_OPTION_IGNORECASE) #define MATCH(s,p,c) \ -{ \ +do { \ return match(s, p, hash, c); \ -} +} while (0) static int match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) @@ -256,13 +315,8 @@ match(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) return 1; } -#define SUBS(s,p,c) \ -{ \ - return subs(s, p, hash, c); \ -} - static int -subs(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) +subx(VALUE str, VALUE rep, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) { VALUE m; @@ -276,280 +330,226 @@ subs(VALUE str, VALUE pat, VALUE hash, int (*cb)(VALUE, VALUE)) be = f_begin(m, INT2FIX(0)); en = f_end(m, INT2FIX(0)); - f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), asp_string()); + f_aset2(str, be, LONG2NUM(NUM2LONG(en) - NUM2LONG(be)), rep); (*cb)(m, hash); } return 1; } -struct zone { - const char *name; - int offset; -}; +#define SUBS(s,p,c) \ +do { \ + return subx(s, asp_string(), p, hash, c); \ +} while (0) -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} -}; +#ifdef TIGHT_PARSER +#define SUBA(s,p,c) \ +do { \ + return subx(s, asuba_string(), p, hash, c); \ +} while (0) -VALUE -date_zone_to_diff(VALUE str) -{ - VALUE offset = Qnil; +#define SUBB(s,p,c) \ +do { \ + return subx(s, asubb_string(), p, hash, c); \ +} while (0) - long l, i; - char *s, *dest, *d; - int sp = 1; +#define SUBW(s,p,c) \ +do { \ + return subx(s, asubw_string(), p, hash, c); \ +} while (0) - l = RSTRING_LEN(str); - s = RSTRING_PTR(str); +#define SUBT(s,p,c) \ +do { \ + return subx(s, asubt_string(), p, hash, c); \ +} while (0) +#endif - dest = d = ALLOCA_N(char, l + 1); +#include "zonetab.h" - for (i = 0; i < l; i++) { - if (isspace(s[i]) || s[i] == '\0') { - if (!sp) - *d++ = ' '; - sp = 1; +static int +str_end_with_word(const char *s, long l, const char *w) +{ + int n = (int)strlen(w); + if (l <= n || !isspace((unsigned char)s[l - n - 1])) return 0; + if (strncasecmp(&s[l - n], w, n)) return 0; + do ++n; while (l > n && isspace((unsigned char)s[l - n - 1])); + return n; +} + +static long +shrunk_size(const char *s, long l) +{ + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace((unsigned char)s[i])) { + if (sp) ni++; + sp = 0; + ni++; } else { - if (isalpha(s[i])) - *d++ = tolower(s[i]); - else - *d++ = s[i]; - sp = 0; + sp = 1; } } - 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; + return ni < l ? ni : 0; +} - if (sl >= 0 && strcmp(ss, STD) == 0) { - str = rb_str_new(RSTRING_PTR(str), sl); - } - else if (dl >= 0 && strcmp(ds, DST) == 0) { - str = rb_str_new(RSTRING_PTR(str), dl); - dst = 1; +static long +shrink_space(char *d, const char *s, long l) +{ + long i, ni; + int sp = 0; + for (i = ni = 0; i < l; ++i) { + if (!isspace((unsigned char)s[i])) { + if (sp) d[ni++] = ' '; + sp = 0; + d[ni++] = s[i]; } -#undef STD -#undef DST else { -#define DST " dst" - char *ds; - long dl; + sp = 1; + } + } + return ni; +} + +VALUE +date_zone_to_diff(VALUE str) +{ + VALUE offset = Qnil; + long l = RSTRING_LEN(str); + const char *s = RSTRING_PTR(str); - dl = RSTRING_LEN(str) - (sizeof DST - 1); - ds = RSTRING_PTR(str) + dl; + { + int dst = 0; + int w; - if (dl >= 0 && strcmp(ds, DST) == 0) { - str = rb_str_new(RSTRING_PTR(str), dl); + if ((w = str_end_with_word(s, l, "time")) > 0) { + int wtime = w; + l -= w; + if ((w = str_end_with_word(s, l, "standard")) > 0) { + l -= w; + } + else if ((w = str_end_with_word(s, l, "daylight")) > 0) { + l -= w; dst = 1; } -#undef DST + else { + l += wtime; + } } + else if ((w = str_end_with_word(s, l, "dst")) > 0) { + l -= w; + dst = 1; + } + { - static VALUE zones = Qnil; + const char *zn = s; + long sl = shrunk_size(s, l); + char shrunk_buff[MAX_WORD_LENGTH]; /* no terminator to be added */ + const struct zone *z = 0; - if (NIL_P(zones)) { - int i; + if (sl <= 0) { + sl = l; + } + else if (sl <= MAX_WORD_LENGTH) { + char *d = shrunk_buff; + sl = shrink_space(d, s, l); + zn = d; + } - 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); - } + if (sl > 0 && sl <= MAX_WORD_LENGTH) { + z = zonetab(zn, (unsigned int)sl); } - offset = f_aref(zones, str); - if (!NIL_P(offset)) { + if (z) { + int d = z->offset; if (dst) - offset = f_add(offset, INT2FIX(3600)); + d += 3600; + offset = INT2FIX(d); goto ok; } } - { - char *s, *p; - VALUE sign; - VALUE hour = Qnil, min = Qnil, sec = Qnil; - VALUE str_orig; - s = RSTRING_PTR(str); - str_orig = str; + { + char *p; + int sign = 0; + long hour = 0, min = 0, sec = 0; - if (strncmp(s, "gmt", 3) == 0 || - strncmp(s, "utc", 3) == 0) + if (l > 3 && + (strncasecmp(s, "gmt", 3) == 0 || + strncasecmp(s, "utc", 3) == 0)) { s += 3; + l -= 3; + } if (issign(*s)) { - sign = rb_str_new(s, 1); + sign = *s == '-'; s++; + l--; - str = rb_str_new2(s); - - if (p = strchr(s, ':')) { - hour = rb_str_new(s, p - s); +#define out_of_range(v, min, max) ((v) < (min) || (max) < (v)) + hour = STRTOUL(s, &p, 10); + if (*p == ':') { + if (out_of_range(hour, 0, 23)) return Qnil; s = ++p; - if (p = strchr(s, ':')) { - min = rb_str_new(s, p - s); + min = STRTOUL(s, &p, 10); + if (out_of_range(min, 0, 59)) return Qnil; + if (*p == ':') { s = ++p; - if (p = strchr(s, ':')) { - sec = rb_str_new(s, p - s); - } - else - sec = rb_str_new2(s); + sec = STRTOUL(s, &p, 10); + if (out_of_range(sec, 0, 59)) return Qnil; } - else - min = rb_str_new2(s); - RB_GC_GUARD(str_orig); - goto num; - } - if (strpbrk(RSTRING_PTR(str), ",.")) { - char *a, *b; - - a = ALLOCA_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 (*p == ',' || *p == '.') { + /* fractional hour */ + size_t n; + int ov; + /* no over precision for offset; 10**-7 hour = 0.36 + * milliseconds should be enough. */ + const size_t max_digits = 7; /* 36 * 10**7 < 32-bit FIXNUM_MAX */ + + if (out_of_range(hour, 0, 23)) return Qnil; + + n = (s + l) - ++p; + if (n > max_digits) n = max_digits; + sec = ruby_scan_digits(p, n, 10, &n, &ov); + if ((p += n) < s + l && *p >= ('5' + !(sec & 1)) && *p <= '9') { + /* round half to even */ + sec++; + } + sec *= 36; + if (sign) { + hour = -hour; + sec = -sec; + } + if (n <= 2) { + /* HH.nn or HH.n */ + if (n == 1) sec *= 10; + offset = INT2FIX(sec + hour * 3600); } 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); + VALUE denom = rb_int_positive_pow(10, (int)(n - 2)); + offset = f_add(rb_rational_new(INT2FIX(sec), denom), INT2FIX(hour * 3600)); + if (rb_rational_den(offset) == INT2FIX(1)) { + offset = rb_rational_num(offset); + } } - goto num; + goto ok; } - num: - if (NIL_P(hour)) - offset = INT2FIX(0); - else { - if (TYPE(hour) == T_STRING) - hour = str2num(hour); - offset = f_mul(hour, INT2FIX(3600)); + else if (l > 2) { + size_t n; + int ov; + + if (l >= 1) + hour = ruby_scan_digits(&s[0], 2 - l % 2, 10, &n, &ov); + if (l >= 3) + min = ruby_scan_digits(&s[2 - l % 2], 2, 10, &n, &ov); + if (l >= 5) + sec = ruby_scan_digits(&s[4 - l % 2], 2, 10, &n, &ov); } - 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); + sec += min * 60 + hour * 3600; + if (sign) sec = -sec; + offset = INT2FIX(sec); +#undef out_of_range } } } @@ -593,11 +593,21 @@ parse_day_cb(VALUE m, VALUE hash) static int parse_day(VALUE str, VALUE hash) { - static const char pat_source[] = "\\b(" ABBR_DAYS ")[^-\\d\\s]*"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(" ABBR_DAYS ")[^-/\\d\\s]*" +#else + "(" VALID_DAYS ")" +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); +#ifndef TIGHT_PARSER SUBS(str, pat, parse_day_cb); +#else + SUBW(str, pat, parse_day_cb); +#endif } static int @@ -681,40 +691,152 @@ parse_time(VALUE str, VALUE hash) { static const char pat_source[] = "(" + "" NUMBER "+\\s*" "(?:" - "\\d+\\s*:\\s*\\d+" "(?:" - "\\s*:\\s*\\d+(?:[,.]\\d*)?" + ":\\s*\\d+" + "(?:" +#ifndef TIGHT_PARSER + "\\s*:\\s*\\d+(?:[,.]\\d*)?" +#else + "\\s*:\\s*\\d+(?:[,.]\\d+)?" +#endif + ")?" + "|" + "h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?" + ")" + "(?:" + "\\s*" + "[ap](?:m\\b|\\.m\\.)" ")?" "|" - "\\d+\\s*h(?:\\s*\\d+m?(?:\\s*\\d+s?)?)?" - ")" - "(?:" - "\\s*" "[ap](?:m\\b|\\.m\\.)" - ")?" - "|" - "\\d+\\s*[ap](?:m\\b|\\.m\\.)" + ")" ")" "(?:" "\\s*" "(" "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?" "|" - "[[:alpha:].\\s]+(?:standard|daylight)\\stime\\b" + "(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\stime\\b" "|" - "[[:alpha:]]+(?:\\sdst)?\\b" + "(?-i:[[:alpha:]]+)(?:\\sdst)?\\b" ")" ")?"; static VALUE pat = Qnil; REGCOMP_I(pat); +#ifndef TIGHT_PARSER SUBS(str, pat, parse_time_cb); +#else + SUBT(str, pat, parse_time_cb); +#endif +} + +#define BEGIN_ERA "\\b" +#define END_ERA "(?!(?<!\\.)[a-z])" + +#ifdef TIGHT_PARSER +static int +parse_era1_cb(VALUE m, VALUE hash) +{ + return 1; } static int +parse_era1(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BEGIN_ERA "(a(?:d\\b|\\.d\\.))" END_ERA; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBA(str, pat, parse_era1_cb); +} + +static int +parse_era2_cb(VALUE m, VALUE hash) +{ + VALUE b; + + b = rb_reg_nth_match(1, m); + if (*RSTRING_PTR(b) == 'B' || + *RSTRING_PTR(b) == 'b') + set_hash("_bc", Qtrue); + return 1; +} + +static int +parse_era2(VALUE str, VALUE hash) +{ + static const char pat_source[] = BEGIN_ERA + "(c(?:e\\b|\\.e\\.)|b(?:ce\\b|\\.c\\.e\\.)|b(?:c\\b|\\.c\\.))" + END_ERA; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBB(str, pat, parse_era2_cb); +} + +static int +parse_era(VALUE str, VALUE hash) +{ + if (parse_era1(str, hash)) /* pre */ + goto ok; + if (parse_era2(str, hash)) /* post */ + goto ok; + return 0; + ok: + return 1; +} +#endif + +#ifdef TIGHT_PARSER +static int +check_year_width(VALUE y) +{ + const char *s; + long l; + + l = RSTRING_LEN(y); + if (l < 2) return 0; + s = RSTRING_PTR(y); + if (!isdigit((unsigned char)s[1])) return 0; + return (l == 2 || !isdigit((unsigned char)s[2])); +} + +static int +check_apost(VALUE a, VALUE b, VALUE c) +{ + int f = 0; + + if (!NIL_P(a) && *RSTRING_PTR(a) == '\'') { + if (!check_year_width(a)) + return 0; + f++; + } + if (!NIL_P(b) && *RSTRING_PTR(b) == '\'') { + if (!check_year_width(b)) + return 0; + if (!NIL_P(c)) + return 0; + f++; + } + if (!NIL_P(c) && *RSTRING_PTR(c) == '\'') { + if (!check_year_width(c)) + return 0; + f++; + } + if (f > 1) + return 0; + return 1; +} +#endif + +static int parse_eu_cb(VALUE m, VALUE hash) { +#ifndef TIGHT_PARSER VALUE y, mon, d, b; d = rb_reg_nth_match(1, m); @@ -727,6 +849,20 @@ parse_eu_cb(VALUE m, VALUE hash) s3e(hash, y, mon, d, !NIL_P(b) && (*RSTRING_PTR(b) == 'B' || *RSTRING_PTR(b) == 'b')); +#else + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); +#endif return 1; } @@ -734,15 +870,44 @@ static int parse_eu(VALUE str, VALUE hash) { static const char pat_source[] = - "'?(\\d+)[^-\\d\\s]*" +#ifdef TIGHT_PARSER + BOS + FPW_COM FPT_COM +#endif +#ifndef TIGHT_PARSER + "('?" NUMBER "+)[^-\\d\\s]*" +#else + "(\\d+)(?:(?:st|nd|rd|th)\\b)?" +#endif "\\s*" +#ifndef TIGHT_PARSER "(" ABBR_MONTHS ")[^-\\d\\s']*" +#else + "(" VALID_MONTHS ")" +#endif "(?:" "\\s*" - "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?" +#ifndef TIGHT_PARSER + "(?:" + BEGIN_ERA + "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))" + END_ERA + ")?" "\\s*" "('?-?\\d+(?:(?:st|nd|rd|th)\\b)?)" - ")?"; +#else + "(?:" FPA ")?" + "\\s*" + "([-']?\\d+)" + "\\s*" + "(?:" FPA "|" FPB ")?" +#endif + ")?" +#ifdef TIGHT_PARSER + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -752,10 +917,12 @@ parse_eu(VALUE str, VALUE hash) static int parse_us_cb(VALUE m, VALUE hash) { +#ifndef TIGHT_PARSER VALUE y, mon, d, b; 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); @@ -764,6 +931,20 @@ parse_us_cb(VALUE m, VALUE hash) s3e(hash, y, mon, d, !NIL_P(b) && (*RSTRING_PTR(b) == 'B' || *RSTRING_PTR(b) == 'b')); +#else + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); +#endif return 1; } @@ -771,15 +952,42 @@ static int parse_us(VALUE str, VALUE hash) { static const char pat_source[] = +#ifdef TIGHT_PARSER + BOS + FPW_COM FPT_COM +#endif +#ifndef TIGHT_PARSER "\\b(" ABBR_MONTHS ")[^-\\d\\s']*" +#else + "\\b(" VALID_MONTHS ")" +#endif "\\s*" +#ifndef TIGHT_PARSER "('?\\d+)[^-\\d\\s']*" +#else + "('?\\d+)(?:(?:st|nd|rd|th)\\b)?" + COM_FPT +#endif "(?:" - "\\s*" + "\\s*+,?" + "\\s*+" +#ifndef TIGHT_PARSER "(c(?:e|\\.e\\.)|b(?:ce|\\.c\\.e\\.)|a(?:d|\\.d\\.)|b(?:c|\\.c\\.))?" "\\s*" "('?-?\\d+)" - ")?"; +#else + "(?:" FPA ")?" + "\\s*" + "([-']?\\d+)" + "\\s*" + "(?:" FPA "|" FPB ")?" +#endif + ")?" +#ifdef TIGHT_PARSER + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -795,6 +1003,11 @@ parse_iso_cb(VALUE m, VALUE hash) mon = rb_reg_nth_match(2, m); d = rb_reg_nth_match(3, m); +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + s3e(hash, y, mon, d, 0); return 1; } @@ -802,7 +1015,17 @@ parse_iso_cb(VALUE m, VALUE hash) static int parse_iso(VALUE str, VALUE hash) { - static const char pat_source[] = "('?[-+]?\\d+)-(\\d+)-('?-?\\d+)"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "('?[-+]?" NUMBER "+)-(\\d+)-('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-+']?\\d+)-(\\d+)-([-']?\\d+)" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat); @@ -831,7 +1054,16 @@ static int parse_iso21(VALUE str, VALUE hash) { static const char pat_source[] = - "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b"; +#ifndef TIGHT_PARSER + "\\b(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d{2}|\\d{4})?-?w(\\d{2})(?:-?(\\d))?" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -851,7 +1083,17 @@ parse_iso22_cb(VALUE m, VALUE hash) static int parse_iso22(VALUE str, VALUE hash) { - static const char pat_source[] = "-w-(\\d)\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "-w-(\\d)\\b" +#else + BOS + FPW_COM FPT_COM + "-w-(\\d)" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -876,7 +1118,17 @@ parse_iso23_cb(VALUE m, VALUE hash) static int parse_iso23(VALUE str, VALUE hash) { - static const char pat_source[] = "--(\\d{2})?-(\\d{2})\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "--(\\d{2})?-(\\d{2})\\b" +#else + BOS + FPW_COM FPT_COM + "--(\\d{2})?-(\\d{2})" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat); @@ -901,7 +1153,17 @@ parse_iso24_cb(VALUE m, VALUE hash) static int parse_iso24(VALUE str, VALUE hash) { - static const char pat_source[] = "--(\\d{2})(\\d{2})?\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "--(\\d{2})(\\d{2})?\\b" +#else + BOS + FPW_COM FPT_COM + "--(\\d{2})(\\d{2})?" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat); @@ -925,9 +1187,29 @@ parse_iso25_cb(VALUE m, VALUE hash) static int parse_iso25(VALUE str, VALUE hash) { - static const char pat0_source[] = "[,.](\\d{2}|\\d{4})-\\d{3}\\b"; + static const char pat0_source[] = +#ifndef TIGHT_PARSER + "[,.](\\d{2}|\\d{4})-\\d{3}\\b" +#else + BOS + FPW_COM FPT_COM + "[,.](\\d{2}|\\d{4})-\\d{3}" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat0 = Qnil; - static const char pat_source[] = "\\b(\\d{2}|\\d{4})-(\\d{3})\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(\\d{2}|\\d{4})-(\\d{3})\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d{2}|\\d{4})-(\\d{3})" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat0); @@ -951,9 +1233,29 @@ parse_iso26_cb(VALUE m, VALUE hash) static int parse_iso26(VALUE str, VALUE hash) { - static const char pat0_source[] = "\\d-\\d{3}\\b"; + static const char pat0_source[] = +#ifndef TIGHT_PARSER + "\\d-\\d{3}\\b" +#else + BOS + FPW_COM FPT_COM + "\\d-\\d{3}" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat0 = Qnil; - static const char pat_source[] = "\\b-(\\d{3})\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b-(\\d{3})\\b" +#else + BOS + FPW_COM FPT_COM + "-(\\d{3})" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat0); @@ -985,6 +1287,9 @@ parse_iso2(VALUE str, VALUE hash) return 1; } +#define JISX0301_ERA_INITIALS "mtshr" +#define JISX0301_DEFAULT_ERA 'H' /* obsolete */ + static int gengo(int c) { @@ -995,6 +1300,7 @@ gengo(int c) case 'T': case 't': e = 1911; break; case 'S': case 's': e = 1925; break; case 'H': case 'h': e = 1988; break; + case 'R': case 'r': e = 2018; break; default: e = 0; break; } return e; @@ -1023,7 +1329,17 @@ parse_jis_cb(VALUE m, VALUE hash) static int parse_jis(VALUE str, VALUE hash) { - static const char pat_source[] = "\\b([mtsh])(\\d+)\\.(\\d+)\\.(\\d+)"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)" +#else + BOS + FPW_COM FPT_COM + "([" JISX0301_ERA_INITIALS "])(\\d+)\\.(\\d+)\\.(\\d+)" + TEE_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -1039,6 +1355,11 @@ parse_vms11_cb(VALUE m, VALUE hash) mon = rb_reg_nth_match(2, m); y = rb_reg_nth_match(3, m); +#ifdef TIGHT_PARSER + if (!check_apost(d, mon, y)) + return 0; +#endif + mon = INT2FIX(mon_num(mon)); s3e(hash, y, mon, d, 0); @@ -1049,8 +1370,18 @@ static int parse_vms11(VALUE str, VALUE hash) { static const char pat_source[] = - "('?-?\\d+)-(" ABBR_MONTHS ")[^-]*" - "-('?-?\\d+)"; +#ifndef TIGHT_PARSER + "('?-?" NUMBER "+)-(" ABBR_MONTHS ")[^-/.]*" + "-('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)-(" DOTLESS_VALID_MONTHS ")" + "-([-']?\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -1066,6 +1397,11 @@ parse_vms12_cb(VALUE m, VALUE hash) d = rb_reg_nth_match(2, m); y = rb_reg_nth_match(3, m); +#ifdef TIGHT_PARSER + if (!check_apost(mon, d, y)) + return 0; +#endif + mon = INT2FIX(mon_num(mon)); s3e(hash, y, mon, d, 0); @@ -1076,8 +1412,18 @@ static int parse_vms12(VALUE str, VALUE hash) { static const char pat_source[] = - "\\b(" ABBR_MONTHS ")[^-]*" - "-('?-?\\d+)(?:-('?-?\\d+))?"; +#ifndef TIGHT_PARSER + "\\b(" ABBR_MONTHS ")[^-/.]*" + "-('?-?\\d+)(?:-('?-?\\d+))?" +#else + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")" + "-([-']?\\d+)(?:-([-']?\\d+))?" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -1106,6 +1452,11 @@ parse_sla_cb(VALUE m, VALUE hash) mon = rb_reg_nth_match(2, m); d = rb_reg_nth_match(3, m); +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + s3e(hash, y, mon, d, 0); return 1; } @@ -1114,13 +1465,92 @@ static int parse_sla(VALUE str, VALUE hash) { static const char pat_source[] = - "('?-?\\d+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?"; +#ifndef TIGHT_PARSER + "('?-?" NUMBER "+)/\\s*('?\\d+)(?:\\D\\s*('?-?\\d+))?" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)/\\s*('?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); SUBS(str, pat, parse_sla_cb); } +#ifdef TIGHT_PARSER +static int +parse_sla2_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_sla2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "([-']?\\d+)/\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_sla2_cb); +} + +static int +parse_sla3_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_sla3(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")/\\s*([-']?\\d+)(?:(?:[-/]|\\s+)\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_sla3_cb); +} +#endif + static int parse_dot_cb(VALUE m, VALUE hash) { @@ -1130,6 +1560,11 @@ parse_dot_cb(VALUE m, VALUE hash) mon = rb_reg_nth_match(2, m); d = rb_reg_nth_match(3, m); +#ifdef TIGHT_PARSER + if (!check_apost(y, mon, d)) + return 0; +#endif + s3e(hash, y, mon, d, 0); return 1; } @@ -1138,13 +1573,92 @@ static int parse_dot(VALUE str, VALUE hash) { static const char pat_source[] = - "('?-?\\d+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)"; +#ifndef TIGHT_PARSER + "('?-?" NUMBER "+)\\.\\s*('?\\d+)\\.\\s*('?-?\\d+)" +#else + BOS + FPW_COM FPT_COM + "([-']?\\d+)\\.\\s*(\\d+)\\.\\s*([-']?\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); SUBS(str, pat, parse_dot_cb); } +#ifdef TIGHT_PARSER +static int +parse_dot2_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + d = rb_reg_nth_match(1, m); + mon = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(d, mon, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_dot2(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "([-']?\\d+)\\.\\s*(" DOTLESS_VALID_MONTHS ")(?:(?:[./])\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_dot2_cb); +} + +static int +parse_dot3_cb(VALUE m, VALUE hash) +{ + VALUE y, mon, d; + + mon = rb_reg_nth_match(1, m); + d = rb_reg_nth_match(2, m); + y = rb_reg_nth_match(3, m); + + if (!check_apost(mon, d, y)) + return 0; + + mon = INT2FIX(mon_num(mon)); + + s3e(hash, y, mon, d, 0); + return 1; +} + +static int +parse_dot3(VALUE str, VALUE hash) +{ + static const char pat_source[] = + BOS + FPW_COM FPT_COM + "(" DOTLESS_VALID_MONTHS ")\\.\\s*([-']?\\d+)(?:(?:[./])\\s*([-']?\\d+))?" + COM_FPT COM_FPW + EOS + ; + static VALUE pat = Qnil; + + REGCOMP_I(pat); + SUBS(str, pat, parse_dot3_cb); +} +#endif + static int parse_year_cb(VALUE m, VALUE hash) { @@ -1158,7 +1672,17 @@ parse_year_cb(VALUE m, VALUE hash) static int parse_year(VALUE str, VALUE hash) { - static const char pat_source[] = "'(\\d+)\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "'(\\d+)\\b" +#else + BOS + FPW_COM FPT_COM + "'(\\d+)" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat); @@ -1178,7 +1702,17 @@ parse_mon_cb(VALUE m, VALUE hash) static int parse_mon(VALUE str, VALUE hash) { - static const char pat_source[] = "\\b(" ABBR_MONTHS ")\\S*"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "\\b(" ABBR_MONTHS ")\\S*" +#else + BOS + FPW_COM FPT_COM + "(" VALID_MONTHS ")" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -1198,7 +1732,17 @@ parse_mday_cb(VALUE m, VALUE hash) static int parse_mday(VALUE str, VALUE hash) { - static const char pat_source[] = "(\\d+)(st|nd|rd|th)\\b"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "(" NUMBER "+)(st|nd|rd|th)\\b" +#else + BOS + FPW_COM FPT_COM + "(\\d+)(st|nd|rd|th)" + COM_FPT COM_FPW + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); @@ -1394,28 +1938,26 @@ parse_ddd_cb(VALUE m, VALUE hash) set_hash("zone", s5); if (*cs5 == '[') { - char *buf = ALLOCA_N(char, l5 + 1); - char *s1, *s2, *s3; + const char *s1, *s2; VALUE zone; - memcpy(buf, cs5, l5); - buf[l5 - 1] = '\0'; - - s1 = buf + 1; - s2 = strchr(buf, ':'); + l5 -= 2; + s1 = cs5 + 1; + s2 = memchr(s1, ':', l5); if (s2) { - *s2 = '\0'; s2++; + zone = rb_str_subseq(s5, s2 - cs5, l5 - (s2 - s1)); + s5 = rb_str_subseq(s5, 1, s2 - s1); } - if (s2) - s3 = s2; - else - s3 = s1; - zone = rb_str_new2(s3); + else { + zone = rb_str_subseq(s5, 1, l5); + if (isdigit((unsigned char)*s1)) + s5 = rb_str_append(rb_str_new_cstr("+"), zone); + else + s5 = zone; + } set_hash("zone", zone); - if (isdigit(*s1)) - *--s1 = '+'; - set_hash("offset", date_zone_to_diff(rb_str_new2(s1))); + set_hash("offset", date_zone_to_diff(s5)); } RB_GC_GUARD(s5); } @@ -1427,7 +1969,10 @@ static int parse_ddd(VALUE str, VALUE hash) { static const char pat_source[] = - "([-+]?)(\\d{2,14})" +#ifdef TIGHT_PARSER + BOS +#endif + "([-+]?)(" NUMBER "{2,14})" "(?:" "\\s*" "t?" @@ -1443,22 +1988,22 @@ parse_ddd(VALUE str, VALUE hash) "|" "\\[[-+]?\\d[^\\]]*\\]" ")" - ")?"; + ")?" +#ifdef TIGHT_PARSER + EOS +#endif + ; static VALUE pat = Qnil; REGCOMP_I(pat); SUBS(str, pat, parse_ddd_cb); } +#ifndef TIGHT_PARSER static int parse_bc_cb(VALUE m, VALUE hash) { - VALUE y; - - y = ref_hash("year"); - if (!NIL_P(y)) - set_hash("year", f_add(f_negate(y), INT2FIX(1))); - + set_hash("_bc", Qtrue); return 1; } @@ -1505,6 +2050,57 @@ parse_frag(VALUE str, VALUE hash) REGCOMP_I(pat); SUBS(str, pat, parse_frag_cb); } +#endif + +#ifdef TIGHT_PARSER +static int +parse_dummy_cb(VALUE m, VALUE hash) +{ + return 1; +} + +static int +parse_wday_only(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*" FPW "\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static int +parse_time_only(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*" FPT "\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static int +parse_wday_and_time(VALUE str, VALUE hash) +{ + static const char pat_source[] = "\\A\\s*(" FPW "\\s+" FPT "|" FPT "\\s+" FPW ")\\s*\\z"; + static VALUE pat = Qnil; + + REGCOMP_0(pat); + SUBS(str, pat, parse_dummy_cb); +} + +static unsigned +have_invalid_char_p(VALUE s) +{ + long i; + + for (i = 0; i < RSTRING_LEN(s); i++) + if (iscntrl((unsigned char)RSTRING_PTR(s)[i]) && + !isspace((unsigned char)RSTRING_PTR(s)[i])) + return 1; + return 0; +} +#endif #define HAVE_ALPHA (1<<0) #define HAVE_DIGIT (1<<1) @@ -1520,9 +2116,9 @@ check_class(VALUE s) flags = 0; for (i = 0; i < RSTRING_LEN(s); i++) { - if (isalpha(RSTRING_PTR(s)[i])) + if (isalpha((unsigned char)RSTRING_PTR(s)[i])) flags |= HAVE_ALPHA; - if (isdigit(RSTRING_PTR(s)[i])) + if (isdigit((unsigned char)RSTRING_PTR(s)[i])) flags |= HAVE_DIGIT; if (RSTRING_PTR(s)[i] == '-') flags |= HAVE_DASH; @@ -1536,16 +2132,31 @@ check_class(VALUE s) #define HAVE_ELEM_P(x) ((check_class(str) & (x)) == (x)) +#ifdef TIGHT_PARSER +#define PARSER_ERROR return rb_hash_new() +#endif + VALUE date__parse(VALUE str, VALUE comp) { VALUE backref, hash; +#ifdef TIGHT_PARSER + if (have_invalid_char_p(str)) + PARSER_ERROR; +#endif + backref = rb_backref_get(); rb_match_busy(backref); { - static const char pat_source[] = "[^-+',./:@[:alnum:]\\[\\]]+"; + static const char pat_source[] = +#ifndef TIGHT_PARSER + "[^-+',./:@[:alnum:]\\[\\]]+" +#else + "[^[:graph:]]+" +#endif + ; static VALUE pat = Qnil; REGCOMP_0(pat); @@ -1561,12 +2172,17 @@ date__parse(VALUE str, VALUE comp) if (HAVE_ELEM_P(HAVE_DIGIT)) parse_time(str, hash); - if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT)) +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA)) + parse_era(str, hash); +#endif + + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT)) { if (parse_eu(str, hash)) goto ok; - if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT)) if (parse_us(str, hash)) goto ok; + } if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DASH)) if (parse_iso(str, hash)) goto ok; @@ -1579,9 +2195,25 @@ date__parse(VALUE str, VALUE comp) if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_SLASH)) if (parse_sla(str, hash)) goto ok; +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_SLASH)) { + if (parse_sla2(str, hash)) + goto ok; + if (parse_sla3(str, hash)) + goto ok; + } +#endif if (HAVE_ELEM_P(HAVE_DIGIT|HAVE_DOT)) if (parse_dot(str, hash)) goto ok; +#ifdef TIGHT_PARSER + if (HAVE_ELEM_P(HAVE_ALPHA|HAVE_DIGIT|HAVE_DOT)) { + if (parse_dot2(str, hash)) + goto ok; + if (parse_dot3(str, hash)) + goto ok; + } +#endif if (HAVE_ELEM_P(HAVE_DIGIT)) if (parse_iso2(str, hash)) goto ok; @@ -1598,14 +2230,42 @@ date__parse(VALUE str, VALUE comp) if (parse_ddd(str, hash)) goto ok; +#ifdef TIGHT_PARSER + if (parse_wday_only(str, hash)) + goto ok; + if (parse_time_only(str, hash)) + goto ok; + if (parse_wday_and_time(str, hash)) + goto ok; + + PARSER_ERROR; /* not found */ +#endif + ok: +#ifndef TIGHT_PARSER if (HAVE_ELEM_P(HAVE_ALPHA)) parse_bc(str, hash); if (HAVE_ELEM_P(HAVE_DIGIT)) parse_frag(str, hash); +#endif { - if (RTEST(ref_hash("_comp"))) { + if (RTEST(del_hash("_bc"))) { + VALUE y; + + y = ref_hash("cwyear"); + if (!NIL_P(y)) { + y = f_add(f_negate(y), INT2FIX(1)); + set_hash("cwyear", y); + } + y = ref_hash("year"); + if (!NIL_P(y)) { + y = f_add(f_negate(y), INT2FIX(1)); + set_hash("year", y); + } + } + + if (RTEST(del_hash("_comp"))) { VALUE y; y = ref_hash("cwyear"); @@ -1625,9 +2285,8 @@ date__parse(VALUE str, VALUE comp) set_hash("year", f_add(y, INT2FIX(2000))); } } - } - del_hash("_comp"); + } { VALUE zone = ref_hash("zone"); @@ -1678,8 +2337,8 @@ iso8601_ext_datetime_cb(VALUE m, VALUE hash) s[i] = rb_reg_nth_match(i, m); } - if (!NIL_P(s[3])) { - set_hash("mday", str2num(s[3])); + if (!NIL_P(s[1])) { + 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) @@ -1736,7 +2395,7 @@ static int iso8601_ext_datetime(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?-(\\d{2})|" + "\\A\\s*(?:([-+]?\\d{2,}|-)-(\\d{2})?(?:-(\\d{2}))?|" "([-+]?\\d{2,})?-(\\d{3})|" "(\\d{4}|\\d{2})?-w(\\d{2})-(\\d)|" "-w-(\\d))" @@ -1875,7 +2534,7 @@ static int iso8601_ext_time(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?)?" + "\\A\\s*(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d+))?" "(z|[-+]\\d{2}(:?\\d{2})?)?)?\\s*\\z"; static VALUE pat = Qnil; @@ -1887,7 +2546,7 @@ static int iso8601_bas_time(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*(?:(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?)?" + "\\A\\s*(\\d{2})(\\d{2})(?:(\\d{2})(?:[,.](\\d+))?" "(z|[-+]\\d{2}(\\d{2})?)?)?\\s*\\z"; static VALUE pat = Qnil; @@ -2147,7 +2806,9 @@ rfc2822_cb(VALUE m, VALUE hash) s[i] = rb_reg_nth_match(i, m); } - set_hash("wday", INT2FIX(day_num(s[1]))); + if (!NIL_P(s[1])) { + 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]); @@ -2365,7 +3026,7 @@ jisx0301_cb(VALUE m, VALUE hash) s[i] = rb_reg_nth_match(i, m); } - ep = gengo(NIL_P(s[1]) ? 'h' : *RSTRING_PTR(s[1])); + ep = gengo(NIL_P(s[1]) ? JISX0301_DEFAULT_ERA : *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])); @@ -2390,7 +3051,7 @@ static int jisx0301(VALUE str, VALUE hash) { static const char pat_source[] = - "\\A\\s*([mtsh])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" + "\\A\\s*([" JISX0301_ERA_INITIALS "])?(\\d{2})\\.(\\d{2})\\.(\\d{2})" "(?:t" "(?:(\\d{2}):(\\d{2})(?::(\\d{2})(?:[,.](\\d*))?)?" "(z|[-+]\\d{2}(?::?\\d{2})?)?)?)?\\s*\\z"; diff --git a/ext/date/date_strftime.c b/ext/date/date_strftime.c index 71e1bd7f00..d7f28989d6 100644 --- a/ext/date/date_strftime.c +++ b/ext/date/date_strftime.c @@ -1,164 +1,24 @@ -/* -*- c-file-style: "linux" -*- */ - /* - * strftime.c - * - * Public-domain implementation of ANSI C library routine. - * - * It's written in old-style C for maximal portability. - * However, since I'm used to prototypes, I've included them too. - * - * If you want stuff in the System V ascftime routine, add the SYSV_EXT define. - * For extensions from SunOS, add SUNOS_EXT. - * For stuff needed to implement the P1003.2 date command, add POSIX2_DATE. - * For VMS dates, add VMS_EXT. - * For a an RFC822 time format, add MAILHEADER_EXT. - * For ISO week years, add ISO_DATE_EXT. - * For complete POSIX semantics, add POSIX_SEMANTICS. - * - * The code for %c, %x, and %X now follows the 1003.2 specification for - * the POSIX locale. - * This version ignores LOCALE information. - * It also doesn't worry about multi-byte characters. - * So there. - * - * This file is also shipped with GAWK (GNU Awk), gawk specific bits of - * code are included if GAWK is defined. - * - * Arnold Robbins - * January, February, March, 1991 - * Updated March, April 1992 - * Updated April, 1993 - * Updated February, 1994 - * Updated May, 1994 - * Updated January, 1995 - * Updated September, 1995 - * Updated January, 1996 - * - * Fixes from ado@elsie.nci.nih.gov - * February 1991, May 1992 - * Fixes from Tor Lillqvist tml@tik.vtt.fi - * May, 1993 - * Further fixes from ado@elsie.nci.nih.gov - * February 1994 - * %z code from chip@chinacat.unicom.com - * Applied September 1995 - * %V code fixed (again) and %G, %g added, - * January 1996 + date_strftime.c: based on a public-domain implementation of ANSI C + library routine strftime, which is originally written by Arnold + Robbins. */ #include "ruby/ruby.h" #include "date_tmx.h" -#ifndef GAWK -#include <stdio.h> -#include <ctype.h> +#include <stdlib.h> #include <string.h> -#include <time.h> -#include <sys/types.h> +#include <ctype.h> #include <errno.h> -#endif -#if defined(TM_IN_SYS_TIME) || !defined(GAWK) -#include <sys/types.h> -#if HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#endif -#include <math.h> - -/* defaults: season to taste */ -#define SYSV_EXT 1 /* stuff in System V ascftime routine */ -#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */ -#define POSIX2_DATE 1 /* stuff in Posix 1003.2 date command */ -#define VMS_EXT 1 /* include %v for VMS date format */ -#define MAILHEADER_EXT 1 /* add %z for HHMM format */ -#define ISO_DATE_EXT 1 /* %G and %g for year of ISO week */ - -#if defined(ISO_DATE_EXT) -#if ! defined(POSIX2_DATE) -#define POSIX2_DATE 1 -#endif -#endif -#if defined(POSIX2_DATE) -#if ! defined(SYSV_EXT) -#define SYSV_EXT 1 -#endif -#if ! defined(SUNOS_EXT) -#define SUNOS_EXT 1 -#endif -#endif - -#if defined(POSIX2_DATE) -#define adddecl(stuff) stuff -#else -#define adddecl(stuff) +#if defined(HAVE_SYS_TIME_H) +#include <sys/time.h> #endif #undef strchr /* avoid AIX weirdness */ -#if 0 -#if !defined __STDC__ && !defined _WIN32 -#define const /**/ -static int weeknumber(); -adddecl(static int iso8601wknum();) -static int weeknumber_v(); -adddecl(static int iso8601wknum_v();) -#else -static int weeknumber(const struct tm *timeptr, int firstweekday); -adddecl(static int iso8601wknum(const struct tm *timeptr);) -static int weeknumber_v(const struct tmx *tmx, int firstweekday); -adddecl(static int iso8601wknum_v(const struct tmx *tmx);) -#endif -#endif - -#ifdef STDC_HEADERS -#include <stdlib.h> -#include <string.h> -#else -extern void *malloc(); -extern void *realloc(); -extern char *getenv(); -extern char *strchr(); -#endif - -#define range(low, item, hi) max((low), min((item), (hi))) - -#undef min /* just in case */ - -/* min --- return minimum of two numbers */ - -#ifndef __STDC__ -static inline int -min(a, b) -int a, b; -#else -static inline int -min(int a, int b) -#endif -{ - return (a < b ? a : b); -} - -#undef max /* also, just in case */ - -/* max --- return maximum of two numbers */ - -#ifndef __STDC__ -static inline int -max(a, b) -int a, b; -#else -static inline int -max(int a, int b) -#endif -{ - return (a > b ? a : b); -} - -#ifdef NO_STRING_LITERAL_CONCATENATION -#error No string literal concatenation -#endif +#define range(low, item, hi) (item) #define add(x,y) (rb_funcall((x), '+', 1, (y))) #define sub(x,y) (rb_funcall((x), '-', 1, (y))) @@ -167,989 +27,612 @@ max(int a, int b) #define div(x,y) (rb_funcall((x), rb_intern("div"), 1, (y))) #define mod(x,y) (rb_funcall((x), '%', 1, (y))) +static void +upcase(char *s, size_t i) +{ + do { + if (ISLOWER(*s)) + *s = TOUPPER(*s); + } while (s++, --i); +} + +static void +downcase(char *s, size_t i) +{ + do { + if (ISUPPER(*s)) + *s = TOLOWER(*s); + } while (s++, --i); +} + /* strftime --- produce formatted time */ static size_t -date_strftime_with_tmx(char *s, size_t maxsize, const char *format, +date_strftime_with_tmx(char *s, const size_t maxsize, const char *format, const struct tmx *tmx) { - char *endp = s + maxsize; - char *start = s; - const char *sp, *tp; - auto char tbuf[100]; - long off; - ptrdiff_t i; - int w; - int precision, flags, colons; - char padding; - enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E}; + char *endp = s + maxsize; + char *start = s; + const char *sp, *tp; + auto char tbuf[100]; + ptrdiff_t i; + int v, w; + size_t colons; + int precision, flags; + char padding; + /* LOCALE_[OE] and COLONS are actually modifiers, not flags */ + enum {LEFT, CHCASE, LOWER, UPPER, LOCALE_O, LOCALE_E, COLONS}; #define BIT_OF(n) (1U<<(n)) - /* various tables, useful in North America */ - static const char days_l[][10] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday", - }; - static const char months_l[][10] = { - "January", "February", "March", "April", - "May", "June", "July", "August", "September", - "October", "November", "December", - }; - static const char ampm[][3] = { "AM", "PM", }; - - if (s == NULL || format == NULL || tmx == NULL || maxsize == 0) - return 0; - - /* quick check if we even need to bother */ - if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) { - err: - errno = ERANGE; - return 0; - } - - for (; *format && s < endp - 1; format++) { -#define FLAG_FOUND() do { \ - if (precision > 0 || flags & (BIT_OF(LOCALE_E)|BIT_OF(LOCALE_O))) \ - goto unknown; \ - } while (0) + /* various tables for locale C */ + static const char days_l[][10] = { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", + }; + static const char months_l[][10] = { + "January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December", + }; + static const char ampm[][3] = { "AM", "PM", }; + + if (s == NULL || format == NULL || tmx == NULL || maxsize == 0) + return 0; + + /* quick check if we even need to bother */ + if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize) { + err: + errno = ERANGE; + return 0; + } + + for (; *format && s < endp - 1; format++) { +#define FLAG_FOUND() do { \ + if (precision > 0 || flags & (BIT_OF(LOCALE_E) | BIT_OF(LOCALE_O) | BIT_OF(COLONS))) \ + goto unknown; \ + } while (0) #define NEEDS(n) do if (s >= endp || (n) >= endp - s - 1) goto err; while (0) -#define FILL_PADDING(i) do { \ - if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \ - NEEDS(precision); \ - memset(s, padding ? padding : ' ', precision - (i)); \ - s += precision - (i); \ - } \ - else { \ - NEEDS(i); \ - } \ -} while (0); -#define FMT(def_pad, def_prec, fmt, val) \ - do { \ - int l; \ - if (precision <= 0) precision = (def_prec); \ - if (flags & BIT_OF(LEFT)) precision = 1; \ - l = snprintf(s, endp - s, \ - ((padding == '0' || (!padding && (def_pad) == '0')) ? "%0*"fmt : "%*"fmt), \ - precision, (val)); \ - if (l < 0) goto err; \ - s += l; \ - } while (0) -#define STRFTIME(fmt) \ - do { \ - i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \ - if (!i) return 0; \ - if (precision > i) {\ - if (start + maxsize < s + precision) { \ - errno = ERANGE; \ - return 0; \ - } \ - memmove(s + precision - i, s, i);\ - memset(s, padding ? padding : ' ', precision - i); \ - s += precision; \ - }\ - else s += i; \ - } while (0) -#define FMTV(def_pad, def_prec, fmt, val) \ - do { \ - VALUE tmp = (val); \ - if (FIXNUM_P(tmp)) { \ - FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \ - } \ - else { \ - VALUE args[2], result; \ - size_t l; \ - if (precision <= 0) precision = (def_prec); \ - if (flags & BIT_OF(LEFT)) precision = 1; \ - args[0] = INT2FIX(precision); \ - args[1] = (val); \ - if (padding == '0' || (!padding && (def_pad) == '0')) \ - result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \ - else \ - result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \ - l = strlcpy(s, StringValueCStr(result), endp-s); \ - if ((size_t)(endp-s) <= l) \ - goto err; \ - s += l; \ - } \ - } while (0) - - if (*format != '%') { - *s++ = *format; - continue; +#define FILL_PADDING(i) do { \ + if (!(flags & BIT_OF(LEFT)) && precision > (i)) { \ + NEEDS(precision); \ + memset(s, padding ? padding : ' ', precision - (i)); \ + s += precision - (i); \ + } \ + else { \ + NEEDS(i); \ + } \ + } while (0); +#define FMT(def_pad, def_prec, fmt, val) \ + do { \ + int l; \ + if (precision <= 0) precision = (def_prec); \ + if (flags & BIT_OF(LEFT)) precision = 1; \ + l = snprintf(s, endp - s, \ + ((padding == '0' || (!padding && (def_pad) == '0')) ? \ + "%0*"fmt : "%*"fmt), \ + precision, (val)); \ + if (l < 0) goto err; \ + s += l; \ + } while (0) +#define STRFTIME(fmt) \ + do { \ + i = date_strftime_with_tmx(s, endp - s, (fmt), tmx); \ + if (!i) return 0; \ + if (flags & BIT_OF(UPPER)) \ + upcase(s, i); \ + if (!(flags & BIT_OF(LEFT)) && precision > i) { \ + if (start + maxsize < s + precision) { \ + errno = ERANGE; \ + return 0; \ + } \ + memmove(s + precision - i, s, i); \ + memset(s, padding ? padding : ' ', precision - i); \ + s += precision; \ + } \ + else s += i; \ + } while (0) +#define FMTV(def_pad, def_prec, fmt, val) \ + do { \ + VALUE tmp = (val); \ + if (FIXNUM_P(tmp)) { \ + FMT((def_pad), (def_prec), "l"fmt, FIX2LONG(tmp)); \ + } \ + else { \ + VALUE args[2], result; \ + size_t l; \ + if (precision <= 0) precision = (def_prec); \ + if (flags & BIT_OF(LEFT)) precision = 1; \ + args[0] = INT2FIX(precision); \ + args[1] = (val); \ + if (padding == '0' || (!padding && (def_pad) == '0')) \ + result = rb_str_format(2, args, rb_str_new2("%0*"fmt)); \ + else \ + result = rb_str_format(2, args, rb_str_new2("%*"fmt)); \ + l = strlcpy(s, StringValueCStr(result), endp - s); \ + if ((size_t)(endp - s) <= l) \ + goto err; \ + s += l; \ + } \ + } while (0) + + if (*format != '%') { + *s++ = *format; + continue; + } + tp = tbuf; + sp = format; + precision = -1; + flags = 0; + padding = 0; + colons = 0; + again: + switch (*++format) { + case '\0': + format--; + goto unknown; + + case 'A': /* full weekday name */ + case 'a': /* abbreviated weekday name */ + if (flags & BIT_OF(CHCASE)) { + flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE)); + flags |= BIT_OF(UPPER); + } + { + int wday = tmx_wday; + if (wday < 0 || wday > 6) + i = 1, tp = "?"; + else { + if (*format == 'A') + i = strlen(tp = days_l[wday]); + else + i = 3, tp = days_l[wday]; } - tp = tbuf; - sp = format; - precision = -1; - flags = 0; - padding = 0; - colons = 0; - again: - switch (*++format) { - case '\0': - format--; - goto unknown; - - case '%': - FILL_PADDING(1); - *s++ = '%'; - continue; - - case 'a': /* abbreviated weekday name */ - if (flags & BIT_OF(CHCASE)) { - flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE)); - flags |= BIT_OF(UPPER); - } - { - int wday = tmx_wday; - if (wday < 0 || wday > 6) - i = 1, tp = "?"; - else - i = 3, tp = days_l[wday]; - } - break; - - case 'A': /* full weekday name */ - if (flags & BIT_OF(CHCASE)) { - flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE)); - flags |= BIT_OF(UPPER); - } - { - int wday = tmx_wday; - if (wday < 0 || wday > 6) - i = 1, tp = "?"; - else - i = strlen(tp = days_l[wday]); - } - break; - -#ifdef SYSV_EXT - case 'h': /* abbreviated month name */ -#endif - case 'b': /* abbreviated month name */ - if (flags & BIT_OF(CHCASE)) { - flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE)); - flags |= BIT_OF(UPPER); - } - { - int mon = tmx_mon; - if (mon < 1 || mon > 12) - i = 1, tp = "?"; - else - i = 3, tp = months_l[mon-1]; - } - break; - - case 'B': /* full month name */ - if (flags & BIT_OF(CHCASE)) { - flags &= ~(BIT_OF(LOWER)|BIT_OF(CHCASE)); - flags |= BIT_OF(UPPER); - } - { - int mon = tmx_mon; - if (mon < 1 || mon > 12) - i = 1, tp = "?"; - else - i = strlen(tp = months_l[mon-1]); - } - break; - - case 'c': /* appropriate date and time representation */ - STRFTIME("%a %b %e %H:%M:%S %Y"); - continue; - - case 'd': /* day of the month, 01 - 31 */ - i = range(1, tmx_mday, 31); - FMT('0', 2, "d", (int)i); - continue; - - case 'H': /* hour, 24-hour clock, 00 - 23 */ - i = range(0, tmx_hour, 23); - FMT('0', 2, "d", (int)i); - continue; - - case 'I': /* hour, 12-hour clock, 01 - 12 */ - i = range(0, tmx_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - FMT('0', 2, "d", (int)i); - continue; - - case 'j': /* day of the year, 001 - 366 */ - FMT('0', 3, "d", tmx_yday); - continue; - - case 'm': /* month, 01 - 12 */ - i = range(1, tmx_mon, 12); - FMT('0', 2, "d", (int)i); - continue; - - case 'M': /* minute, 00 - 59 */ - i = range(0, tmx_min, 59); - FMT('0', 2, "d", (int)i); - continue; - - case 'p': /* AM or PM based on 12-hour clock */ - case 'P': /* am or pm based on 12-hour clock */ - if ((*format == 'p' && (flags & BIT_OF(CHCASE))) || - (*format == 'P' && !(flags & (BIT_OF(CHCASE)|BIT_OF(UPPER))))) { - flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE)); - flags |= BIT_OF(LOWER); - } - i = range(0, tmx_hour, 23); - if (i < 12) - tp = ampm[0]; - else - tp = ampm[1]; - i = 2; - break; - - case 's': - FMTV('0', 1, "d", tmx_secs); - continue; - - case 'Q': - FMTV('0', 1, "d", tmx_msecs); - continue; - - case 'S': /* second, 00 - 59 */ - i = range(0, tmx_sec, 59); - FMT('0', 2, "d", (int)i); - continue; - - case 'U': /* week of year, Sunday is first day of week */ - FMT('0', 2, "d", tmx_wnum0); - continue; - - case 'w': /* weekday, Sunday == 0, 0 - 6 */ - i = range(0, tmx_wday, 6); - FMT('0', 1, "d", (int)i); - continue; - - case 'W': /* week of year, Monday is first day of week */ - FMT('0', 2, "d", tmx_wnum1); - continue; - - case 'x': /* appropriate date representation */ - STRFTIME("%m/%d/%y"); - continue; - - case 'X': /* appropriate time representation */ - STRFTIME("%H:%M:%S"); - continue; - - case 'y': /* year without a century, 00 - 99 */ - i = NUM2INT(mod(tmx_year, INT2FIX(100))); - FMT('0', 2, "d", (int)i); - continue; - - case 'Y': /* year with century */ - { - VALUE year = tmx_year; - if (FIXNUM_P(year)) { - long y = FIX2LONG(year); - FMT('0', 0 <= y ? 4 : 5, "ld", y); - } - else { - FMTV('0', 4, "d", year); - } - } - continue; - -#ifdef MAILHEADER_EXT - case 'z': /* time zone offset east of GMT e.g. -0600 */ - { - long aoff; - int hl, hw; - - off = NUM2LONG(rb_funcall(tmx_offset, rb_intern("round"), 0)); - - aoff = off; - if (aoff < 0) - aoff = -off; - - if ((aoff / 3600) < 10) - hl = 1; - else - hl = 2; - hw = 2; - if (flags & BIT_OF(LEFT) && hl == 1) - hw = 1; - - switch (colons) { - case 0: /* %z -> +hhmm */ - precision = precision <= (3 + hw) ? hw : precision-3; - NEEDS(precision + 3); - break; - - case 1: /* %:z -> +hh:mm */ - precision = precision <= (4 + hw) ? hw : precision-4; - NEEDS(precision + 4); - break; - - case 2: /* %::z -> +hh:mm:ss */ - precision = precision <= (7 + hw) ? hw : precision-7; - NEEDS(precision + 7); - break; - - case 3: /* %:::z -> +hh[:mm[:ss]] */ - { - if (aoff % 3600 == 0) { - precision = precision <= (1 + hw) ? hw : precision-1; - NEEDS(precision + 3); - } - else if (aoff % 60 == 0) { - precision = precision <= (4 + hw) ? hw : precision-4; - NEEDS(precision + 4); - } - else { - precision = precision <= (7 + hw) ? hw : precision-7; - NEEDS(precision + 7); - } - } - break; - - default: - format--; - goto unknown; - } - if (padding == ' ' && precision > hl) { - i = snprintf(s, endp - s, "%*s", precision - hl, ""); - precision = hl; - if (i < 0) goto err; - s += i; - } - if (off < 0) { - off = -off; - *s++ = '-'; - } else { - *s++ = '+'; - } - i = snprintf(s, endp - s, "%.*ld", precision, off / 3600); - if (i < 0) goto err; - s += i; - off = off % 3600; - if (colons == 3 && off == 0) - continue; - if (1 <= colons) - *s++ = ':'; - i = snprintf(s, endp - s, "%02d", (int)(off / 60)); - if (i < 0) goto err; - s += i; - off = off % 60; - if (colons == 3 && off == 0) - continue; - if (2 <= colons) { - *s++ = ':'; - i = snprintf(s, endp - s, "%02d", (int)off); - if (i < 0) goto err; - s += i; - } - } - continue; -#endif /* MAILHEADER_EXT */ - - case 'Z': /* time zone name or abbreviation */ - if (flags & BIT_OF(CHCASE)) { - flags &= ~(BIT_OF(UPPER)|BIT_OF(CHCASE)); - flags |= BIT_OF(LOWER); - } - { - char *zone = tmx_zone; - if (zone == NULL) - tp = ""; - else - tp = zone; - i = strlen(tp); - } - break; - -#ifdef SYSV_EXT - case 'n': /* same as \n */ - FILL_PADDING(1); - *s++ = '\n'; - continue; - - case 't': /* same as \t */ - FILL_PADDING(1); - *s++ = '\t'; - continue; - - case 'D': /* date as %m/%d/%y */ - STRFTIME("%m/%d/%y"); - continue; - - case 'e': /* day of month, blank padded */ - FMT(' ', 2, "d", range(1, tmx_mday, 31)); - continue; - - case 'r': /* time as %I:%M:%S %p */ - STRFTIME("%I:%M:%S %p"); - continue; - - case 'R': /* time as %H:%M */ - STRFTIME("%H:%M"); - continue; - - case 'T': /* time as %H:%M:%S */ - STRFTIME("%H:%M:%S"); - continue; -#endif - -#ifdef SUNOS_EXT - case 'k': /* hour, 24-hour clock, blank pad */ - i = range(0, tmx_hour, 23); - FMT(' ', 2, "d", (int)i); - continue; - - case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ - i = range(0, tmx_hour, 23); - if (i == 0) - i = 12; - else if (i > 12) - i -= 12; - FMT(' ', 2, "d", (int)i); - continue; -#endif - -#ifdef VMS_EXT - case 'v': /* date as dd-bbb-YYYY */ - STRFTIME("%e-%b-%Y"); - continue; -#endif - -#ifdef POSIX2_DATE - case 'C': - FMTV('0', 2, "d", div(tmx_year, INT2FIX(100))); - continue; - - case 'E': - /* POSIX locale extensions, ignored for now */ - flags |= BIT_OF(LOCALE_E); - if (*(format + 1) && strchr("cCxXyY", *(format + 1))) - goto again; - goto unknown; - case 'O': - /* POSIX locale extensions, ignored for now */ - flags |= BIT_OF(LOCALE_O); - if (*(format + 1) && strchr("deHImMSuUVwWy", - *(format + 1))) - goto again; - goto unknown; - case 'V': /* week of year according ISO 8601 */ - FMT('0', 2, "d", tmx_cweek); - continue; - - case 'u': - /* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */ - FMT('0', 1, "d", tmx_cwday); - continue; -#endif /* POSIX2_DATE */ - -#ifdef ISO_DATE_EXT - case 'g': /* year of ISO week without a century */ - i = NUM2INT(mod(tmx_cwyear, INT2FIX(100))); - FMT('0', 2, "d", (int)i); - continue; - - case 'G': /* year of ISO week with century */ - { - VALUE year = tmx_cwyear; - if (FIXNUM_P(year)) { - long y = FIX2LONG(year); - FMT('0', 0 <= y ? 4 : 5, "ld", y); - } - else { - FMTV('0', 4, "d", year); - } - continue; + } + break; + + case 'B': /* full month name */ + case 'b': /* abbreviated month name */ + case 'h': /* same as %b */ + if (flags & BIT_OF(CHCASE)) { + flags &= ~(BIT_OF(LOWER) | BIT_OF(CHCASE)); + flags |= BIT_OF(UPPER); + } + { + int mon = tmx_mon; + if (mon < 1 || mon > 12) + i = 1, tp = "?"; + else { + if (*format == 'B') + i = strlen(tp = months_l[mon - 1]); + else + i = 3, tp = months_l[mon - 1]; + } + } + break; + + case 'C': /* century (year/100) */ + FMTV('0', 2, "d", div(tmx_year, INT2FIX(100))); + continue; + + case 'c': /* appropriate date and time representation */ + STRFTIME("%a %b %e %H:%M:%S %Y"); + continue; + + case 'D': + STRFTIME("%m/%d/%y"); + continue; + + case 'd': /* day of the month, 01 - 31 */ + case 'e': /* day of month, blank padded */ + v = range(1, tmx_mday, 31); + FMT((*format == 'd') ? '0' : ' ', 2, "d", v); + continue; + + case 'F': + STRFTIME("%Y-%m-%d"); + continue; + + case 'G': /* year of ISO week with century */ + case 'Y': /* year with century */ + { + VALUE year = (*format == 'G') ? tmx_cwyear : tmx_year; + if (FIXNUM_P(year)) { + long y = FIX2LONG(year); + FMT('0', 0 <= y ? 4 : 5, "ld", y); + } + else { + FMTV('0', 4, "d", year); + } + } + continue; + + case 'g': /* year of ISO week without a century */ + case 'y': /* year without a century */ + v = NUM2INT(mod((*format == 'g') ? tmx_cwyear : tmx_year, INT2FIX(100))); + FMT('0', 2, "d", v); + continue; + + case 'H': /* hour, 24-hour clock, 00 - 23 */ + case 'k': /* hour, 24-hour clock, blank pad */ + v = range(0, tmx_hour, 23); + FMT((*format == 'H') ? '0' : ' ', 2, "d", v); + continue; + + case 'I': /* hour, 12-hour clock, 01 - 12 */ + case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */ + v = range(0, tmx_hour, 23); + if (v == 0) + v = 12; + else if (v > 12) + v -= 12; + FMT((*format == 'I') ? '0' : ' ', 2, "d", v); + continue; + + case 'j': /* day of the year, 001 - 366 */ + v = range(1, tmx_yday, 366); + FMT('0', 3, "d", v); + continue; + + case 'L': /* millisecond */ + case 'N': /* nanosecond */ + if (*format == 'L') + w = 3; + else + w = 9; + if (precision <= 0) + precision = w; + NEEDS(precision); + + { + VALUE subsec = tmx_sec_fraction; + int ww; + long n; + + ww = precision; + while (9 <= ww) { + subsec = mul(subsec, INT2FIX(1000000000)); + ww -= 9; + } + n = 1; + for (; 0 < ww; ww--) + n *= 10; + if (n != 1) + subsec = mul(subsec, INT2FIX(n)); + subsec = div(subsec, INT2FIX(1)); + + if (FIXNUM_P(subsec)) { + (void)snprintf(s, endp - s, "%0*ld", + precision, FIX2LONG(subsec)); + s += precision; + } + else { + VALUE args[2], result; + args[0] = INT2FIX(precision); + args[1] = subsec; + result = rb_str_format(2, args, rb_str_new2("%0*d")); + (void)strlcpy(s, StringValueCStr(result), endp - s); + s += precision; + } + } + continue; + + case 'M': /* minute, 00 - 59 */ + v = range(0, tmx_min, 59); + FMT('0', 2, "d", v); + continue; + + case 'm': /* month, 01 - 12 */ + v = range(1, tmx_mon, 12); + FMT('0', 2, "d", v); + continue; + + case 'n': /* same as \n */ + FILL_PADDING(1); + *s++ = '\n'; + continue; + + case 't': /* same as \t */ + FILL_PADDING(1); + *s++ = '\t'; + continue; + + case 'P': /* am or pm based on 12-hour clock */ + case 'p': /* AM or PM based on 12-hour clock */ + if ((*format == 'p' && (flags & BIT_OF(CHCASE))) || + (*format == 'P' && !(flags & (BIT_OF(CHCASE) | BIT_OF(UPPER))))) { + flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE)); + flags |= BIT_OF(LOWER); + } + v = range(0, tmx_hour, 23); + if (v < 12) + tp = ampm[0]; + else + tp = ampm[1]; + i = 2; + break; + + case 'Q': /* milliseconds since Unix epoch */ + FMTV('0', 1, "d", tmx_msecs); + continue; + + case 'R': + STRFTIME("%H:%M"); + continue; + + case 'r': + STRFTIME("%I:%M:%S %p"); + continue; + + case 'S': /* second, 00 - 59 */ + v = range(0, tmx_sec, 59); + FMT('0', 2, "d", v); + continue; + + case 's': /* seconds since Unix epoch */ + FMTV('0', 1, "d", tmx_secs); + continue; + + case 'T': + STRFTIME("%H:%M:%S"); + continue; + + case 'U': /* week of year, Sunday is first day of week */ + case 'W': /* week of year, Monday is first day of week */ + v = range(0, (*format == 'U') ? tmx_wnum0 : tmx_wnum1, 53); + FMT('0', 2, "d", v); + continue; + + case 'u': /* weekday, Monday == 1, 1 - 7 */ + v = range(1, tmx_cwday, 7); + FMT('0', 1, "d", v); + continue; + + case 'V': /* week of year according ISO 8601 */ + v = range(1, tmx_cweek, 53); + FMT('0', 2, "d", v); + continue; + + case 'v': + STRFTIME("%e-%^b-%Y"); + continue; + + case 'w': /* weekday, Sunday == 0, 0 - 6 */ + v = range(0, tmx_wday, 6); + FMT('0', 1, "d", v); + continue; + + case 'X': /* appropriate time representation */ + STRFTIME("%H:%M:%S"); + continue; + + case 'x': /* appropriate date representation */ + STRFTIME("%m/%d/%y"); + continue; + + case 'Z': /* time zone name or abbreviation */ + if (flags & BIT_OF(CHCASE)) { + flags &= ~(BIT_OF(UPPER) | BIT_OF(CHCASE)); + flags |= BIT_OF(LOWER); + } + { + char *zone = tmx_zone; + if (zone == NULL) + tp = ""; + else + tp = zone; + i = strlen(tp); + } + break; + + case 'z': /* offset from UTC */ + { + long off, aoff; + int hl, hw; + + off = tmx_offset; + aoff = off; + if (aoff < 0) + aoff = -off; + + if ((aoff / 3600) < 10) + hl = 1; + else + hl = 2; + hw = 2; + if (flags & BIT_OF(LEFT) && hl == 1) + hw = 1; + + switch (colons) { + case 0: /* %z -> +hhmm */ + precision = precision <= (3 + hw) ? hw : precision - 3; + NEEDS(precision + 3); + break; + + case 1: /* %:z -> +hh:mm */ + precision = precision <= (4 + hw) ? hw : precision - 4; + NEEDS(precision + 4); + break; + + case 2: /* %::z -> +hh:mm:ss */ + precision = precision <= (7 + hw) ? hw : precision - 7; + NEEDS(precision + 7); + break; + + case 3: /* %:::z -> +hh[:mm[:ss]] */ + { + if (aoff % 3600 == 0) { + precision = precision <= (1 + hw) ? + hw : precision - 1; + NEEDS(precision + 3); } - -#endif /* ISO_DATE_EXT */ - - case 'L': - w = 3; - goto subsec; - - case 'N': - /* - * fractional second digits. default is 9 digits - * (nanosecond). - * - * %3N millisecond (3 digits) - * %6N microsecond (6 digits) - * %9N nanosecond (9 digits) - */ - w = 9; - subsec: - if (precision <= 0) { - precision = w; - } - NEEDS(precision); - - { - VALUE subsec = tmx_sec_fraction; - int ww; - long n; - - ww = precision; - while (9 <= ww) { - subsec = mul(subsec, INT2FIX(1000000000)); - ww -= 9; - } - n = 1; - for (; 0 < ww; ww--) - n *= 10; - if (n != 1) - subsec = mul(subsec, INT2FIX(n)); - subsec = div(subsec, INT2FIX(1)); - - if (FIXNUM_P(subsec)) { - (void)snprintf(s, endp - s, "%0*ld", precision, FIX2LONG(subsec)); - s += precision; - } - else { - VALUE args[2], result; - args[0] = INT2FIX(precision); - args[1] = subsec; - result = rb_str_format(2, args, rb_str_new2("%0*d")); - (void)strlcpy(s, StringValueCStr(result), endp-s); - s += precision; - } + else if (aoff % 60 == 0) { + precision = precision <= (4 + hw) ? + hw : precision - 4; + NEEDS(precision + 4); } - continue; - - case 'F': /* Equivalent to %Y-%m-%d */ - STRFTIME("%Y-%m-%d"); - continue; - case '+': - STRFTIME("%a %b %e %H:%M:%S %Z %Y"); - continue; - - case '-': - FLAG_FOUND(); - flags |= BIT_OF(LEFT); - padding = precision = 0; - goto again; - - case '^': - FLAG_FOUND(); - flags |= BIT_OF(UPPER); - goto again; - - case '#': - FLAG_FOUND(); - flags |= BIT_OF(CHCASE); - goto again; - - case '_': - FLAG_FOUND(); - padding = ' '; - goto again; - - case ':': - colons++; - goto again; - - case '0': - padding = '0'; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - { - char *e; - precision = (int)strtoul(format, &e, 10); - format = e - 1; - goto again; + else { + precision = precision <= (7 + hw) ? + hw : precision - 7; + NEEDS(precision + 7); } + } + break; - default: - unknown: - i = format - sp + 1; - tp = sp; - precision = -1; - flags = 0; - padding = 0; - colons = 0; - break; + default: + format--; + goto unknown; } - if (i) { - FILL_PADDING(i); - memcpy(s, tp, i); - switch (flags & (BIT_OF(UPPER)|BIT_OF(LOWER))) { - case BIT_OF(UPPER): - do { - if (ISLOWER(*s)) *s = TOUPPER(*s); - } while (s++, --i); - break; - case BIT_OF(LOWER): - do { - if (ISUPPER(*s)) *s = TOLOWER(*s); - } while (s++, --i); - break; - default: - s += i; - break; - } + if (padding == ' ' && precision > hl) { + i = snprintf(s, endp - s, "%*s", precision - hl, ""); + precision = hl; + if (i < 0) goto err; + s += i; + } + if (off < 0) { + off = -off; + *s++ = '-'; + } else { + *s++ = '+'; + } + i = snprintf(s, endp - s, "%.*ld", precision, off / 3600); + if (i < 0) goto err; + s += i; + off = off % 3600; + if (colons == 3 && off == 0) + continue; + if (1 <= colons) + *s++ = ':'; + i = snprintf(s, endp - s, "%02d", (int)(off / 60)); + if (i < 0) goto err; + s += i; + off = off % 60; + if (colons == 3 && off == 0) + continue; + if (2 <= colons) { + *s++ = ':'; + i = snprintf(s, endp - s, "%02d", (int)off); + if (i < 0) goto err; + s += i; + } + } + continue; + + case '+': + STRFTIME("%a %b %e %H:%M:%S %Z %Y"); + continue; + + case 'E': + /* POSIX locale extensions, ignored for now */ + flags |= BIT_OF(LOCALE_E); + if (*(format + 1) && strchr("cCxXyY", *(format + 1))) + goto again; + goto unknown; + case 'O': + /* POSIX locale extensions, ignored for now */ + flags |= BIT_OF(LOCALE_O); + if (*(format + 1) && strchr("deHkIlmMSuUVwWy", *(format + 1))) + goto again; + goto unknown; + + case ':': + flags |= BIT_OF(COLONS); + { + size_t l = strspn(format, ":"); + format += l; + if (*format == 'z') { + colons = l; + format--; + goto again; + } + format -= l; + } + goto unknown; + + case '_': + FLAG_FOUND(); + padding = ' '; + goto again; + + case '-': + FLAG_FOUND(); + flags |= BIT_OF(LEFT); + goto again; + + case '^': + FLAG_FOUND(); + flags |= BIT_OF(UPPER); + goto again; + + case '#': + FLAG_FOUND(); + flags |= BIT_OF(CHCASE); + goto again; + + case '0': + FLAG_FOUND(); + padding = '0'; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + char *e; + unsigned long prec = strtoul(format, &e, 10); + if (prec > INT_MAX || prec > maxsize) { + errno = ERANGE; + return 0; } + precision = (int)prec; + format = e - 1; + goto again; + } + + case '%': + FILL_PADDING(1); + *s++ = '%'; + continue; + + default: + unknown: + i = format - sp + 1; + tp = sp; + precision = -1; + flags = 0; + padding = 0; + colons = 0; + break; } - if (s >= endp) { - goto err; + if (i) { + FILL_PADDING(i); + memcpy(s, tp, i); + switch (flags & (BIT_OF(UPPER) | BIT_OF(LOWER))) { + case BIT_OF(UPPER): + upcase(s, i); + break; + case BIT_OF(LOWER): + downcase(s, i); + break; + } + s += i; } - if (*format == '\0') { - *s = '\0'; - return (s - start); - } else - return 0; + } + if (s >= endp) { + goto err; + } + if (*format == '\0') { + *s = '\0'; + return (s - start); + } + return 0; } size_t date_strftime(char *s, size_t maxsize, const char *format, const struct tmx *tmx) { - return date_strftime_with_tmx(s, maxsize, format, tmx); -} - -#if 0 -/* isleap --- is a year a leap year? */ - -#ifndef __STDC__ -static int -isleap(year) -long year; -#else -static int -isleap(long year) -#endif -{ - return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); -} - -static void -tmx2tm_noyear(const struct tmx *tmx, struct tm *result) -{ - struct tm tm; - - /* for isleap() in iso8601wknum. +100 is -1900 (mod 400). */ - tm.tm_year = FIX2INT(mod(tmx_year, INT2FIX(400))) + 100; - - tm.tm_mon = tmx_mon-1; - tm.tm_mday = tmx_mday; - tm.tm_hour = tmx_hour; - tm.tm_min = tmx_min; - tm.tm_sec = tmx_sec; - tm.tm_wday = tmx_wday; - tm.tm_yday = tmx_yday-1; - tm.tm_isdst = 0; -#if defined(HAVE_STRUCT_TM_TM_GMTOFF) - tm.tm_gmtoff = NUM2LONG(tmx_offset); -#endif -#if defined(HAVE_TM_ZONE) - tm.tm_zone = (char *)tmx_zone; -#endif - *result = tm; -} - -#ifdef POSIX2_DATE -/* iso8601wknum --- compute week number according to ISO 8601 */ - -#ifndef __STDC__ -static int -iso8601wknum(timeptr) -const struct tm *timeptr; -#else -static int -iso8601wknum(const struct tm *timeptr) -#endif -{ - /* - * From 1003.2: - * If the week (Monday to Sunday) containing January 1 - * has four or more days in the new year, then it is week 1; - * otherwise it is the highest numbered week of the previous - * year (52 or 53), and the next week is week 1. - * - * ADR: This means if Jan 1 was Monday through Thursday, - * it was week 1, otherwise week 52 or 53. - * - * XPG4 erroneously included POSIX.2 rationale text in the - * main body of the standard. Thus it requires week 53. - */ - - int weeknum, jan1day; - - /* get week number, Monday as first day of the week */ - weeknum = weeknumber(timeptr, 1); - - /* - * With thanks and tip of the hatlo to tml@tik.vtt.fi - * - * What day of the week does January 1 fall on? - * We know that - * (timeptr->tm_yday - jan1.tm_yday) MOD 7 == - * (timeptr->tm_wday - jan1.tm_wday) MOD 7 - * and that - * jan1.tm_yday == 0 - * and that - * timeptr->tm_wday MOD 7 == timeptr->tm_wday - * from which it follows that. . . - */ - jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7); - if (jan1day < 0) - jan1day += 7; - - /* - * If Jan 1 was a Monday through Thursday, it was in - * week 1. Otherwise it was last year's highest week, which is - * this year's week 0. - * - * What does that mean? - * If Jan 1 was Monday, the week number is exactly right, it can - * never be 0. - * If it was Tuesday through Thursday, the weeknumber is one - * less than it should be, so we add one. - * Otherwise, Friday, Saturday or Sunday, the week number is - * OK, but if it is 0, it needs to be 52 or 53. - */ - switch (jan1day) { - case 1: /* Monday */ - break; - case 2: /* Tuesday */ - case 3: /* Wednesday */ - case 4: /* Thursday */ - weeknum++; - break; - case 5: /* Friday */ - case 6: /* Saturday */ - case 0: /* Sunday */ - if (weeknum == 0) { -#ifdef USE_BROKEN_XPG4 - /* XPG4 (as of March 1994) says 53 unconditionally */ - weeknum = 53; -#else - /* get week number of last week of last year */ - struct tm dec31ly; /* 12/31 last year */ - dec31ly = *timeptr; - dec31ly.tm_year--; - dec31ly.tm_mon = 11; - dec31ly.tm_mday = 31; - dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1; - dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900L); - weeknum = iso8601wknum(& dec31ly); -#endif - } - break; - } - - if (timeptr->tm_mon == 11) { - /* - * The last week of the year - * can be in week 1 of next year. - * Sigh. - * - * This can only happen if - * M T W - * 29 30 31 - * 30 31 - * 31 - */ - int wday, mday; - - wday = timeptr->tm_wday; - mday = timeptr->tm_mday; - if ( (wday == 1 && (mday >= 29 && mday <= 31)) - || (wday == 2 && (mday == 30 || mday == 31)) - || (wday == 3 && mday == 31)) - weeknum = 1; - } - - return weeknum; -} - -static int -iso8601wknum_v(const struct tmx *tmx) -{ - struct tm tm; - tmx2tm_noyear(tmx, &tm); - return iso8601wknum(&tm); -} - -#endif - -/* weeknumber --- figure how many weeks into the year */ - -/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */ - -#ifndef __STDC__ -static int -weeknumber(timeptr, firstweekday) -const struct tm *timeptr; -int firstweekday; -#else -static int -weeknumber(const struct tm *timeptr, int firstweekday) -#endif -{ - int wday = timeptr->tm_wday; - int ret; - - if (firstweekday == 1) { - if (wday == 0) /* sunday */ - wday = 6; - else - wday--; - } - ret = ((timeptr->tm_yday + 7 - wday) / 7); - if (ret < 0) - ret = 0; - return ret; -} - -static int -weeknumber_v(const struct tmx *tmx, int firstweekday) -{ - struct tm tm; - tmx2tm_noyear(tmx, &tm); - return weeknumber(&tm, firstweekday); -} -#endif - -#if 0 -/* ADR --- I'm loathe to mess with ado's code ... */ - -Date: Wed, 24 Apr 91 20:54:08 MDT -From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK> -To: arnold@audiofax.com - -Hi Arnold, -in a process of fixing of strftime() in libraries on Atari ST I grabbed -some pieces of code from your own strftime. When doing that it came -to mind that your weeknumber() function compiles a little bit nicer -in the following form: -/* - * firstweekday is 0 if starting in Sunday, non-zero if in Monday - */ -{ - return (timeptr->tm_yday - timeptr->tm_wday + - (firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7; + return date_strftime_with_tmx(s, maxsize, format, tmx); } -How nicer it depends on a compiler, of course, but always a tiny bit. - - Cheers, - Michal - ntomczak@vm.ucs.ualberta.ca -#endif - -#ifdef TEST_STRFTIME /* - * NAME: - * tst - * - * SYNOPSIS: - * tst - * - * DESCRIPTION: - * "tst" is a test driver for the function "strftime". - * - * OPTIONS: - * None. - * - * AUTHOR: - * Karl Vogel - * Control Data Systems, Inc. - * vogelke@c-17igp.wpafb.af.mil - * - * BUGS: - * None noticed yet. - * - * COMPILE: - * cc -o tst -DTEST_STRFTIME strftime.c - */ - -/* ADR: I reformatted this to my liking, and deleted some unneeded code. */ - -#ifndef NULL -#include <stdio.h> -#endif -#include <time.h> -#include <sys/time.h> -#include <string.h> - -#define MAXTIME 132 - -/* - * Array of time formats. - */ - -static char *array[] = -{ - "(%%A) full weekday name, var length (Sunday..Saturday) %A", - "(%%B) full month name, var length (January..December) %B", - "(%%C) Century %C", - "(%%D) date (%%m/%%d/%%y) %D", - "(%%E) Locale extensions (ignored) %E", - "(%%H) hour (24-hour clock, 00..23) %H", - "(%%I) hour (12-hour clock, 01..12) %I", - "(%%M) minute (00..59) %M", - "(%%O) Locale extensions (ignored) %O", - "(%%R) time, 24-hour (%%H:%%M) %R", - "(%%S) second (00..60) %S", - "(%%T) time, 24-hour (%%H:%%M:%%S) %T", - "(%%U) week of year, Sunday as first day of week (00..53) %U", - "(%%V) week of year according to ISO 8601 %V", - "(%%W) week of year, Monday as first day of week (00..53) %W", - "(%%X) appropriate locale time representation (%H:%M:%S) %X", - "(%%Y) year with century (1970...) %Y", - "(%%Z) timezone (EDT), or blank if timezone not determinable %Z", - "(%%a) locale's abbreviated weekday name (Sun..Sat) %a", - "(%%b) locale's abbreviated month name (Jan..Dec) %b", - "(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c", - "(%%d) day of the month (01..31) %d", - "(%%e) day of the month, blank-padded ( 1..31) %e", - "(%%h) should be same as (%%b) %h", - "(%%j) day of the year (001..366) %j", - "(%%k) hour, 24-hour clock, blank pad ( 0..23) %k", - "(%%l) hour, 12-hour clock, blank pad ( 1..12) %l", - "(%%m) month (01..12) %m", - "(%%p) locale's AM or PM based on 12-hour clock %p", - "(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r", - "(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u", - "(%%v) VMS date (dd-bbb-YYYY) %v", - "(%%w) day of week (0..6, Sunday == 0) %w", - "(%%x) appropriate locale date representation %x", - "(%%y) last two digits of year (00..99) %y", - "(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z", - (char *) NULL -}; - -/* main routine. */ - -int -main(argc, argv) -int argc; -char **argv; -{ - char *next; - char string[MAXTIME]; - - int k; - int length; - - struct tm *tm; - - time_t clock; - - /* Call the function. */ - - clock = time(NULL); - tm = localtime(&clock); - - for (k = 0; next = array[k]; k++) { - length = strftime(string, MAXTIME, next, tm); - printf("%s\n", string); - } - - exit(0); -} -#endif /* TEST_STRFTIME */ +Local variables: +c-file-style: "ruby" +End: +*/ diff --git a/ext/date/date_strptime.c b/ext/date/date_strptime.c index eaec8e716b..1dde5fa3ec 100644 --- a/ext/date/date_strptime.c +++ b/ext/date/date_strptime.c @@ -7,31 +7,21 @@ #include "ruby/re.h" #include <ctype.h> +#undef strncasecmp +#define strncasecmp STRNCASECMP + static const char *day_names[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", - "Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat" }; +static const int ABBREVIATED_DAY_NAME_LENGTH = 3; static const char *month_names[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static const char *merid_names[] = { - "am", "pm", - "a.m.", "p.m." -}; - -static const char *extz_pats[] = { - ":z", - "::z", - ":::z" }; +static const int ABBREVIATED_MONTH_NAME_LENGTH = 3; #define sizeof_array(o) (sizeof o / sizeof o[0]) @@ -58,14 +48,15 @@ static const char *extz_pats[] = { static int num_pattern_p(const char *s) { - if (isdigit(*s)) + if (isdigit((unsigned char)*s)) return 1; if (*s == '%') { s++; if (*s == 'E' || *s == 'O') s++; if (*s && - (strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) || isdigit(*s))) + (strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) || + isdigit((unsigned char)*s))) return 1; } return 0; @@ -74,18 +65,21 @@ num_pattern_p(const char *s) #define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1]) static long -read_digits(const char *s, VALUE *n, size_t width) +read_digits(const char *s, size_t slen, VALUE *n, size_t width) { size_t l; - l = strspn(s, "0123456789"); + if (!width) + return 0; + + l = 0; + while (l < slen && ISDIGIT(s[l])) { + if (++l == width) break; + } if (l == 0) return 0; - if (width < l) - l = width; - if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) { const char *os = s; long v; @@ -102,34 +96,37 @@ read_digits(const char *s, VALUE *n, size_t width) return l; } else { - char *s2 = ALLOCA_N(char, l + 1); + VALUE vbuf = 0; + char *s2 = ALLOCV_N(char, vbuf, l + 1); memcpy(s2, s, l); s2[l] = '\0'; *n = rb_cstr_to_inum(s2, 10, 0); + ALLOCV_END(vbuf); return l; } } -#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))) +#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""))) #define fail() \ -{ \ +do { \ set_hash("_fail", Qtrue); \ return 0; \ -} +} while (0) #define fail_p() (!NIL_P(ref_hash("_fail"))) #define READ_DIGITS(n,w) \ -{ \ +do { \ size_t l; \ - l = read_digits(&str[si], &n, w); \ - if (l == 0) \ + l = read_digits(&str[si], slen - si, &n, w); \ + if (l == 0) { \ fail(); \ + } \ si += l; \ -} +} while (0) #define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX) @@ -144,17 +141,23 @@ valid_range_p(VALUE v, int a, int b) } #define recur(fmt) \ -{ \ +do { \ size_t l; \ l = date__strptime_internal(&str[si], slen - si, \ fmt, sizeof fmt - 1, hash); \ if (fail_p()) \ return 0; \ si += l; \ -} +} while (0) VALUE date_zone_to_diff(VALUE); +static inline int +head_match_p(size_t len, const char *name, const char *str, size_t slen, size_t si) +{ + return slen - si >= len && strncasecmp(name, &str[si], len) == 0; +} + static size_t date__strptime_internal(const char *str, size_t slen, const char *fmt, size_t flen, VALUE hash) @@ -162,9 +165,18 @@ date__strptime_internal(const char *str, size_t slen, size_t si, fi; int c; +#define HEAD_MATCH_P(len, name) head_match_p(len, name, str, slen, si) si = fi = 0; while (fi < flen) { + if (isspace((unsigned char)fmt[fi])) { + while (si < slen && isspace((unsigned char)str[si])) + si++; + while (++fi < flen && isspace((unsigned char)fmt[fi])); + continue; + } + + if (si >= slen) fail(); switch (fmt[fi]) { case '%': @@ -188,12 +200,11 @@ date__strptime_internal(const char *str, size_t slen, { int i; - for (i = 0; i < (int)sizeof_array(extz_pats); i++) - if (strncmp(extz_pats[i], &fmt[fi], - strlen(extz_pats[i])) == 0) { - fi += i; - goto again; - } + for (i = 1; i < 3 && fi + i < flen && fmt[fi+i] == ':'; ++i); + if (fmt[fi+i] == 'z') { + fi += i - 1; + goto again; + } fail(); } @@ -203,10 +214,12 @@ date__strptime_internal(const char *str, size_t slen, int i; for (i = 0; i < (int)sizeof_array(day_names); i++) { - size_t l = strlen(day_names[i]); - if (strncasecmp(day_names[i], &str[si], l) == 0) { + const char *day_name = day_names[i]; + size_t l = strlen(day_name); + if (HEAD_MATCH_P(l, day_name) || + HEAD_MATCH_P(l = ABBREVIATED_DAY_NAME_LENGTH, day_name)) { si += l; - set_hash("wday", INT2FIX(i % 7)); + set_hash("wday", INT2FIX(i)); goto matched; } } @@ -219,10 +232,12 @@ date__strptime_internal(const char *str, size_t slen, int i; for (i = 0; i < (int)sizeof_array(month_names); i++) { - size_t l = strlen(month_names[i]); - if (strncasecmp(month_names[i], &str[si], l) == 0) { + const char *month_name = month_names[i]; + size_t l = strlen(month_name); + if (HEAD_MATCH_P(l, month_name) || + HEAD_MATCH_P(l = ABBREVIATED_MONTH_NAME_LENGTH, month_name)) { si += l; - set_hash("mon", INT2FIX((i % 12) + 1)); + set_hash("mon", INT2FIX(i + 1)); goto matched; } } @@ -234,9 +249,9 @@ date__strptime_internal(const char *str, size_t slen, VALUE n; if (NUM_PATTERN_P()) - READ_DIGITS(n, 2) + READ_DIGITS(n, 2); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); set_hash("_cent", n); goto matched; } @@ -275,9 +290,9 @@ date__strptime_internal(const char *str, size_t slen, VALUE n; if (NUM_PATTERN_P()) - READ_DIGITS(n, 4) + READ_DIGITS(n, 4); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); set_hash("cwyear", n); goto matched; } @@ -290,8 +305,9 @@ date__strptime_internal(const char *str, size_t slen, if (!valid_range_p(n, 0, 99)) fail(); set_hash("cwyear",n); - set_hash("_cent", - INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); + if (NIL_P(ref_hash("_cent"))) + set_hash("_cent", + INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); goto matched; } @@ -354,9 +370,9 @@ date__strptime_internal(const char *str, size_t slen, } osi = si; if (NUM_PATTERN_P()) - READ_DIGITS(n, c == 'L' ? 3 : 9) + READ_DIGITS(n, c == 'L' ? 3 : 9); else - READ_DIGITS_MAX(n) + READ_DIGITS_MAX(n); if (sign == -1) n = f_negate(n); set_hash("sec_fraction", @@ -395,18 +411,19 @@ date__strptime_internal(const char *str, size_t slen, case 'P': case 'p': + if (slen - si < 2) fail(); { - int i; - - for (i = 0; i < 4; i++) { - size_t l = strlen(merid_names[i]); - if (strncasecmp(merid_names[i], &str[si], l) == 0) { - si += l; - set_hash("_merid", INT2FIX((i % 2) == 0 ? 0 : 12)); - goto matched; - } + char c = str[si]; + const int hour = (c == 'P' || c == 'p') ? 12 : 0; + if (!hour && !(c == 'A' || c == 'a')) fail(); + if ((c = str[si+1]) == '.') { + if (slen - si < 4 || str[si+3] != '.') fail(); + c = str[si += 2]; } - fail(); + if (!(c == 'M' || c == 'm')) fail(); + si += 2; + set_hash("_merid", INT2FIX(hour)); + goto matched; } case 'Q': @@ -422,9 +439,7 @@ date__strptime_internal(const char *str, size_t slen, if (sign == -1) n = f_negate(n); set_hash("seconds", - rb_rational_new2(n, - f_expt(INT2FIX(10), - INT2FIX(3)))); + rb_rational_new2(n, INT2FIX(1000))); goto matched; } @@ -525,24 +540,24 @@ date__strptime_internal(const char *str, size_t slen, goto matched; case 'Y': - { - VALUE n; - int sign = 1; - - if (issign(str[si])) { - if (str[si] == '-') - sign = -1; - si++; - } - if (NUM_PATTERN_P()) - READ_DIGITS(n, 4) - else - READ_DIGITS_MAX(n) + { + VALUE n; + int sign = 1; + + if (issign(str[si])) { + if (str[si] == '-') + sign = -1; + si++; + } + if (NUM_PATTERN_P()) + READ_DIGITS(n, 4); + else + READ_DIGITS_MAX(n); if (sign == -1) n = f_negate(n); - set_hash("year", n); - goto matched; - } + set_hash("year", n); + goto matched; + } case 'y': { @@ -555,8 +570,9 @@ date__strptime_internal(const char *str, size_t slen, if (sign == -1) n = f_negate(n); set_hash("year", n); - set_hash("_cent", - INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); + if (NIL_P(ref_hash("_cent"))) + set_hash("_cent", + INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20)); goto matched; } @@ -566,8 +582,8 @@ date__strptime_internal(const char *str, size_t slen, static const char pat_source[] = "\\A(" "(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?" - "|[[:alpha:].\\s]+(?:standard|daylight)\\s+time\\b" - "|[[:alpha:]]+(?:\\s+dst)?\\b" + "|(?-i:[[:alpha:].\\s]+)(?:standard|daylight)\\s+time\\b" + "|(?-i:[[:alpha:]]+)(?:\\s+dst)?\\b" ")"; static VALUE pat = Qnil; VALUE m, b; @@ -575,12 +591,13 @@ date__strptime_internal(const char *str, size_t slen, if (NIL_P(pat)) { pat = rb_reg_new(pat_source, sizeof pat_source - 1, ONIG_OPTION_IGNORECASE); + rb_obj_freeze(pat); rb_gc_register_mark_object(pat); } b = rb_backref_get(); rb_match_busy(b); - m = f_match(pat, rb_usascii_str_new2(&str[si])); + m = f_match(pat, rb_usascii_str_new(&str[si], slen - si)); if (!NIL_P(m)) { VALUE s, l, o; @@ -612,22 +629,13 @@ date__strptime_internal(const char *str, size_t slen, if (str[si] != '%') fail(); si++; - if (fi < flen) - if (str[si] != fmt[fi]) + if (fi < flen) { + if (si >= slen || str[si] != fmt[fi]) fail(); - si++; + si++; + } goto matched; } - case ' ': - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - while (isspace(str[si])) - si++; - fi++; - break; default: ordinal: if (str[si] != fmt[fi]) @@ -653,6 +661,9 @@ date__strptime(const char *str, size_t slen, si = date__strptime_internal(str, slen, fmt, flen, hash); + if (fail_p()) + return Qnil; + if (slen > si) { VALUE s; @@ -660,10 +671,7 @@ date__strptime(const char *str, size_t slen, set_hash("leftover", s); } - if (fail_p()) - return Qnil; - - cent = ref_hash("_cent"); + cent = del_hash("_cent"); if (!NIL_P(cent)) { VALUE year; @@ -673,10 +681,9 @@ date__strptime(const char *str, size_t slen, year = ref_hash("year"); if (!NIL_P(year)) set_hash("year", f_add(year, f_mul(cent, INT2FIX(100)))); - del_hash("_cent"); } - merid = ref_hash("_merid"); + merid = del_hash("_merid"); if (!NIL_P(merid)) { VALUE hour; @@ -685,7 +692,6 @@ date__strptime(const char *str, size_t slen, hour = f_mod(hour, INT2FIX(12)); set_hash("hour", f_add(hour, merid)); } - del_hash("_merid"); } return hash; diff --git a/ext/date/date_tmx.h b/ext/date/date_tmx.h index 0e56c9b4f0..993a15327d 100644 --- a/ext/date/date_tmx.h +++ b/ext/date/date_tmx.h @@ -18,12 +18,12 @@ struct tmx_funcs { VALUE (*sec_fraction)(void *dat); VALUE (*secs)(void *dat); VALUE (*msecs)(void *dat); - VALUE (*offset)(void *dat); + int (*offset)(void *dat); char *(*zone)(void *dat); }; struct tmx { void *dat; - struct tmx_funcs *funcs; + const struct tmx_funcs *funcs; }; #define tmx_attr(x) (tmx->funcs->x)(tmx->dat) diff --git a/ext/date/depend b/ext/date/depend index 7e5d62e79d..4fb78149a1 100644 --- a/ext/date/depend +++ b/ext/date/depend @@ -1,2 +1,692 @@ +# AUTOGENERATED DEPENDENCIES START +date_core.o: $(RUBY_EXTCONF_H) +date_core.o: $(arch_hdrdir)/ruby/config.h +date_core.o: $(hdrdir)/ruby.h +date_core.o: $(hdrdir)/ruby/assert.h +date_core.o: $(hdrdir)/ruby/backward.h +date_core.o: $(hdrdir)/ruby/backward/2/assume.h +date_core.o: $(hdrdir)/ruby/backward/2/attributes.h +date_core.o: $(hdrdir)/ruby/backward/2/bool.h +date_core.o: $(hdrdir)/ruby/backward/2/inttypes.h +date_core.o: $(hdrdir)/ruby/backward/2/limits.h +date_core.o: $(hdrdir)/ruby/backward/2/long_long.h +date_core.o: $(hdrdir)/ruby/backward/2/stdalign.h +date_core.o: $(hdrdir)/ruby/backward/2/stdarg.h +date_core.o: $(hdrdir)/ruby/defines.h +date_core.o: $(hdrdir)/ruby/encoding.h +date_core.o: $(hdrdir)/ruby/intern.h +date_core.o: $(hdrdir)/ruby/internal/abi.h +date_core.o: $(hdrdir)/ruby/internal/anyargs.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/char.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/double.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/int.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/long.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/short.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +date_core.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +date_core.o: $(hdrdir)/ruby/internal/assume.h +date_core.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +date_core.o: $(hdrdir)/ruby/internal/attr/artificial.h +date_core.o: $(hdrdir)/ruby/internal/attr/cold.h +date_core.o: $(hdrdir)/ruby/internal/attr/const.h +date_core.o: $(hdrdir)/ruby/internal/attr/constexpr.h +date_core.o: $(hdrdir)/ruby/internal/attr/deprecated.h +date_core.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +date_core.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +date_core.o: $(hdrdir)/ruby/internal/attr/error.h +date_core.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +date_core.o: $(hdrdir)/ruby/internal/attr/forceinline.h +date_core.o: $(hdrdir)/ruby/internal/attr/format.h +date_core.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +date_core.o: $(hdrdir)/ruby/internal/attr/noalias.h +date_core.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +date_core.o: $(hdrdir)/ruby/internal/attr/noexcept.h +date_core.o: $(hdrdir)/ruby/internal/attr/noinline.h +date_core.o: $(hdrdir)/ruby/internal/attr/nonnull.h +date_core.o: $(hdrdir)/ruby/internal/attr/noreturn.h +date_core.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +date_core.o: $(hdrdir)/ruby/internal/attr/pure.h +date_core.o: $(hdrdir)/ruby/internal/attr/restrict.h +date_core.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +date_core.o: $(hdrdir)/ruby/internal/attr/warning.h +date_core.o: $(hdrdir)/ruby/internal/attr/weakref.h +date_core.o: $(hdrdir)/ruby/internal/cast.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +date_core.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +date_core.o: $(hdrdir)/ruby/internal/compiler_since.h +date_core.o: $(hdrdir)/ruby/internal/config.h +date_core.o: $(hdrdir)/ruby/internal/constant_p.h +date_core.o: $(hdrdir)/ruby/internal/core.h +date_core.o: $(hdrdir)/ruby/internal/core/rarray.h +date_core.o: $(hdrdir)/ruby/internal/core/rbasic.h +date_core.o: $(hdrdir)/ruby/internal/core/rbignum.h +date_core.o: $(hdrdir)/ruby/internal/core/rclass.h +date_core.o: $(hdrdir)/ruby/internal/core/rdata.h +date_core.o: $(hdrdir)/ruby/internal/core/rfile.h +date_core.o: $(hdrdir)/ruby/internal/core/rhash.h +date_core.o: $(hdrdir)/ruby/internal/core/robject.h +date_core.o: $(hdrdir)/ruby/internal/core/rregexp.h +date_core.o: $(hdrdir)/ruby/internal/core/rstring.h +date_core.o: $(hdrdir)/ruby/internal/core/rstruct.h +date_core.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +date_core.o: $(hdrdir)/ruby/internal/ctype.h +date_core.o: $(hdrdir)/ruby/internal/dllexport.h +date_core.o: $(hdrdir)/ruby/internal/dosish.h +date_core.o: $(hdrdir)/ruby/internal/encoding/coderange.h +date_core.o: $(hdrdir)/ruby/internal/encoding/ctype.h +date_core.o: $(hdrdir)/ruby/internal/encoding/encoding.h +date_core.o: $(hdrdir)/ruby/internal/encoding/pathname.h +date_core.o: $(hdrdir)/ruby/internal/encoding/re.h +date_core.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +date_core.o: $(hdrdir)/ruby/internal/encoding/string.h +date_core.o: $(hdrdir)/ruby/internal/encoding/symbol.h +date_core.o: $(hdrdir)/ruby/internal/encoding/transcode.h +date_core.o: $(hdrdir)/ruby/internal/error.h +date_core.o: $(hdrdir)/ruby/internal/eval.h +date_core.o: $(hdrdir)/ruby/internal/event.h +date_core.o: $(hdrdir)/ruby/internal/fl_type.h +date_core.o: $(hdrdir)/ruby/internal/gc.h +date_core.o: $(hdrdir)/ruby/internal/glob.h +date_core.o: $(hdrdir)/ruby/internal/globals.h +date_core.o: $(hdrdir)/ruby/internal/has/attribute.h +date_core.o: $(hdrdir)/ruby/internal/has/builtin.h +date_core.o: $(hdrdir)/ruby/internal/has/c_attribute.h +date_core.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +date_core.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +date_core.o: $(hdrdir)/ruby/internal/has/extension.h +date_core.o: $(hdrdir)/ruby/internal/has/feature.h +date_core.o: $(hdrdir)/ruby/internal/has/warning.h +date_core.o: $(hdrdir)/ruby/internal/intern/array.h +date_core.o: $(hdrdir)/ruby/internal/intern/bignum.h +date_core.o: $(hdrdir)/ruby/internal/intern/class.h +date_core.o: $(hdrdir)/ruby/internal/intern/compar.h +date_core.o: $(hdrdir)/ruby/internal/intern/complex.h +date_core.o: $(hdrdir)/ruby/internal/intern/cont.h +date_core.o: $(hdrdir)/ruby/internal/intern/dir.h +date_core.o: $(hdrdir)/ruby/internal/intern/enum.h +date_core.o: $(hdrdir)/ruby/internal/intern/enumerator.h +date_core.o: $(hdrdir)/ruby/internal/intern/error.h +date_core.o: $(hdrdir)/ruby/internal/intern/eval.h +date_core.o: $(hdrdir)/ruby/internal/intern/file.h +date_core.o: $(hdrdir)/ruby/internal/intern/hash.h +date_core.o: $(hdrdir)/ruby/internal/intern/io.h +date_core.o: $(hdrdir)/ruby/internal/intern/load.h +date_core.o: $(hdrdir)/ruby/internal/intern/marshal.h +date_core.o: $(hdrdir)/ruby/internal/intern/numeric.h +date_core.o: $(hdrdir)/ruby/internal/intern/object.h +date_core.o: $(hdrdir)/ruby/internal/intern/parse.h +date_core.o: $(hdrdir)/ruby/internal/intern/proc.h +date_core.o: $(hdrdir)/ruby/internal/intern/process.h +date_core.o: $(hdrdir)/ruby/internal/intern/random.h +date_core.o: $(hdrdir)/ruby/internal/intern/range.h +date_core.o: $(hdrdir)/ruby/internal/intern/rational.h +date_core.o: $(hdrdir)/ruby/internal/intern/re.h +date_core.o: $(hdrdir)/ruby/internal/intern/ruby.h +date_core.o: $(hdrdir)/ruby/internal/intern/select.h +date_core.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +date_core.o: $(hdrdir)/ruby/internal/intern/set.h +date_core.o: $(hdrdir)/ruby/internal/intern/signal.h +date_core.o: $(hdrdir)/ruby/internal/intern/sprintf.h +date_core.o: $(hdrdir)/ruby/internal/intern/string.h +date_core.o: $(hdrdir)/ruby/internal/intern/struct.h +date_core.o: $(hdrdir)/ruby/internal/intern/thread.h +date_core.o: $(hdrdir)/ruby/internal/intern/time.h +date_core.o: $(hdrdir)/ruby/internal/intern/variable.h +date_core.o: $(hdrdir)/ruby/internal/intern/vm.h +date_core.o: $(hdrdir)/ruby/internal/interpreter.h +date_core.o: $(hdrdir)/ruby/internal/iterator.h +date_core.o: $(hdrdir)/ruby/internal/memory.h +date_core.o: $(hdrdir)/ruby/internal/method.h +date_core.o: $(hdrdir)/ruby/internal/module.h +date_core.o: $(hdrdir)/ruby/internal/newobj.h +date_core.o: $(hdrdir)/ruby/internal/scan_args.h +date_core.o: $(hdrdir)/ruby/internal/special_consts.h +date_core.o: $(hdrdir)/ruby/internal/static_assert.h +date_core.o: $(hdrdir)/ruby/internal/stdalign.h +date_core.o: $(hdrdir)/ruby/internal/stdbool.h +date_core.o: $(hdrdir)/ruby/internal/stdckdint.h +date_core.o: $(hdrdir)/ruby/internal/symbol.h +date_core.o: $(hdrdir)/ruby/internal/value.h +date_core.o: $(hdrdir)/ruby/internal/value_type.h +date_core.o: $(hdrdir)/ruby/internal/variable.h +date_core.o: $(hdrdir)/ruby/internal/warning_push.h +date_core.o: $(hdrdir)/ruby/internal/xmalloc.h +date_core.o: $(hdrdir)/ruby/missing.h +date_core.o: $(hdrdir)/ruby/onigmo.h +date_core.o: $(hdrdir)/ruby/oniguruma.h +date_core.o: $(hdrdir)/ruby/ruby.h +date_core.o: $(hdrdir)/ruby/st.h +date_core.o: $(hdrdir)/ruby/subst.h +date_core.o: $(hdrdir)/ruby/util.h +date_core.o: date_core.c date_core.o: date_tmx.h +date_parse.o: $(RUBY_EXTCONF_H) +date_parse.o: $(arch_hdrdir)/ruby/config.h +date_parse.o: $(hdrdir)/ruby.h +date_parse.o: $(hdrdir)/ruby/assert.h +date_parse.o: $(hdrdir)/ruby/backward.h +date_parse.o: $(hdrdir)/ruby/backward/2/assume.h +date_parse.o: $(hdrdir)/ruby/backward/2/attributes.h +date_parse.o: $(hdrdir)/ruby/backward/2/bool.h +date_parse.o: $(hdrdir)/ruby/backward/2/inttypes.h +date_parse.o: $(hdrdir)/ruby/backward/2/limits.h +date_parse.o: $(hdrdir)/ruby/backward/2/long_long.h +date_parse.o: $(hdrdir)/ruby/backward/2/stdalign.h +date_parse.o: $(hdrdir)/ruby/backward/2/stdarg.h +date_parse.o: $(hdrdir)/ruby/defines.h +date_parse.o: $(hdrdir)/ruby/encoding.h +date_parse.o: $(hdrdir)/ruby/intern.h +date_parse.o: $(hdrdir)/ruby/internal/abi.h +date_parse.o: $(hdrdir)/ruby/internal/anyargs.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/char.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/double.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/int.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/long.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/short.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +date_parse.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +date_parse.o: $(hdrdir)/ruby/internal/assume.h +date_parse.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +date_parse.o: $(hdrdir)/ruby/internal/attr/artificial.h +date_parse.o: $(hdrdir)/ruby/internal/attr/cold.h +date_parse.o: $(hdrdir)/ruby/internal/attr/const.h +date_parse.o: $(hdrdir)/ruby/internal/attr/constexpr.h +date_parse.o: $(hdrdir)/ruby/internal/attr/deprecated.h +date_parse.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +date_parse.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +date_parse.o: $(hdrdir)/ruby/internal/attr/error.h +date_parse.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +date_parse.o: $(hdrdir)/ruby/internal/attr/forceinline.h +date_parse.o: $(hdrdir)/ruby/internal/attr/format.h +date_parse.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +date_parse.o: $(hdrdir)/ruby/internal/attr/noalias.h +date_parse.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +date_parse.o: $(hdrdir)/ruby/internal/attr/noexcept.h +date_parse.o: $(hdrdir)/ruby/internal/attr/noinline.h +date_parse.o: $(hdrdir)/ruby/internal/attr/nonnull.h +date_parse.o: $(hdrdir)/ruby/internal/attr/noreturn.h +date_parse.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +date_parse.o: $(hdrdir)/ruby/internal/attr/pure.h +date_parse.o: $(hdrdir)/ruby/internal/attr/restrict.h +date_parse.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +date_parse.o: $(hdrdir)/ruby/internal/attr/warning.h +date_parse.o: $(hdrdir)/ruby/internal/attr/weakref.h +date_parse.o: $(hdrdir)/ruby/internal/cast.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +date_parse.o: $(hdrdir)/ruby/internal/compiler_since.h +date_parse.o: $(hdrdir)/ruby/internal/config.h +date_parse.o: $(hdrdir)/ruby/internal/constant_p.h +date_parse.o: $(hdrdir)/ruby/internal/core.h +date_parse.o: $(hdrdir)/ruby/internal/core/rarray.h +date_parse.o: $(hdrdir)/ruby/internal/core/rbasic.h +date_parse.o: $(hdrdir)/ruby/internal/core/rbignum.h +date_parse.o: $(hdrdir)/ruby/internal/core/rclass.h +date_parse.o: $(hdrdir)/ruby/internal/core/rdata.h +date_parse.o: $(hdrdir)/ruby/internal/core/rfile.h +date_parse.o: $(hdrdir)/ruby/internal/core/rhash.h +date_parse.o: $(hdrdir)/ruby/internal/core/rmatch.h +date_parse.o: $(hdrdir)/ruby/internal/core/robject.h +date_parse.o: $(hdrdir)/ruby/internal/core/rregexp.h +date_parse.o: $(hdrdir)/ruby/internal/core/rstring.h +date_parse.o: $(hdrdir)/ruby/internal/core/rstruct.h +date_parse.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +date_parse.o: $(hdrdir)/ruby/internal/ctype.h +date_parse.o: $(hdrdir)/ruby/internal/dllexport.h +date_parse.o: $(hdrdir)/ruby/internal/dosish.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/coderange.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/ctype.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/encoding.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/pathname.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/re.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/string.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/symbol.h +date_parse.o: $(hdrdir)/ruby/internal/encoding/transcode.h +date_parse.o: $(hdrdir)/ruby/internal/error.h +date_parse.o: $(hdrdir)/ruby/internal/eval.h +date_parse.o: $(hdrdir)/ruby/internal/event.h +date_parse.o: $(hdrdir)/ruby/internal/fl_type.h +date_parse.o: $(hdrdir)/ruby/internal/gc.h +date_parse.o: $(hdrdir)/ruby/internal/glob.h +date_parse.o: $(hdrdir)/ruby/internal/globals.h +date_parse.o: $(hdrdir)/ruby/internal/has/attribute.h +date_parse.o: $(hdrdir)/ruby/internal/has/builtin.h +date_parse.o: $(hdrdir)/ruby/internal/has/c_attribute.h +date_parse.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +date_parse.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +date_parse.o: $(hdrdir)/ruby/internal/has/extension.h +date_parse.o: $(hdrdir)/ruby/internal/has/feature.h +date_parse.o: $(hdrdir)/ruby/internal/has/warning.h +date_parse.o: $(hdrdir)/ruby/internal/intern/array.h +date_parse.o: $(hdrdir)/ruby/internal/intern/bignum.h +date_parse.o: $(hdrdir)/ruby/internal/intern/class.h +date_parse.o: $(hdrdir)/ruby/internal/intern/compar.h +date_parse.o: $(hdrdir)/ruby/internal/intern/complex.h +date_parse.o: $(hdrdir)/ruby/internal/intern/cont.h +date_parse.o: $(hdrdir)/ruby/internal/intern/dir.h +date_parse.o: $(hdrdir)/ruby/internal/intern/enum.h +date_parse.o: $(hdrdir)/ruby/internal/intern/enumerator.h +date_parse.o: $(hdrdir)/ruby/internal/intern/error.h +date_parse.o: $(hdrdir)/ruby/internal/intern/eval.h +date_parse.o: $(hdrdir)/ruby/internal/intern/file.h +date_parse.o: $(hdrdir)/ruby/internal/intern/hash.h +date_parse.o: $(hdrdir)/ruby/internal/intern/io.h +date_parse.o: $(hdrdir)/ruby/internal/intern/load.h +date_parse.o: $(hdrdir)/ruby/internal/intern/marshal.h +date_parse.o: $(hdrdir)/ruby/internal/intern/numeric.h +date_parse.o: $(hdrdir)/ruby/internal/intern/object.h +date_parse.o: $(hdrdir)/ruby/internal/intern/parse.h +date_parse.o: $(hdrdir)/ruby/internal/intern/proc.h +date_parse.o: $(hdrdir)/ruby/internal/intern/process.h +date_parse.o: $(hdrdir)/ruby/internal/intern/random.h +date_parse.o: $(hdrdir)/ruby/internal/intern/range.h +date_parse.o: $(hdrdir)/ruby/internal/intern/rational.h +date_parse.o: $(hdrdir)/ruby/internal/intern/re.h +date_parse.o: $(hdrdir)/ruby/internal/intern/ruby.h +date_parse.o: $(hdrdir)/ruby/internal/intern/select.h +date_parse.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +date_parse.o: $(hdrdir)/ruby/internal/intern/set.h +date_parse.o: $(hdrdir)/ruby/internal/intern/signal.h +date_parse.o: $(hdrdir)/ruby/internal/intern/sprintf.h +date_parse.o: $(hdrdir)/ruby/internal/intern/string.h +date_parse.o: $(hdrdir)/ruby/internal/intern/struct.h +date_parse.o: $(hdrdir)/ruby/internal/intern/thread.h +date_parse.o: $(hdrdir)/ruby/internal/intern/time.h +date_parse.o: $(hdrdir)/ruby/internal/intern/variable.h +date_parse.o: $(hdrdir)/ruby/internal/intern/vm.h +date_parse.o: $(hdrdir)/ruby/internal/interpreter.h +date_parse.o: $(hdrdir)/ruby/internal/iterator.h +date_parse.o: $(hdrdir)/ruby/internal/memory.h +date_parse.o: $(hdrdir)/ruby/internal/method.h +date_parse.o: $(hdrdir)/ruby/internal/module.h +date_parse.o: $(hdrdir)/ruby/internal/newobj.h +date_parse.o: $(hdrdir)/ruby/internal/scan_args.h +date_parse.o: $(hdrdir)/ruby/internal/special_consts.h +date_parse.o: $(hdrdir)/ruby/internal/static_assert.h +date_parse.o: $(hdrdir)/ruby/internal/stdalign.h +date_parse.o: $(hdrdir)/ruby/internal/stdbool.h +date_parse.o: $(hdrdir)/ruby/internal/stdckdint.h +date_parse.o: $(hdrdir)/ruby/internal/symbol.h +date_parse.o: $(hdrdir)/ruby/internal/value.h +date_parse.o: $(hdrdir)/ruby/internal/value_type.h +date_parse.o: $(hdrdir)/ruby/internal/variable.h +date_parse.o: $(hdrdir)/ruby/internal/warning_push.h +date_parse.o: $(hdrdir)/ruby/internal/xmalloc.h +date_parse.o: $(hdrdir)/ruby/missing.h +date_parse.o: $(hdrdir)/ruby/onigmo.h +date_parse.o: $(hdrdir)/ruby/oniguruma.h +date_parse.o: $(hdrdir)/ruby/re.h +date_parse.o: $(hdrdir)/ruby/regex.h +date_parse.o: $(hdrdir)/ruby/ruby.h +date_parse.o: $(hdrdir)/ruby/st.h +date_parse.o: $(hdrdir)/ruby/subst.h +date_parse.o: date_parse.c +date_parse.o: zonetab.h +date_parse.o: zonetab.list +date_strftime.o: $(RUBY_EXTCONF_H) +date_strftime.o: $(arch_hdrdir)/ruby/config.h +date_strftime.o: $(hdrdir)/ruby/assert.h +date_strftime.o: $(hdrdir)/ruby/backward.h +date_strftime.o: $(hdrdir)/ruby/backward/2/assume.h +date_strftime.o: $(hdrdir)/ruby/backward/2/attributes.h +date_strftime.o: $(hdrdir)/ruby/backward/2/bool.h +date_strftime.o: $(hdrdir)/ruby/backward/2/inttypes.h +date_strftime.o: $(hdrdir)/ruby/backward/2/limits.h +date_strftime.o: $(hdrdir)/ruby/backward/2/long_long.h +date_strftime.o: $(hdrdir)/ruby/backward/2/stdalign.h +date_strftime.o: $(hdrdir)/ruby/backward/2/stdarg.h +date_strftime.o: $(hdrdir)/ruby/defines.h +date_strftime.o: $(hdrdir)/ruby/intern.h +date_strftime.o: $(hdrdir)/ruby/internal/abi.h +date_strftime.o: $(hdrdir)/ruby/internal/anyargs.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/char.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/double.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/int.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/long.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/short.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +date_strftime.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +date_strftime.o: $(hdrdir)/ruby/internal/assume.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/artificial.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/cold.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/const.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/constexpr.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/deprecated.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/error.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/forceinline.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/format.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/noalias.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/noexcept.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/noinline.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/nonnull.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/noreturn.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/pure.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/restrict.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/warning.h +date_strftime.o: $(hdrdir)/ruby/internal/attr/weakref.h +date_strftime.o: $(hdrdir)/ruby/internal/cast.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +date_strftime.o: $(hdrdir)/ruby/internal/compiler_since.h +date_strftime.o: $(hdrdir)/ruby/internal/config.h +date_strftime.o: $(hdrdir)/ruby/internal/constant_p.h +date_strftime.o: $(hdrdir)/ruby/internal/core.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rarray.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rbasic.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rbignum.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rclass.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rdata.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rfile.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rhash.h +date_strftime.o: $(hdrdir)/ruby/internal/core/robject.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rregexp.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rstring.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rstruct.h +date_strftime.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +date_strftime.o: $(hdrdir)/ruby/internal/ctype.h +date_strftime.o: $(hdrdir)/ruby/internal/dllexport.h +date_strftime.o: $(hdrdir)/ruby/internal/dosish.h +date_strftime.o: $(hdrdir)/ruby/internal/error.h +date_strftime.o: $(hdrdir)/ruby/internal/eval.h +date_strftime.o: $(hdrdir)/ruby/internal/event.h +date_strftime.o: $(hdrdir)/ruby/internal/fl_type.h +date_strftime.o: $(hdrdir)/ruby/internal/gc.h +date_strftime.o: $(hdrdir)/ruby/internal/glob.h +date_strftime.o: $(hdrdir)/ruby/internal/globals.h +date_strftime.o: $(hdrdir)/ruby/internal/has/attribute.h +date_strftime.o: $(hdrdir)/ruby/internal/has/builtin.h +date_strftime.o: $(hdrdir)/ruby/internal/has/c_attribute.h +date_strftime.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +date_strftime.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +date_strftime.o: $(hdrdir)/ruby/internal/has/extension.h +date_strftime.o: $(hdrdir)/ruby/internal/has/feature.h +date_strftime.o: $(hdrdir)/ruby/internal/has/warning.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/array.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/bignum.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/class.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/compar.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/complex.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/cont.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/dir.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/enum.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/enumerator.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/error.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/eval.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/file.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/hash.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/io.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/load.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/marshal.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/numeric.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/object.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/parse.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/proc.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/process.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/random.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/range.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/rational.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/re.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/ruby.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/select.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/set.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/signal.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/sprintf.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/string.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/struct.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/thread.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/time.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/variable.h +date_strftime.o: $(hdrdir)/ruby/internal/intern/vm.h +date_strftime.o: $(hdrdir)/ruby/internal/interpreter.h +date_strftime.o: $(hdrdir)/ruby/internal/iterator.h +date_strftime.o: $(hdrdir)/ruby/internal/memory.h +date_strftime.o: $(hdrdir)/ruby/internal/method.h +date_strftime.o: $(hdrdir)/ruby/internal/module.h +date_strftime.o: $(hdrdir)/ruby/internal/newobj.h +date_strftime.o: $(hdrdir)/ruby/internal/scan_args.h +date_strftime.o: $(hdrdir)/ruby/internal/special_consts.h +date_strftime.o: $(hdrdir)/ruby/internal/static_assert.h +date_strftime.o: $(hdrdir)/ruby/internal/stdalign.h +date_strftime.o: $(hdrdir)/ruby/internal/stdbool.h +date_strftime.o: $(hdrdir)/ruby/internal/stdckdint.h +date_strftime.o: $(hdrdir)/ruby/internal/symbol.h +date_strftime.o: $(hdrdir)/ruby/internal/value.h +date_strftime.o: $(hdrdir)/ruby/internal/value_type.h +date_strftime.o: $(hdrdir)/ruby/internal/variable.h +date_strftime.o: $(hdrdir)/ruby/internal/warning_push.h +date_strftime.o: $(hdrdir)/ruby/internal/xmalloc.h +date_strftime.o: $(hdrdir)/ruby/missing.h +date_strftime.o: $(hdrdir)/ruby/ruby.h +date_strftime.o: $(hdrdir)/ruby/st.h +date_strftime.o: $(hdrdir)/ruby/subst.h +date_strftime.o: date_strftime.c date_strftime.o: date_tmx.h +date_strptime.o: $(RUBY_EXTCONF_H) +date_strptime.o: $(arch_hdrdir)/ruby/config.h +date_strptime.o: $(hdrdir)/ruby.h +date_strptime.o: $(hdrdir)/ruby/assert.h +date_strptime.o: $(hdrdir)/ruby/backward.h +date_strptime.o: $(hdrdir)/ruby/backward/2/assume.h +date_strptime.o: $(hdrdir)/ruby/backward/2/attributes.h +date_strptime.o: $(hdrdir)/ruby/backward/2/bool.h +date_strptime.o: $(hdrdir)/ruby/backward/2/inttypes.h +date_strptime.o: $(hdrdir)/ruby/backward/2/limits.h +date_strptime.o: $(hdrdir)/ruby/backward/2/long_long.h +date_strptime.o: $(hdrdir)/ruby/backward/2/stdalign.h +date_strptime.o: $(hdrdir)/ruby/backward/2/stdarg.h +date_strptime.o: $(hdrdir)/ruby/defines.h +date_strptime.o: $(hdrdir)/ruby/encoding.h +date_strptime.o: $(hdrdir)/ruby/intern.h +date_strptime.o: $(hdrdir)/ruby/internal/abi.h +date_strptime.o: $(hdrdir)/ruby/internal/anyargs.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/char.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/double.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/int.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/long.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/short.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +date_strptime.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +date_strptime.o: $(hdrdir)/ruby/internal/assume.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/artificial.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/cold.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/const.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/constexpr.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/deprecated.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/error.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/forceinline.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/format.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/noalias.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/noexcept.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/noinline.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/nonnull.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/noreturn.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/pure.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/restrict.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/warning.h +date_strptime.o: $(hdrdir)/ruby/internal/attr/weakref.h +date_strptime.o: $(hdrdir)/ruby/internal/cast.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +date_strptime.o: $(hdrdir)/ruby/internal/compiler_since.h +date_strptime.o: $(hdrdir)/ruby/internal/config.h +date_strptime.o: $(hdrdir)/ruby/internal/constant_p.h +date_strptime.o: $(hdrdir)/ruby/internal/core.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rarray.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rbasic.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rbignum.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rclass.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rdata.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rfile.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rhash.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rmatch.h +date_strptime.o: $(hdrdir)/ruby/internal/core/robject.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rregexp.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rstring.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rstruct.h +date_strptime.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +date_strptime.o: $(hdrdir)/ruby/internal/ctype.h +date_strptime.o: $(hdrdir)/ruby/internal/dllexport.h +date_strptime.o: $(hdrdir)/ruby/internal/dosish.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/coderange.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/ctype.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/encoding.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/pathname.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/re.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/string.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/symbol.h +date_strptime.o: $(hdrdir)/ruby/internal/encoding/transcode.h +date_strptime.o: $(hdrdir)/ruby/internal/error.h +date_strptime.o: $(hdrdir)/ruby/internal/eval.h +date_strptime.o: $(hdrdir)/ruby/internal/event.h +date_strptime.o: $(hdrdir)/ruby/internal/fl_type.h +date_strptime.o: $(hdrdir)/ruby/internal/gc.h +date_strptime.o: $(hdrdir)/ruby/internal/glob.h +date_strptime.o: $(hdrdir)/ruby/internal/globals.h +date_strptime.o: $(hdrdir)/ruby/internal/has/attribute.h +date_strptime.o: $(hdrdir)/ruby/internal/has/builtin.h +date_strptime.o: $(hdrdir)/ruby/internal/has/c_attribute.h +date_strptime.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +date_strptime.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +date_strptime.o: $(hdrdir)/ruby/internal/has/extension.h +date_strptime.o: $(hdrdir)/ruby/internal/has/feature.h +date_strptime.o: $(hdrdir)/ruby/internal/has/warning.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/array.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/bignum.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/class.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/compar.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/complex.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/cont.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/dir.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/enum.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/enumerator.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/error.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/eval.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/file.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/hash.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/io.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/load.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/marshal.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/numeric.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/object.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/parse.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/proc.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/process.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/random.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/range.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/rational.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/re.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/ruby.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/select.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/set.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/signal.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/sprintf.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/string.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/struct.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/thread.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/time.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/variable.h +date_strptime.o: $(hdrdir)/ruby/internal/intern/vm.h +date_strptime.o: $(hdrdir)/ruby/internal/interpreter.h +date_strptime.o: $(hdrdir)/ruby/internal/iterator.h +date_strptime.o: $(hdrdir)/ruby/internal/memory.h +date_strptime.o: $(hdrdir)/ruby/internal/method.h +date_strptime.o: $(hdrdir)/ruby/internal/module.h +date_strptime.o: $(hdrdir)/ruby/internal/newobj.h +date_strptime.o: $(hdrdir)/ruby/internal/scan_args.h +date_strptime.o: $(hdrdir)/ruby/internal/special_consts.h +date_strptime.o: $(hdrdir)/ruby/internal/static_assert.h +date_strptime.o: $(hdrdir)/ruby/internal/stdalign.h +date_strptime.o: $(hdrdir)/ruby/internal/stdbool.h +date_strptime.o: $(hdrdir)/ruby/internal/stdckdint.h +date_strptime.o: $(hdrdir)/ruby/internal/symbol.h +date_strptime.o: $(hdrdir)/ruby/internal/value.h +date_strptime.o: $(hdrdir)/ruby/internal/value_type.h +date_strptime.o: $(hdrdir)/ruby/internal/variable.h +date_strptime.o: $(hdrdir)/ruby/internal/warning_push.h +date_strptime.o: $(hdrdir)/ruby/internal/xmalloc.h +date_strptime.o: $(hdrdir)/ruby/missing.h +date_strptime.o: $(hdrdir)/ruby/onigmo.h +date_strptime.o: $(hdrdir)/ruby/oniguruma.h +date_strptime.o: $(hdrdir)/ruby/re.h +date_strptime.o: $(hdrdir)/ruby/regex.h +date_strptime.o: $(hdrdir)/ruby/ruby.h +date_strptime.o: $(hdrdir)/ruby/st.h +date_strptime.o: $(hdrdir)/ruby/subst.h +date_strptime.o: date_strptime.c +# AUTOGENERATED DEPENDENCIES END diff --git a/ext/date/extconf.rb b/ext/date/extconf.rb index 9f7d3e8f0b..8a1467df09 100644 --- a/ext/date/extconf.rb +++ b/ext/date/extconf.rb @@ -1,2 +1,13 @@ +# frozen_string_literal: true require 'mkmf' + +config_string("strict_warnflags") {|w| $warnflags += " #{w}"} + +append_cflags("-Wno-compound-token-split-by-macro") if RUBY_VERSION < "2.7." +have_func("rb_category_warn") +with_werror("", {:werror => true}) do |opt, | + have_var("timezone", "time.h", opt) + have_var("altzone", "time.h", opt) +end + create_makefile('date_core') diff --git a/ext/date/lib/date.rb b/ext/date/lib/date.rb index d235d76e6f..0cb763017f 100644 --- a/ext/date/lib/date.rb +++ b/ext/date/lib/date.rb @@ -1,13 +1,20 @@ +# frozen_string_literal: true # date.rb: Written by Tadayoshi Funaba 1998-2011 require 'date_core' -require 'date/format' class Date + VERSION = "3.5.1" # :nodoc: - class Infinity < Numeric # :nodoc: + # call-seq: + # infinite? -> false + # + # Returns +false+ + def infinite? + false + end - include Comparable + class Infinity < Numeric # :nodoc: def initialize(d=1) @d = d <=> 0 end @@ -15,26 +22,28 @@ class Date protected :d - def zero? () false end - def finite? () false end - def infinite? () d.nonzero? end - def nan? () d.zero? end + def zero?() false end + def finite?() false end + def infinite?() d.nonzero? end + def nan?() d.zero? end def abs() self.class.new end - def -@ () self.class.new(-d) end - def +@ () self.class.new(+d) end + def -@() self.class.new(-d) end + def +@() self.class.new(+d) end - def <=> (other) + def <=>(other) case other when Infinity; return d <=> other.d + when Float::INFINITY; return d <=> 1 + when -Float::INFINITY; return d <=> -1 when Numeric; return d else - begin - l, r = other.coerce(self) - return l <=> r - rescue NoMethodError - end + begin + l, r = other.coerce(self) + return l <=> r + rescue NoMethodError + end end nil end @@ -43,16 +52,16 @@ class Date case other when Numeric; return -d, d else - super + super end end def to_f return 0 if @d == 0 if @d > 0 - Float::INFINITY + Float::INFINITY else - -Float::INFINITY + -Float::INFINITY end end diff --git a/ext/date/lib/date/format.rb b/ext/date/lib/date/format.rb deleted file mode 100644 index 892e7aacaa..0000000000 --- a/ext/date/lib/date/format.rb +++ /dev/null @@ -1 +0,0 @@ -# format.rb: Written by Tadayoshi Funaba 1999-2011 diff --git a/ext/date/prereq.mk b/ext/date/prereq.mk new file mode 100644 index 0000000000..b5d271a32c --- /dev/null +++ b/ext/date/prereq.mk @@ -0,0 +1,19 @@ +.SUFFIXES: .list + +.list.h: + gperf --ignore-case -L ANSI-C -C -c -P -p -j1 -i 1 -g -o -t -N $(*F) $< \ + | sed -f $(top_srcdir)/tool/gperf.sed \ + > $(@F) + +zonetab.h: zonetab.list + +.PHONY: update-zonetab +update-zonetab: + $(RUBY) -C $(srcdir) update-abbr + +.PHONY: update-nothing +update-nothing: + +update = nothing + +zonetab.list: update-$(update) diff --git a/ext/date/update-abbr b/ext/date/update-abbr new file mode 100644 index 0000000000..7fe9734e6d --- /dev/null +++ b/ext/date/update-abbr @@ -0,0 +1,52 @@ +# -*- mode: ruby -*- +require 'nokogiri' +require 'open-uri' + +doc = Nokogiri::HTML(URI.open(ARGV[0] || 'https://www.timeanddate.com/time/zones/')) + +h = {} + +doc.css('#tz-abb tbody tr').each do |tr| + tds = tr.css('td') + abbr = tds[0].text.strip.downcase + offset = tds[3].text.strip.gsub(/UTC\s*/, '') + next if offset.include?('/') # skip ambiguous timezones + next if offset.empty? + + + hour, min = offset.split(':', 2) + offset = (Integer(hour) * 60 + (Integer(min || 0)))*60 + if h.has_key?(abbr) + h[abbr] = false + else + h[abbr] = offset + end +end + +h.delete_if{|_,v| !v} + +lines = File.readlines('zonetab.list') +lines.map! do |l| + if (sep = /^%%/ =~ l)...(sep = /^%%/ =~ l) and !sep + z, o = l.split(/,\s*/, 2) + o.strip! + if ho = h.delete(z) and ho != eval(o) + warn "offset of #{z}: #{o} -> #{ho}" + l = l.sub(/,\s*\K.*/) { + if o.include?("*") + o1, o2 = ho.abs.divmod(3600) + o1 = "#{o1}*3600" + o1 = "(#{o1}+#{o2})" if o2 != 0 + ho < 0 ? "-#{o1}" : o1 + else + ho.to_s + end + } + end + end + l +end + +lines.insert(-2, h.sort.map{|k,v| "#{k},#{v}\n"}) +lines.flatten! +File.write('zonetab.list', lines.join) diff --git a/ext/date/zonetab.h b/ext/date/zonetab.h new file mode 100644 index 0000000000..2a2e8910c9 --- /dev/null +++ b/ext/date/zonetab.h @@ -0,0 +1,1564 @@ +/* ANSI-C code produced by gperf version 3.1 */ +/* Command-line: gperf --ignore-case -L ANSI-C -C -c -P -p -j1 -i 1 -g -o -t -N zonetab zonetab.list */ +/* Computed positions: -k'1-4,9' */ + +#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ + && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ + && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ + && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ + && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ + && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ + && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ + && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ + && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ + && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ + && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ + && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ + && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ + && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ + && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ + && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ + && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ + && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ + && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ + && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ + && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ + && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ + && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) +/* The character set is not based on ISO-646. */ +#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>." +#endif + +#line 1 "zonetab.list" + +#define GPERF_DOWNCASE 1 +#define GPERF_CASE_STRNCMP 1 +#define gperf_case_strncmp strncasecmp +struct zone { + int name; + int offset; +}; +static const struct zone *zonetab(register const char *str, register size_t len); +#line 12 "zonetab.list" +struct zone; + +#define TOTAL_KEYWORDS 316 +#define MIN_WORD_LENGTH 1 +#define MAX_WORD_LENGTH 17 +#define MIN_HASH_VALUE 2 +#define MAX_HASH_VALUE 619 +/* maximum key range = 618, duplicates = 0 */ + +#ifndef GPERF_DOWNCASE +#define GPERF_DOWNCASE 1 +static unsigned char gperf_downcase[256] = + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, + 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255 + }; +#endif + +#ifndef GPERF_CASE_STRNCMP +#define GPERF_CASE_STRNCMP 1 +static int +gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n) +{ + for (; n > 0;) + { + unsigned char c1 = gperf_downcase[(unsigned char)*s1++]; + unsigned char c2 = gperf_downcase[(unsigned char)*s2++]; + if (c1 != 0 && c1 == c2) + { + n--; + continue; + } + return (int)c1 - (int)c2; + } + return 0; +} +#endif + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static unsigned int +hash (register const char *str, register size_t len) +{ + static const unsigned short asso_values[] = + { + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 17, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 3, 2, 620, 620, 620, + 620, 620, 70, 8, 3, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 39, 176, 207, 70, 168, + 1, 5, 18, 74, 218, 2, 117, 130, 48, 88, + 125, 225, 92, 1, 1, 12, 54, 30, 36, 13, + 48, 168, 263, 59, 114, 166, 109, 39, 176, 207, + 70, 168, 1, 5, 18, 74, 218, 2, 117, 130, + 48, 88, 125, 225, 92, 1, 1, 12, 54, 30, + 36, 13, 48, 168, 263, 59, 114, 166, 109, 27, + 104, 1, 9, 4, 309, 190, 188, 177, 255, 108, + 2, 341, 3, 620, 620, 620, 620, 620, 620, 12, + 54, 30, 36, 13, 48, 168, 263, 59, 114, 166, + 109, 27, 104, 1, 9, 4, 309, 190, 188, 177, + 255, 108, 2, 341, 3, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620, 620, 620, + 620, 620, 620, 620, 620, 620, 620, 620 + }; + register unsigned int hval = (unsigned int)len; + + switch (hval) + { + default: + hval += asso_values[(unsigned char)str[8]]; + /*FALLTHROUGH*/ + case 8: + case 7: + case 6: + case 5: + case 4: + hval += asso_values[(unsigned char)str[3]]; + /*FALLTHROUGH*/ + case 3: + hval += asso_values[(unsigned char)str[2]]; + /*FALLTHROUGH*/ + case 2: + hval += asso_values[(unsigned char)str[1]+6]; + /*FALLTHROUGH*/ + case 1: + hval += asso_values[(unsigned char)str[0]+52]; + break; + } + return (unsigned int)hval; +} + +struct stringpool_t + { + char stringpool_str2[sizeof("o")]; + char stringpool_str3[sizeof("x")]; + char stringpool_str4[sizeof("z")]; + char stringpool_str5[sizeof("q")]; + char stringpool_str8[sizeof("omst")]; + char stringpool_str9[sizeof("omsst")]; + char stringpool_str10[sizeof("p")]; + char stringpool_str13[sizeof("a")]; + char stringpool_str14[sizeof("e")]; + char stringpool_str15[sizeof("pet")]; + char stringpool_str16[sizeof("pmst")]; + char stringpool_str17[sizeof("pett")]; + char stringpool_str18[sizeof("petst")]; + char stringpool_str19[sizeof("eet")]; + char stringpool_str20[sizeof("aest")]; + char stringpool_str21[sizeof("eest")]; + char stringpool_str22[sizeof("eat")]; + char stringpool_str24[sizeof("east")]; + char stringpool_str25[sizeof("easst")]; + char stringpool_str26[sizeof("pst")]; + char stringpool_str27[sizeof("eastern")]; + char stringpool_str28[sizeof("m")]; + char stringpool_str29[sizeof("ast")]; + char stringpool_str30[sizeof("est")]; + char stringpool_str31[sizeof("c")]; + char stringpool_str32[sizeof("mmt")]; + char stringpool_str33[sizeof("met")]; + char stringpool_str35[sizeof("mest")]; + char stringpool_str36[sizeof("cet")]; + char stringpool_str37[sizeof("d")]; + char stringpool_str38[sizeof("cest")]; + char stringpool_str39[sizeof("cat")]; + char stringpool_str41[sizeof("cast")]; + char stringpool_str42[sizeof("magt")]; + char stringpool_str43[sizeof("magst")]; + char stringpool_str44[sizeof("mst")]; + char stringpool_str45[sizeof("msk")]; + char stringpool_str46[sizeof("cot")]; + char stringpool_str47[sizeof("cst")]; + char stringpool_str48[sizeof("aqtt")]; + char stringpool_str49[sizeof("f")]; + char stringpool_str52[sizeof("art")]; + char stringpool_str53[sizeof("fnt")]; + char stringpool_str54[sizeof("fet")]; + char stringpool_str55[sizeof("b")]; + char stringpool_str57[sizeof("anat")]; + char stringpool_str58[sizeof("anast")]; + char stringpool_str59[sizeof("bnt")]; + char stringpool_str60[sizeof("i")]; + char stringpool_str61[sizeof("pht")]; + char stringpool_str62[sizeof("at")]; + char stringpool_str63[sizeof("zp6")]; + char stringpool_str64[sizeof("mewt")]; + char stringpool_str65[sizeof("fst")]; + char stringpool_str66[sizeof("ahst")]; + char stringpool_str67[sizeof("mawt")]; + char stringpool_str68[sizeof("zp5")]; + char stringpool_str70[sizeof("bot")]; + char stringpool_str71[sizeof("bst")]; + char stringpool_str72[sizeof("pwt")]; + char stringpool_str74[sizeof("pont")]; + char stringpool_str75[sizeof("iot")]; + char stringpool_str76[sizeof("ist")]; + char stringpool_str77[sizeof("awst")]; + char stringpool_str79[sizeof("mht")]; + char stringpool_str80[sizeof("mez")]; + char stringpool_str81[sizeof("orat")]; + char stringpool_str82[sizeof("mesz")]; + char stringpool_str84[sizeof("chst")]; + char stringpool_str85[sizeof("pmdt")]; + char stringpool_str88[sizeof("central")]; + char stringpool_str89[sizeof("aedt")]; + char stringpool_str90[sizeof("act")]; + char stringpool_str91[sizeof("ect")]; + char stringpool_str92[sizeof("acst")]; + char stringpool_str93[sizeof("eadt")]; + char stringpool_str94[sizeof("brt")]; + char stringpool_str95[sizeof("chut")]; + char stringpool_str96[sizeof("brst")]; + char stringpool_str97[sizeof("cen. australia")]; + char stringpool_str100[sizeof("davt")]; + char stringpool_str101[sizeof("irst")]; + char stringpool_str102[sizeof("irkt")]; + char stringpool_str103[sizeof("irkst")]; + char stringpool_str104[sizeof("bt")]; + char stringpool_str105[sizeof("n")]; + char stringpool_str106[sizeof("btt")]; + char stringpool_str107[sizeof("mountain")]; + char stringpool_str108[sizeof("cct")]; + char stringpool_str109[sizeof("w")]; + char stringpool_str110[sizeof("l")]; + char stringpool_str111[sizeof("fwt")]; + char stringpool_str113[sizeof("msd")]; + char stringpool_str114[sizeof("wet")]; + char stringpool_str116[sizeof("west")]; + char stringpool_str117[sizeof("wat")]; + char stringpool_str119[sizeof("wast")]; + char stringpool_str120[sizeof("wakt")]; + char stringpool_str121[sizeof("nst")]; + char stringpool_str122[sizeof("acwst")]; + char stringpool_str123[sizeof("chast")]; + char stringpool_str124[sizeof("cist")]; + char stringpool_str125[sizeof("azt")]; + char stringpool_str126[sizeof("clt")]; + char stringpool_str127[sizeof("azst")]; + char stringpool_str128[sizeof("clst")]; + char stringpool_str129[sizeof("mart")]; + char stringpool_str130[sizeof("zp4")]; + char stringpool_str131[sizeof("jst")]; + char stringpool_str132[sizeof("central asia")]; + char stringpool_str133[sizeof("aft")]; + char stringpool_str134[sizeof("e. south america")]; + char stringpool_str135[sizeof("central america")]; + char stringpool_str137[sizeof("ict")]; + char stringpool_str143[sizeof("pgt")]; + char stringpool_str144[sizeof("nrt")]; + char stringpool_str145[sizeof("mexico")]; + char stringpool_str146[sizeof("awdt")]; + char stringpool_str147[sizeof("egt")]; + char stringpool_str148[sizeof("cxt")]; + char stringpool_str149[sizeof("egst")]; + char stringpool_str150[sizeof("phot")]; + char stringpool_str151[sizeof("alaskan")]; + char stringpool_str154[sizeof("nt")]; + char stringpool_str158[sizeof("wt")]; + char stringpool_str160[sizeof("west asia")]; + char stringpool_str161[sizeof("acdt")]; + char stringpool_str162[sizeof("npt")]; + char stringpool_str163[sizeof("lhst")]; + char stringpool_str164[sizeof("afghanistan")]; + char stringpool_str167[sizeof("k")]; + char stringpool_str169[sizeof("g")]; + char stringpool_str170[sizeof("irdt")]; + char stringpool_str171[sizeof("chot")]; + char stringpool_str172[sizeof("chost")]; + char stringpool_str173[sizeof("gmt")]; + char stringpool_str174[sizeof("get")]; + char stringpool_str175[sizeof("novt")]; + char stringpool_str176[sizeof("novst")]; + char stringpool_str177[sizeof("fjt")]; + char stringpool_str178[sizeof("u")]; + char stringpool_str179[sizeof("fjst")]; + char stringpool_str181[sizeof("pyst")]; + char stringpool_str182[sizeof("nct")]; + char stringpool_str183[sizeof("kst")]; + char stringpool_str184[sizeof("kost")]; + char stringpool_str185[sizeof("gst")]; + char stringpool_str186[sizeof("iran")]; + char stringpool_str187[sizeof("e. africa")]; + char stringpool_str188[sizeof("wadt")]; + char stringpool_str189[sizeof("t")]; + char stringpool_str190[sizeof("e. australia")]; + char stringpool_str191[sizeof("s")]; + char stringpool_str192[sizeof("chadt")]; + char stringpool_str193[sizeof("tmt")]; + char stringpool_str194[sizeof("cidst")]; + char stringpool_str195[sizeof("aoe")]; + char stringpool_str197[sizeof("myt")]; + char stringpool_str198[sizeof("west pacific")]; + char stringpool_str199[sizeof("mut")]; + char stringpool_str200[sizeof("wit")]; + char stringpool_str201[sizeof("sast")]; + char stringpool_str202[sizeof("sakt")]; + char stringpool_str203[sizeof("new zealand")]; + char stringpool_str204[sizeof("tot")]; + char stringpool_str205[sizeof("china")]; + char stringpool_str206[sizeof("tost")]; + char stringpool_str207[sizeof("sst")]; + char stringpool_str209[sizeof("india")]; + char stringpool_str211[sizeof("warst")]; + char stringpool_str212[sizeof("sbt")]; + char stringpool_str214[sizeof("azot")]; + char stringpool_str215[sizeof("azost")]; + char stringpool_str216[sizeof("taht")]; + char stringpool_str217[sizeof("nzt")]; + char stringpool_str218[sizeof("dateline")]; + char stringpool_str219[sizeof("nzst")]; + char stringpool_str220[sizeof("tokyo")]; + char stringpool_str221[sizeof("central pacific")]; + char stringpool_str223[sizeof("qyzt")]; + char stringpool_str224[sizeof("atlantic")]; + char stringpool_str225[sizeof("nft")]; + char stringpool_str227[sizeof("ut")]; + char stringpool_str228[sizeof("trt")]; + char stringpool_str229[sizeof("wft")]; + char stringpool_str230[sizeof("srt")]; + char stringpool_str231[sizeof("pdt")]; + char stringpool_str232[sizeof("lhdt")]; + char stringpool_str234[sizeof("adt")]; + char stringpool_str235[sizeof("edt")]; + char stringpool_str238[sizeof("pkt")]; + char stringpool_str239[sizeof("almt")]; + char stringpool_str240[sizeof("wita")]; + char stringpool_str242[sizeof("wgt")]; + char stringpool_str243[sizeof("akst")]; + char stringpool_str244[sizeof("wgst")]; + char stringpool_str246[sizeof("krat")]; + char stringpool_str247[sizeof("krast")]; + char stringpool_str248[sizeof("mid-atlantic")]; + char stringpool_str249[sizeof("mdt")]; + char stringpool_str250[sizeof("lint")]; + char stringpool_str251[sizeof("malay peninsula")]; + char stringpool_str252[sizeof("cdt")]; + char stringpool_str253[sizeof("swt")]; + char stringpool_str255[sizeof("se asia")]; + char stringpool_str256[sizeof("v")]; + char stringpool_str258[sizeof("tonga")]; + char stringpool_str259[sizeof("ckt")]; + char stringpool_str261[sizeof("vet")]; + char stringpool_str262[sizeof("caucasus")]; + char stringpool_str263[sizeof("central europe")]; + char stringpool_str264[sizeof("h")]; + char stringpool_str265[sizeof("central european")]; + char stringpool_str266[sizeof("newfoundland")]; + char stringpool_str267[sizeof("arab")]; + char stringpool_str268[sizeof("sct")]; + char stringpool_str269[sizeof("arabic")]; + char stringpool_str270[sizeof("arabian")]; + char stringpool_str271[sizeof("ddut")]; + char stringpool_str273[sizeof("vost")]; + char stringpool_str274[sizeof("hast")]; + char stringpool_str275[sizeof("nepal")]; + char stringpool_str276[sizeof("nut")]; + char stringpool_str277[sizeof("fkt")]; + char stringpool_str279[sizeof("fkst")]; + char stringpool_str280[sizeof("hst")]; + char stringpool_str281[sizeof("idt")]; + char stringpool_str284[sizeof("tlt")]; + char stringpool_str285[sizeof("w. australia")]; + char stringpool_str286[sizeof("egypt")]; + char stringpool_str287[sizeof("myanmar")]; + char stringpool_str288[sizeof("nzdt")]; + char stringpool_str289[sizeof("gft")]; + char stringpool_str290[sizeof("uzt")]; + char stringpool_str293[sizeof("north asia")]; + char stringpool_str294[sizeof("mvt")]; + char stringpool_str295[sizeof("galt")]; + char stringpool_str296[sizeof("nfdt")]; + char stringpool_str297[sizeof("cvt")]; + char stringpool_str298[sizeof("north asia east")]; + char stringpool_str300[sizeof("kgt")]; + char stringpool_str301[sizeof("aus central")]; + char stringpool_str302[sizeof("pacific")]; + char stringpool_str304[sizeof("canada central")]; + char stringpool_str306[sizeof("pacific sa")]; + char stringpool_str307[sizeof("azores")]; + char stringpool_str308[sizeof("gamt")]; + char stringpool_str309[sizeof("tft")]; + char stringpool_str310[sizeof("r")]; + char stringpool_str311[sizeof("fle")]; + char stringpool_str312[sizeof("akdt")]; + char stringpool_str313[sizeof("ulat")]; + char stringpool_str314[sizeof("ulast")]; + char stringpool_str315[sizeof("ret")]; + char stringpool_str317[sizeof("tjt")]; + char stringpool_str319[sizeof("south africa")]; + char stringpool_str324[sizeof("sgt")]; + char stringpool_str326[sizeof("ndt")]; + char stringpool_str327[sizeof("rott")]; + char stringpool_str330[sizeof("samt")]; + char stringpool_str332[sizeof("tasmania")]; + char stringpool_str334[sizeof("hovt")]; + char stringpool_str335[sizeof("hovst")]; + char stringpool_str338[sizeof("gyt")]; + char stringpool_str342[sizeof("y")]; + char stringpool_str343[sizeof("hadt")]; + char stringpool_str344[sizeof("sa western")]; + char stringpool_str345[sizeof("hawaiian")]; + char stringpool_str347[sizeof("uyt")]; + char stringpool_str349[sizeof("uyst")]; + char stringpool_str350[sizeof("yekt")]; + char stringpool_str351[sizeof("yekst")]; + char stringpool_str352[sizeof("kuyt")]; + char stringpool_str353[sizeof("yakt")]; + char stringpool_str354[sizeof("yakst")]; + char stringpool_str358[sizeof("yst")]; + char stringpool_str359[sizeof("jerusalem")]; + char stringpool_str365[sizeof("sri lanka")]; + char stringpool_str367[sizeof("yakutsk")]; + char stringpool_str375[sizeof("wib")]; + char stringpool_str377[sizeof("aus eastern")]; + char stringpool_str378[sizeof("gilt")]; + char stringpool_str387[sizeof("us mountain")]; + char stringpool_str391[sizeof("vlat")]; + char stringpool_str392[sizeof("vlast")]; + char stringpool_str395[sizeof("gtb")]; + char stringpool_str398[sizeof("taipei")]; + char stringpool_str399[sizeof("sret")]; + char stringpool_str408[sizeof("cape verde")]; + char stringpool_str417[sizeof("tkt")]; + char stringpool_str418[sizeof("samoa")]; + char stringpool_str421[sizeof("sa pacific")]; + char stringpool_str427[sizeof("vut")]; + char stringpool_str428[sizeof("idlw")]; + char stringpool_str432[sizeof("fiji")]; + char stringpool_str435[sizeof("utc")]; + char stringpool_str443[sizeof("korea")]; + char stringpool_str445[sizeof("e. europe")]; + char stringpool_str449[sizeof("syot")]; + char stringpool_str452[sizeof("n. central asia")]; + char stringpool_str455[sizeof("tvt")]; + char stringpool_str458[sizeof("w. central africa")]; + char stringpool_str466[sizeof("ekaterinburg")]; + char stringpool_str468[sizeof("vladivostok")]; + char stringpool_str476[sizeof("yapt")]; + char stringpool_str477[sizeof("us eastern")]; + char stringpool_str482[sizeof("sa eastern")]; + char stringpool_str485[sizeof("hdt")]; + char stringpool_str486[sizeof("russian")]; + char stringpool_str492[sizeof("hkt")]; + char stringpool_str497[sizeof("romance")]; + char stringpool_str540[sizeof("w. europe")]; + char stringpool_str563[sizeof("ydt")]; + char stringpool_str566[sizeof("idle")]; + char stringpool_str567[sizeof("greenwich")]; + char stringpool_str619[sizeof("greenland")]; + }; +static const struct stringpool_t stringpool_contents = + { + "o", + "x", + "z", + "q", + "omst", + "omsst", + "p", + "a", + "e", + "pet", + "pmst", + "pett", + "petst", + "eet", + "aest", + "eest", + "eat", + "east", + "easst", + "pst", + "eastern", + "m", + "ast", + "est", + "c", + "mmt", + "met", + "mest", + "cet", + "d", + "cest", + "cat", + "cast", + "magt", + "magst", + "mst", + "msk", + "cot", + "cst", + "aqtt", + "f", + "art", + "fnt", + "fet", + "b", + "anat", + "anast", + "bnt", + "i", + "pht", + "at", + "zp6", + "mewt", + "fst", + "ahst", + "mawt", + "zp5", + "bot", + "bst", + "pwt", + "pont", + "iot", + "ist", + "awst", + "mht", + "mez", + "orat", + "mesz", + "chst", + "pmdt", + "central", + "aedt", + "act", + "ect", + "acst", + "eadt", + "brt", + "chut", + "brst", + "cen. australia", + "davt", + "irst", + "irkt", + "irkst", + "bt", + "n", + "btt", + "mountain", + "cct", + "w", + "l", + "fwt", + "msd", + "wet", + "west", + "wat", + "wast", + "wakt", + "nst", + "acwst", + "chast", + "cist", + "azt", + "clt", + "azst", + "clst", + "mart", + "zp4", + "jst", + "central asia", + "aft", + "e. south america", + "central america", + "ict", + "pgt", + "nrt", + "mexico", + "awdt", + "egt", + "cxt", + "egst", + "phot", + "alaskan", + "nt", + "wt", + "west asia", + "acdt", + "npt", + "lhst", + "afghanistan", + "k", + "g", + "irdt", + "chot", + "chost", + "gmt", + "get", + "novt", + "novst", + "fjt", + "u", + "fjst", + "pyst", + "nct", + "kst", + "kost", + "gst", + "iran", + "e. africa", + "wadt", + "t", + "e. australia", + "s", + "chadt", + "tmt", + "cidst", + "aoe", + "myt", + "west pacific", + "mut", + "wit", + "sast", + "sakt", + "new zealand", + "tot", + "china", + "tost", + "sst", + "india", + "warst", + "sbt", + "azot", + "azost", + "taht", + "nzt", + "dateline", + "nzst", + "tokyo", + "central pacific", + "qyzt", + "atlantic", + "nft", + "ut", + "trt", + "wft", + "srt", + "pdt", + "lhdt", + "adt", + "edt", + "pkt", + "almt", + "wita", + "wgt", + "akst", + "wgst", + "krat", + "krast", + "mid-atlantic", + "mdt", + "lint", + "malay peninsula", + "cdt", + "swt", + "se asia", + "v", + "tonga", + "ckt", + "vet", + "caucasus", + "central europe", + "h", + "central european", + "newfoundland", + "arab", + "sct", + "arabic", + "arabian", + "ddut", + "vost", + "hast", + "nepal", + "nut", + "fkt", + "fkst", + "hst", + "idt", + "tlt", + "w. australia", + "egypt", + "myanmar", + "nzdt", + "gft", + "uzt", + "north asia", + "mvt", + "galt", + "nfdt", + "cvt", + "north asia east", + "kgt", + "aus central", + "pacific", + "canada central", + "pacific sa", + "azores", + "gamt", + "tft", + "r", + "fle", + "akdt", + "ulat", + "ulast", + "ret", + "tjt", + "south africa", + "sgt", + "ndt", + "rott", + "samt", + "tasmania", + "hovt", + "hovst", + "gyt", + "y", + "hadt", + "sa western", + "hawaiian", + "uyt", + "uyst", + "yekt", + "yekst", + "kuyt", + "yakt", + "yakst", + "yst", + "jerusalem", + "sri lanka", + "yakutsk", + "wib", + "aus eastern", + "gilt", + "us mountain", + "vlat", + "vlast", + "gtb", + "taipei", + "sret", + "cape verde", + "tkt", + "samoa", + "sa pacific", + "vut", + "idlw", + "fiji", + "utc", + "korea", + "e. europe", + "syot", + "n. central asia", + "tvt", + "w. central africa", + "ekaterinburg", + "vladivostok", + "yapt", + "us eastern", + "sa eastern", + "hdt", + "russian", + "hkt", + "romance", + "w. europe", + "ydt", + "idle", + "greenwich", + "greenland" + }; +#define stringpool ((const char *) &stringpool_contents) +const struct zone * +zonetab (register const char *str, register size_t len) +{ + static const struct zone wordlist[] = + { + {-1}, {-1}, +#line 37 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str2, -2*3600}, +#line 46 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str3, -11*3600}, +#line 48 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str4, 0*3600}, +#line 39 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str5, -4*3600}, + {-1}, {-1}, +#line 272 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str8,21600}, +#line 271 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str9,25200}, +#line 38 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str10, -3*3600}, + {-1}, {-1}, +#line 24 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str13, 1*3600}, +#line 28 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str14, 5*3600}, +#line 274 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str15,-18000}, +#line 282 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str16,-10800}, +#line 276 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str17,43200}, +#line 275 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str18,43200}, +#line 83 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str19, 2*3600}, +#line 189 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str20,36000}, +#line 91 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str21, 3*3600}, +#line 90 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str22, 3*3600}, + {-1}, +#line 104 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str24,-6*3600}, +#line 220 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str25,-18000}, +#line 22 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str26, -8*3600}, +#line 136 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str27, -18000}, +#line 35 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str28, 12*3600}, +#line 59 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str29, -4*3600}, +#line 16 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str30, -5*3600}, +#line 26 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str31, 3*3600}, +#line 259 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str32,23400}, +#line 76 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str33, 1*3600}, + {-1}, +#line 85 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str35, 2*3600}, +#line 74 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str36, 1*3600}, +#line 27 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str37, 4*3600}, +#line 82 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str38, 2*3600}, +#line 68 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str39,2*3600}, + {-1}, +#line 205 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str41,28800}, +#line 255 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str42,39600}, +#line 254 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str43,43200}, +#line 20 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str44, -7*3600}, +#line 92 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str45, 3*3600}, +#line 215 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str46,-18000}, +#line 18 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str47, -6*3600}, +#line 195 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str48,18000}, +#line 29 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str49, 6*3600}, + {-1}, {-1}, +#line 54 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str52, -3*3600}, +#line 229 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str53,-7200}, +#line 224 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str54,10800}, +#line 25 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str55, 2*3600}, + {-1}, +#line 193 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str57,43200}, +#line 192 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str58,43200}, +#line 202 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str59,28800}, +#line 32 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str60, 9*3600}, +#line 279 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str61,28800}, +#line 51 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str62, -2*3600}, +#line 97 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str63, 6*3600}, +#line 77 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str64, 1*3600}, +#line 84 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str65, 2*3600}, +#line 67 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str66,-10*3600}, +#line 257 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str67,18000}, +#line 95 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str68, 5*3600}, + {-1}, +#line 203 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str70,-14400}, +#line 73 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str71, 1*3600}, +#line 284 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str72,32400}, + {-1}, +#line 283 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str74,39600}, +#line 241 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str75,21600}, +#line 96 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str76, (5*3600+1800)}, +#line 197 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str77,28800}, + {-1}, +#line 258 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str79,43200}, +#line 78 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str80, 1*3600}, +#line 273 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str81,18000}, +#line 86 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str82, 2*3600}, + {-1}, +#line 210 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str84,36000}, +#line 281 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str85,-7200}, + {-1}, {-1}, +#line 129 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str88, -21600}, +#line 188 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str89,39600}, +#line 186 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str90,-18000}, +#line 221 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str91,-18000}, +#line 185 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str92,34200}, +#line 106 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str93,11*3600}, +#line 56 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str94, -3*3600}, +#line 211 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str95,36000}, +#line 52 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str96,-2*3600}, +#line 123 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str97, 34200}, + {-1}, {-1}, +#line 218 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str100,25200}, +#line 245 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str101,12600}, +#line 244 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str102,28800}, +#line 243 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str103,32400}, +#line 89 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str104, 3*3600}, +#line 36 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str105, -1*3600}, +#line 204 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str106,21600}, +#line 151 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str107, -25200}, +#line 99 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str108, (6*3600+1800)}, +#line 45 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str109, -10*3600}, +#line 34 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str110, 11*3600}, +#line 75 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str111, 1*3600}, + {-1}, +#line 93 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str113, 4*3600}, +#line 50 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str114, 0*3600}, + {-1}, +#line 81 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str116, 1*3600}, +#line 80 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str117, 1*3600}, + {-1}, +#line 98 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str119, 2*3600}, +#line 316 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str120,43200}, +#line 58 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str121, -(2*3600+1800)}, +#line 187 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str122,31500}, +#line 207 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str123,45900}, +#line 213 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str124,-18000}, +#line 201 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str125,14400}, +#line 60 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str126, -4*3600}, +#line 200 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str127,18000}, +#line 57 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str128,-3*3600}, +#line 256 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str129,-30600}, +#line 94 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str130, 4*3600}, +#line 102 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str131, 9*3600}, +#line 125 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str132, 21600}, +#line 190 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str133,16200}, +#line 135 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str134, -10800}, +#line 124 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str135, -21600}, + {-1}, +#line 239 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str137,25200}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 277 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str143,36000}, +#line 269 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str144,43200}, +#line 149 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str145, -21600}, +#line 196 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str146,32400}, +#line 223 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str147,-3600}, +#line 217 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str148,25200}, +#line 222 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str149,0}, +#line 278 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str150,46800}, +#line 112 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str151, -32400}, + {-1}, {-1}, +#line 71 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str154, -11*3600}, + {-1}, {-1}, {-1}, +#line 324 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str158,0}, + {-1}, +#line 181 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str160, 18000}, +#line 184 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str161,37800}, +#line 268 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str162,20700}, +#line 252 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str163,37800}, +#line 111 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str164, 16200}, + {-1}, {-1}, +#line 33 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str167, 10*3600}, + {-1}, +#line 30 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str169, 7*3600}, +#line 242 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str170,16200}, +#line 209 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str171,28800}, +#line 208 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str172,32400}, +#line 15 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str173, 0*3600}, +#line 232 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str174,14400}, +#line 267 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str175,25200}, +#line 266 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str176,25200}, +#line 226 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str177,43200}, +#line 43 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str178, -8*3600}, +#line 225 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str179,46800}, + {-1}, +#line 285 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str181,-10800}, +#line 263 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str182,39600}, +#line 103 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str183, 9*3600}, +#line 247 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str184,39600}, +#line 105 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str185, 10*3600}, +#line 146 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str186, 12600}, +#line 132 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str187, 10800}, +#line 101 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str188, 8*3600}, +#line 42 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str189, -7*3600}, +#line 133 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str190, 36000}, +#line 41 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str191, -6*3600}, +#line 206 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str192,49500}, +#line 301 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str193,18000}, +#line 212 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str194,-14400}, +#line 194 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str195,-43200}, + {-1}, +#line 262 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str197,28800}, +#line 182 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str198, 36000}, +#line 260 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str199,14400}, +#line 322 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str200,32400}, +#line 87 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str201, 2*3600}, +#line 289 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str202,39600}, +#line 155 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str203, 43200}, +#line 303 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str204,46800}, +#line 130 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str205, 28800}, +#line 302 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str206,50400}, +#line 88 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str207, -11*3600}, + {-1}, +#line 145 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str209, 19800}, + {-1}, +#line 317 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str211,-10800}, +#line 291 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str212,39600}, + {-1}, +#line 199 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str214,-3600}, +#line 198 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str215,0}, +#line 296 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str216,-36000}, +#line 109 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str217, 12*3600}, +#line 131 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str218, -43200}, +#line 108 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str219,12*3600}, +#line 173 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str220, 32400}, +#line 128 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str221, 39600}, + {-1}, +#line 286 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str223,21600}, +#line 116 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str224, -14400}, +#line 265 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str225,39600}, + {-1}, +#line 14 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str227, 0*3600}, +#line 304 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str228,10800}, +#line 318 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str229,43200}, +#line 294 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str230,-10800}, +#line 23 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str231, -7*3600}, +#line 251 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str232,39600}, + {-1}, +#line 55 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str234, -3*3600}, +#line 17 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str235, -4*3600}, + {-1}, {-1}, +#line 280 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str238,18000}, +#line 191 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str239,21600}, +#line 323 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str240,28800}, + {-1}, +#line 320 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str242,-7200}, +#line 63 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str243,-9*3600}, +#line 319 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str244,-3600}, + {-1}, +#line 249 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str246,25200}, +#line 248 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str247,28800}, +#line 150 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str248, -7200}, +#line 21 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str249, -6*3600}, +#line 253 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str250,50400}, +#line 168 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str251, 28800}, +#line 19 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str252, -5*3600}, +#line 79 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str253, 1*3600}, + {-1}, +#line 167 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str255, 25200}, +#line 44 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str256, -9*3600}, + {-1}, +#line 174 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str258, 46800}, +#line 214 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str259,-36000}, + {-1}, +#line 311 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str261,-14400}, +#line 122 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str262, 14400}, +#line 126 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str263, 3600}, +#line 31 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str264, 8*3600}, +#line 127 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str265, 3600}, +#line 156 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str266, -12600}, +#line 113 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str267, 10800}, +#line 292 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str268,14400}, +#line 115 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str269, 10800}, +#line 114 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str270, 14400}, +#line 219 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str271,36000}, + {-1}, +#line 314 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str273,21600}, +#line 69 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str274,-10*3600}, +#line 154 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str275, 20700}, +#line 270 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str276,-39600}, +#line 228 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str277,-14400}, + {-1}, +#line 227 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str279,-10800}, +#line 70 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str280,-10*3600}, +#line 240 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str281,10800}, + {-1}, {-1}, +#line 300 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str284,32400}, +#line 178 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str285, 28800}, +#line 137 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str286, 7200}, +#line 152 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str287, 23400}, +#line 110 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str288,13*3600}, +#line 233 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str289,-10800}, +#line 310 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str290,18000}, + {-1}, {-1}, +#line 158 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str293, 25200}, +#line 261 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str294,18000}, +#line 230 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str295,-21600}, +#line 264 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str296,43200}, +#line 216 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str297,-3600}, +#line 157 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str298, 28800}, + {-1}, +#line 246 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str300,21600}, +#line 117 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str301, 34200}, +#line 160 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str302, -28800}, + {-1}, +#line 120 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str304, -21600}, + {-1}, +#line 159 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str306, -14400}, +#line 119 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str307, -3600}, +#line 231 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str308,-32400}, +#line 297 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str309,18000}, +#line 40 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str310, -5*3600}, +#line 140 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str311, 7200}, +#line 61 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str312,-8*3600}, +#line 307 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str313,28800}, +#line 306 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str314,32400}, +#line 287 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str315,14400}, + {-1}, +#line 298 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str317,18000}, + {-1}, +#line 169 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str319, 7200}, + {-1}, {-1}, {-1}, {-1}, +#line 100 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str324, 8*3600}, + {-1}, +#line 53 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str326, -(1*3600+1800)}, +#line 288 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str327,-10800}, + {-1}, {-1}, +#line 290 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str330,14400}, + {-1}, +#line 172 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str332, 36000}, + {-1}, +#line 238 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str334,25200}, +#line 237 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str335,28800}, + {-1}, {-1}, +#line 235 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str338,-14400}, + {-1}, {-1}, {-1}, +#line 47 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str342, -12*3600}, +#line 64 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str343,-9*3600}, +#line 165 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str344, -14400}, +#line 144 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str345, -36000}, + {-1}, +#line 309 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str347,-10800}, + {-1}, +#line 308 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str349,-7200}, +#line 329 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str350,18000}, +#line 328 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str351,21600}, +#line 250 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str352,14400}, +#line 326 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str353,32400}, +#line 325 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str354,36000}, + {-1}, {-1}, {-1}, +#line 66 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str358, -9*3600}, +#line 147 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str359, 7200}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 170 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str365, 21600}, + {-1}, +#line 183 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str367, 32400}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 321 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str375,25200}, + {-1}, +#line 118 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str377, 36000}, +#line 234 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str378,43200}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 176 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str387, -25200}, + {-1}, {-1}, {-1}, +#line 313 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str391,36000}, +#line 312 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str392,39600}, + {-1}, {-1}, +#line 143 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str395, 7200}, + {-1}, {-1}, +#line 171 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str398, 28800}, +#line 293 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str399,39600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 121 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str408, -3600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 299 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str417,46800}, +#line 166 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str418, -39600}, + {-1}, {-1}, +#line 164 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str421, -18000}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 315 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str427,39600}, +#line 72 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str428,-12*3600}, + {-1}, {-1}, {-1}, +#line 139 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str432, 43200}, + {-1}, {-1}, +#line 49 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str435, 0*3600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 148 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str443, 32400}, + {-1}, +#line 134 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str445, 7200}, + {-1}, {-1}, {-1}, +#line 295 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str449,10800}, + {-1}, {-1}, +#line 153 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str452, 21600}, + {-1}, {-1}, +#line 305 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str455,43200}, + {-1}, {-1}, +#line 179 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str458, 3600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 138 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str466, 18000}, + {-1}, +#line 177 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str468, 36000}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 327 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str476,36000}, +#line 175 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str477, -18000}, + {-1}, {-1}, {-1}, {-1}, +#line 163 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str482, -10800}, + {-1}, {-1}, +#line 65 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str485, -9*3600}, +#line 162 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str486, 10800}, + {-1}, {-1}, {-1}, {-1}, {-1}, +#line 236 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str492,28800}, + {-1}, {-1}, {-1}, {-1}, +#line 161 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str497, 3600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 180 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str540, 3600}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, +#line 62 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str563, -8*3600}, + {-1}, {-1}, +#line 107 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str566,12*3600}, +#line 142 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str567, 0}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, + {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, +#line 141 "zonetab.list" + {(int)(size_t)&((struct stringpool_t *)0)->stringpool_str619, -10800} + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register unsigned int key = hash (str, len); + + if (key <= MAX_HASH_VALUE) + { + register int o = wordlist[key].name; + if (o >= 0) + { + register const char *s = o + stringpool; + + if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strncmp (str, s, len) && s[len] == '\0') + return &wordlist[key]; + } + } + } + return 0; +} +#line 330 "zonetab.list" + diff --git a/ext/date/zonetab.list b/ext/date/zonetab.list new file mode 100644 index 0000000000..63b6873447 --- /dev/null +++ b/ext/date/zonetab.list @@ -0,0 +1,330 @@ +%{ +#define GPERF_DOWNCASE 1 +#define GPERF_CASE_STRNCMP 1 +#define gperf_case_strncmp strncasecmp +struct zone { + int name; + int offset; +}; +static const struct zone *zonetab(register const char *str, register size_t len); +%} + +struct zone; +%% +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, -(1*3600+1800) +art, -3*3600 +adt, -3*3600 +brt, -3*3600 +clst,-3*3600 +nst, -(2*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,2*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, -11*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, 2*3600 +cct, (6*3600+1800) +sgt, 8*3600 +wadt, 8*3600 +jst, 9*3600 +kst, 9*3600 +east,-6*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 +acdt,37800 +acst,34200 +act,-18000 +acwst,31500 +aedt,39600 +aest,36000 +aft,16200 +almt,21600 +anast,43200 +anat,43200 +aoe,-43200 +aqtt,18000 +awdt,32400 +awst,28800 +azost,0 +azot,-3600 +azst,18000 +azt,14400 +bnt,28800 +bot,-14400 +btt,21600 +cast,28800 +chadt,49500 +chast,45900 +chost,32400 +chot,28800 +chst,36000 +chut,36000 +cidst,-14400 +cist,-18000 +ckt,-36000 +cot,-18000 +cvt,-3600 +cxt,25200 +davt,25200 +ddut,36000 +easst,-18000 +ect,-18000 +egst,0 +egt,-3600 +fet,10800 +fjst,46800 +fjt,43200 +fkst,-10800 +fkt,-14400 +fnt,-7200 +galt,-21600 +gamt,-32400 +get,14400 +gft,-10800 +gilt,43200 +gyt,-14400 +hkt,28800 +hovst,28800 +hovt,25200 +ict,25200 +idt,10800 +iot,21600 +irdt,16200 +irkst,32400 +irkt,28800 +irst,12600 +kgt,21600 +kost,39600 +krast,28800 +krat,25200 +kuyt,14400 +lhdt,39600 +lhst,37800 +lint,50400 +magst,43200 +magt,39600 +mart,-30600 +mawt,18000 +mht,43200 +mmt,23400 +mut,14400 +mvt,18000 +myt,28800 +nct,39600 +nfdt,43200 +nft,39600 +novst,25200 +novt,25200 +npt,20700 +nrt,43200 +nut,-39600 +omsst,25200 +omst,21600 +orat,18000 +pet,-18000 +petst,43200 +pett,43200 +pgt,36000 +phot,46800 +pht,28800 +pkt,18000 +pmdt,-7200 +pmst,-10800 +pont,39600 +pwt,32400 +pyst,-10800 +qyzt,21600 +ret,14400 +rott,-10800 +sakt,39600 +samt,14400 +sbt,39600 +sct,14400 +sret,39600 +srt,-10800 +syot,10800 +taht,-36000 +tft,18000 +tjt,18000 +tkt,46800 +tlt,32400 +tmt,18000 +tost,50400 +tot,46800 +trt,10800 +tvt,43200 +ulast,32400 +ulat,28800 +uyst,-7200 +uyt,-10800 +uzt,18000 +vet,-14400 +vlast,39600 +vlat,36000 +vost,21600 +vut,39600 +wakt,43200 +warst,-10800 +wft,43200 +wgst,-3600 +wgt,-7200 +wib,25200 +wit,32400 +wita,28800 +wt,0 +yakst,36000 +yakt,32400 +yapt,36000 +yekst,21600 +yekt,18000 +%% |
