date 3.3.0 → 3.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45f9dbfb1646ace90580d6570a44a1bb30d0754e1724d95d714999e94aff623c
4
- data.tar.gz: 95773c2dc052bcb4e14d17eef85ec9d8bf9d743d3c050fea36ba698c6211b1e7
3
+ metadata.gz: 6ccf42407789dcdf94598ab68332e1860f4f2b5f5820d7b2b2bd8ae283088160
4
+ data.tar.gz: 988c7bded5cb20a4b68283216eeaaddf874a15765705919fe372bdeaf58d1c2a
5
5
  SHA512:
6
- metadata.gz: b32ae525d4bfe627069b342527ff6af61550f1f1d7bafd8de7aa0736a3a48e9333769103987138c4abb86c84ec0ce4389843fb9333d6c8dfe2dd47b7defb7490
7
- data.tar.gz: 299a268ba590b6a291a6535096e64c02cd45f12e0e7b92114fdba075d932d4e72862c59ad0200e7c034ab74b1fcac47514cd25bc28bb7e7d8696bac685a2b7c2
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.0" # :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.0
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-05 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
  - - ">="