date 3.3.1 → 3.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3f6bf4ad3ef248851b47ae7c04b9e2378f699d6d93c59bd369284f681da476c
4
- data.tar.gz: 47680dd596954c5bd32176e047a7f7709e69e45067a5dd7019174e6779105492
3
+ metadata.gz: 6ccf42407789dcdf94598ab68332e1860f4f2b5f5820d7b2b2bd8ae283088160
4
+ data.tar.gz: 988c7bded5cb20a4b68283216eeaaddf874a15765705919fe372bdeaf58d1c2a
5
5
  SHA512:
6
- metadata.gz: 31b0f01bbec9b877fd40f02806290120920b8fa327f27f513bca9faa7a358f9f3d423c2ca6f3e0c67212fc1350cdaeedb483000974de74d622ce24e9c6e208d1
7
- data.tar.gz: 639bd03636d459e671b472031999e14917c817804cdd65df9ef95a4070823a6a2dfa906e9c55fb12bc5ac5033f325b5117f9af92a421cf491f876802958a41a5
6
+ metadata.gz: f99b7157afc55d925ffe6ea0f786ce4dc377a30786bb8045b71019db65cd056c83edbd4a979925060ed0daaae2f0cc71f19c04d0b89df53b6a39c70ad6005457
7
+ data.tar.gz: d4d955554151f00b3e0db05cf684d5e7c47655654fd3174aa3e1c67b14a9fa8696092219eac5e540ae9d9abe8c05b06e13bb4ff74c754c33b7e075e9b5498597
data/ext/date/date_core.c CHANGED
@@ -27,6 +27,10 @@ static VALUE eDateError;
27
27
  static VALUE half_days_in_day, day_in_nanoseconds;
28
28
  static double positive_inf, negative_inf;
29
29
 
30
+ // used by deconstruct_keys
31
+ static VALUE sym_year, sym_month, sym_day, sym_yday, sym_wday;
32
+ static VALUE sym_hour, sym_min, sym_sec, sym_sec_fraction, sym_zone;
33
+
30
34
  #define f_boolcast(x) ((x) ? Qtrue : Qfalse)
31
35
 
32
36
  #define f_abs(x) rb_funcall(x, rb_intern("abs"), 0)
@@ -60,7 +64,8 @@ static VALUE datetime_initialize(int argc, VALUE *argv, VALUE self);
60
64
 
61
65
  #define RETURN_FALSE_UNLESS_NUMERIC(obj) if(!RTEST(rb_obj_is_kind_of((obj), rb_cNumeric))) return Qfalse
62
66
  inline static void
63
- check_numeric(VALUE obj, const char* field) {
67
+ check_numeric(VALUE obj, const char* field)
68
+ {
64
69
  if(!RTEST(rb_obj_is_kind_of(obj, rb_cNumeric))) {
65
70
  rb_raise(rb_eTypeError, "invalid %s (not numeric)", field);
66
71
  }
@@ -7432,6 +7437,96 @@ d_lite_jisx0301(VALUE self)
7432
7437
  return strftimev(fmt, self, set_tmx);
7433
7438
  }
7434
7439
 
7440
+ static VALUE
7441
+ deconstruct_keys(VALUE self, VALUE keys, int is_datetime)
7442
+ {
7443
+ VALUE h = rb_hash_new();
7444
+ long i;
7445
+
7446
+ get_d1(self);
7447
+
7448
+ if (NIL_P(keys)) {
7449
+ rb_hash_aset(h, sym_year, m_real_year(dat));
7450
+ rb_hash_aset(h, sym_month, INT2FIX(m_mon(dat)));
7451
+ rb_hash_aset(h, sym_day, INT2FIX(m_mday(dat)));
7452
+ rb_hash_aset(h, sym_yday, INT2FIX(m_yday(dat)));
7453
+ rb_hash_aset(h, sym_wday, INT2FIX(m_wday(dat)));
7454
+ if (is_datetime) {
7455
+ rb_hash_aset(h, sym_hour, INT2FIX(m_hour(dat)));
7456
+ rb_hash_aset(h, sym_min, INT2FIX(m_min(dat)));
7457
+ rb_hash_aset(h, sym_sec, INT2FIX(m_sec(dat)));
7458
+ rb_hash_aset(h, sym_sec_fraction, m_sf_in_sec(dat));
7459
+ rb_hash_aset(h, sym_zone, m_zone(dat));
7460
+ }
7461
+
7462
+ return h;
7463
+ }
7464
+ if (!RB_TYPE_P(keys, T_ARRAY)) {
7465
+ rb_raise(rb_eTypeError,
7466
+ "wrong argument type %"PRIsVALUE" (expected Array or nil)",
7467
+ rb_obj_class(keys));
7468
+
7469
+ }
7470
+
7471
+ for (i=0; i<RARRAY_LEN(keys); i++) {
7472
+ VALUE key = RARRAY_AREF(keys, i);
7473
+
7474
+ if (sym_year == key) rb_hash_aset(h, key, m_real_year(dat));
7475
+ if (sym_month == key) rb_hash_aset(h, key, INT2FIX(m_mon(dat)));
7476
+ if (sym_day == key) rb_hash_aset(h, key, INT2FIX(m_mday(dat)));
7477
+ if (sym_yday == key) rb_hash_aset(h, key, INT2FIX(m_yday(dat)));
7478
+ if (sym_wday == key) rb_hash_aset(h, key, INT2FIX(m_wday(dat)));
7479
+ if (is_datetime) {
7480
+ if (sym_hour == key) rb_hash_aset(h, key, INT2FIX(m_hour(dat)));
7481
+ if (sym_min == key) rb_hash_aset(h, key, INT2FIX(m_min(dat)));
7482
+ if (sym_sec == key) rb_hash_aset(h, key, INT2FIX(m_sec(dat)));
7483
+ if (sym_sec_fraction == key) rb_hash_aset(h, key, m_sf_in_sec(dat));
7484
+ if (sym_zone == key) rb_hash_aset(h, key, m_zone(dat));
7485
+ }
7486
+ }
7487
+ return h;
7488
+ }
7489
+
7490
+ /*
7491
+ * call-seq:
7492
+ * deconstruct_keys(array_of_names_or_nil) -> hash
7493
+ *
7494
+ * Returns a hash of the name/value pairs, to use in pattern matching.
7495
+ * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
7496
+ * <tt>:wday</tt>, <tt>:yday</tt>.
7497
+ *
7498
+ * Possible usages:
7499
+ *
7500
+ * d = Date.new(2022, 10, 5)
7501
+ *
7502
+ * if d in wday: 3, day: ..7 # uses deconstruct_keys underneath
7503
+ * puts "first Wednesday of the month"
7504
+ * end
7505
+ * #=> prints "first Wednesday of the month"
7506
+ *
7507
+ * case d
7508
+ * in year: ...2022
7509
+ * puts "too old"
7510
+ * in month: ..9
7511
+ * puts "quarter 1-3"
7512
+ * in wday: 1..5, month:
7513
+ * puts "working day in month #{month}"
7514
+ * end
7515
+ * #=> prints "working day in month 10"
7516
+ *
7517
+ * Note that deconstruction by pattern can also be combined with class check:
7518
+ *
7519
+ * if d in Date(wday: 3, day: ..7)
7520
+ * puts "first Wednesday of the month"
7521
+ * end
7522
+ *
7523
+ */
7524
+ static VALUE
7525
+ d_lite_deconstruct_keys(VALUE self, VALUE keys)
7526
+ {
7527
+ return deconstruct_keys(self, keys, /* is_datetime=false */ 0);
7528
+ }
7529
+
7435
7530
  #ifndef NDEBUG
7436
7531
  /* :nodoc: */
7437
7532
  static VALUE
@@ -8740,6 +8835,47 @@ dt_lite_jisx0301(int argc, VALUE *argv, VALUE self)
8740
8835
  iso8601_timediv(self, n));
8741
8836
  }
8742
8837
 
8838
+ /*
8839
+ * call-seq:
8840
+ * deconstruct_keys(array_of_names_or_nil) -> hash
8841
+ *
8842
+ * Returns a hash of the name/value pairs, to use in pattern matching.
8843
+ * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
8844
+ * <tt>:wday</tt>, <tt>:yday</tt>, <tt>:hour</tt>, <tt>:min</tt>,
8845
+ * <tt>:sec</tt>, <tt>:sec_fraction</tt>, <tt>:zone</tt>.
8846
+ *
8847
+ * Possible usages:
8848
+ *
8849
+ * dt = DateTime.new(2022, 10, 5, 13, 30)
8850
+ *
8851
+ * if d in wday: 1..5, hour: 10..18 # uses deconstruct_keys underneath
8852
+ * puts "Working time"
8853
+ * end
8854
+ * #=> prints "Working time"
8855
+ *
8856
+ * case dt
8857
+ * in year: ...2022
8858
+ * puts "too old"
8859
+ * in month: ..9
8860
+ * puts "quarter 1-3"
8861
+ * in wday: 1..5, month:
8862
+ * puts "working day in month #{month}"
8863
+ * end
8864
+ * #=> prints "working day in month 10"
8865
+ *
8866
+ * Note that deconstruction by pattern can also be combined with class check:
8867
+ *
8868
+ * if d in DateTime(wday: 1..5, hour: 10..18, day: ..7)
8869
+ * puts "Working time, first week of the month"
8870
+ * end
8871
+ *
8872
+ */
8873
+ static VALUE
8874
+ dt_lite_deconstruct_keys(VALUE self, VALUE keys)
8875
+ {
8876
+ return deconstruct_keys(self, keys, /* is_datetime=true */ 1);
8877
+ }
8878
+
8743
8879
  /* conversions */
8744
8880
 
8745
8881
  #define f_subsec(x) rb_funcall(x, rb_intern("subsec"), 0)
@@ -9370,6 +9506,17 @@ Init_date_core(void)
9370
9506
  id_ge_p = rb_intern_const(">=");
9371
9507
  id_eqeq_p = rb_intern_const("==");
9372
9508
 
9509
+ sym_year = ID2SYM(rb_intern_const("year"));
9510
+ sym_month = ID2SYM(rb_intern_const("month"));
9511
+ sym_yday = ID2SYM(rb_intern_const("yday"));
9512
+ sym_wday = ID2SYM(rb_intern_const("wday"));
9513
+ sym_day = ID2SYM(rb_intern_const("day"));
9514
+ sym_hour = ID2SYM(rb_intern_const("hour"));
9515
+ sym_min = ID2SYM(rb_intern_const("min"));
9516
+ sym_sec = ID2SYM(rb_intern_const("sec"));
9517
+ sym_sec_fraction = ID2SYM(rb_intern_const("sec_fraction"));
9518
+ sym_zone = ID2SYM(rb_intern_const("zone"));
9519
+
9373
9520
  half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
9374
9521
 
9375
9522
  #if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
@@ -9691,6 +9838,8 @@ Init_date_core(void)
9691
9838
  rb_define_method(cDate, "httpdate", d_lite_httpdate, 0);
9692
9839
  rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0);
9693
9840
 
9841
+ rb_define_method(cDate, "deconstruct_keys", d_lite_deconstruct_keys, 1);
9842
+
9694
9843
  #ifndef NDEBUG
9695
9844
  rb_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0);
9696
9845
  #endif
@@ -9901,6 +10050,8 @@ Init_date_core(void)
9901
10050
  rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1);
9902
10051
  rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1);
9903
10052
 
10053
+ rb_define_method(cDateTime, "deconstruct_keys", dt_lite_deconstruct_keys, 1);
10054
+
9904
10055
  /* conversions */
9905
10056
 
9906
10057
  rb_define_method(rb_cTime, "to_time", time_to_time, 0);
@@ -10,28 +10,15 @@
10
10
  static const char *day_names[] = {
11
11
  "Sunday", "Monday", "Tuesday", "Wednesday",
12
12
  "Thursday", "Friday", "Saturday",
13
- "Sun", "Mon", "Tue", "Wed",
14
- "Thu", "Fri", "Sat"
15
13
  };
14
+ static const int ABBREVIATED_DAY_NAME_LENGTH = 3;
16
15
 
17
16
  static const char *month_names[] = {
18
17
  "January", "February", "March", "April",
19
18
  "May", "June", "July", "August", "September",
20
19
  "October", "November", "December",
21
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
22
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
23
- };
24
-
25
- static const char *merid_names[] = {
26
- "am", "pm",
27
- "a.m.", "p.m."
28
- };
29
-
30
- static const char *extz_pats[] = {
31
- ":z",
32
- "::z",
33
- ":::z"
34
20
  };
21
+ static const int ABBREVIATED_MONTH_NAME_LENGTH = 3;
35
22
 
36
23
  #define sizeof_array(o) (sizeof o / sizeof o[0])
37
24
 
@@ -75,7 +62,7 @@ num_pattern_p(const char *s)
75
62
  #define NUM_PATTERN_P() num_pattern_p(&fmt[fi + 1])
76
63
 
77
64
  static long
78
- read_digits(const char *s, VALUE *n, size_t width)
65
+ read_digits(const char *s, size_t slen, VALUE *n, size_t width)
79
66
  {
80
67
  size_t l;
81
68
 
@@ -83,7 +70,7 @@ read_digits(const char *s, VALUE *n, size_t width)
83
70
  return 0;
84
71
 
85
72
  l = 0;
86
- while (ISDIGIT(s[l])) {
73
+ while (l < slen && ISDIGIT(s[l])) {
87
74
  if (++l == width) break;
88
75
  }
89
76
 
@@ -131,7 +118,7 @@ do { \
131
118
  #define READ_DIGITS(n,w) \
132
119
  do { \
133
120
  size_t l; \
134
- l = read_digits(&str[si], &n, w); \
121
+ l = read_digits(&str[si], slen - si, &n, w); \
135
122
  if (l == 0) \
136
123
  fail(); \
137
124
  si += l; \
@@ -161,6 +148,12 @@ do { \
161
148
 
162
149
  VALUE date_zone_to_diff(VALUE);
163
150
 
151
+ static inline int
152
+ head_match_p(size_t len, const char *name, const char *str, size_t slen, size_t si)
153
+ {
154
+ return slen - si >= len && strncasecmp(name, &str[si], len) == 0;
155
+ }
156
+
164
157
  static size_t
165
158
  date__strptime_internal(const char *str, size_t slen,
166
159
  const char *fmt, size_t flen, VALUE hash)
@@ -168,9 +161,18 @@ date__strptime_internal(const char *str, size_t slen,
168
161
  size_t si, fi;
169
162
  int c;
170
163
 
164
+ #define HEAD_MATCH_P(len, name) head_match_p(len, name, str, slen, si)
171
165
  si = fi = 0;
172
166
 
173
167
  while (fi < flen) {
168
+ if (isspace((unsigned char)fmt[fi])) {
169
+ while (si < slen && isspace((unsigned char)str[si]))
170
+ si++;
171
+ while (++fi < flen && isspace((unsigned char)fmt[fi]));
172
+ continue;
173
+ }
174
+
175
+ if (si >= slen) fail();
174
176
 
175
177
  switch (fmt[fi]) {
176
178
  case '%':
@@ -194,12 +196,11 @@ date__strptime_internal(const char *str, size_t slen,
194
196
  {
195
197
  int i;
196
198
 
197
- for (i = 0; i < (int)sizeof_array(extz_pats); i++)
198
- if (strncmp(extz_pats[i], &fmt[fi],
199
- strlen(extz_pats[i])) == 0) {
200
- fi += i;
201
- goto again;
202
- }
199
+ for (i = 1; i < 3 && fi + i < flen && fmt[fi+i] == ':'; ++i);
200
+ if (fmt[fi+i] == 'z') {
201
+ fi += i - 1;
202
+ goto again;
203
+ }
203
204
  fail();
204
205
  }
205
206
 
@@ -209,10 +210,12 @@ date__strptime_internal(const char *str, size_t slen,
209
210
  int i;
210
211
 
211
212
  for (i = 0; i < (int)sizeof_array(day_names); i++) {
212
- size_t l = strlen(day_names[i]);
213
- if (strncasecmp(day_names[i], &str[si], l) == 0) {
213
+ const char *day_name = day_names[i];
214
+ size_t l = strlen(day_name);
215
+ if (HEAD_MATCH_P(l, day_name) ||
216
+ HEAD_MATCH_P(l = ABBREVIATED_DAY_NAME_LENGTH, day_name)) {
214
217
  si += l;
215
- set_hash("wday", INT2FIX(i % 7));
218
+ set_hash("wday", INT2FIX(i));
216
219
  goto matched;
217
220
  }
218
221
  }
@@ -225,10 +228,12 @@ date__strptime_internal(const char *str, size_t slen,
225
228
  int i;
226
229
 
227
230
  for (i = 0; i < (int)sizeof_array(month_names); i++) {
228
- size_t l = strlen(month_names[i]);
229
- if (strncasecmp(month_names[i], &str[si], l) == 0) {
231
+ const char *month_name = month_names[i];
232
+ size_t l = strlen(month_name);
233
+ if (HEAD_MATCH_P(l, month_name) ||
234
+ HEAD_MATCH_P(l = ABBREVIATED_MONTH_NAME_LENGTH, month_name)) {
230
235
  si += l;
231
- set_hash("mon", INT2FIX((i % 12) + 1));
236
+ set_hash("mon", INT2FIX(i + 1));
232
237
  goto matched;
233
238
  }
234
239
  }
@@ -402,18 +407,19 @@ date__strptime_internal(const char *str, size_t slen,
402
407
 
403
408
  case 'P':
404
409
  case 'p':
410
+ if (slen - si < 2) fail();
405
411
  {
406
- int i;
407
-
408
- for (i = 0; i < 4; i++) {
409
- size_t l = strlen(merid_names[i]);
410
- if (strncasecmp(merid_names[i], &str[si], l) == 0) {
411
- si += l;
412
- set_hash("_merid", INT2FIX((i % 2) == 0 ? 0 : 12));
413
- goto matched;
414
- }
412
+ char c = str[si];
413
+ const int hour = (c == 'P' || c == 'p') ? 12 : 0;
414
+ if (!hour && !(c == 'A' || c == 'a')) fail();
415
+ if ((c = str[si+1]) == '.') {
416
+ if (slen - si < 4 || str[si+3] != '.') fail();
417
+ c = str[si += 2];
415
418
  }
416
- fail();
419
+ if (!(c == 'M' || c == 'm')) fail();
420
+ si += 2;
421
+ set_hash("_merid", INT2FIX(hour));
422
+ goto matched;
417
423
  }
418
424
 
419
425
  case 'Q':
@@ -587,7 +593,7 @@ date__strptime_internal(const char *str, size_t slen,
587
593
 
588
594
  b = rb_backref_get();
589
595
  rb_match_busy(b);
590
- m = f_match(pat, rb_usascii_str_new2(&str[si]));
596
+ m = f_match(pat, rb_usascii_str_new(&str[si], slen - si));
591
597
 
592
598
  if (!NIL_P(m)) {
593
599
  VALUE s, l, o;
@@ -619,22 +625,13 @@ date__strptime_internal(const char *str, size_t slen,
619
625
  if (str[si] != '%')
620
626
  fail();
621
627
  si++;
622
- if (fi < flen)
623
- if (str[si] != fmt[fi])
628
+ if (fi < flen) {
629
+ if (si >= slen || str[si] != fmt[fi])
624
630
  fail();
625
- si++;
631
+ si++;
632
+ }
626
633
  goto matched;
627
634
  }
628
- case ' ':
629
- case '\t':
630
- case '\n':
631
- case '\v':
632
- case '\f':
633
- case '\r':
634
- while (isspace((unsigned char)str[si]))
635
- si++;
636
- fi++;
637
- break;
638
635
  default:
639
636
  ordinal:
640
637
  if (str[si] != fmt[fi])
data/lib/date.rb CHANGED
@@ -4,7 +4,7 @@
4
4
  require 'date_core'
5
5
 
6
6
  class Date
7
- VERSION = "3.3.1" # :nodoc:
7
+ VERSION = "3.3.3" # :nodoc:
8
8
 
9
9
  # call-seq:
10
10
  # infinite? -> false
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: date
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.1
4
+ version: 3.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tadayoshi Funaba
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-09 00:00:00.000000000 Z
11
+ date: 2022-12-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A subclass of Object includes Comparable module for handling dates.
14
14
  email:
@@ -42,7 +42,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: 2.4.0
45
+ version: 2.6.0
46
46
  required_rubygems_version: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="