summaryrefslogtreecommitdiff
path: root/ext/date
diff options
context:
space:
mode:
Diffstat (limited to 'ext/date')
-rw-r--r--ext/date/date.gemspec36
-rw-r--r--ext/date/date_core.c4286
-rw-r--r--ext/date/date_parse.c1327
-rw-r--r--ext/date/date_strftime.c1699
-rw-r--r--ext/date/date_strptime.c222
-rw-r--r--ext/date/date_tmx.h4
-rw-r--r--ext/date/depend690
-rw-r--r--ext/date/extconf.rb11
-rw-r--r--ext/date/lib/date.rb45
-rw-r--r--ext/date/lib/date/format.rb1
-rw-r--r--ext/date/prereq.mk19
-rw-r--r--ext/date/update-abbr52
-rw-r--r--ext/date/zonetab.h1564
-rw-r--r--ext/date/zonetab.list330
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
+%%