summaryrefslogtreecommitdiff
path: root/ext/date/date_core.c
diff options
context:
space:
mode:
authortadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-03-20 12:44:47 +0000
committertadf <tadf@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2011-03-20 12:44:47 +0000
commit434157444fed90d00d3919e604fbcc9319d97ed6 (patch)
tree3096972e90ded69bad4875b1be8ea556371aed13 /ext/date/date_core.c
parent7bc47c026066831295b3fdf1ed8f7f8bfafef957 (diff)
* ext/date/date_core.c: replacement of implementation of
strftime. It has some limitations that is same as Time's one. [experimental] * ext/date/date_strftime.c: new. * ext/date/lib/date/format.c: removed ruby version of strftime. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@31135 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/date/date_core.c')
-rw-r--r--ext/date/date_core.c234
1 files changed, 227 insertions, 7 deletions
diff --git a/ext/date/date_core.c b/ext/date/date_core.c
index 00c5dda6e4..d65f8f73d7 100644
--- a/ext/date/date_core.c
+++ b/ext/date/date_core.c
@@ -1464,6 +1464,17 @@ d_lite_year(VALUE self)
}
}
+static const int yeartab[2][13] = {
+ { 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 },
+ { 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 }
+};
+
+static int
+civil_to_yday(int y, int m, int d)
+{
+ return yeartab[leap_p(y) ? 1 : 0][m] + d;
+}
+
/*
* call-seq:
* d.yday
@@ -1481,9 +1492,8 @@ d_lite_yday(VALUE self)
if (!light_mode_p(dat))
return iforward0("yday_r");
{
- get_d_jd(dat);
- jd_to_ordinal(dat->l.jd, dat->l.sg, &ry, &rd);
- return INT2FIX(rd);
+ get_d_civil(dat);
+ return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
@@ -2322,6 +2332,158 @@ d_lite_inspect(VALUE self)
}
}
+#include <errno.h>
+#include "timev.h"
+
+size_t
+date_strftime(char *s, size_t maxsize, const char *format,
+ const struct vtm *vtm, VALUE timev, int gmt);
+
+#define SMALLBUF 100
+static size_t
+date_strftime_alloc(char **buf, const char *format,
+ struct vtm *vtm, VALUE timev)
+{
+ size_t size, len, flen;
+
+ (*buf)[0] = '\0';
+ flen = strlen(format);
+ if (flen == 0) {
+ return 0;
+ }
+ errno = 0;
+ len = date_strftime(*buf, SMALLBUF, format, vtm, timev, 0);
+ if (len != 0 || (**buf == '\0' && errno != ERANGE)) return len;
+ for (size=1024; ; size*=2) {
+ *buf = xmalloc(size);
+ (*buf)[0] = '\0';
+ len = date_strftime(*buf, size, format, vtm, timev, 0);
+ /*
+ * buflen can be zero EITHER because there's not enough
+ * room in the string, or because the control command
+ * goes to the empty string. Make a reasonable guess that
+ * if the buffer is 1024 times bigger than the length of the
+ * format string, it's not failing for lack of room.
+ */
+ if (len > 0 || size >= 1024 * flen) break;
+ xfree(*buf);
+ }
+ return len;
+}
+
+static void
+d_lite_set_vtm_and_timev(VALUE self, struct vtm *vtm, VALUE *timev)
+{
+ get_d1(self);
+
+ if (!light_mode_p(dat)) {
+ vtm->year = iforward0("year_r");
+ vtm->mon = FIX2INT(iforward0("mon_r"));
+ vtm->mday = FIX2INT(iforward0("mday_r"));
+ vtm->hour = FIX2INT(iforward0("hour_r"));
+ vtm->min = FIX2INT(iforward0("min_r"));
+ vtm->sec = FIX2INT(iforward0("sec_r"));
+ vtm->subsecx = iforward0("sec_fraction_r");
+ vtm->utc_offset = INT2FIX(0);
+ vtm->wday = FIX2INT(iforward0("wday_r"));
+ vtm->yday = FIX2INT(iforward0("yday_r"));
+ vtm->isdst = 0;
+ vtm->zone = RSTRING_PTR(iforward0("zone_r"));
+ *timev = f_mul(f_sub(dat->r.ajd,
+ rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
+ INT2FIX(86400));
+ }
+ else {
+ get_d_jd(dat);
+ get_d_civil(dat);
+
+ vtm->year = LONG2NUM(dat->l.year);
+ vtm->mon = dat->l.mon;
+ vtm->mday = dat->l.mday;
+ vtm->hour = 0;
+ vtm->min = 0;
+ vtm->sec = 0;
+ vtm->subsecx = INT2FIX(0);
+ vtm->utc_offset = INT2FIX(0);
+ vtm->wday = jd_to_wday(dat->l.jd);
+ vtm->yday = civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday);
+ vtm->isdst = 0;
+ vtm->zone = "+00:00";
+ *timev = f_mul(INT2FIX(dat->l.jd - 2440588),
+ INT2FIX(86400));
+ }
+}
+
+static VALUE
+date_strftime_internal(int argc, VALUE *argv, VALUE self,
+ const char *default_fmt,
+ void (*func)(VALUE, struct vtm *, VALUE *))
+{
+ get_d1(self);
+ {
+ VALUE vfmt;
+ const char *fmt;
+ long len;
+ char buffer[SMALLBUF], *buf = buffer;
+ struct vtm vtm;
+ VALUE timev;
+ VALUE str;
+
+ rb_scan_args(argc, argv, "01", &vfmt);
+
+ if (argc < 1)
+ vfmt = rb_usascii_str_new2(default_fmt);
+ else {
+ StringValue(vfmt);
+ if (!rb_enc_str_asciicompat_p(vfmt)) {
+ rb_raise(rb_eArgError,
+ "format should have ASCII compatible encoding");
+ }
+ }
+ fmt = RSTRING_PTR(vfmt);
+ len = RSTRING_LEN(vfmt);
+ (*func)(self, &vtm, &timev);
+ if (memchr(fmt, '\0', len)) {
+ /* Ruby string may contain \0's. */
+ const char *p = fmt, *pe = fmt + len;
+
+ str = rb_str_new(0, 0);
+ while (p < pe) {
+ len = date_strftime_alloc(&buf, p, &vtm, timev);
+ rb_str_cat(str, buf, len);
+ p += strlen(p);
+ if (buf != buffer) {
+ xfree(buf);
+ buf = buffer;
+ }
+ for (fmt = p; p < pe && !*p; ++p);
+ if (p > fmt) rb_str_cat(str, fmt, p - fmt);
+ }
+ return str;
+ }
+ else
+ len = date_strftime_alloc(&buf, fmt, &vtm, timev);
+
+ str = rb_str_new(buf, len);
+ if (buf != buffer) xfree(buf);
+ rb_enc_copy(str, vfmt);
+ return str;
+ }
+}
+
+/*
+ * call-seq:
+ * d.strftime([format="%F"])
+ *
+ * Return a formatted string.
+ */
+static VALUE
+d_lite_strftime(int argc, VALUE *argv, VALUE self)
+{
+ return date_strftime_internal(argc, argv, self,
+ "%F", d_lite_set_vtm_and_timev);
+}
+
/*
* call-seq:
* d.marshal_dump
@@ -3074,10 +3236,8 @@ dt_lite_yday(VALUE self)
if (!light_mode_p(dat))
return iforward0("yday_r");
{
- get_dt_jd(dat);
- get_dt_df(dat);
- jd_to_ordinal(local_jd(dat), dat->l.sg, &ry, &rd);
- return INT2FIX(rd);
+ get_dt_civil(dat);
+ return INT2FIX(civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday));
}
}
@@ -3806,6 +3966,64 @@ dt_lite_inspect(VALUE self)
}
}
+static void
+dt_lite_set_vtm_and_timev(VALUE self, struct vtm *vtm, VALUE *timev)
+{
+ get_dt1(self);
+
+ if (!light_mode_p(dat)) {
+ vtm->year = iforward0("year_r");
+ vtm->mon = FIX2INT(iforward0("mon_r"));
+ vtm->mday = FIX2INT(iforward0("mday_r"));
+ vtm->hour = FIX2INT(iforward0("hour_r"));
+ vtm->min = FIX2INT(iforward0("min_r"));
+ vtm->sec = FIX2INT(iforward0("sec_r"));
+ vtm->subsecx = iforward0("sec_fraction_r");
+ vtm->utc_offset = INT2FIX(0);
+ vtm->wday = FIX2INT(iforward0("wday_r"));
+ vtm->yday = FIX2INT(iforward0("yday_r"));
+ vtm->isdst = 0;
+ vtm->zone = RSTRING_PTR(iforward0("zone_r"));
+ *timev = f_mul(f_sub(dat->r.ajd,
+ rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
+ INT2FIX(86400));
+ }
+ else {
+ get_dt_jd(dat);
+ get_dt_civil(dat);
+ get_dt_time(dat);
+
+ vtm->year = LONG2NUM(dat->l.year);
+ vtm->mon = dat->l.mon;
+ vtm->mday = dat->l.mday;
+ vtm->hour = dat->l.hour;
+ vtm->min = dat->l.min;
+ vtm->sec = dat->l.sec;
+ vtm->subsecx = LONG2NUM(dat->l.sf);
+ vtm->utc_offset = INT2FIX(dat->l.of);
+ vtm->wday = jd_to_wday(local_jd(dat));
+ vtm->yday = civil_to_yday(dat->l.year, dat->l.mon, dat->l.mday);
+ vtm->isdst = 0;
+ vtm->zone = RSTRING_PTR(dt_lite_zone(self));
+ *timev = f_mul(f_sub(dt_lite_ajd(self),
+ rb_rational_new2(INT2FIX(4881175), INT2FIX(2))),
+ INT2FIX(86400));
+ }
+}
+
+/*
+ * call-seq:
+ * dt.strftime([format="%FT%T%:z"])
+ *
+ * Return a formatted string.
+ */
+static VALUE
+dt_lite_strftime(int argc, VALUE *argv, VALUE self)
+{
+ return date_strftime_internal(argc, argv, self,
+ "%FT%T%:z", dt_lite_set_vtm_and_timev);
+}
+
/*
* call-seq:
* dt.marshal_dump
@@ -4214,6 +4432,7 @@ Init_date_core(void)
rb_define_method(cDate, "to_s", d_lite_to_s, 0);
rb_define_method(cDate, "inspect", d_lite_inspect, 0);
+ rb_define_method(cDate, "strftime", d_lite_strftime, -1);
rb_define_method(cDate, "marshal_dump", d_lite_marshal_dump, 0);
rb_define_method(cDate, "marshal_load", d_lite_marshal_load, 1);
@@ -4288,6 +4507,7 @@ Init_date_core(void)
rb_define_method(cDateTime, "to_s", dt_lite_to_s, 0);
rb_define_method(cDateTime, "inspect", dt_lite_inspect, 0);
+ rb_define_method(cDateTime, "strftime", dt_lite_strftime, -1);
rb_define_method(cDateTime, "marshal_dump", dt_lite_marshal_dump, 0);
rb_define_method(cDateTime, "marshal_load", dt_lite_marshal_load, 1);