2
date_strptime.c: Coded by Tadayoshi Funaba 2011
6
#include "ruby/encoding.h"
10
static const char *day_names[] = {
11
"Sunday", "Monday", "Tuesday", "Wednesday",
12
"Thursday", "Friday", "Saturday",
13
"Sun", "Mon", "Tue", "Wed",
17
static const char *month_names[] = {
18
"January", "February", "March", "April",
19
"May", "June", "July", "August", "September",
20
"October", "November", "December",
21
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
22
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
25
static const char *merid_names[] = {
30
static const char *extz_pats[] = {
36
#define sizeof_array(o) (sizeof o / sizeof o[0])
38
#define f_negate(x) rb_funcall(x, rb_intern("-@"), 0)
39
#define f_add(x,y) rb_funcall(x, '+', 1, y)
40
#define f_sub(x,y) rb_funcall(x, '-', 1, y)
41
#define f_mul(x,y) rb_funcall(x, '*', 1, y)
42
#define f_div(x,y) rb_funcall(x, '/', 1, y)
43
#define f_idiv(x,y) rb_funcall(x, rb_intern("div"), 1, y)
44
#define f_mod(x,y) rb_funcall(x, '%', 1, y)
45
#define f_expt(x,y) rb_funcall(x, rb_intern("**"), 1, y)
47
#define f_lt_p(x,y) rb_funcall(x, '<', 1, y)
48
#define f_gt_p(x,y) rb_funcall(x, '>', 1, y)
49
#define f_le_p(x,y) rb_funcall(x, rb_intern("<="), 1, y)
50
#define f_ge_p(x,y) rb_funcall(x, rb_intern(">="), 1, y)
52
#define f_match(r,s) rb_funcall(r, rb_intern("match"), 1, s)
53
#define f_aref(o,i) rb_funcall(o, rb_intern("[]"), 1, i)
54
#define f_end(o,i) rb_funcall(o, rb_intern("end"), 1, i)
56
#define issign(c) ((c) == '-' || (c) == '+')
59
num_pattern_p(const char *s)
65
if (*s == 'E' || *s == 'O')
68
(strchr("CDdeFGgHIjkLlMmNQRrSsTUuVvWwXxYy", *s) || isdigit(*s)))
74
#define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1])
77
read_digits(const char *s, VALUE *n, size_t width)
81
l = strspn(s, "0123456789");
89
if ((4 * l * sizeof(char)) <= (sizeof(long)*CHAR_BIT)) {
94
while ((size_t)(s - os) < l) {
105
char *s2 = ALLOCA_N(char, l + 1);
108
*n = rb_cstr_to_inum(s2, 10, 0);
113
#define set_hash(k,v) rb_hash_aset(hash, ID2SYM(rb_intern(k)), v)
114
#define ref_hash(k) rb_hash_aref(hash, ID2SYM(rb_intern(k)))
115
#define del_hash(k) rb_hash_delete(hash, ID2SYM(rb_intern(k)))
119
set_hash("_fail", Qtrue); \
123
#define fail_p() (!NIL_P(ref_hash("_fail")))
125
#define READ_DIGITS(n,w) \
128
l = read_digits(&str[si], &n, w); \
134
#define READ_DIGITS_MAX(n) READ_DIGITS(n, LONG_MAX)
137
valid_range_p(VALUE v, int a, int b)
141
return !(vi < a || vi > b);
143
return !(f_lt_p(v, INT2NUM(a)) || f_gt_p(v, INT2NUM(b)));
149
l = date__strptime_internal(&str[si], slen - si, \
150
fmt, sizeof fmt - 1, hash); \
156
VALUE date_zone_to_diff(VALUE);
159
date__strptime_internal(const char *str, size_t slen,
160
const char *fmt, size_t flen, VALUE hash)
178
if (fmt[fi + 1] && strchr("cCxXyY", fmt[fi + 1]))
183
if (fmt[fi + 1] && strchr("deHImMSuUVwWy", fmt[fi + 1]))
191
for (i = 0; i < (int)sizeof_array(extz_pats); i++)
192
if (strncmp(extz_pats[i], &fmt[fi],
193
strlen(extz_pats[i])) == 0) {
205
for (i = 0; i < (int)sizeof_array(day_names); i++) {
206
size_t l = strlen(day_names[i]);
207
if (strncasecmp(day_names[i], &str[si], l) == 0) {
209
set_hash("wday", INT2FIX(i % 7));
221
for (i = 0; i < (int)sizeof_array(month_names); i++) {
222
size_t l = strlen(month_names[i]);
223
if (strncasecmp(month_names[i], &str[si], l) == 0) {
225
set_hash("mon", INT2FIX((i % 12) + 1));
240
set_hash("_cent", n);
245
recur("%a %b %e %H:%M:%S %Y");
257
if (str[si] == ' ') {
263
if (!valid_range_p(n, 1, 31))
281
set_hash("cwyear", n);
290
if (!valid_range_p(n, 0, 99))
292
set_hash("cwyear",n);
294
INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20));
303
if (str[si] == ' ') {
309
if (!valid_range_p(n, 0, 24))
320
if (str[si] == ' ') {
326
if (!valid_range_p(n, 1, 12))
337
if (!valid_range_p(n, 1, 366))
350
if (issign(str[si])) {
357
READ_DIGITS(n, c == 'L' ? 3 : 9)
362
set_hash("sec_fraction",
365
ULONG2NUM(si - osi))));
374
if (!valid_range_p(n, 0, 59))
385
if (!valid_range_p(n, 1, 12))
401
for (i = 0; i < 4; i++) {
402
size_t l = strlen(merid_names[i]);
403
if (strncasecmp(merid_names[i], &str[si], l) == 0) {
405
set_hash("_merid", INT2FIX((i % 2) == 0 ? 0 : 12));
417
if (str[si] == '-') {
436
recur("%I:%M:%S %p");
444
if (!valid_range_p(n, 0, 60))
455
if (str[si] == '-') {
462
set_hash("seconds", n);
476
if (!valid_range_p(n, 0, 53))
478
set_hash(c == 'U' ? "wnum0" : "wnum1", n);
487
if (!valid_range_p(n, 1, 7))
489
set_hash("cwday", n);
498
if (!valid_range_p(n, 1, 53))
500
set_hash("cweek", n);
513
if (!valid_range_p(n, 0, 6))
532
if (issign(str[si])) {
553
if (!valid_range_p(n, 0, 99))
559
INT2FIX(f_ge_p(n, INT2FIX(69)) ? 19 : 20));
566
static const char pat_source[] =
568
"(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?"
569
"|[[:alpha:].\\s]+(?:standard|daylight)\\s+time\\b"
570
"|[[:alpha:]]+(?:\\s+dst)?\\b"
572
static VALUE pat = Qnil;
576
pat = rb_reg_new(pat_source, sizeof pat_source - 1,
577
ONIG_OPTION_IGNORECASE);
578
rb_gc_register_mark_object(pat);
581
b = rb_backref_get();
583
m = f_match(pat, rb_usascii_str_new2(&str[si]));
588
s = rb_reg_nth_match(1, m);
589
l = f_end(m, INT2FIX(0));
590
o = date_zone_to_diff(s);
593
set_hash("offset", o);
608
recur("%a %b %e %H:%M:%S %Z %Y");
616
if (str[si] != fmt[fi])
627
while (isspace(str[si]))
633
if (str[si] != fmt[fi])
648
s = rb_usascii_str_new(&str[si], slen - si);
649
set_hash("leftover", s);
657
date__strptime(const char *str, size_t slen,
658
const char *fmt, size_t flen, VALUE hash)
662
date__strptime_internal(str, slen, fmt, flen, hash);
667
cent = ref_hash("_cent");
671
year = ref_hash("cwyear");
673
set_hash("cwyear", f_add(year, f_mul(cent, INT2FIX(100))));
674
year = ref_hash("year");
676
set_hash("year", f_add(year, f_mul(cent, INT2FIX(100))));
680
merid = ref_hash("_merid");
684
hour = ref_hash("hour");
686
hour = f_mod(hour, INT2FIX(12));
687
set_hash("hour", f_add(hour, merid));