date 3.3.1 → 3.4.1

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: d3f6bf4ad3ef248851b47ae7c04b9e2378f699d6d93c59bd369284f681da476c
4
- data.tar.gz: 47680dd596954c5bd32176e047a7f7709e69e45067a5dd7019174e6779105492
3
+ metadata.gz: 9b82de0c3b7d4685d8aa478af5ce4d919808d79d83b71012b0f61052c37a1506
4
+ data.tar.gz: 6a1adeb0b3d43f3afdc9edb06c1b2bfd081f726e3b91dff9d5d482e77cf87d11
5
5
  SHA512:
6
- metadata.gz: 31b0f01bbec9b877fd40f02806290120920b8fa327f27f513bca9faa7a358f9f3d423c2ca6f3e0c67212fc1350cdaeedb483000974de74d622ce24e9c6e208d1
7
- data.tar.gz: 639bd03636d459e671b472031999e14917c817804cdd65df9ef95a4070823a6a2dfa906e9c55fb12bc5ac5033f325b5117f9af92a421cf491f876802958a41a5
6
+ metadata.gz: 69bc90e06d9f020e5c391732c6b95c8fabe8abe705be5760b5f303980b90ffda96ae55c0ad837a23c8c6701b63783a0a7c16bd2e13f82f7903c1c47089312645
7
+ data.tar.gz: 7c0aff9c2c9a43f3ac6b1f53a9530805792c7941c45074f5bb58cb90b24890efc641b374cbee7fd36ac8124426a748da92a67d148bb07329b62a90f14bfb9194
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)
@@ -53,14 +57,15 @@ static double positive_inf, negative_inf;
53
57
  #define f_add3(x,y,z) f_add(f_add(x, y), z)
54
58
  #define f_sub3(x,y,z) f_sub(f_sub(x, y), z)
55
59
 
56
- #define f_frozen_ary(...) rb_obj_freeze(rb_ary_new3(__VA_ARGS__))
60
+ #define f_frozen_ary(...) rb_ary_freeze(rb_ary_new3(__VA_ARGS__))
57
61
 
58
62
  static VALUE date_initialize(int argc, VALUE *argv, VALUE self);
59
63
  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
  }
@@ -243,6 +248,11 @@ f_negative_p(VALUE x)
243
248
  #define date_sg_t double
244
249
  #endif
245
250
 
251
+ #define JULIAN_EPOCH_DATE "-4712-01-01"
252
+ #define JULIAN_EPOCH_DATETIME JULIAN_EPOCH_DATE "T00:00:00+00:00"
253
+ #define JULIAN_EPOCH_DATETIME_RFC3339 "Mon, 1 Jan -4712 00:00:00 +0000"
254
+ #define JULIAN_EPOCH_DATETIME_HTTPDATE "Mon, 01 Jan -4712 00:00:00 GMT"
255
+
246
256
  /* A set of nth, jd, df and sf denote ajd + 1/2. Each ajd begin at
247
257
  * noon of GMT (assume equal to UTC). However, this begins at
248
258
  * midnight.
@@ -2584,8 +2594,6 @@ date_s__valid_civil_p(int argc, VALUE *argv, VALUE klass)
2584
2594
  *
2585
2595
  * See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
2586
2596
  *
2587
- * Date.valid_date? is an alias for Date.valid_civil?.
2588
- *
2589
2597
  * Related: Date.jd, Date.new.
2590
2598
  */
2591
2599
  static VALUE
@@ -2981,8 +2989,6 @@ date_s_julian_leap_p(VALUE klass, VALUE y)
2981
2989
  * Date.gregorian_leap?(2000) # => true
2982
2990
  * Date.gregorian_leap?(2001) # => false
2983
2991
  *
2984
- * Date.leap? is an alias for Date.gregorian_leap?.
2985
- *
2986
2992
  * Related: Date.julian_leap?.
2987
2993
  */
2988
2994
  static VALUE
@@ -3488,8 +3494,6 @@ date_s_civil(int argc, VALUE *argv, VALUE klass)
3488
3494
  *
3489
3495
  * See argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
3490
3496
  *
3491
- * Date.civil is an alias for Date.new.
3492
- *
3493
3497
  * Related: Date.jd.
3494
3498
  */
3495
3499
  static VALUE
@@ -4426,7 +4430,7 @@ date_s_strptime(int argc, VALUE *argv, VALUE klass)
4426
4430
 
4427
4431
  switch (argc) {
4428
4432
  case 0:
4429
- str = rb_str_new2("-4712-01-01");
4433
+ str = rb_str_new2(JULIAN_EPOCH_DATE);
4430
4434
  case 1:
4431
4435
  fmt = rb_str_new2("%F");
4432
4436
  case 2:
@@ -4465,12 +4469,6 @@ check_limit(VALUE str, VALUE opt)
4465
4469
  {
4466
4470
  size_t slen, limit;
4467
4471
  if (NIL_P(str)) return;
4468
- if (SYMBOL_P(str)) {
4469
- rb_category_warn(RB_WARN_CATEGORY_DEPRECATED,
4470
- "The ability to parse Symbol is an unintentional bug and is deprecated");
4471
- str = rb_sym2str(str);
4472
- }
4473
-
4474
4472
  StringValue(str);
4475
4473
  slen = RSTRING_LEN(str);
4476
4474
  limit = get_limit(opt);
@@ -4485,8 +4483,7 @@ date_s__parse_internal(int argc, VALUE *argv, VALUE klass)
4485
4483
  {
4486
4484
  VALUE vstr, vcomp, hash, opt;
4487
4485
 
4488
- rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
4489
- if (!NIL_P(opt)) argc--;
4486
+ argc = rb_scan_args(argc, argv, "11:", &vstr, &vcomp, &opt);
4490
4487
  check_limit(vstr, opt);
4491
4488
  StringValue(vstr);
4492
4489
  if (!rb_enc_str_asciicompat_p(vstr))
@@ -4573,12 +4570,11 @@ date_s_parse(int argc, VALUE *argv, VALUE klass)
4573
4570
  {
4574
4571
  VALUE str, comp, sg, opt;
4575
4572
 
4576
- rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
4577
- if (!NIL_P(opt)) argc--;
4573
+ argc = rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
4578
4574
 
4579
4575
  switch (argc) {
4580
4576
  case 0:
4581
- str = rb_str_new2("-4712-01-01");
4577
+ str = rb_str_new2(JULIAN_EPOCH_DATE);
4582
4578
  case 1:
4583
4579
  comp = Qtrue;
4584
4580
  case 2:
@@ -4653,12 +4649,11 @@ date_s_iso8601(int argc, VALUE *argv, VALUE klass)
4653
4649
  {
4654
4650
  VALUE str, sg, opt;
4655
4651
 
4656
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4657
- if (!NIL_P(opt)) argc--;
4652
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4658
4653
 
4659
4654
  switch (argc) {
4660
4655
  case 0:
4661
- str = rb_str_new2("-4712-01-01");
4656
+ str = rb_str_new2(JULIAN_EPOCH_DATE);
4662
4657
  case 1:
4663
4658
  sg = INT2FIX(DEFAULT_SG);
4664
4659
  }
@@ -4724,12 +4719,11 @@ date_s_rfc3339(int argc, VALUE *argv, VALUE klass)
4724
4719
  {
4725
4720
  VALUE str, sg, opt;
4726
4721
 
4727
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4728
- if (!NIL_P(opt)) argc--;
4722
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4729
4723
 
4730
4724
  switch (argc) {
4731
4725
  case 0:
4732
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
4726
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
4733
4727
  case 1:
4734
4728
  sg = INT2FIX(DEFAULT_SG);
4735
4729
  }
@@ -4793,12 +4787,11 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
4793
4787
  {
4794
4788
  VALUE str, sg, opt;
4795
4789
 
4796
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4797
- if (!NIL_P(opt)) argc--;
4790
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4798
4791
 
4799
4792
  switch (argc) {
4800
4793
  case 0:
4801
- str = rb_str_new2("-4712-01-01");
4794
+ str = rb_str_new2(JULIAN_EPOCH_DATE);
4802
4795
  case 1:
4803
4796
  sg = INT2FIX(DEFAULT_SG);
4804
4797
  }
@@ -4827,8 +4820,6 @@ date_s_xmlschema(int argc, VALUE *argv, VALUE klass)
4827
4820
  *
4828
4821
  * See argument {limit}[rdoc-ref:Date@Argument+limit].
4829
4822
  *
4830
- * Date._rfc822 is an alias for Date._rfc2822.
4831
- *
4832
4823
  * Related: Date.rfc2822 (returns a \Date object).
4833
4824
  */
4834
4825
  static VALUE
@@ -4859,8 +4850,6 @@ date_s__rfc2822(int argc, VALUE *argv, VALUE klass)
4859
4850
  * - Argument {start}[rdoc-ref:calendars.rdoc@Argument+start].
4860
4851
  * - Argument {limit}[rdoc-ref:Date@Argument+limit].
4861
4852
  *
4862
- * Date.rfc822 is an alias for Date.rfc2822.
4863
- *
4864
4853
  * Related: Date._rfc2822 (returns a hash).
4865
4854
  */
4866
4855
  static VALUE
@@ -4868,11 +4857,11 @@ date_s_rfc2822(int argc, VALUE *argv, VALUE klass)
4868
4857
  {
4869
4858
  VALUE str, sg, opt;
4870
4859
 
4871
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4860
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4872
4861
 
4873
4862
  switch (argc) {
4874
4863
  case 0:
4875
- str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
4864
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339);
4876
4865
  case 1:
4877
4866
  sg = INT2FIX(DEFAULT_SG);
4878
4867
  }
@@ -4936,11 +4925,11 @@ date_s_httpdate(int argc, VALUE *argv, VALUE klass)
4936
4925
  {
4937
4926
  VALUE str, sg, opt;
4938
4927
 
4939
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4928
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
4940
4929
 
4941
4930
  switch (argc) {
4942
4931
  case 0:
4943
- str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
4932
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME_HTTPDATE);
4944
4933
  case 1:
4945
4934
  sg = INT2FIX(DEFAULT_SG);
4946
4935
  }
@@ -5008,12 +4997,11 @@ date_s_jisx0301(int argc, VALUE *argv, VALUE klass)
5008
4997
  {
5009
4998
  VALUE str, sg, opt;
5010
4999
 
5011
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
5012
- if (!NIL_P(opt)) argc--;
5000
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
5013
5001
 
5014
5002
  switch (argc) {
5015
5003
  case 0:
5016
- str = rb_str_new2("-4712-01-01");
5004
+ str = rb_str_new2(JULIAN_EPOCH_DATE);
5017
5005
  case 1:
5018
5006
  sg = INT2FIX(DEFAULT_SG);
5019
5007
  }
@@ -5341,7 +5329,6 @@ d_lite_yday(VALUE self)
5341
5329
  *
5342
5330
  * Date.new(2001, 2, 3).mon # => 2
5343
5331
  *
5344
- * Date#month is an alias for Date#mon.
5345
5332
  */
5346
5333
  static VALUE
5347
5334
  d_lite_mon(VALUE self)
@@ -5358,7 +5345,6 @@ d_lite_mon(VALUE self)
5358
5345
  *
5359
5346
  * Date.new(2001, 2, 3).mday # => 3
5360
5347
  *
5361
- * Date#day is an alias for Date#mday.
5362
5348
  */
5363
5349
  static VALUE
5364
5350
  d_lite_mday(VALUE self)
@@ -5608,7 +5594,6 @@ d_lite_hour(VALUE self)
5608
5594
  *
5609
5595
  * DateTime.new(2001, 2, 3, 4, 5, 6).min # => 5
5610
5596
  *
5611
- * Date#minute is an alias for Date#min.
5612
5597
  */
5613
5598
  static VALUE
5614
5599
  d_lite_min(VALUE self)
@@ -5625,7 +5610,6 @@ d_lite_min(VALUE self)
5625
5610
  *
5626
5611
  * DateTime.new(2001, 2, 3, 4, 5, 6).sec # => 6
5627
5612
  *
5628
- * Date#second is an alias for Date#sec.
5629
5613
  */
5630
5614
  static VALUE
5631
5615
  d_lite_sec(VALUE self)
@@ -5643,7 +5627,6 @@ d_lite_sec(VALUE self)
5643
5627
  *
5644
5628
  * DateTime.new(2001, 2, 3, 4, 5, 6.5).sec_fraction # => (1/2)
5645
5629
  *
5646
- * Date#second_fraction is an alias for Date#sec_fraction.
5647
5630
  */
5648
5631
  static VALUE
5649
5632
  d_lite_sec_fraction(VALUE self)
@@ -6342,9 +6325,11 @@ minus_dd(VALUE self, VALUE other)
6342
6325
  * call-seq:
6343
6326
  * d - other -> date or rational
6344
6327
  *
6345
- * Returns the difference between the two dates if the other is a date
6346
- * object. If the other is a numeric value, returns a date object
6347
- * pointing +other+ days before self. If the other is a fractional number,
6328
+ * If the other is a date object, returns a Rational
6329
+ * whose value is the difference between the two dates in days.
6330
+ * If the other is a numeric value, returns a date object
6331
+ * pointing +other+ days before self.
6332
+ * If the other is a fractional number,
6348
6333
  * assumes its precision is at most nanosecond.
6349
6334
  *
6350
6335
  * Date.new(2001,2,3) - 1 #=> #<Date: 2001-02-02 ...>
@@ -6419,7 +6404,6 @@ d_lite_prev_day(int argc, VALUE *argv, VALUE self)
6419
6404
  * d.to_s # => "2001-02-03"
6420
6405
  * d.next.to_s # => "2001-02-04"
6421
6406
  *
6422
- * Date#succ is an alias for Date#next.
6423
6407
  */
6424
6408
  static VALUE
6425
6409
  d_lite_next(VALUE self)
@@ -7293,7 +7277,6 @@ strftimev(const char *fmt, VALUE self,
7293
7277
  *
7294
7278
  * See {asctime}[https://linux.die.net/man/3/asctime].
7295
7279
  *
7296
- * Date#ctime is an alias for Date#asctime.
7297
7280
  */
7298
7281
  static VALUE
7299
7282
  d_lite_asctime(VALUE self)
@@ -7311,7 +7294,6 @@ d_lite_asctime(VALUE self)
7311
7294
  *
7312
7295
  * Date.new(2001, 2, 3).iso8601 # => "2001-02-03"
7313
7296
  *
7314
- * Date#xmlschema is an alias for Date#iso8601.
7315
7297
  */
7316
7298
  static VALUE
7317
7299
  d_lite_iso8601(VALUE self)
@@ -7344,7 +7326,6 @@ d_lite_rfc3339(VALUE self)
7344
7326
  *
7345
7327
  * Date.new(2001, 2, 3).rfc2822 # => "Sat, 3 Feb 2001 00:00:00 +0000"
7346
7328
  *
7347
- * Date#rfc822 is an alias for Date#rfc2822.
7348
7329
  */
7349
7330
  static VALUE
7350
7331
  d_lite_rfc2822(VALUE self)
@@ -7432,6 +7413,96 @@ d_lite_jisx0301(VALUE self)
7432
7413
  return strftimev(fmt, self, set_tmx);
7433
7414
  }
7434
7415
 
7416
+ static VALUE
7417
+ deconstruct_keys(VALUE self, VALUE keys, int is_datetime)
7418
+ {
7419
+ VALUE h = rb_hash_new();
7420
+ long i;
7421
+
7422
+ get_d1(self);
7423
+
7424
+ if (NIL_P(keys)) {
7425
+ rb_hash_aset(h, sym_year, m_real_year(dat));
7426
+ rb_hash_aset(h, sym_month, INT2FIX(m_mon(dat)));
7427
+ rb_hash_aset(h, sym_day, INT2FIX(m_mday(dat)));
7428
+ rb_hash_aset(h, sym_yday, INT2FIX(m_yday(dat)));
7429
+ rb_hash_aset(h, sym_wday, INT2FIX(m_wday(dat)));
7430
+ if (is_datetime) {
7431
+ rb_hash_aset(h, sym_hour, INT2FIX(m_hour(dat)));
7432
+ rb_hash_aset(h, sym_min, INT2FIX(m_min(dat)));
7433
+ rb_hash_aset(h, sym_sec, INT2FIX(m_sec(dat)));
7434
+ rb_hash_aset(h, sym_sec_fraction, m_sf_in_sec(dat));
7435
+ rb_hash_aset(h, sym_zone, m_zone(dat));
7436
+ }
7437
+
7438
+ return h;
7439
+ }
7440
+ if (!RB_TYPE_P(keys, T_ARRAY)) {
7441
+ rb_raise(rb_eTypeError,
7442
+ "wrong argument type %"PRIsVALUE" (expected Array or nil)",
7443
+ rb_obj_class(keys));
7444
+
7445
+ }
7446
+
7447
+ for (i=0; i<RARRAY_LEN(keys); i++) {
7448
+ VALUE key = RARRAY_AREF(keys, i);
7449
+
7450
+ if (sym_year == key) rb_hash_aset(h, key, m_real_year(dat));
7451
+ if (sym_month == key) rb_hash_aset(h, key, INT2FIX(m_mon(dat)));
7452
+ if (sym_day == key) rb_hash_aset(h, key, INT2FIX(m_mday(dat)));
7453
+ if (sym_yday == key) rb_hash_aset(h, key, INT2FIX(m_yday(dat)));
7454
+ if (sym_wday == key) rb_hash_aset(h, key, INT2FIX(m_wday(dat)));
7455
+ if (is_datetime) {
7456
+ if (sym_hour == key) rb_hash_aset(h, key, INT2FIX(m_hour(dat)));
7457
+ if (sym_min == key) rb_hash_aset(h, key, INT2FIX(m_min(dat)));
7458
+ if (sym_sec == key) rb_hash_aset(h, key, INT2FIX(m_sec(dat)));
7459
+ if (sym_sec_fraction == key) rb_hash_aset(h, key, m_sf_in_sec(dat));
7460
+ if (sym_zone == key) rb_hash_aset(h, key, m_zone(dat));
7461
+ }
7462
+ }
7463
+ return h;
7464
+ }
7465
+
7466
+ /*
7467
+ * call-seq:
7468
+ * deconstruct_keys(array_of_names_or_nil) -> hash
7469
+ *
7470
+ * Returns a hash of the name/value pairs, to use in pattern matching.
7471
+ * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
7472
+ * <tt>:wday</tt>, <tt>:yday</tt>.
7473
+ *
7474
+ * Possible usages:
7475
+ *
7476
+ * d = Date.new(2022, 10, 5)
7477
+ *
7478
+ * if d in wday: 3, day: ..7 # uses deconstruct_keys underneath
7479
+ * puts "first Wednesday of the month"
7480
+ * end
7481
+ * #=> prints "first Wednesday of the month"
7482
+ *
7483
+ * case d
7484
+ * in year: ...2022
7485
+ * puts "too old"
7486
+ * in month: ..9
7487
+ * puts "quarter 1-3"
7488
+ * in wday: 1..5, month:
7489
+ * puts "working day in month #{month}"
7490
+ * end
7491
+ * #=> prints "working day in month 10"
7492
+ *
7493
+ * Note that deconstruction by pattern can also be combined with class check:
7494
+ *
7495
+ * if d in Date(wday: 3, day: ..7)
7496
+ * puts "first Wednesday of the month"
7497
+ * end
7498
+ *
7499
+ */
7500
+ static VALUE
7501
+ d_lite_deconstruct_keys(VALUE self, VALUE keys)
7502
+ {
7503
+ return deconstruct_keys(self, keys, /* is_datetime=false */ 0);
7504
+ }
7505
+
7435
7506
  #ifndef NDEBUG
7436
7507
  /* :nodoc: */
7437
7508
  static VALUE
@@ -8303,7 +8374,7 @@ datetime_s_strptime(int argc, VALUE *argv, VALUE klass)
8303
8374
 
8304
8375
  switch (argc) {
8305
8376
  case 0:
8306
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8377
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8307
8378
  case 1:
8308
8379
  fmt = rb_str_new2("%FT%T%z");
8309
8380
  case 2:
@@ -8351,12 +8422,11 @@ datetime_s_parse(int argc, VALUE *argv, VALUE klass)
8351
8422
  {
8352
8423
  VALUE str, comp, sg, opt;
8353
8424
 
8354
- rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
8355
- if (!NIL_P(opt)) argc--;
8425
+ argc = rb_scan_args(argc, argv, "03:", &str, &comp, &sg, &opt);
8356
8426
 
8357
8427
  switch (argc) {
8358
8428
  case 0:
8359
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8429
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8360
8430
  case 1:
8361
8431
  comp = Qtrue;
8362
8432
  case 2:
@@ -8398,12 +8468,11 @@ datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
8398
8468
  {
8399
8469
  VALUE str, sg, opt;
8400
8470
 
8401
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8402
- if (!NIL_P(opt)) argc--;
8471
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8403
8472
 
8404
8473
  switch (argc) {
8405
8474
  case 0:
8406
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8475
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8407
8476
  case 1:
8408
8477
  sg = INT2FIX(DEFAULT_SG);
8409
8478
  }
@@ -8413,7 +8482,7 @@ datetime_s_iso8601(int argc, VALUE *argv, VALUE klass)
8413
8482
  VALUE argv2[2], hash;
8414
8483
  argv2[0] = str;
8415
8484
  argv2[1] = opt;
8416
- if (!NIL_P(opt)) argc2--;
8485
+ if (!NIL_P(opt)) argc2++;
8417
8486
  hash = date_s__iso8601(argc2, argv2, klass);
8418
8487
  return dt_new_by_frags(klass, hash, sg);
8419
8488
  }
@@ -8438,12 +8507,11 @@ datetime_s_rfc3339(int argc, VALUE *argv, VALUE klass)
8438
8507
  {
8439
8508
  VALUE str, sg, opt;
8440
8509
 
8441
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8442
- if (!NIL_P(opt)) argc--;
8510
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8443
8511
 
8444
8512
  switch (argc) {
8445
8513
  case 0:
8446
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8514
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8447
8515
  case 1:
8448
8516
  sg = INT2FIX(DEFAULT_SG);
8449
8517
  }
@@ -8478,12 +8546,11 @@ datetime_s_xmlschema(int argc, VALUE *argv, VALUE klass)
8478
8546
  {
8479
8547
  VALUE str, sg, opt;
8480
8548
 
8481
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8482
- if (!NIL_P(opt)) argc--;
8549
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8483
8550
 
8484
8551
  switch (argc) {
8485
8552
  case 0:
8486
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8553
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8487
8554
  case 1:
8488
8555
  sg = INT2FIX(DEFAULT_SG);
8489
8556
  }
@@ -8519,12 +8586,11 @@ datetime_s_rfc2822(int argc, VALUE *argv, VALUE klass)
8519
8586
  {
8520
8587
  VALUE str, sg, opt;
8521
8588
 
8522
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8523
- if (!NIL_P(opt)) argc--;
8589
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8524
8590
 
8525
8591
  switch (argc) {
8526
8592
  case 0:
8527
- str = rb_str_new2("Mon, 1 Jan -4712 00:00:00 +0000");
8593
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME_RFC3339);
8528
8594
  case 1:
8529
8595
  sg = INT2FIX(DEFAULT_SG);
8530
8596
  }
@@ -8559,12 +8625,11 @@ datetime_s_httpdate(int argc, VALUE *argv, VALUE klass)
8559
8625
  {
8560
8626
  VALUE str, sg, opt;
8561
8627
 
8562
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8563
- if (!NIL_P(opt)) argc--;
8628
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8564
8629
 
8565
8630
  switch (argc) {
8566
8631
  case 0:
8567
- str = rb_str_new2("Mon, 01 Jan -4712 00:00:00 GMT");
8632
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME_HTTPDATE);
8568
8633
  case 1:
8569
8634
  sg = INT2FIX(DEFAULT_SG);
8570
8635
  }
@@ -8604,12 +8669,11 @@ datetime_s_jisx0301(int argc, VALUE *argv, VALUE klass)
8604
8669
  {
8605
8670
  VALUE str, sg, opt;
8606
8671
 
8607
- rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8608
- if (!NIL_P(opt)) argc--;
8672
+ argc = rb_scan_args(argc, argv, "02:", &str, &sg, &opt);
8609
8673
 
8610
8674
  switch (argc) {
8611
8675
  case 0:
8612
- str = rb_str_new2("-4712-01-01T00:00:00+00:00");
8676
+ str = rb_str_new2(JULIAN_EPOCH_DATETIME);
8613
8677
  case 1:
8614
8678
  sg = INT2FIX(DEFAULT_SG);
8615
8679
  }
@@ -8650,8 +8714,8 @@ dt_lite_to_s(VALUE self)
8650
8714
  *
8651
8715
  * DateTime.now.strftime # => "2022-07-01T11:03:19-05:00"
8652
8716
  *
8653
- * For other formats, see
8654
- * {Formats for Dates and Times}[doc/strftime_formatting.rdoc].
8717
+ * For other formats,
8718
+ * see {Formats for Dates and Times}[https://docs.ruby-lang.org/en/master/strftime_formatting_rdoc.html]:
8655
8719
  *
8656
8720
  */
8657
8721
  static VALUE
@@ -8740,6 +8804,47 @@ dt_lite_jisx0301(int argc, VALUE *argv, VALUE self)
8740
8804
  iso8601_timediv(self, n));
8741
8805
  }
8742
8806
 
8807
+ /*
8808
+ * call-seq:
8809
+ * deconstruct_keys(array_of_names_or_nil) -> hash
8810
+ *
8811
+ * Returns a hash of the name/value pairs, to use in pattern matching.
8812
+ * Possible keys are: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>,
8813
+ * <tt>:wday</tt>, <tt>:yday</tt>, <tt>:hour</tt>, <tt>:min</tt>,
8814
+ * <tt>:sec</tt>, <tt>:sec_fraction</tt>, <tt>:zone</tt>.
8815
+ *
8816
+ * Possible usages:
8817
+ *
8818
+ * dt = DateTime.new(2022, 10, 5, 13, 30)
8819
+ *
8820
+ * if d in wday: 1..5, hour: 10..18 # uses deconstruct_keys underneath
8821
+ * puts "Working time"
8822
+ * end
8823
+ * #=> prints "Working time"
8824
+ *
8825
+ * case dt
8826
+ * in year: ...2022
8827
+ * puts "too old"
8828
+ * in month: ..9
8829
+ * puts "quarter 1-3"
8830
+ * in wday: 1..5, month:
8831
+ * puts "working day in month #{month}"
8832
+ * end
8833
+ * #=> prints "working day in month 10"
8834
+ *
8835
+ * Note that deconstruction by pattern can also be combined with class check:
8836
+ *
8837
+ * if d in DateTime(wday: 1..5, hour: 10..18, day: ..7)
8838
+ * puts "Working time, first week of the month"
8839
+ * end
8840
+ *
8841
+ */
8842
+ static VALUE
8843
+ dt_lite_deconstruct_keys(VALUE self, VALUE keys)
8844
+ {
8845
+ return deconstruct_keys(self, keys, /* is_datetime=true */ 1);
8846
+ }
8847
+
8743
8848
  /* conversions */
8744
8849
 
8745
8850
  #define f_subsec(x) rb_funcall(x, rb_intern("subsec"), 0)
@@ -8844,18 +8949,23 @@ time_to_datetime(VALUE self)
8844
8949
  static VALUE
8845
8950
  date_to_time(VALUE self)
8846
8951
  {
8952
+ VALUE t;
8953
+
8847
8954
  get_d1a(self);
8848
8955
 
8849
8956
  if (m_julian_p(adat)) {
8850
- VALUE tmp = d_lite_gregorian(self);
8851
- get_d1b(tmp);
8957
+ VALUE g = d_lite_gregorian(self);
8958
+ get_d1b(g);
8852
8959
  adat = bdat;
8960
+ self = g;
8853
8961
  }
8854
8962
 
8855
- return f_local3(rb_cTime,
8963
+ t = f_local3(rb_cTime,
8856
8964
  m_real_year(adat),
8857
8965
  INT2FIX(m_mon(adat)),
8858
8966
  INT2FIX(m_mday(adat)));
8967
+ RB_GC_GUARD(self); /* may be the converted gregorian */
8968
+ return t;
8859
8969
  }
8860
8970
 
8861
8971
  /*
@@ -8925,9 +9035,10 @@ datetime_to_time(VALUE self)
8925
9035
  get_d1(self);
8926
9036
 
8927
9037
  if (m_julian_p(dat)) {
8928
- self = d_lite_gregorian(self);
8929
- get_d1a(self);
9038
+ VALUE g = d_lite_gregorian(self);
9039
+ get_d1a(g);
8930
9040
  dat = adat;
9041
+ self = g;
8931
9042
  }
8932
9043
 
8933
9044
  {
@@ -8944,6 +9055,7 @@ datetime_to_time(VALUE self)
8944
9055
  f_add(INT2FIX(m_sec(dat)),
8945
9056
  m_sf_in_sec(dat)),
8946
9057
  INT2FIX(m_of(dat)));
9058
+ RB_GC_GUARD(self); /* may be the converted gregorian */
8947
9059
  return t;
8948
9060
  }
8949
9061
  }
@@ -9348,7 +9460,7 @@ mk_ary_of_str(long len, const char *a[])
9348
9460
  }
9349
9461
  rb_ary_push(o, e);
9350
9462
  }
9351
- rb_obj_freeze(o);
9463
+ rb_ary_freeze(o);
9352
9464
  return o;
9353
9465
  }
9354
9466
 
@@ -9370,6 +9482,17 @@ Init_date_core(void)
9370
9482
  id_ge_p = rb_intern_const(">=");
9371
9483
  id_eqeq_p = rb_intern_const("==");
9372
9484
 
9485
+ sym_year = ID2SYM(rb_intern_const("year"));
9486
+ sym_month = ID2SYM(rb_intern_const("month"));
9487
+ sym_yday = ID2SYM(rb_intern_const("yday"));
9488
+ sym_wday = ID2SYM(rb_intern_const("wday"));
9489
+ sym_day = ID2SYM(rb_intern_const("day"));
9490
+ sym_hour = ID2SYM(rb_intern_const("hour"));
9491
+ sym_min = ID2SYM(rb_intern_const("min"));
9492
+ sym_sec = ID2SYM(rb_intern_const("sec"));
9493
+ sym_sec_fraction = ID2SYM(rb_intern_const("sec_fraction"));
9494
+ sym_zone = ID2SYM(rb_intern_const("zone"));
9495
+
9373
9496
  half_days_in_day = rb_rational_new2(INT2FIX(1), INT2FIX(2));
9374
9497
 
9375
9498
  #if (LONG_MAX / DAY_IN_SECONDS) > SECOND_IN_NANOSECONDS
@@ -9691,6 +9814,8 @@ Init_date_core(void)
9691
9814
  rb_define_method(cDate, "httpdate", d_lite_httpdate, 0);
9692
9815
  rb_define_method(cDate, "jisx0301", d_lite_jisx0301, 0);
9693
9816
 
9817
+ rb_define_method(cDate, "deconstruct_keys", d_lite_deconstruct_keys, 1);
9818
+
9694
9819
  #ifndef NDEBUG
9695
9820
  rb_define_method(cDate, "marshal_dump_old", d_lite_marshal_dump_old, 0);
9696
9821
  #endif
@@ -9901,6 +10026,8 @@ Init_date_core(void)
9901
10026
  rb_define_method(cDateTime, "rfc3339", dt_lite_rfc3339, -1);
9902
10027
  rb_define_method(cDateTime, "jisx0301", dt_lite_jisx0301, -1);
9903
10028
 
10029
+ rb_define_method(cDateTime, "deconstruct_keys", dt_lite_deconstruct_keys, 1);
10030
+
9904
10031
  /* conversions */
9905
10032
 
9906
10033
  rb_define_method(rb_cTime, "to_time", time_to_time, 0);
@@ -7,6 +7,9 @@
7
7
  #include "ruby/re.h"
8
8
  #include <ctype.h>
9
9
 
10
+ #undef strncasecmp
11
+ #define strncasecmp STRNCASECMP
12
+
10
13
  RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y);
11
14
  RUBY_EXTERN unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow);
12
15