home_run 0.9.0-x86-mswin32

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.
Files changed (75) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +19 -0
  3. data/README.rdoc +314 -0
  4. data/Rakefile +135 -0
  5. data/bench/cpu_bench.rb +279 -0
  6. data/bench/dt_garbage_bench.rb +11 -0
  7. data/bench/dt_mem_bench.rb +14 -0
  8. data/bench/garbage_bench.rb +11 -0
  9. data/bench/mem_bench.rb +14 -0
  10. data/bin/home_run +91 -0
  11. data/default.mspec +12 -0
  12. data/ext/1.8/date_ext.so +0 -0
  13. data/ext/1.9/date_ext.so +0 -0
  14. data/ext/date.rb +7 -0
  15. data/ext/date/format.rb +842 -0
  16. data/ext/date_ext.c +4548 -0
  17. data/ext/date_parser.c +367 -0
  18. data/ext/date_parser.rl +134 -0
  19. data/ext/datetime.c +2804 -0
  20. data/ext/extconf.rb +6 -0
  21. data/spec/date/accessor_spec.rb +176 -0
  22. data/spec/date/add_month_spec.rb +26 -0
  23. data/spec/date/add_spec.rb +23 -0
  24. data/spec/date/boat_spec.rb +38 -0
  25. data/spec/date/civil_spec.rb +147 -0
  26. data/spec/date/commercial_spec.rb +153 -0
  27. data/spec/date/constants_spec.rb +44 -0
  28. data/spec/date/conversions_spec.rb +246 -0
  29. data/spec/date/day_spec.rb +73 -0
  30. data/spec/date/downto_spec.rb +17 -0
  31. data/spec/date/eql_spec.rb +16 -0
  32. data/spec/date/format_spec.rb +52 -0
  33. data/spec/date/gregorian_spec.rb +52 -0
  34. data/spec/date/hash_spec.rb +11 -0
  35. data/spec/date/julian_spec.rb +129 -0
  36. data/spec/date/leap_spec.rb +19 -0
  37. data/spec/date/minus_month_spec.rb +25 -0
  38. data/spec/date/minus_spec.rb +51 -0
  39. data/spec/date/next_prev_spec.rb +108 -0
  40. data/spec/date/ordinal_spec.rb +83 -0
  41. data/spec/date/parse_spec.rb +442 -0
  42. data/spec/date/parsing_spec.rb +77 -0
  43. data/spec/date/relationship_spec.rb +28 -0
  44. data/spec/date/step_spec.rb +109 -0
  45. data/spec/date/strftime_spec.rb +223 -0
  46. data/spec/date/strptime_spec.rb +201 -0
  47. data/spec/date/succ_spec.rb +20 -0
  48. data/spec/date/today_spec.rb +15 -0
  49. data/spec/date/upto_spec.rb +17 -0
  50. data/spec/datetime/accessor_spec.rb +218 -0
  51. data/spec/datetime/add_month_spec.rb +26 -0
  52. data/spec/datetime/add_spec.rb +36 -0
  53. data/spec/datetime/boat_spec.rb +43 -0
  54. data/spec/datetime/constructor_spec.rb +142 -0
  55. data/spec/datetime/conversions_spec.rb +54 -0
  56. data/spec/datetime/day_spec.rb +73 -0
  57. data/spec/datetime/downto_spec.rb +39 -0
  58. data/spec/datetime/eql_spec.rb +17 -0
  59. data/spec/datetime/format_spec.rb +59 -0
  60. data/spec/datetime/hash_spec.rb +11 -0
  61. data/spec/datetime/leap_spec.rb +19 -0
  62. data/spec/datetime/minus_month_spec.rb +25 -0
  63. data/spec/datetime/minus_spec.rb +77 -0
  64. data/spec/datetime/next_prev_spec.rb +138 -0
  65. data/spec/datetime/now_spec.rb +18 -0
  66. data/spec/datetime/parse_spec.rb +390 -0
  67. data/spec/datetime/parsing_spec.rb +77 -0
  68. data/spec/datetime/relationship_spec.rb +28 -0
  69. data/spec/datetime/step_spec.rb +155 -0
  70. data/spec/datetime/strftime_spec.rb +118 -0
  71. data/spec/datetime/strptime_spec.rb +117 -0
  72. data/spec/datetime/succ_spec.rb +24 -0
  73. data/spec/datetime/upto_spec.rb +39 -0
  74. data/spec/spec_helper.rb +59 -0
  75. metadata +154 -0
@@ -0,0 +1,4548 @@
1
+
2
+ #include <math.h>
3
+ #include <stdio.h>
4
+ #include <stdlib.h>
5
+ #include <inttypes.h>
6
+ #include <ruby.h>
7
+
8
+ #ifdef RUBY19
9
+ #define RHR_DEFAULT_CWYEAR -4713
10
+ #define RHR_DEFAULT_CWEEK 1
11
+ #define RHR_DEFAULT_CWDAY 1
12
+ #else
13
+ #define RHR_DEFAULT_CWYEAR 1582
14
+ #define RHR_DEFAULT_CWEEK 41
15
+ #define RHR_DEFAULT_CWDAY 5
16
+ #endif
17
+
18
+ #define RHR_JD_MJD 2400001
19
+ #define RHR_JD_LD 2299160
20
+ #define RHR_JD_ITALY 2299161
21
+ #define RHR_JD_ENGLAND 2361222
22
+ #define RHR_UNIX_EPOCH 2440588
23
+ #define RHR_SECONDS_PER_HOUR 3600
24
+ #define RHR_MINUTES_PER_DAYD 1440.0
25
+ #define RHR_SECONDS_PER_DAY 86400
26
+ #define RHR_SECONDS_PER_DAYD 86400.0
27
+ #define RHR_MAX_OFFSET_MINUTES 864
28
+ #define RHR_MAX_OFFSET_FRACT 0.6
29
+ #define RHR_MIN_OFFSET_MINUTES -864
30
+ #define RHR_MIN_OFFSET_FRACT -0.6
31
+
32
+ /*
33
+ In both the 32-bit and 64-bit cases, the limits are chosen so that you cannot
34
+ store a civil date where converting it to a jd would cause an overflow.
35
+ */
36
+ #if __LP64__
37
+ /*
38
+ On 64-bit systems, the limits depend on the number of significant digits in
39
+ a double (15). These are slightly below the maximum so that all numbers used
40
+ in calculations have fewer than 15 digits.
41
+ */
42
+ #define RHR_JD_MAX 999979466117609
43
+ #define RHR_JD_MIN -999979466119058
44
+ #define RHR_YEAR_MAX 2737850782415
45
+ #define RHR_MONTH_MAX 12
46
+ #define RHR_DAY_MAX 5
47
+ #define RHR_YEAR_MIN -2737850791845
48
+ #define RHR_MONTH_MIN 11
49
+ #define RHR_DAY_MIN 26
50
+
51
+ #else
52
+ /*
53
+ On 32-bit systems, the limits depend on the storage limits of 32-bit integers.
54
+ The numbers are slightly less than 2**31 - 1 and slightly greater than -2**31
55
+ so that no calculations can overflow.
56
+ */
57
+ #define RHR_JD_MAX 2147438064
58
+ #define RHR_JD_MIN -2145083647
59
+ #define RHR_YEAR_MAX 5874773
60
+ #define RHR_MONTH_MAX 8
61
+ #define RHR_DAY_MAX 15
62
+ #define RHR_YEAR_MIN -5877752
63
+ #define RHR_MONTH_MIN 5
64
+ #define RHR_DAY_MIN 8
65
+ #endif
66
+
67
+ #define RHR_HAVE_JD 1
68
+ #define RHR_HAVE_CIVIL 2
69
+ #define RHR_HAVE_NANOS 4
70
+ #define RHR_HAVE_HMS 8
71
+
72
+ #define RHR_NANOS_PER_MILLISECOND 1000000LL
73
+ #define RHR_NANOS_PER_SECOND 1000000000LL
74
+ #define RHR_NANOS_PER_MINUTE 60000000000LL
75
+ #define RHR_NANOS_PER_DAY 86400000000000LL
76
+ #define RHR_NANOS_PER_DAYD 86400000000000.0
77
+ #define RHR_NANOS_PER_SECONDD 1000000000.0
78
+
79
+ #define RHRR_YEAR_SET 0x1
80
+ #define RHRR_MONTH_SET 0x2
81
+ #define RHRR_DAY_SET 0x4
82
+ #define RHRR_YDAY_SET 0x8
83
+ #define RHRR_HOUR_SET 0x10
84
+ #define RHRR_MINUTE_SET 0x20
85
+ #define RHRR_SECOND_SET 0x40
86
+ #define RHRR_WDAY_SET 0x80
87
+ #define RHRR_CENTURY_SET 0x100
88
+ #define RHRR_CWYEAR_SET 0x200
89
+ #define RHRR_CWEEK_SET 0x400
90
+ #define RHRR_CWDAY_SET 0x800
91
+ #define RHRR_SEC_FRACTION_SET 0x1000
92
+ #define RHRR_UNIX_SET 0x2000
93
+ #define RHRR_WNUM0_SET 0x4000
94
+ #define RHRR_WNUM1_SET 0x8000
95
+ #define RHRR_MERIDIAN_SET 0x10000
96
+ #define RHRR_ZONE_SET 0x20000
97
+ #define RHRR_OFFSET_SET 0x40000
98
+ #define RHRR_UNIXM_SET 0x80000
99
+
100
+ #define RHR_HAS_JD(d) (((d)->flags & RHR_HAVE_JD) == RHR_HAVE_JD)
101
+ #define RHR_HAS_CIVIL(d) (((d)->flags & RHR_HAVE_CIVIL) == RHR_HAVE_CIVIL)
102
+
103
+ #define RHR_FILL_JD(d) if (((d)->flags & RHR_HAVE_JD) == 0) { rhrd__civil_to_jd(d); }
104
+ #define RHR_FILL_CIVIL(d) if (((d)->flags & RHR_HAVE_CIVIL) == 0) { rhrd__jd_to_civil(d); }
105
+
106
+ #define RHRDT_FILL_JD(d) if (!((d)->flags & RHR_HAVE_JD)) { rhrdt__civil_to_jd(d); }
107
+ #define RHRDT_FILL_CIVIL(d) if (!((d)->flags & RHR_HAVE_CIVIL)) { rhrdt__jd_to_civil(d); }
108
+ #define RHRDT_FILL_HMS(d) if (!((d)->flags & RHR_HAVE_HMS)) { rhrdt__nanos_to_hms(d); }
109
+ #define RHRDT_FILL_NANOS(d) if (!((d)->flags & RHR_HAVE_NANOS)) { rhrdt__hms_to_nanos(d); }
110
+
111
+ #ifdef RUBY186
112
+ #define RHR_RETURN_RESIZED_STR(s, len) return rb_str_resize(s, len);
113
+ #else
114
+ #define RHR_RETURN_RESIZED_STR(s, len) rb_str_set_len(s, len); return s;
115
+ #endif
116
+
117
+ #define RHR_SPACE_SHIP(x, l, r) if (l < r) { x = -1; } else if (l == r) { x = 0; } else { x = 1; }
118
+
119
+ #define RHR_CHECK_JD(d) if ((d->jd > RHR_JD_MAX) || (d->jd < RHR_JD_MIN)) { rb_raise(rb_eRangeError, "date out of range: jd = %li", d->jd);}
120
+ #define RHR_CHECK_CIVIL(d) if (!rhrd__valid_civil_limits(d->year, d->month, d->day)) { rb_raise(rb_eRangeError, "date out of range: year = %li, month = %hhi, day = %hhi", d->year, d->month, d->day);}
121
+
122
+ #define RHR_CACHED_IV(self, iv) VALUE v = rb_ivar_get(self, iv); if (RTEST(v)) {return v;}
123
+
124
+ typedef struct rhrd_s {
125
+ long jd;
126
+ long year;
127
+ unsigned char month;
128
+ unsigned char day;
129
+ unsigned char flags;
130
+ } rhrd_t;
131
+
132
+ typedef struct rhrdt_s {
133
+ long long nanos; /* Nanoseconds since start of day */
134
+ long jd;
135
+ long year;
136
+ short offset; /* Offset from UTC in minutes */
137
+ unsigned char month;
138
+ unsigned char day;
139
+ unsigned char hour;
140
+ unsigned char minute;
141
+ unsigned char second;
142
+ unsigned char flags;
143
+ } rhrdt_t;
144
+
145
+ const unsigned char rhrd_days_in_month[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
146
+ const long rhrd_cumulative_days_in_month[13] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
147
+ const unsigned char rhrd_yday_to_month[366] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12};
148
+ const unsigned char rhrd_leap_yday_to_month[367] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12};
149
+ const char * rhrd__month_names[13] = {"", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
150
+ const char * rhrd__abbr_month_names[13] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
151
+ const char * rhrd__day_names[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
152
+ const char * rhrd__abbr_day_names[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
153
+ const char rhrd__zone_re_str[] = "\\A(?:gmt|utc?)?[-+]\\d+(?:[,.:]\\d+(?::\\d+)?)?|[[:alpha:].\\s]+(?:standard|daylight)\\s+time\\b|[[:alpha:]]+(?:\\s+dst)?\\b";
154
+ const char rhrd__zone_dst_re_str[] = "\\s+(?:(?:(standard)|daylight)\\s+time|dst)\\z";
155
+ const char rhrd__zone_sign_re_str[] = "\\A(?:gmt|utc?)?(?:(-)|\\+)";
156
+
157
+ VALUE rhrd_class;
158
+ VALUE rhrd_s_class;
159
+ VALUE rhrdt_class;
160
+ VALUE rhrdt_s_class;
161
+ VALUE rhrd_monthnames;
162
+ VALUE rhrd_abbr_monthnames;
163
+ VALUE rhrd_daynames;
164
+ VALUE rhrd_abbr_daynames;
165
+ VALUE rhrd_zone_re;
166
+ VALUE rhrd_zone_dst_re;
167
+ VALUE rhrd_zone_sign_re;
168
+ VALUE rhrd_zones_hash;
169
+ VALUE rhrd_empty_string;
170
+ VALUE rhrd_start_num;
171
+ VALUE rhrd_string_colon;
172
+ VALUE rhrd_re_comma_period;
173
+
174
+ ID rhrd_id_op_array;
175
+ ID rhrd_id_op_gte;
176
+ ID rhrd_id_op_lt;
177
+ ID rhrd_id__parse;
178
+ ID rhrd_id_cwday;
179
+ ID rhrd_id_cweek;
180
+ ID rhrd_id_cwyear;
181
+ ID rhrd_id_downcase;
182
+ ID rhrd_id_getlocal;
183
+ ID rhrd_id_hash;
184
+ ID rhrd_id_include_q;
185
+ ID rhrd_id_length;
186
+ ID rhrd_id_local;
187
+ ID rhrd_id_localtime;
188
+ ID rhrd_id_match;
189
+ ID rhrd_id_now;
190
+ ID rhrd_id_offset;
191
+ ID rhrd_id_slice;
192
+ ID rhrd_id_split;
193
+ ID rhrd_id_sub_b;
194
+ ID rhrd_id_to_i;
195
+ #ifdef RUBY19
196
+ ID rhrd_id_nsec;
197
+ #else
198
+ ID rhrd_id_usec;
199
+ #endif
200
+ ID rhrd_id_utc;
201
+ ID rhrd_id_utc_offset;
202
+
203
+ #ifdef RUBY19
204
+ ID rhrd_id__httpdate;
205
+ ID rhrd_id__iso8601;
206
+ ID rhrd_id__jisx0301;
207
+ ID rhrd_id__rfc2822;
208
+ ID rhrd_id__rfc3339;
209
+ ID rhrd_id__xmlschema;
210
+ #endif
211
+
212
+ VALUE rhrd_sym_cwday;
213
+ VALUE rhrd_sym_cweek;
214
+ VALUE rhrd_sym_cwyear;
215
+ VALUE rhrd_sym_hour;
216
+ #ifdef RUBY19
217
+ VALUE rhrd_sym_leftover;
218
+ #endif
219
+ VALUE rhrd_sym_mday;
220
+ VALUE rhrd_sym_min;
221
+ VALUE rhrd_sym_mon;
222
+ VALUE rhrd_sym_offset;
223
+ VALUE rhrd_sym_sec;
224
+ VALUE rhrd_sym_sec_fraction;
225
+ VALUE rhrd_sym_seconds;
226
+ VALUE rhrd_sym_wday;
227
+ VALUE rhrd_sym_wnum0;
228
+ VALUE rhrd_sym_wnum1;
229
+ VALUE rhrd_sym_yday;
230
+ VALUE rhrd_sym_year;
231
+ VALUE rhrd_sym_zone;
232
+
233
+ static VALUE rhrd_step(int argc, VALUE *argv, VALUE self);
234
+ static VALUE rhrdt_step(int argc, VALUE *argv, VALUE self);
235
+ static VALUE rhrd_to_s(VALUE self);
236
+ static VALUE rhrdt_to_s(VALUE self);
237
+ static VALUE rhrd_s_zone_to_diff(VALUE self, VALUE zone);
238
+ VALUE rhrdt__new_offset(VALUE self, double offset);
239
+ void rhrdt__civil_to_jd(rhrdt_t *d);
240
+ void rhrdt__jd_to_civil(rhrdt_t *date);
241
+ void rhrdt__nanos_to_hms(rhrdt_t *d);
242
+ void rhrdt__hms_to_nanos(rhrdt_t *d);
243
+
244
+ /* C helper methods */
245
+
246
+ /* C % operator can (must in C99) return negative number for negative
247
+ * dividend, this always returns a positive number, similar to ruby. */
248
+ long rhrd__mod(long a, long b) {
249
+ long c;
250
+ c = a % b;
251
+ if (c < 0) {
252
+ c += b;
253
+ }
254
+ return c;
255
+ }
256
+
257
+ /* Same as above but for long long dividend. */
258
+ long rhrd__modll(long long a, long b) {
259
+ long c;
260
+ c = a % b;
261
+ if (c < 0) {
262
+ c += b;
263
+ }
264
+ return c;
265
+ }
266
+
267
+ /* Return 0 if the year, month, day provided are greater than
268
+ * the allowed limits, 1 otherwise. */
269
+ int rhrd__valid_civil_limits(long year, long month, long day) {
270
+ if (year > RHR_YEAR_MAX || year < RHR_YEAR_MIN) {
271
+ return 0;
272
+ }
273
+ else if (year == RHR_YEAR_MAX) {
274
+ if (month > RHR_MONTH_MAX) {
275
+ return 0;
276
+ } else if (month == RHR_MONTH_MAX) {
277
+ if (day > RHR_DAY_MAX) {
278
+ return 0;
279
+ }
280
+ }
281
+ } else if (year == RHR_YEAR_MIN) {
282
+ if (month < RHR_MONTH_MIN) {
283
+ return 0;
284
+ } else if (month == RHR_MONTH_MIN) {
285
+ if (day < RHR_DAY_MIN) {
286
+ return 0;
287
+ }
288
+ }
289
+ }
290
+ return 1;
291
+ }
292
+
293
+ /* Add two numbers, raising a RangeError on
294
+ * overflow. */
295
+ long rhrd__safe_add_long(long a, long b) {
296
+ if ((a > 0 && b > 0 && (a > LONG_MAX - b)) ||
297
+ (a < 0 && b < 0 && (a < LONG_MIN - b))) {
298
+ rb_raise(rb_eRangeError, "addition would overflow");
299
+ }
300
+ return a + b;
301
+ }
302
+
303
+ /* Convert a year, month, day to a julian date. */
304
+ long rhrd__ymd_to_jd(long year, long month, long day) {
305
+ long a;
306
+ if (month <= 2) {
307
+ a = (long)floor((year - 1)/100.0);
308
+ return (long)floor(365.25 * (year + 4715)) + \
309
+ (long)floor(30.6001 * (month + 13)) + \
310
+ day - 1524 + (2 - a + (long)floor(a / 4.0));
311
+ } else {
312
+ a = (long)floor(year/100.0);
313
+ return (long)floor(365.25 * (year + 4716)) + \
314
+ (long)floor(30.6001 * (month + 1)) + \
315
+ day - 1524 + (2 - a + (long)floor(a / 4.0));
316
+ }
317
+ }
318
+
319
+ /* Fill the jd field rhrd_t with the info from the year,
320
+ * month, and day fields. This assumes the year,
321
+ * month, and day fields have already been filled in. */
322
+ void rhrd__civil_to_jd(rhrd_t *d) {
323
+ d->jd = rhrd__ymd_to_jd(d->year, d->month, d->day);
324
+ d->flags |= RHR_HAVE_JD;
325
+ }
326
+
327
+ /* Fill in the year, month, and day fields for an
328
+ * rhrd_t, using the jd field. This assumes the jd
329
+ * field has already been filled in. */
330
+ void rhrd__jd_to_civil(rhrd_t *date) {
331
+ long x, a, b, c, d, e;
332
+ x = (long)floor((date->jd - 1867216.25) / 36524.25);
333
+ a = date->jd + 1 + x - (long)floor(x / 4.0);
334
+ b = a + 1524;
335
+ c = (long)floor((b - 122.1) / 365.25);
336
+ d = (long)floor(365.25 * c);
337
+ e = (long)floor((b - d) / 30.6001);
338
+ date->day = b - d - (long)floor(30.6001 * e);
339
+ if (e <= 13) {
340
+ date->month = e - 1;
341
+ date->year = c - 4716;
342
+ } else {
343
+ date->month = e - 13;
344
+ date->year = c - 4715;
345
+ }
346
+ date->flags |= RHR_HAVE_CIVIL;
347
+ }
348
+
349
+ /* Returns 1 if the given year is a leap year in the Gregorian
350
+ * calendar, 0 if not. */
351
+ int rhrd__leap_year(long year) {
352
+ if (year % 400 == 0) {
353
+ return 1;
354
+ } else if (year % 100 == 0) {
355
+ return 0;
356
+ } else if (year % 4 == 0) {
357
+ return 1;
358
+ } else {
359
+ return 0;
360
+ }
361
+ }
362
+
363
+ /* Check if the year, month, and day given are a valid date
364
+ * in the Gregorian calendar, filling in the appropriate
365
+ * fields in the rhrd_t and returning 1 if so. If the fields
366
+ * given are not a valid date, return 0.
367
+ * This also handles wrap around if the month or day is negative. */
368
+ int rhrd__valid_civil(rhrd_t *d, long year, long month, long day) {
369
+ if (month < 0 && month >= -12) {
370
+ month += 13;
371
+ }
372
+ if (month < 1 || month > 12) {
373
+ return 0;
374
+ }
375
+
376
+ if (day < 0) {
377
+ if (month == 2) {
378
+ day += rhrd__leap_year(year) ? 30 : 29;
379
+ } else {
380
+ day += rhrd_days_in_month[month] + 1;
381
+ }
382
+ }
383
+ if (day < 1 || day > 28) {
384
+ if (day > 31 || day <= 0) {
385
+ return 0;
386
+ } else if (month == 2) {
387
+ if (rhrd__leap_year(year)) {
388
+ if (day > 29) {
389
+ return 0;
390
+ }
391
+ } else if (day > 28) {
392
+ return 0;
393
+ }
394
+ } else if (day > rhrd_days_in_month[month]) {
395
+ return 0;
396
+ }
397
+ }
398
+
399
+ if(!rhrd__valid_civil_limits(year, month, day)) {
400
+ return 0;
401
+ }
402
+
403
+ d->year = year;
404
+ d->month = (unsigned char)month;
405
+ d->day = (unsigned char)day;
406
+ d->flags |= RHR_HAVE_CIVIL;
407
+ return 1;
408
+ }
409
+
410
+ /* Return the number of days in the given month in the given year */
411
+ unsigned char rhrd__days_in_month(long year, unsigned char month) {
412
+ if (month == 2) {
413
+ return rhrd__leap_year(year) ? 29 : 28;
414
+ } else {
415
+ return rhrd_days_in_month[month];
416
+ }
417
+ }
418
+
419
+ /* Add n days to the the given Date object. n can be negative if
420
+ * you want to subtract days from the object. Returns a new ruby
421
+ * Date object. */
422
+ VALUE rhrd__add_days(VALUE self, long n) {
423
+ rhrd_t *d;
424
+ rhrd_t *newd;
425
+ VALUE new;
426
+ long x;
427
+ Data_Get_Struct(self, rhrd_t, d);
428
+ new = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, newd);
429
+
430
+ if(!(RHR_HAS_JD(d))) {
431
+ x = rhrd__safe_add_long(n, (long)(d->day));
432
+ if (x >= 1 && x <= 28) {
433
+ newd->year = d->year;
434
+ newd->month = d->month;
435
+ newd->day = (unsigned char)x;
436
+ RHR_CHECK_CIVIL(newd)
437
+ newd->flags = RHR_HAVE_CIVIL;
438
+ return new;
439
+ }
440
+ RHR_FILL_JD(d)
441
+ }
442
+
443
+ newd->jd = rhrd__safe_add_long(n, d->jd);
444
+ RHR_CHECK_JD(newd)
445
+ newd->flags = RHR_HAVE_JD;
446
+ return new;
447
+ }
448
+
449
+ /* Add n months to the given ruby Date object. n can be negative
450
+ * if you want to subtract months from the object. Returns a new
451
+ * ruby Date object. */
452
+ VALUE rhrd__add_months(VALUE self, long n) {
453
+ rhrd_t *d;
454
+ rhrd_t *newd;
455
+ VALUE new;
456
+ long x;
457
+ Data_Get_Struct(self, rhrd_t, d);
458
+
459
+ new = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, newd);
460
+ RHR_FILL_CIVIL(d)
461
+ n = rhrd__safe_add_long(n, (long)(d->month));
462
+ if(n > 1 && n <= 12) {
463
+ newd->year = d->year;
464
+ newd->month = n;
465
+ } else {
466
+ x = n / 12;
467
+ n = n % 12;
468
+ if (n <= 0) {
469
+ newd->year = d->year + x - 1;
470
+ newd->month = n + 12;
471
+ } else {
472
+ newd->year = d->year + x;
473
+ newd->month = (unsigned char)n;
474
+ }
475
+ }
476
+ x = rhrd__days_in_month(newd->year, newd->month);
477
+ newd->day = (unsigned char)(d->day > x ? x : d->day);
478
+ RHR_CHECK_CIVIL(newd)
479
+ newd->flags = RHR_HAVE_CIVIL;
480
+ return new;
481
+ }
482
+
483
+ /* Return 0 if the given two rhrd_t objects have the
484
+ * same julian or civil dates, -1 if the first is
485
+ * less than the second, or 1 otherwise. */
486
+ long rhrd__spaceship(rhrd_t *d, rhrd_t *o) {
487
+ long diff;
488
+ if (RHR_HAS_JD(d) && RHR_HAS_JD(o)) {
489
+ RHR_SPACE_SHIP(diff, d->jd, o->jd)
490
+ } else if (RHR_HAS_CIVIL(d) && RHR_HAS_CIVIL(o)) {
491
+ RHR_SPACE_SHIP(diff, d->year, o->year)
492
+ if (!diff) {
493
+ RHR_SPACE_SHIP(diff, d->month, o->month)
494
+ if (!diff) {
495
+ RHR_SPACE_SHIP(diff, d->day, o->day)
496
+ }
497
+ }
498
+ } else {
499
+ RHR_FILL_JD(d)
500
+ RHR_FILL_JD(o)
501
+ RHR_SPACE_SHIP(diff, d->jd, o->jd)
502
+ }
503
+ return diff;
504
+ }
505
+
506
+ /* Convert the given cwyear, cweek, and cwday arguments to
507
+ * a julian date. */
508
+ long rhrd__commercial_to_jd(long cwyear, long cweek, long cwday) {
509
+ rhrd_t n;
510
+ memset(&n, 0, sizeof(rhrd_t));
511
+
512
+ n.year = cwyear;
513
+ n.month = 1;
514
+ n.day = 4;
515
+ rhrd__civil_to_jd(&n);
516
+ return n.jd - rhrd__mod(n.jd, 7) + 7 * (cweek - 1) + (cwday - 1);
517
+ }
518
+
519
+ /* Convert the given julian date to a cwday (range: [1-7]). */
520
+ long rhrd__jd_to_cwday(long jd) {
521
+ long day;
522
+ day = (jd + 1) % 7;
523
+ if (day <= 0) {
524
+ day += 7;
525
+ }
526
+ return day;
527
+ }
528
+
529
+ /* Convert the given julian date to a weekday number
530
+ * (range: [0-6], 0 is Sunday). */
531
+ long rhrd__jd_to_wday(long jd) {
532
+ return rhrd__mod(jd + 1, 7);
533
+ }
534
+
535
+
536
+ /* Fill the given rhrd_t with the commercial week
537
+ * information specified by its julian date.
538
+ * Abuses the year, month, and day fields to store
539
+ * cwyear, cweek, and cwday, so it should not be
540
+ * used on a ruby Date object that has its civil
541
+ * date filled in. */
542
+ void rhrd__fill_commercial(rhrd_t *d) {
543
+ long a;
544
+ rhrd_t n;
545
+ memset(&n, 0, sizeof(rhrd_t));
546
+
547
+ n.jd = d->jd - 3;
548
+ rhrd__jd_to_civil(&n);
549
+ a = n.year;
550
+ d->year = d->jd >= rhrd__commercial_to_jd(a + 1, 1, 1) ? a + 1 : a;
551
+ d->month = 1 + (d->jd - rhrd__commercial_to_jd(d->year, 1, 1)) / 7;
552
+ d->day = (unsigned char)rhrd__jd_to_cwday(d->jd);
553
+ }
554
+
555
+ /* Fill in the jd field for the given rhrd_t using the cwyear, cweek,
556
+ * and cwday arguments, if the date is valid, and return 1. If the
557
+ * date is not valid, return 0. This also handles wrap around if
558
+ * the cweek or cwday arguments is negative. */
559
+ int rhrd__valid_commercial(rhrd_t *d, long cwyear, long cweek, long cwday) {
560
+ rhrd_t n;
561
+ memset(&n, 0, sizeof(rhrd_t));
562
+
563
+ if (cwday < 0) {
564
+ if (cwday < -8) {
565
+ return 0;
566
+ }
567
+ cwday += 8;
568
+ }
569
+ if (cweek < 0) {
570
+ if (cweek < -53) {
571
+ return 0;
572
+ }
573
+ n.jd = rhrd__commercial_to_jd(cwyear + 1, 1, 1) + cweek * 7;
574
+ rhrd__fill_commercial(&n);
575
+ if (n.year != cwyear) {
576
+ return 0;
577
+ }
578
+ cweek = n.month;
579
+ memset(&n, 0, sizeof(rhrd_t));
580
+ }
581
+
582
+ n.jd = rhrd__commercial_to_jd(cwyear, cweek, cwday);
583
+ rhrd__fill_commercial(&n);
584
+ if(cwyear != n.year || cweek != n.month || cwday != n.day) {
585
+ return 0;
586
+ }
587
+
588
+ if ((n.jd > RHR_JD_MAX) || (n.jd < RHR_JD_MIN)) {
589
+ return 0;
590
+ }
591
+
592
+ d->jd = n.jd;
593
+ d->flags = RHR_HAVE_JD;
594
+ return 1;
595
+ }
596
+
597
+ /* Return the ordinal day number for the given civil day fields. */
598
+ long rhrd__ordinal_day(long year, unsigned char month, unsigned char day) {
599
+ long yday;
600
+ yday = rhrd_cumulative_days_in_month[month] + day;
601
+ if(month > 2 && rhrd__leap_year(year)) {
602
+ yday += 1;
603
+ }
604
+ return yday;
605
+ }
606
+
607
+ /* Fill in the civil date fields in the rhrd_t with the
608
+ * given ordinal day fields, if they are valid. Returns
609
+ * 1 if the date is valid, 0 if not. This also handles
610
+ * wrap around for a negative yday argument. */
611
+ int rhrd__valid_ordinal(rhrd_t *d, long year, long yday) {
612
+ int leap;
613
+ long month, day;
614
+
615
+ leap = rhrd__leap_year(year);
616
+ if (yday < 0) {
617
+ if (leap) {
618
+ yday += 367;
619
+ } else {
620
+ yday += 366;
621
+ }
622
+ }
623
+ if (yday < 1 || yday > (leap ? 366 : 365)) {
624
+ return 0;
625
+ }
626
+ if (leap) {
627
+ month = rhrd_leap_yday_to_month[yday];
628
+ if (yday > 60) {
629
+ day = yday - rhrd_cumulative_days_in_month[month] - 1;
630
+ } else {
631
+ day = yday - rhrd_cumulative_days_in_month[month];
632
+ }
633
+ } else {
634
+ month = rhrd_yday_to_month[yday];
635
+ day = yday - rhrd_cumulative_days_in_month[month];
636
+ }
637
+
638
+ if(!rhrd__valid_civil_limits(year, month, day)) {
639
+ return 0;
640
+ }
641
+
642
+ d->year = year;
643
+ d->month = (unsigned char)month;
644
+ d->day = (unsigned char)day;
645
+ d->flags |= RHR_HAVE_CIVIL;
646
+ return 1;
647
+ }
648
+
649
+ /* Convert the given jd to the unix time integer
650
+ * for the given day at midnight UTC. */
651
+ long long rhrd__jd_to_unix(long long jd) {
652
+ return (jd - RHR_UNIX_EPOCH) * RHR_SECONDS_PER_DAY;
653
+ }
654
+
655
+ /* Convert the given unix time integer into a
656
+ * julian date, losing any information about
657
+ * fractional days. */
658
+ long rhrd__unix_to_jd(long long t) {
659
+ return t/RHR_SECONDS_PER_DAY + RHR_UNIX_EPOCH;
660
+ }
661
+
662
+ /* Fill the given rhrt_d's jd field based on the
663
+ * current local time. */
664
+ void rhrd__today(rhrd_t * d) {
665
+ VALUE t;
666
+ t = rb_funcall(rb_cTime, rhrd_id_now, 0);
667
+ d->jd = rhrd__unix_to_jd(NUM2LONG(rb_funcall(t, rhrd_id_to_i, 0)) + NUM2LONG(rb_funcall(t, rhrd_id_utc_offset, 0)));
668
+ d->flags |= RHR_HAVE_JD;
669
+ RHR_CHECK_JD(d);
670
+ }
671
+
672
+ /* Return the current year. */
673
+ long rhrd__current_year(void) {
674
+ rhrd_t d;
675
+ memset(&d, 0, sizeof(rhrd_t));
676
+ rhrd__today(&d);
677
+ RHR_FILL_CIVIL(&d);
678
+ return d.year;
679
+ }
680
+
681
+ /* Return the current month. */
682
+ long rhrd__current_month(void) {
683
+ rhrd_t d;
684
+ memset(&d, 0, sizeof(rhrd_t));
685
+ rhrd__today(&d);
686
+ RHR_FILL_CIVIL(&d);
687
+ return d.month;
688
+ }
689
+
690
+ /* Return the julian date of the first day of the
691
+ * given year. */
692
+ long rhrd__yday1_jd(long year) {
693
+ rhrd_t d;
694
+
695
+ memset(&d, 0, sizeof(rhrd_t));
696
+ d.year = year;
697
+ d.month = 1;
698
+ d.day = 1;
699
+ d.flags = RHR_HAVE_CIVIL;
700
+ RHR_FILL_JD(&d);
701
+
702
+ return d.jd;
703
+ }
704
+
705
+ /* Convert the given julian date to a week number given that
706
+ * f is a number representing a week day (Sunday = 0) such that
707
+ * the week 1 of the year starts on first week day of that year
708
+ * (with days before then as week 0).
709
+ * So if January 1st is a Monday and f = 1, January 1-7 would be
710
+ * in week 1. However, if f = 0, January 1-6 would be in week 0,
711
+ * and January 7-13 would be in week 1. */
712
+ long rhrd__jd_to_weeknum(long jd, int f) {
713
+ long yday1_jd;
714
+ rhrd_t d;
715
+
716
+ memset(&d, 0, sizeof(rhrd_t));
717
+ d.jd = jd;
718
+ d.flags = RHR_HAVE_JD;
719
+ RHR_FILL_CIVIL(&d)
720
+
721
+ yday1_jd = rhrd__yday1_jd(d.year) + 6;
722
+ return (jd - (yday1_jd - (rhrd__mod(yday1_jd - f + 1, 7) + 7))) / 7;
723
+ }
724
+
725
+ /* Convert a given week number and week day to a julian day given
726
+ * that f means the same as it does in the prior function. */
727
+ long rhrd__weeknum_to_jd(long year, long week, long wday, int f) {
728
+ long yday1_jd;
729
+ yday1_jd = rhrd__yday1_jd(year) + 6;
730
+ return (yday1_jd - rhrd__mod(yday1_jd - f + 1, 7) - 7) + 7 * week + wday;
731
+ }
732
+
733
+ /* Using the values in the given ruby hash, fill the appropriate date fields
734
+ * in the given rhrd_t. Returns:
735
+ * 0: No errors (i.e. jd and/or year, month, day filled)
736
+ * 1: Bad date information given (e.g. 2009-02-29)
737
+ * -1: No date information given */
738
+ int rhrd__fill_from_hash(rhrd_t *d, VALUE hash) {
739
+ long year = 0;
740
+ long month = 0;
741
+ long day = 0;
742
+ long yday = 0;
743
+ long wday = 0;
744
+ long cwyear = 0;
745
+ long cweek = 0;
746
+ long cwday = 0;
747
+ VALUE ryear, rmonth, rday, ryday, rwday, rcwyear, rcweek, rcwday, runix, rwnum0, rwnum1;
748
+
749
+ if (!RTEST(hash)) {
750
+ return -1;
751
+ }
752
+ runix = rb_hash_aref(hash, rhrd_sym_seconds);
753
+ if (RTEST(runix)) {
754
+ d->jd = rhrd__unix_to_jd(NUM2LL(runix));
755
+ d->flags |= RHR_HAVE_JD;
756
+ return 0;
757
+ }
758
+
759
+ ryear = rb_hash_aref(hash, rhrd_sym_year);
760
+ rmonth = rb_hash_aref(hash, rhrd_sym_mon);
761
+ rday = rb_hash_aref(hash, rhrd_sym_mday);
762
+ ryday = rb_hash_aref(hash, rhrd_sym_yday);
763
+ rwday = rb_hash_aref(hash, rhrd_sym_wday);
764
+ rcwyear = rb_hash_aref(hash, rhrd_sym_cwyear);
765
+ rcweek = rb_hash_aref(hash, rhrd_sym_cweek);
766
+ rcwday = rb_hash_aref(hash, rhrd_sym_cwday);
767
+ rwnum0 = rb_hash_aref(hash, rhrd_sym_wnum0);
768
+ rwnum1 = rb_hash_aref(hash, rhrd_sym_wnum1);
769
+
770
+ if (RTEST(ryear)) {
771
+ year = NUM2LONG(ryear);
772
+ if (RTEST(ryday)) {
773
+ yday = NUM2LONG(ryday);
774
+ } else if (RTEST(rmonth) && RTEST(rday)) {
775
+ month = NUM2LONG(rmonth);
776
+ day = NUM2LONG(rday);
777
+ } else if (RTEST(rwday)) {
778
+ d->jd = rhrd__yday1_jd(year);
779
+ d->flags |= RHR_HAVE_JD;
780
+ rhrd__fill_commercial(d);
781
+ if(!rhrd__valid_commercial(d, d->year, 1, NUM2LONG(rwday))) {
782
+ return 1;
783
+ }
784
+ d->flags &= ~RHR_HAVE_CIVIL;
785
+ return 0;
786
+ } else if (RTEST(rwnum0)) {
787
+ d->jd = rhrd__weeknum_to_jd(year, NUM2LONG(rwnum0), RTEST(rwday) ? NUM2LONG(rwday) : (RTEST(rcwday) ? rhrd__mod(NUM2LONG(rcwday), 7) : 0), 0);
788
+ d->flags |= RHR_HAVE_JD;
789
+ return 0;
790
+ } else if (RTEST(rwnum1)) {
791
+ d->jd = rhrd__weeknum_to_jd(year, NUM2LONG(rwnum1), RTEST(rwday) ? rhrd__mod(NUM2LONG(rwday) - 1, 7) : (RTEST(rcwday) ? rhrd__mod(NUM2LONG(rcwday) - 1, 7) : 0), 1);
792
+ d->flags |= RHR_HAVE_JD;
793
+ return 0;
794
+ } else {
795
+ month = RTEST(rmonth) ? NUM2LONG(rmonth) : 1;
796
+ day = RTEST(rday) ? NUM2LONG(rday) : 1;
797
+ }
798
+ } else if (RTEST(rmonth)) {
799
+ year = rhrd__current_year();
800
+ month = NUM2LONG(rmonth);
801
+ day = RTEST(rday) ? NUM2LONG(rday) : 1;
802
+ } else if (RTEST(rday)) {
803
+ year = rhrd__current_year();
804
+ month = rhrd__current_month();
805
+ day = NUM2LONG(rday);
806
+ } else if (RTEST(ryday)) {
807
+ year = rhrd__current_year();
808
+ yday = NUM2LONG(ryday);
809
+ } else if (RTEST(rwnum0)) {
810
+ d->jd = rhrd__weeknum_to_jd(rhrd__current_year(), NUM2LONG(rwnum0), RTEST(rwday) ? NUM2LONG(rwday) : (RTEST(rcwday) ? rhrd__mod(NUM2LONG(rcwday), 7) : 0), 0);
811
+ d->flags |= RHR_HAVE_JD;
812
+ return 0;
813
+ } else if (RTEST(rwnum1)) {
814
+ d->jd = rhrd__weeknum_to_jd(rhrd__current_year(), NUM2LONG(rwnum1), RTEST(rwday) ? rhrd__mod(NUM2LONG(rwday) - 1, 7) : (RTEST(rcwday) ? rhrd__mod(NUM2LONG(rcwday) - 1, 7) : 0), 1);
815
+ d->flags |= RHR_HAVE_JD;
816
+ return 0;
817
+ } else if (RTEST(rcwyear)) {
818
+ cwyear = NUM2LONG(rcwyear);
819
+ cweek = RTEST(rcweek) ? NUM2LONG(rcweek) : 1;
820
+ cwday = RTEST(rcwday) ? NUM2LONG(rcwday) : 1;
821
+ } else if (RTEST(rcweek)) {
822
+ cwyear = rhrd__current_year();
823
+ cweek = NUM2LONG(rcweek);
824
+ cwday = RTEST(rcwday) ? NUM2LONG(rcwday) : 1;
825
+ } else if (RTEST(rcwday)) {
826
+ cwyear = rhrd__current_year();
827
+ cweek = 1;
828
+ cwday = NUM2LONG(rcwday);
829
+ } else if (RTEST(rwday)) {
830
+ wday = NUM2LONG(rwday);
831
+ rhrd__today(d);
832
+ d->jd += wday - rhrd__jd_to_wday(d->jd);
833
+ d->flags &= ~RHR_HAVE_CIVIL;
834
+ return 0;
835
+ } else {
836
+ return -1;
837
+ }
838
+ if (yday && rhrd__valid_ordinal(d, year, yday)) {
839
+ return 0;
840
+ } else if (cweek && cwday && rhrd__valid_commercial(d, cwyear, cweek, cwday)) {
841
+ return 0;
842
+ } else if (!rhrd__valid_civil(d, year, month, day)) {
843
+ return 1;
844
+ }
845
+
846
+ return 0;
847
+ }
848
+
849
+ /* Returns a new ruby object filled with information from
850
+ * the given hash, or raises an error if the given hash
851
+ * did not contain valid date information. */
852
+ VALUE rhrd__from_hash(VALUE hash) {
853
+ rhrd_t *d;
854
+ VALUE rd = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, d);
855
+ if(rhrd__fill_from_hash(d, hash)) {
856
+ rb_raise(rb_eArgError, "invalid date");
857
+ } else {
858
+ RHR_FILL_JD(d)
859
+ RHR_CHECK_JD(d)
860
+ return rd;
861
+ }
862
+ }
863
+
864
+ /* Return a ruby string using the information in the given
865
+ * rhrdt_t and the given format string information. */
866
+ VALUE rhrd__strftime(rhrdt_t *d, const char * fmt, int fmt_len) {
867
+ int i;
868
+ int cp = 0;
869
+ int str_len = 128;
870
+ int str_lim = 64;
871
+ int mod = 0;
872
+ char * str;
873
+ char c;
874
+ VALUE s;
875
+ rhrd_t cd;
876
+
877
+ memset(&cd, 0, sizeof(rhrd_t));
878
+ cd.jd = d->jd;
879
+ cd.flags = RHR_HAVE_JD;
880
+ rhrd__fill_commercial(&cd);
881
+
882
+ s = rb_str_buf_new(str_len);
883
+ str = RSTRING_PTR(s);
884
+ for (i = 0; i < fmt_len; i++) {
885
+ if (cp >= str_lim) {
886
+ str_len *= 2;
887
+ str_lim = str_len - 64;
888
+ #ifndef RUBY186
889
+ rb_str_set_len(s, cp);
890
+ #endif
891
+ s = rb_str_resize(s, str_len);
892
+ str = RSTRING_PTR(s);
893
+ }
894
+ c = fmt[i];
895
+
896
+ if (mod) {
897
+ switch (c) {
898
+ case 'a':
899
+ cp += sprintf(str + cp, "%s", rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)]);
900
+ break;
901
+ case 'A':
902
+ cp += sprintf(str + cp, "%s", rhrd__day_names[rhrd__jd_to_wday(d->jd)]);
903
+ break;
904
+ case 'h':
905
+ case 'b':
906
+ cp += sprintf(str + cp, "%s", rhrd__abbr_month_names[d->month]);
907
+ break;
908
+ case 'B':
909
+ cp += sprintf(str + cp, "%s", rhrd__month_names[d->month]);
910
+ break;
911
+ case 'c':
912
+ cp += sprintf(str + cp, "%s %s %2hhi %02hhi:%02hhi:%02hhi %04li", rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)], rhrd__abbr_month_names[d->month], d->day, d->hour, d->minute, d->second, d->year);
913
+ break;
914
+ case 'C':
915
+ cp += sprintf(str + cp, "%02li", d->year / 100);
916
+ break;
917
+ case 'd':
918
+ cp += sprintf(str + cp, "%02hhi", d->day);
919
+ break;
920
+ case 'e':
921
+ cp += sprintf(str + cp, "%2hhi", d->day);
922
+ break;
923
+ case 'F':
924
+ cp += sprintf(str + cp, "%04li-%02hhi-%02hhi", d->year, d->month, d->day);
925
+ break;
926
+ case 'g':
927
+ cp += sprintf(str + cp, "%02li", cd.year % 100);
928
+ break;
929
+ case 'G':
930
+ cp += sprintf(str + cp, "%04li", cd.year);
931
+ break;
932
+ case 'H':
933
+ cp += sprintf(str + cp, "%02hhi", d->hour);
934
+ break;
935
+ case 'I':
936
+ cp += sprintf(str + cp, "%02hhi", (d->hour == 12 || d->hour == 0) ? 12 : d->hour % 12);
937
+ break;
938
+ case 'j':
939
+ cp += sprintf(str + cp, "%03li", rhrd__ordinal_day(d->year, d->month, d->day));
940
+ break;
941
+ case 'k':
942
+ cp += sprintf(str + cp, "%2hhi", d->hour);
943
+ break;
944
+ case 'l':
945
+ cp += sprintf(str + cp, "%2hhi", (d->hour == 12 || d->hour == 0) ? 12 : d->hour % 12);
946
+ break;
947
+ case 'L':
948
+ cp += sprintf(str + cp, "%03" PRId64, (d->nanos % RHR_NANOS_PER_SECOND)/1000000);
949
+ break;
950
+ case 'm':
951
+ cp += sprintf(str + cp, "%02hhi", d->month);
952
+ break;
953
+ case 'M':
954
+ cp += sprintf(str + cp, "%02hhi", d->minute);
955
+ break;
956
+ case 'N':
957
+ cp += sprintf(str + cp, "%09" PRId64, (d->nanos % RHR_NANOS_PER_SECOND));
958
+ break;
959
+ case 'n':
960
+ cp += sprintf(str + cp, "\n");
961
+ break;
962
+ case 'p':
963
+ cp += sprintf(str + cp, d->hour >= 12 ? "PM" : "AM");
964
+ break;
965
+ case 'P':
966
+ cp += sprintf(str + cp, d->hour >= 12 ? "pm" : "am");
967
+ break;
968
+ case 'Q':
969
+ cp += sprintf(str + cp, "%" PRId64, rhrd__jd_to_unix(d->jd) * 1000 + d->nanos/RHR_NANOS_PER_MILLISECOND - d->offset * 60000);
970
+ break;
971
+ case 'r':
972
+ cp += sprintf(str + cp, "%2hhi:%02hhi:%02hhi %s", (d->hour == 12 || d->hour == 0) ? 12 : d->hour % 12, d->minute, d->second, d->hour >= 12 ? "PM" : "AM");
973
+ break;
974
+ case 'R':
975
+ cp += sprintf(str + cp, "%02hhi:%02hhi", d->hour, d->minute);
976
+ break;
977
+ case 's':
978
+ cp += sprintf(str + cp, "%" PRId64, rhrd__jd_to_unix(d->jd) + d->nanos/RHR_NANOS_PER_SECOND - d->offset * 60);
979
+ break;
980
+ case 'S':
981
+ cp += sprintf(str + cp, "%02hhi", d->second);
982
+ break;
983
+ case 't':
984
+ cp += sprintf(str + cp, "\t");
985
+ break;
986
+ case 'X':
987
+ case 'T':
988
+ cp += sprintf(str + cp, "%02hhi:%02hhi:%02hhi", d->hour, d->minute, d->second);
989
+ break;
990
+ case 'u':
991
+ cp += sprintf(str + cp, "%hhi", cd.day);
992
+ break;
993
+ case 'U':
994
+ cp += sprintf(str + cp, "%li", rhrd__jd_to_weeknum(d->jd, 0));
995
+ break;
996
+ case 'v':
997
+ cp += sprintf(str + cp, "%2hhi-%s-%04li", d->day, rhrd__abbr_month_names[d->month], d->year);
998
+ break;
999
+ case 'V':
1000
+ cp += sprintf(str + cp, "%02hhi", cd.month);
1001
+ break;
1002
+ case 'w':
1003
+ cp += sprintf(str + cp, "%li", rhrd__jd_to_wday(d->jd));
1004
+ break;
1005
+ case 'W':
1006
+ cp += sprintf(str + cp, "%li", rhrd__jd_to_weeknum(d->jd, 1));
1007
+ break;
1008
+ case 'D':
1009
+ case 'x':
1010
+ cp += sprintf(str + cp, "%02hhi/%02hhi/%02li", d->month, d->day, d->year % 100);
1011
+ break;
1012
+ case 'y':
1013
+ cp += sprintf(str + cp, "%02li", d->year % 100);
1014
+ break;
1015
+ case 'Y':
1016
+ cp += sprintf(str + cp, "%04li", d->year);
1017
+ break;
1018
+ case 'z':
1019
+ cp += sprintf(str + cp, "%+03i%02i", d->offset/60, abs(d->offset % 60));
1020
+ break;
1021
+ case 'Z':
1022
+ cp += sprintf(str + cp, "%+03i:%02i", d->offset/60, abs(d->offset % 60));
1023
+ break;
1024
+ case '+':
1025
+ cp += sprintf(str + cp, "%s %s %2hhi %02hhi:%02hhi:%02hhi %+03i:%02i %04li", rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)], rhrd__abbr_month_names[d->month], d->day, d->hour, d->minute, d->second, d->offset/60, abs(d->offset % 60), d->year);
1026
+ break;
1027
+ default:
1028
+ str[cp] = c;
1029
+ cp += 1;
1030
+ }
1031
+ mod = 0;
1032
+ } else {
1033
+ if (c == '%') {
1034
+ mod = 1;
1035
+ } else {
1036
+ str[cp] = c;
1037
+ cp += 1;
1038
+ }
1039
+ }
1040
+ }
1041
+
1042
+ RHR_RETURN_RESIZED_STR(s, cp)
1043
+ }
1044
+
1045
+ /* Return a ruby hash using the given ruby string and the format
1046
+ * string information. */
1047
+ VALUE rhrd__strptime(VALUE rstr, const char *fmt_str, long fmt_len) {
1048
+ char * str;
1049
+ long len;
1050
+ long year = 0;
1051
+ long month = 0;
1052
+ long day = 0;
1053
+ long yday = 0;
1054
+ long wday = 0;
1055
+ long cwyear = 0;
1056
+ long cweek = 0;
1057
+ long cwday = 0;
1058
+ long century = 0;
1059
+ long hour = 0;
1060
+ long minute = 0;
1061
+ long second = 0;
1062
+ long long seconds = 0;
1063
+ long long milliseconds = 0;
1064
+ long sec_fraction_num = 0;
1065
+ double sec_fraction = 0.0;
1066
+ long meridian = 0;
1067
+ long state = 0;
1068
+ long mod = 0;
1069
+ long pos = 0;
1070
+ long wnum0 = 0;
1071
+ long wnum1 = 0;
1072
+ long i;
1073
+ long fmt_pos;
1074
+ int scan_len;
1075
+ VALUE zone = Qnil;
1076
+ VALUE hash;
1077
+ rstr = rb_str_to_str(rstr);
1078
+ str = RSTRING_PTR(rstr);
1079
+ len = RSTRING_LEN(rstr);
1080
+
1081
+ for (fmt_pos = 0; fmt_pos < fmt_len; fmt_pos++) {
1082
+ if (pos >= len) {
1083
+ #ifdef DEBUG
1084
+ printf("format longer than input\n");
1085
+ #endif
1086
+ return Qnil;
1087
+ }
1088
+ if (mod) {
1089
+ scan_len = 0;
1090
+ switch (fmt_str[fmt_pos]) {
1091
+ case 'a':
1092
+ #define RHR_PARSE_a if (pos + 3 > len) {\
1093
+ return Qnil;\
1094
+ }\
1095
+ for(i = 0; i < 7; i++) {\
1096
+ if(strncasecmp(str + pos, rhrd__abbr_day_names[i], 3) == 0) {\
1097
+ wday = i;\
1098
+ break;\
1099
+ }\
1100
+ }\
1101
+ if (i >= 7) {\
1102
+ return Qnil;\
1103
+ }\
1104
+ scan_len = 3;\
1105
+ state |= RHRR_WDAY_SET;
1106
+ RHR_PARSE_a
1107
+ break;
1108
+ case 'A':
1109
+ for(i = 0; i < 7; i++) {
1110
+ scan_len = strlen(rhrd__day_names[i]);
1111
+ if (pos + scan_len <= len) {
1112
+ if(strncasecmp(str + pos, rhrd__day_names[i], scan_len) == 0) {
1113
+ wday = i;
1114
+ break;
1115
+ }
1116
+ }
1117
+ }
1118
+ if (i >= 7) {
1119
+ return Qnil;
1120
+ }
1121
+ state |= RHRR_WDAY_SET;
1122
+ break;
1123
+ case 'h':
1124
+ case 'b':
1125
+ #define RHR_PARSE_b if (pos + 3 > len) {\
1126
+ return Qnil;\
1127
+ }\
1128
+ for(i = 1; i < 13; i++) {\
1129
+ if(strncasecmp(str + pos, rhrd__abbr_month_names[i], 3) == 0) {\
1130
+ month = i;\
1131
+ break;\
1132
+ }\
1133
+ }\
1134
+ if (i >= 13) {\
1135
+ return Qnil;\
1136
+ }\
1137
+ scan_len = 3;\
1138
+ state |= RHRR_MONTH_SET;
1139
+ RHR_PARSE_b
1140
+ break;
1141
+ case 'B':
1142
+ for(i = 1; i < 13; i++) {
1143
+ scan_len = strlen(rhrd__month_names[i]);
1144
+ if (pos + scan_len <= len) {
1145
+ if(strncasecmp(str + pos, rhrd__month_names[i], scan_len) == 0) {
1146
+ month = i;
1147
+ break;
1148
+ }
1149
+ }
1150
+ }
1151
+ if (i >= 13) {
1152
+ return Qnil;
1153
+ }
1154
+ state |= RHRR_MONTH_SET;
1155
+ break;
1156
+ case 'C':
1157
+ if (sscanf(str + pos, "%2ld%n", &century, &scan_len) != 1) {
1158
+ return Qnil;
1159
+ }
1160
+ state |= RHRR_CENTURY_SET;
1161
+ break;
1162
+ case 'e':
1163
+ case 'd':
1164
+ #define RHR_PARSE_d if (sscanf(str + pos, "%02ld%n", &day, &scan_len) != 1) {\
1165
+ return Qnil;\
1166
+ }\
1167
+ if (day < 1 || day > 31) {\
1168
+ return Qnil;\
1169
+ }\
1170
+ state |= RHRR_DAY_SET;
1171
+ RHR_PARSE_d
1172
+ break;
1173
+ case 'g':
1174
+ if (sscanf(str + pos, "%02ld%n", &cwyear, &scan_len) != 1) {
1175
+ return Qnil;
1176
+ }
1177
+ if (!(state & RHRR_CENTURY_SET)) {
1178
+ century = cwyear < 69 ? 20 : 19;
1179
+ }
1180
+ state |= RHRR_CWYEAR_SET | RHRR_CENTURY_SET;
1181
+ break;
1182
+ case 'G':
1183
+ if (sscanf(str + pos, "%ld%n", &cwyear, &scan_len) != 1) {
1184
+ return Qnil;
1185
+ }
1186
+ state |= RHRR_CWYEAR_SET + RHRR_CENTURY_SET;
1187
+ break;
1188
+ case 'k':
1189
+ case 'H':
1190
+ #define RHR_PARSE_H if (sscanf(str + pos, "%02ld%n", &hour, &scan_len) != 1) {\
1191
+ return Qnil;\
1192
+ }\
1193
+ if (hour < 0 || hour > 24) {\
1194
+ return Qnil;\
1195
+ }\
1196
+ state |= RHRR_HOUR_SET;
1197
+ RHR_PARSE_H
1198
+ break;
1199
+ case 'l':
1200
+ case 'I':
1201
+ #define RHR_PARSE_I if (sscanf(str + pos, "%02ld%n", &hour, &scan_len) != 1) {\
1202
+ return Qnil;\
1203
+ }\
1204
+ if (hour < 1 || hour > 12) {\
1205
+ return Qnil;\
1206
+ }\
1207
+ state |= RHRR_HOUR_SET;
1208
+ RHR_PARSE_I
1209
+ break;
1210
+ case 'j':
1211
+ if (sscanf(str + pos, "%03ld%n", &yday, &scan_len) != 1) {
1212
+ return Qnil;
1213
+ }
1214
+ if (yday < 1 || yday > 366) {
1215
+ return Qnil;
1216
+ }
1217
+ state |= RHRR_YDAY_SET;
1218
+ break;
1219
+ case 'L':
1220
+ if (sscanf(str + pos, "%03ld%n", &sec_fraction_num, &scan_len) != 1) {
1221
+ return Qnil;
1222
+ }
1223
+ sec_fraction = sec_fraction_num/pow(10, scan_len);
1224
+ state |= RHRR_SEC_FRACTION_SET;
1225
+ break;
1226
+ case 'm':
1227
+ #define RHR_PARSE_m if (sscanf(str + pos, "%02ld%n", &month, &scan_len) != 1) {\
1228
+ return Qnil;\
1229
+ }\
1230
+ if (month < 1 || month > 12) {\
1231
+ return Qnil;\
1232
+ }\
1233
+ state |= RHRR_MONTH_SET;
1234
+ RHR_PARSE_m
1235
+ break;
1236
+ case 'M':
1237
+ #define RHR_PARSE_M if (sscanf(str + pos, "%02ld%n", &minute, &scan_len) != 1) {\
1238
+ return Qnil;\
1239
+ }\
1240
+ if (minute < 0 || minute > 59) {\
1241
+ return Qnil;\
1242
+ }\
1243
+ state |= RHRR_MINUTE_SET;
1244
+ RHR_PARSE_M
1245
+ break;
1246
+ case 'n':
1247
+ if (str[pos] != '\n') {
1248
+ return Qnil;
1249
+ }
1250
+ pos++;
1251
+ break;
1252
+ case 'N':
1253
+ if (sscanf(str + pos, "%09ld%n", &sec_fraction_num, &scan_len) != 1) {
1254
+ return Qnil;
1255
+ }
1256
+ sec_fraction = sec_fraction_num/pow(10, scan_len);
1257
+ state |= RHRR_SEC_FRACTION_SET;
1258
+ break;
1259
+ case 'P':
1260
+ case 'p':
1261
+ #define RHR_PARSE_p if (!(str[pos] == 'a' || str[pos] == 'A' ||\
1262
+ str[pos] == 'p' || str[pos] == 'P')) {\
1263
+ return Qnil;\
1264
+ } else {\
1265
+ state |= RHRR_MERIDIAN_SET;\
1266
+ meridian = str[pos] == 'p' || str[pos] == 'P';\
1267
+ }\
1268
+ if (pos + 2 <= len) {\
1269
+ if (!(str[pos + 1] == 'M' || str[pos + 1] == 'm')) {\
1270
+ if (pos + 4 <= len) {\
1271
+ if (!((str[pos + 2] == 'M' || str[pos + 2] == 'm') &&\
1272
+ str[pos + 1] == '.' && str[pos + 3] == '.')) {\
1273
+ return Qnil;\
1274
+ }\
1275
+ } else {\
1276
+ return Qnil;\
1277
+ }\
1278
+ }\
1279
+ } else {\
1280
+ return Qnil;\
1281
+ }
1282
+ RHR_PARSE_p
1283
+ break;
1284
+ case 'Q':
1285
+ if (sscanf(str + pos, "%" SCNd64 "%n", &milliseconds, &scan_len) != 1) {
1286
+ return Qnil;
1287
+ }
1288
+ state |= RHRR_UNIXM_SET;
1289
+ break;
1290
+ case 's':
1291
+ if (sscanf(str + pos, "%" SCNd64 "%n", &seconds, &scan_len) != 1) {
1292
+ return Qnil;
1293
+ }
1294
+ state |= RHRR_UNIX_SET;
1295
+ break;
1296
+ case 'S':
1297
+ #define RHR_PARSE_S if (sscanf(str + pos, "%02ld%n", &second, &scan_len) != 1) {\
1298
+ return Qnil;\
1299
+ }\
1300
+ if (second < 0 || second > 59) {\
1301
+ return Qnil;\
1302
+ }\
1303
+ state |= RHRR_SECOND_SET;
1304
+ RHR_PARSE_S
1305
+ break;
1306
+ case 't':
1307
+ if (str[pos] != '\t') {
1308
+ return Qnil;
1309
+ }
1310
+ pos++;
1311
+ break;
1312
+ case 'u':
1313
+ if (sscanf(str + pos, "%02ld%n", &cwday, &scan_len) != 1) {
1314
+ return Qnil;
1315
+ }
1316
+ if (cwday < 1 || cwday > 7) {
1317
+ return Qnil;
1318
+ }
1319
+ state |= RHRR_CWDAY_SET;
1320
+ break;
1321
+ case 'U':
1322
+ if (sscanf(str + pos, "%02ld%n", &wnum0, &scan_len) != 1) {
1323
+ return Qnil;
1324
+ }
1325
+ if (wnum0 < 0 || wnum0 > 53) {
1326
+ return Qnil;
1327
+ }
1328
+ state |= RHRR_WNUM0_SET;
1329
+ break;
1330
+ case 'V':
1331
+ if (sscanf(str + pos, "%02ld%n", &cweek, &scan_len) != 1) {
1332
+ return Qnil;
1333
+ }
1334
+ if (cweek < 1 || cweek > 53) {
1335
+ return Qnil;
1336
+ }
1337
+ state |= RHRR_CWEEK_SET;
1338
+ break;
1339
+ case 'w':
1340
+ if (sscanf(str + pos, "%02ld%n", &wday, &scan_len) != 1) {
1341
+ return Qnil;
1342
+ }
1343
+ if (wday < 0 || wday > 6) {
1344
+ return Qnil;
1345
+ }
1346
+ state |= RHRR_WDAY_SET;
1347
+ break;
1348
+ case 'W':
1349
+ if (sscanf(str + pos, "%02ld%n", &wnum1, &scan_len) != 1) {
1350
+ return Qnil;
1351
+ }
1352
+ if (wnum1 < 0 || wnum1 > 53) {
1353
+ return Qnil;
1354
+ }
1355
+ state |= RHRR_WNUM1_SET;
1356
+ break;
1357
+ case 'y':
1358
+ #define RHR_PARSE_y if (sscanf(str + pos, "%02ld%n", &year, &scan_len) != 1) {\
1359
+ return Qnil;\
1360
+ }\
1361
+ if (!(state & RHRR_CENTURY_SET)) {\
1362
+ century = year < 69 ? 20 : 19;\
1363
+ }\
1364
+ state |= RHRR_YEAR_SET | RHRR_CENTURY_SET;
1365
+ RHR_PARSE_y
1366
+ break;
1367
+ case 'Y':
1368
+ #define RHR_PARSE_Y if (sscanf(str + pos, "%ld%n", &year, &scan_len) != 1) {\
1369
+ return Qnil;\
1370
+ }\
1371
+ state |= RHRR_YEAR_SET + RHRR_CENTURY_SET;
1372
+ RHR_PARSE_Y
1373
+ break;
1374
+ case 'z':
1375
+ case 'Z':
1376
+ #define RHR_PARSE_Z zone = rb_funcall(rhrd_zone_re, rhrd_id_match, 1, rb_funcall(rstr, rhrd_id_slice, 2, LONG2NUM(pos), LONG2NUM(len)));\
1377
+ if (RTEST(zone)) {\
1378
+ zone = rb_funcall(zone, rhrd_id_op_array, 1, LONG2NUM(0));\
1379
+ scan_len = NUM2LONG(rb_funcall(zone, rhrd_id_length, 0));\
1380
+ } else {\
1381
+ return Qnil;\
1382
+ }
1383
+ RHR_PARSE_Z
1384
+ break;
1385
+ /* Composite formats */
1386
+ #define RHR_PARSE_sep(x) pos += scan_len;\
1387
+ scan_len = 0;\
1388
+ if (str[pos] != x) {\
1389
+ return Qnil;\
1390
+ }\
1391
+ pos++;
1392
+ case 'c':
1393
+ RHR_PARSE_a
1394
+ RHR_PARSE_sep(' ')
1395
+ RHR_PARSE_b
1396
+ RHR_PARSE_sep(' ')
1397
+ RHR_PARSE_d
1398
+ RHR_PARSE_sep(' ')
1399
+ RHR_PARSE_H
1400
+ RHR_PARSE_sep(':')
1401
+ RHR_PARSE_M
1402
+ RHR_PARSE_sep(':')
1403
+ RHR_PARSE_S
1404
+ RHR_PARSE_sep(' ')
1405
+ RHR_PARSE_Y
1406
+ break;
1407
+ case 'x':
1408
+ case 'D':
1409
+ RHR_PARSE_m
1410
+ RHR_PARSE_sep('/')
1411
+ RHR_PARSE_d
1412
+ RHR_PARSE_sep('/')
1413
+ RHR_PARSE_y
1414
+ break;
1415
+ case 'F':
1416
+ RHR_PARSE_Y
1417
+ RHR_PARSE_sep('-')
1418
+ RHR_PARSE_m
1419
+ RHR_PARSE_sep('-')
1420
+ RHR_PARSE_d
1421
+ break;
1422
+ case 'r':
1423
+ RHR_PARSE_I
1424
+ RHR_PARSE_sep(':')
1425
+ RHR_PARSE_M
1426
+ RHR_PARSE_sep(':')
1427
+ RHR_PARSE_S
1428
+ RHR_PARSE_sep(' ')
1429
+ RHR_PARSE_p
1430
+ break;
1431
+ case 'R':
1432
+ RHR_PARSE_H
1433
+ RHR_PARSE_sep(':')
1434
+ RHR_PARSE_M
1435
+ break;
1436
+ case 'X':
1437
+ case 'T':
1438
+ RHR_PARSE_H
1439
+ RHR_PARSE_sep(':')
1440
+ RHR_PARSE_M
1441
+ RHR_PARSE_sep(':')
1442
+ RHR_PARSE_S
1443
+ break;
1444
+ case 'v':
1445
+ RHR_PARSE_d
1446
+ RHR_PARSE_sep('-')
1447
+ RHR_PARSE_b
1448
+ RHR_PARSE_sep('-')
1449
+ RHR_PARSE_Y
1450
+ break;
1451
+ case '+':
1452
+ RHR_PARSE_a
1453
+ RHR_PARSE_sep(' ')
1454
+ RHR_PARSE_b
1455
+ RHR_PARSE_sep(' ')
1456
+ RHR_PARSE_d
1457
+ RHR_PARSE_sep(' ')
1458
+ RHR_PARSE_H
1459
+ RHR_PARSE_sep(':')
1460
+ RHR_PARSE_M
1461
+ RHR_PARSE_sep(':')
1462
+ RHR_PARSE_S
1463
+ RHR_PARSE_sep(' ')
1464
+ RHR_PARSE_Z
1465
+ RHR_PARSE_sep(' ')
1466
+ RHR_PARSE_Y
1467
+ break;
1468
+ default:
1469
+ if (str[pos] != fmt_str[fmt_pos]) {
1470
+ return Qnil;
1471
+ }
1472
+ pos++;
1473
+ break;
1474
+ }
1475
+ pos += scan_len;
1476
+ mod = 0;
1477
+ } else if (fmt_str[fmt_pos] == '%') {
1478
+ mod = 1;
1479
+ } else {
1480
+ pos++;
1481
+ }
1482
+ }
1483
+
1484
+ hash = rb_hash_new();
1485
+ if(state & RHRR_YEAR_SET) {
1486
+ if (state & RHRR_CENTURY_SET && year < 100) {
1487
+ year += century * 100;
1488
+ }
1489
+ rb_hash_aset(hash, rhrd_sym_year, LONG2NUM(year));
1490
+ }
1491
+ if(state & RHRR_MONTH_SET) {
1492
+ rb_hash_aset(hash, rhrd_sym_mon, LONG2NUM(month));
1493
+ }
1494
+ if(state & RHRR_DAY_SET) {
1495
+ rb_hash_aset(hash, rhrd_sym_mday, LONG2NUM(day));
1496
+ }
1497
+ if(state & RHRR_YDAY_SET) {
1498
+ rb_hash_aset(hash, rhrd_sym_yday, LONG2NUM(yday));
1499
+ }
1500
+ if(state & RHRR_WDAY_SET) {
1501
+ rb_hash_aset(hash, rhrd_sym_wday, LONG2NUM(wday));
1502
+ }
1503
+ if(state & RHRR_CWYEAR_SET) {
1504
+ if (state & RHRR_CENTURY_SET && cwyear < 100) {
1505
+ cwyear += century * 100;
1506
+ }
1507
+ rb_hash_aset(hash, rhrd_sym_cwyear, LONG2NUM(cwyear));
1508
+ }
1509
+ if(state & RHRR_CWEEK_SET) {
1510
+ rb_hash_aset(hash, rhrd_sym_cweek, LONG2NUM(cweek));
1511
+ }
1512
+ if(state & RHRR_CWDAY_SET) {
1513
+ rb_hash_aset(hash, rhrd_sym_cwday, LONG2NUM(cwday));
1514
+ }
1515
+ if(state & RHRR_HOUR_SET) {
1516
+ if (state & RHRR_MERIDIAN_SET) {
1517
+ if (meridian) {
1518
+ if (hour < 12) {
1519
+ hour += 12;
1520
+ }
1521
+ }
1522
+ else if (hour == 12) {
1523
+ hour = 0;
1524
+ }
1525
+ }
1526
+ rb_hash_aset(hash, rhrd_sym_hour, LONG2NUM(hour));
1527
+ }
1528
+ if(state & RHRR_MINUTE_SET) {
1529
+ rb_hash_aset(hash, rhrd_sym_min, LONG2NUM(minute));
1530
+ }
1531
+ if(state & RHRR_SECOND_SET) {
1532
+ rb_hash_aset(hash, rhrd_sym_sec, LONG2NUM(second));
1533
+ }
1534
+ if(state & RHRR_SEC_FRACTION_SET) {
1535
+ rb_hash_aset(hash, rhrd_sym_sec_fraction, rb_float_new(sec_fraction));
1536
+ }
1537
+ if(state & RHRR_UNIX_SET) {
1538
+ rb_hash_aset(hash, rhrd_sym_seconds, LL2NUM(seconds));
1539
+ }
1540
+ if(state & RHRR_UNIXM_SET) {
1541
+ rb_hash_aset(hash, rhrd_sym_seconds, LL2NUM(milliseconds/1000));
1542
+ rb_hash_aset(hash, rhrd_sym_sec_fraction, rb_float_new((milliseconds % 1000)/1000.0));
1543
+ }
1544
+ if(RTEST(zone)) {
1545
+ rb_hash_aset(hash, rhrd_sym_zone, zone);
1546
+ zone = rhrd_s_zone_to_diff(rstr, zone);
1547
+ if(RTEST(zone)) {
1548
+ rb_hash_aset(hash, rhrd_sym_offset, zone);
1549
+ }
1550
+ }
1551
+ if(state & RHRR_WNUM0_SET) {
1552
+ rb_hash_aset(hash, rhrd_sym_wnum0, LONG2NUM(wnum0));
1553
+ }
1554
+ if(state & RHRR_WNUM1_SET) {
1555
+ rb_hash_aset(hash, rhrd_sym_wnum1, LONG2NUM(wnum1));
1556
+ }
1557
+ #ifdef RUBY19
1558
+ if(pos < len) {
1559
+ rb_hash_aset(hash, rhrd_sym_leftover, rb_str_new(str + pos, len - pos));
1560
+ }
1561
+ #endif
1562
+ return hash;
1563
+ }
1564
+
1565
+ /* Set the commercial week cached instance variables. */
1566
+ void rhrd__set_cw_ivs(VALUE self, rhrd_t *d) {
1567
+ rb_ivar_set(self, rhrd_id_cwyear, LONG2NUM(d->year));
1568
+ rb_ivar_set(self, rhrd_id_cweek, LONG2NUM(d->month));
1569
+ rb_ivar_set(self, rhrd_id_cwday, LONG2NUM(d->day));
1570
+ }
1571
+
1572
+ #include "date_parser.c"
1573
+
1574
+ /* Ruby class methods */
1575
+
1576
+ /* call-seq:
1577
+ * _load(string) -> Date
1578
+ *
1579
+ * Unmarshal a dumped +Date+ object. Not generally called directly,
1580
+ * usually called by <tt>Marshal.load</tt>.
1581
+ *
1582
+ * Note that this does not handle the marshalling format used by
1583
+ * the stdlib's +Date+, it only handles marshalled versions of
1584
+ * this library's +Date+ objects.
1585
+ */
1586
+ static VALUE rhrd_s__load(VALUE klass, VALUE string) {
1587
+ rhrd_t * d;
1588
+ VALUE jd, rd;
1589
+ jd = rb_marshal_load(string);
1590
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1591
+ d->jd = NUM2LONG(jd);
1592
+ RHR_CHECK_JD(d)
1593
+ d->flags = RHR_HAVE_JD;
1594
+ return rd;
1595
+ }
1596
+
1597
+
1598
+ /* call-seq:
1599
+ * _ragel_parse(string) -> Hash or nil
1600
+ *
1601
+ * Attemps to parse the string with Ragel, returning a hash
1602
+ * if there is a match (or +nil+ if no match).
1603
+ */
1604
+ static VALUE rhrd_s__ragel_parse(VALUE klass, VALUE s) {
1605
+ s = rb_str_to_str(s);
1606
+ return rhrd__ragel_parse(RSTRING_PTR(s), RSTRING_LEN(s));
1607
+ }
1608
+
1609
+ /* call-seq:
1610
+ * _strptime(string, format='%F') -> Hash or nil
1611
+ *
1612
+ * Attemps to parse the string using the given format, returning
1613
+ * a hash if there is a match (or +nil+ if no match).
1614
+ *
1615
+ * +_strptime+ supports the same formats that <tt>Date#strftime</tt> does.
1616
+ */
1617
+ static VALUE rhrd_s__strptime(int argc, VALUE *argv, VALUE klass) {
1618
+ const char * fmt_str = "%F";
1619
+ long fmt_len = 2;
1620
+ VALUE r;
1621
+
1622
+ switch(argc) {
1623
+ case 2:
1624
+ r = rb_str_to_str(argv[1]);
1625
+ fmt_str = RSTRING_PTR(r);
1626
+ fmt_len = RSTRING_LEN(r);
1627
+ case 1:
1628
+ break;
1629
+ default:
1630
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
1631
+ break;
1632
+ }
1633
+
1634
+ return rhrd__strptime(argv[0], fmt_str, fmt_len);
1635
+ }
1636
+
1637
+ /* call-seq:
1638
+ * civil() -> Date <br />
1639
+ * civil(year, month=1, day=1, sg=nil) -> Date
1640
+ *
1641
+ * If no arguments are given, returns a +Date+ for julian day 0.
1642
+ * Otherwise, returns a +Date+ for the year, month, and day given.
1643
+ * Raises an +ArgumentError+ for invalid dates.
1644
+ * Ignores the 4th argument.
1645
+ */
1646
+ static VALUE rhrd_s_civil(int argc, VALUE *argv, VALUE klass) {
1647
+ rhrd_t *d;
1648
+ long year;
1649
+ long month = 1;
1650
+ long day = 1;
1651
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1652
+
1653
+ switch(argc) {
1654
+ case 3:
1655
+ case 4:
1656
+ day = NUM2LONG(argv[2]);
1657
+ case 2:
1658
+ month = NUM2LONG(argv[1]);
1659
+ case 1:
1660
+ year = NUM2LONG(argv[0]);
1661
+ break;
1662
+ case 0:
1663
+ d->flags = RHR_HAVE_JD;
1664
+ return rd;
1665
+ default:
1666
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
1667
+ break;
1668
+ }
1669
+
1670
+ if (!rhrd__valid_civil(d, year, month, day)) {
1671
+ RHR_CHECK_CIVIL(d)
1672
+ rb_raise(rb_eArgError, "invalid date (year: %li, month: %li, day: %li)", year, month, day);
1673
+ }
1674
+ return rd;
1675
+ }
1676
+
1677
+ /* call-seq:
1678
+ * commercial() -> Date <br />
1679
+ * commercial(cwyear, cweek=41, cwday=5, sg=nil) -> Date [ruby 1-8] <br />
1680
+ * commercial(cwyear, cweek=1, cwday=1, sg=nil) -> Date [ruby 1-9]
1681
+ *
1682
+ * If no arguments are given:
1683
+ * * ruby 1.8: returns a +Date+ for 1582-10-15 (the Day of Calendar Reform in Italy)
1684
+ * * ruby 1.9: returns a +Date+ for julian day 0
1685
+ *
1686
+ * Otherwise, returns a +Date+ for the commercial week year, commercial week, and
1687
+ * commercial week day given.
1688
+ * Raises an +ArgumentError+ for invalid dates.
1689
+ * Ignores the 4th argument.
1690
+ */
1691
+ static VALUE rhrd_s_commercial(int argc, VALUE *argv, VALUE klass) {
1692
+ rhrd_t *d;
1693
+ long cwyear = RHR_DEFAULT_CWYEAR;
1694
+ long cweek = RHR_DEFAULT_CWEEK;
1695
+ long cwday = RHR_DEFAULT_CWDAY;
1696
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1697
+
1698
+ switch(argc) {
1699
+ case 3:
1700
+ case 4:
1701
+ cwday = NUM2LONG(argv[2]);
1702
+ case 2:
1703
+ cweek = NUM2LONG(argv[1]);
1704
+ case 1:
1705
+ cwyear = NUM2LONG(argv[0]);
1706
+ #ifdef RUBY19
1707
+ break;
1708
+ case 0:
1709
+ d->flags = RHR_HAVE_JD;
1710
+ return rd;
1711
+ #else
1712
+ case 0:
1713
+ break;
1714
+ #endif
1715
+ default:
1716
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
1717
+ break;
1718
+ }
1719
+
1720
+ if(!rhrd__valid_commercial(d, cwyear, cweek, cwday)) {
1721
+ RHR_CHECK_JD(d)
1722
+ rb_raise(rb_eArgError, "invalid date (cwyear: %li, cweek: %li, cwday: %li)", cwyear, cweek, cwday);
1723
+ }
1724
+ return rd;
1725
+ }
1726
+
1727
+ /* call-seq:
1728
+ * gregorian_leap?(year) -> true or false
1729
+ *
1730
+ * Returns true if the given year is a leap year in the Gregorian
1731
+ * calendar, or false if not.
1732
+ */
1733
+ static VALUE rhrd_s_gregorian_leap_q(VALUE klass, VALUE year) {
1734
+ return rhrd__leap_year(NUM2LONG(year)) ? Qtrue : Qfalse;
1735
+ }
1736
+
1737
+ /* call-seq:
1738
+ * jd(jd=0, sg=nil) -> Date
1739
+ *
1740
+ * Returns a +Date+ for the julian day number given.
1741
+ * Ignores the 2nd argument.
1742
+ */
1743
+ static VALUE rhrd_s_jd (int argc, VALUE *argv, VALUE klass) {
1744
+ rhrd_t *d;
1745
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1746
+
1747
+ switch(argc) {
1748
+ case 0:
1749
+ d->flags = RHR_HAVE_JD;
1750
+ return rd;
1751
+ case 1:
1752
+ case 2:
1753
+ d->jd = NUM2LONG(argv[0]);
1754
+ break;
1755
+ default:
1756
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 2", argc);
1757
+ break;
1758
+ }
1759
+ RHR_CHECK_JD(d)
1760
+ d->flags = RHR_HAVE_JD;
1761
+ return rd;
1762
+ }
1763
+
1764
+ /* call-seq:
1765
+ * julian_leap?(year) -> true or false
1766
+ *
1767
+ * Returns true if the given year is a leap year in the Julian
1768
+ * calendar (i.e. divisible by 4), or false if not.
1769
+ */
1770
+ static VALUE rhrd_s_julian_leap_q(VALUE klass, VALUE y) {
1771
+ return NUM2LONG(y) % 4 == 0 ? Qtrue : Qfalse;
1772
+ }
1773
+
1774
+ /* call-seq:
1775
+ * new!(jd=0, offset=nil, sg=nil) -> Date
1776
+ *
1777
+ * Returns a +Date+ for the julian day number given.
1778
+ * Ignores the 2nd and 3rd arguments.
1779
+ */
1780
+ static VALUE rhrd_s_new_b(int argc, VALUE *argv, VALUE klass) {
1781
+ rhrd_t *d;
1782
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1783
+
1784
+ switch(argc) {
1785
+ case 0:
1786
+ d->flags = RHR_HAVE_JD;
1787
+ return rd;
1788
+ case 1:
1789
+ case 2:
1790
+ case 3:
1791
+ d->jd = NUM2LONG(argv[0]);
1792
+ break;
1793
+ default:
1794
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
1795
+ break;
1796
+ }
1797
+ RHR_CHECK_JD(d)
1798
+ d->flags = RHR_HAVE_JD;
1799
+ return rd;
1800
+ }
1801
+
1802
+ /* call-seq:
1803
+ * ordinal() -> Date <br />
1804
+ * ordinal(year, yday=1, sg=nil) -> Date
1805
+ *
1806
+ * If no arguments are given, returns a +Date+ for julian day 0.
1807
+ * Otherwise, returns a +Date+ for the year and day of year given.
1808
+ * Raises an +ArgumentError+ for invalid dates.
1809
+ * Ignores the 3rd argument.
1810
+ */
1811
+ static VALUE rhrd_s_ordinal(int argc, VALUE *argv, VALUE klass) {
1812
+ long year;
1813
+ long day = 1;
1814
+ rhrd_t *d;
1815
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1816
+
1817
+ switch(argc) {
1818
+ case 2:
1819
+ case 3:
1820
+ day = NUM2LONG(argv[1]);
1821
+ case 1:
1822
+ year = NUM2LONG(argv[0]);
1823
+ if(!rhrd__valid_ordinal(d, year, day)) {
1824
+ RHR_CHECK_JD(d)
1825
+ rb_raise(rb_eArgError, "invalid date (year: %li, yday: %li)", year, day);
1826
+ }
1827
+ break;
1828
+ case 0:
1829
+ d->flags = RHR_HAVE_JD;
1830
+ return rd;
1831
+ default:
1832
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
1833
+ break;
1834
+ }
1835
+
1836
+ return rd;
1837
+ }
1838
+
1839
+ /* call-seq:
1840
+ * parse() -> Date <br />
1841
+ * parse(string, comp=true, sg=nil) -> Date
1842
+ *
1843
+ * If no arguments are given, returns a +Date+ for julian day 0.
1844
+ * Otherwise returns a +Date+ for the date represented by the given
1845
+ * +string+. Raises an +ArgumentError+ if the string was not in
1846
+ * a recognized format, or if the recognized format represents
1847
+ * an invalid date.
1848
+ * If +comp+ is true, expands 2-digit years to 4-digits years.
1849
+ * Ignores the 3rd argument.
1850
+ */
1851
+ static VALUE rhrd_s_parse(int argc, VALUE *argv, VALUE klass) {
1852
+ rhrd_t *d;
1853
+ VALUE rd;
1854
+
1855
+ switch(argc) {
1856
+ case 0:
1857
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1858
+ d->flags = RHR_HAVE_JD;
1859
+ return rd;
1860
+ case 1:
1861
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__parse, 1, argv[0]));
1862
+ case 2:
1863
+ case 3:
1864
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__parse, 2, argv[0], argv[1]));
1865
+ default:
1866
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 3)", argc);
1867
+ break;
1868
+ }
1869
+ }
1870
+
1871
+ /* call-seq:
1872
+ * strptime() -> Date <br />
1873
+ * strptime(string, format="%F", sg=nil) -> Date
1874
+ *
1875
+ * If no arguments are given, returns a +Date+ for julian day 0.
1876
+ * Other returns a +Date+ for the date represented by the given
1877
+ * +string+, parsed using the given +format+.
1878
+ * Raises an +ArgumentError+ if the string did not match the format
1879
+ * given, or if it did match and it represented an invalid date.
1880
+ * Ignores the 3rd argument.
1881
+ */
1882
+ static VALUE rhrd_s_strptime(int argc, VALUE *argv, VALUE klass) {
1883
+ rhrd_t *d;
1884
+ VALUE rd;
1885
+
1886
+ switch(argc) {
1887
+ case 0:
1888
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1889
+ d->flags = RHR_HAVE_JD;
1890
+ return rd;
1891
+ case 1:
1892
+ case 2:
1893
+ break;
1894
+ case 3:
1895
+ argc = 2;
1896
+ break;
1897
+ default:
1898
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 3)", argc);
1899
+ break;
1900
+ }
1901
+
1902
+ rd = rhrd_s__strptime(argc, argv, klass);
1903
+ if (RTEST(rd)) {
1904
+ return rhrd__from_hash(rd);
1905
+ }
1906
+ rb_raise(rb_eArgError, "invalid date");
1907
+ }
1908
+
1909
+ /* call-seq:
1910
+ * today(sg=nil) -> Date
1911
+ *
1912
+ * Returns a +Date+ representing the current local date.
1913
+ * Ignores an argument if given.
1914
+ */
1915
+ static VALUE rhrd_s_today(int argc, VALUE *argv, VALUE klass) {
1916
+ rhrd_t *d;
1917
+ VALUE rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
1918
+
1919
+ switch(argc) {
1920
+ case 0:
1921
+ case 1:
1922
+ break;
1923
+ default:
1924
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
1925
+ break;
1926
+ }
1927
+
1928
+ rhrd__today(d);
1929
+ return rd;
1930
+ }
1931
+
1932
+ /* call-seq:
1933
+ * valid_civil?(year, month, day, sg=nil) -> Integer or nil [ruby 1-8] <br />
1934
+ * valid_civil?(year, month, day, sg=nil) -> true or false [ruby 1-9]
1935
+ *
1936
+ * On ruby 1.8, returns the julian date +Integer+ for the given +year+, +month+,
1937
+ * and +day+, or nil if the given values are not a valid date.
1938
+ *
1939
+ * On ruby 1.9, returns true if the given +year+, +month+, and +day+ represent
1940
+ * a valid date, or false otherwise.
1941
+ *
1942
+ * Ignores the 4th argument.
1943
+ */
1944
+ static VALUE rhrd_s_valid_civil_q(int argc, VALUE *argv, VALUE klass) {
1945
+ rhrd_t d;
1946
+ memset(&d, 0, sizeof(rhrd_t));
1947
+
1948
+ switch(argc) {
1949
+ case 3:
1950
+ case 4:
1951
+ if (!rhrd__valid_civil(&d, NUM2LONG(argv[0]), NUM2LONG(argv[1]), NUM2LONG(argv[2]))) {
1952
+ #ifdef RUBY19
1953
+ return Qfalse;
1954
+ #else
1955
+ return Qnil;
1956
+ #endif
1957
+ }
1958
+ break;
1959
+ default:
1960
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
1961
+ break;
1962
+ }
1963
+
1964
+ #ifdef RUBY19
1965
+ return Qtrue;
1966
+ #else
1967
+ RHR_FILL_JD(&d)
1968
+ return LONG2NUM(d.jd);
1969
+ #endif
1970
+ }
1971
+
1972
+ /* call-seq:
1973
+ * valid_commercial?(cwyear, cweek, cwday, sg=nil) -> Integer or nil [ruby 1-8] <br />
1974
+ * valid_commercial?(cwyear, cweek, cwday, sg=nil) -> true or false [ruby 1-9]
1975
+ *
1976
+ * On ruby 1.8, returns the julian date +Integer+ for the given +cwyear+, +cweek+,
1977
+ * and +cwday+, or nil if the given values are not a valid date.
1978
+ *
1979
+ * On ruby 1.9, returns true if the given +cwyear+, +cweek+, and +cwday+ represent
1980
+ * a valid date, or false otherwise.
1981
+ *
1982
+ * Ignores the 4th argument.
1983
+ */
1984
+ static VALUE rhrd_s_valid_commercial_q(int argc, VALUE *argv, VALUE klass) {
1985
+ rhrd_t d;
1986
+ memset(&d, 0, sizeof(rhrd_t));
1987
+
1988
+ switch(argc) {
1989
+ case 3:
1990
+ case 4:
1991
+ if (!rhrd__valid_commercial(&d, NUM2LONG(argv[0]), NUM2LONG(argv[1]), NUM2LONG(argv[2]))) {
1992
+ #ifdef RUBY19
1993
+ return Qfalse;
1994
+ #else
1995
+ return Qnil;
1996
+ #endif
1997
+ }
1998
+ break;
1999
+ default:
2000
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
2001
+ break;
2002
+ }
2003
+
2004
+ #ifdef RUBY19
2005
+ return Qtrue;
2006
+ #else
2007
+ return LONG2NUM(d.jd);
2008
+ #endif
2009
+ }
2010
+
2011
+ /* call-seq:
2012
+ * valid_jd?(jd, sg=nil) -> Object [ruby 1-8] <br />
2013
+ * valid_jd?(jd, sg=nil) -> true [ruby 1-9]
2014
+ *
2015
+ * On ruby 1.8, returns the first argument.
2016
+ * On ruby 1.9, returns true.
2017
+ * Ignores the 2nd argument.
2018
+ */
2019
+ static VALUE rhrd_s_valid_jd_q(int argc, VALUE *argv, VALUE klass) {
2020
+ switch(argc) {
2021
+ case 1:
2022
+ case 2:
2023
+ break;
2024
+ default:
2025
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 2", argc);
2026
+ break;
2027
+ }
2028
+
2029
+ #ifdef RUBY19
2030
+ return Qtrue;
2031
+ #else
2032
+ return argv[0];
2033
+ #endif
2034
+ }
2035
+
2036
+ /* call-seq:
2037
+ * valid_ordinal?(year, yday, sg=nil) -> Integer or nil [ruby 1-8] <br />
2038
+ * valid_ordinal?(year, yday, sg=nil) -> true or false [ruby 1-9]
2039
+ *
2040
+ * On ruby 1.8, returns the julian date +Integer+ for the given +year+ and +yday+,
2041
+ * or nil if the given values are not a valid date.
2042
+ *
2043
+ * On ruby 1.9, returns true if the given +year+ and +yday+ represent
2044
+ * a valid date, or false otherwise.
2045
+ *
2046
+ * Ignores the 3rd argument.
2047
+ */
2048
+ static VALUE rhrd_s_valid_ordinal_q(int argc, VALUE *argv, VALUE klass) {
2049
+ rhrd_t d;
2050
+ memset(&d, 0, sizeof(rhrd_t));
2051
+
2052
+ switch(argc) {
2053
+ case 2:
2054
+ case 3:
2055
+ if (!rhrd__valid_ordinal(&d, NUM2LONG(argv[0]), NUM2LONG(argv[1]))) {
2056
+ #ifdef RUBY19
2057
+ return Qfalse;
2058
+ #else
2059
+ return Qnil;
2060
+ #endif
2061
+ }
2062
+ break;
2063
+ default:
2064
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
2065
+ break;
2066
+ }
2067
+
2068
+ #ifdef RUBY19
2069
+ return Qtrue;
2070
+ #else
2071
+ RHR_FILL_JD(&d)
2072
+ return LONG2NUM(d.jd);
2073
+ #endif
2074
+ }
2075
+
2076
+ /* call-seq:
2077
+ * zone_to_diff(zone) -> Integer <br />
2078
+ *
2079
+ * Returns an +Integer+ representing the number of seconds that the given
2080
+ * zone string is offset from UTC. For example, 'PDT' is Pacific Daylight Time, which
2081
+ * 7 hours before UTC, so <tt>Date.zone_to_diff('PDT')</tt> will return <tt>-25200</tt>.
2082
+ *
2083
+ * In addition to handling time zone names, this also handles time zones specified
2084
+ * numerically, such as <tt>"+08:00"</tt> and <tt>"-0800"</tt>.
2085
+ *
2086
+ * If the time zone is not recognized, returns 0.
2087
+ *
2088
+ * On ruby 1.9, this method is private.
2089
+ */
2090
+ static VALUE rhrd_s_zone_to_diff(VALUE klass, VALUE str) {
2091
+ long offset = 0;
2092
+ long len, i, j;
2093
+ char *s;
2094
+ VALUE v, e;
2095
+
2096
+ str = rb_funcall(str, rhrd_id_downcase, 0);
2097
+ if(RTEST(rb_funcall(str, rhrd_id_sub_b, 2, rhrd_zone_dst_re, rhrd_empty_string))) {
2098
+ if (!RTEST(rb_reg_nth_match(1, rb_gv_get("$~")))) {
2099
+ offset += RHR_SECONDS_PER_HOUR;
2100
+ }
2101
+ }
2102
+
2103
+ if(RTEST(v = rb_hash_aref(rhrd_zones_hash, str))) {
2104
+ return LONG2NUM(offset + NUM2LONG(v));
2105
+ }
2106
+
2107
+ if(RTEST(rb_funcall(str, rhrd_id_sub_b, 2, rhrd_zone_sign_re, rhrd_empty_string))) {
2108
+ if (RTEST(rb_reg_nth_match(1, rb_gv_get("$~")))) {
2109
+ offset = -1;
2110
+ } else {
2111
+ offset = 1;
2112
+ }
2113
+ str = rb_str_to_str(str);
2114
+ s = RSTRING_PTR(str);
2115
+ len = RSTRING_LEN(str);
2116
+ for(i=0; i < len; i++) {
2117
+ if(s[i] == ':') {
2118
+ v = rb_funcall(str, rhrd_id_split, 1, rhrd_string_colon);
2119
+ return LONG2NUM((NUM2LONG(rb_funcall(rb_ary_entry(v, 0), rhrd_id_to_i, 0)) * RHR_SECONDS_PER_HOUR
2120
+ + NUM2LONG(rb_funcall(rb_ary_entry(v, 1), rhrd_id_to_i, 0)) * 60
2121
+ + NUM2LONG(rb_funcall(rb_ary_entry(v, 2), rhrd_id_to_i, 0))) * offset);
2122
+ }
2123
+ }
2124
+ for(i=0; i < len; i++) {
2125
+ if((s[i] == ',') || (s[i] == '.')) {
2126
+ v = rb_funcall(str, rhrd_id_split, 1, rhrd_re_comma_period);
2127
+ e = rb_ary_entry(v, 1);
2128
+ return LONG2NUM((NUM2LONG(rb_funcall(rb_ary_entry(v, 0), rhrd_id_to_i, 0)) * RHR_SECONDS_PER_HOUR)
2129
+ + (NUM2LONG(rb_funcall(e, rhrd_id_to_i, 0)) * RHR_SECONDS_PER_HOUR) / (long)pow(10, RSTRING_LEN(rb_str_to_str(e))) * offset);
2130
+ }
2131
+ }
2132
+ switch (len) {
2133
+ case 0:
2134
+ return LONG2NUM(0);
2135
+ case 1:
2136
+ case 2:
2137
+ return LONG2NUM(atol(s) * RHR_SECONDS_PER_HOUR * offset);
2138
+ case 3:
2139
+ i = atol(s + 1);
2140
+ s[1] = '\0';
2141
+ len = atol(s);
2142
+ return LONG2NUM((len * RHR_SECONDS_PER_HOUR + i * 60) * offset);
2143
+ case 4:
2144
+ i = atol(s + 2);
2145
+ s[2] = '\0';
2146
+ len = atol(s);
2147
+ return LONG2NUM((len * RHR_SECONDS_PER_HOUR + i * 60) * offset);
2148
+ default:
2149
+ s[6] = '\0';
2150
+ case 6:
2151
+ case 5:
2152
+ j = atol(s + 4);
2153
+ s[4] = '\0';
2154
+ i = atol(s + 2);
2155
+ s[2] = '\0';
2156
+ len = atol(s);
2157
+ return LONG2NUM((len * RHR_SECONDS_PER_HOUR + i * 60 + j) * offset);
2158
+ }
2159
+ }
2160
+
2161
+ return LONG2NUM(0);
2162
+ }
2163
+
2164
+ /* Ruby instance methods */
2165
+
2166
+ /* call-seq:
2167
+ * _dump(limit) -> String
2168
+ *
2169
+ * Returns a marshalled representation of the receiver as a +String+.
2170
+ * Generally not called directly, usually called by <tt>Marshal.dump</tt>.
2171
+ */
2172
+ static VALUE rhrd__dump(VALUE self, VALUE limit) {
2173
+ rhrd_t *d;
2174
+ Data_Get_Struct(self, rhrd_t, d);
2175
+ RHR_FILL_JD(d)
2176
+ return rb_marshal_dump(LONG2NUM(d->jd), LONG2NUM(NUM2LONG(limit) - 1));
2177
+ }
2178
+
2179
+ /* call-seq:
2180
+ * asctime() -> String
2181
+ *
2182
+ * Returns a string representation of the receiver. Example:
2183
+ *
2184
+ * Date.civil(2009, 1, 2).asctime
2185
+ * # => "Fri Jan 2 00:00:00 2009"
2186
+ */
2187
+ static VALUE rhrd_asctime(VALUE self) {
2188
+ VALUE s;
2189
+ rhrd_t *d;
2190
+ int len;
2191
+ Data_Get_Struct(self, rhrd_t, d);
2192
+ RHR_FILL_CIVIL(d)
2193
+ RHR_FILL_JD(d)
2194
+
2195
+ s = rb_str_buf_new(128);
2196
+ len = snprintf(RSTRING_PTR(s), 128, "%s %s %2hhi 00:00:00 %04li",
2197
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
2198
+ rhrd__abbr_month_names[d->month],
2199
+ d->day,
2200
+ d->year);
2201
+ if (len == -1 || len > 127) {
2202
+ rb_raise(rb_eNoMemError, "in Date#asctime (in snprintf)");
2203
+ }
2204
+
2205
+ RHR_RETURN_RESIZED_STR(s, len)
2206
+ }
2207
+
2208
+ /* call-seq:
2209
+ * cwday() -> Integer
2210
+ *
2211
+ * Returns the commercial week day as an +Integer+. Example:
2212
+ *
2213
+ * Date.civil(2009, 1, 2).cwday
2214
+ * # => 5
2215
+ * Date.civil(2010, 1, 2).cwday
2216
+ * # => 6
2217
+ */
2218
+ static VALUE rhrd_cwday(VALUE self) {
2219
+ rhrd_t *d;
2220
+ rhrd_t n;
2221
+ RHR_CACHED_IV(self, rhrd_id_cwday)
2222
+ memset(&n, 0, sizeof(rhrd_t));
2223
+ Data_Get_Struct(self, rhrd_t, d);
2224
+ RHR_FILL_JD(d)
2225
+ n.jd = d->jd;
2226
+ rhrd__fill_commercial(&n);
2227
+ rhrd__set_cw_ivs(self, &n);
2228
+ return LONG2NUM(n.day);
2229
+ }
2230
+
2231
+ /* call-seq:
2232
+ * cweek() -> Integer
2233
+ *
2234
+ * Returns the commercial week as an +Integer+. Example:
2235
+ *
2236
+ * Date.civil(2009, 1, 2).cweek
2237
+ * # => 1
2238
+ * Date.civil(2010, 1, 2).cweek
2239
+ * # => 53
2240
+ */
2241
+ static VALUE rhrd_cweek(VALUE self) {
2242
+ rhrd_t *d;
2243
+ rhrd_t n;
2244
+ RHR_CACHED_IV(self, rhrd_id_cweek)
2245
+ memset(&n, 0, sizeof(rhrd_t));
2246
+ Data_Get_Struct(self, rhrd_t, d);
2247
+ RHR_FILL_JD(d)
2248
+ n.jd = d->jd;
2249
+ rhrd__fill_commercial(&n);
2250
+ rhrd__set_cw_ivs(self, &n);
2251
+ return LONG2NUM(n.month);
2252
+ }
2253
+
2254
+ /* call-seq:
2255
+ * cwyear() -> Integer
2256
+ *
2257
+ * Returns the commercial week year as an +Integer+. Example:
2258
+ *
2259
+ * Date.civil(2009, 1, 2).cwyear
2260
+ * # => 2009
2261
+ * Date.civil(2010, 1, 2).cwyear
2262
+ * # => 2009
2263
+ */
2264
+ static VALUE rhrd_cwyear(VALUE self) {
2265
+ rhrd_t *d;
2266
+ rhrd_t n;
2267
+ RHR_CACHED_IV(self, rhrd_id_cwyear)
2268
+ memset(&n, 0, sizeof(rhrd_t));
2269
+ Data_Get_Struct(self, rhrd_t, d);
2270
+ RHR_FILL_JD(d)
2271
+ n.jd = d->jd;
2272
+ rhrd__fill_commercial(&n);
2273
+ rhrd__set_cw_ivs(self, &n);
2274
+ return LONG2NUM(n.year);
2275
+ }
2276
+
2277
+ /* call-seq:
2278
+ * day() -> Integer
2279
+ *
2280
+ * Returns the day of the month as an +Integer+. Example:
2281
+ *
2282
+ * Date.civil(2009, 1, 2).day
2283
+ * # => 2
2284
+ */
2285
+ static VALUE rhrd_day(VALUE self) {
2286
+ rhrd_t *d;
2287
+ Data_Get_Struct(self, rhrd_t, d);
2288
+ RHR_FILL_CIVIL(d)
2289
+ return LONG2NUM(d->day);
2290
+ }
2291
+
2292
+ /* call-seq:
2293
+ * day_fraction() -> 0
2294
+ *
2295
+ * +Date+ objects due not hold fractional days, so 0 is always returned.
2296
+ */
2297
+ static VALUE rhrd_day_fraction(VALUE self) {
2298
+ return LONG2NUM(0);
2299
+ }
2300
+
2301
+ /* call-seq:
2302
+ * downto(target){|date|} -> Date
2303
+ *
2304
+ * Equivalent to calling +step+ with the +target+ as the first argument
2305
+ * and <tt>-1</tt> as the second argument. Returns self.
2306
+ *
2307
+ * Date.civil(2009, 1, 2).downto(Date.civil(2009, 1, 1)) do |date|
2308
+ * puts date
2309
+ * end
2310
+ * # Output:
2311
+ * # 2009-01-02
2312
+ * # 2009-01-01
2313
+ */
2314
+ static VALUE rhrd_downto(VALUE self, VALUE other) {
2315
+ VALUE argv[2];
2316
+ argv[0] = other;
2317
+ argv[1] = INT2FIX(-1);
2318
+ return rhrd_step(2, argv, self);
2319
+ }
2320
+
2321
+ /* call-seq:
2322
+ * eql?(date) -> true or false
2323
+ *
2324
+ * Returns true only if the +date+ given is the same date as the receiver.
2325
+ * If +date+ is an instance of +DateTime+, returns +true+ only if +date+ is
2326
+ * for the same date as the receiver and has no fractional component.
2327
+ * Otherwise, returns +false+. Example:
2328
+ *
2329
+ * Date.civil(2009, 1, 2).eql?(Date.civil(2009, 1, 2))
2330
+ * # => true
2331
+ * Date.civil(2009, 1, 2).eql?(Date.civil(2009, 1, 1))
2332
+ * # => false
2333
+ * Date.civil(2009, 1, 2).eql?(DateTime.civil(2009, 1, 2))
2334
+ * # => true
2335
+ * Date.civil(2009, 1, 2).eql?(DateTime.civil(2009, 1, 2, 1))
2336
+ * # => false
2337
+ */
2338
+ static VALUE rhrd_eql_q(VALUE self, VALUE other) {
2339
+ rhrd_t *d, *o;
2340
+ rhrdt_t *odt;
2341
+ long diff;
2342
+ Data_Get_Struct(self, rhrd_t, d);
2343
+
2344
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
2345
+ Data_Get_Struct(other, rhrdt_t, odt);
2346
+ RHR_FILL_JD(d)
2347
+ RHRDT_FILL_JD(odt)
2348
+ RHR_SPACE_SHIP(diff, d->jd, odt->jd)
2349
+ if (diff == 0) {
2350
+ RHRDT_FILL_NANOS(odt)
2351
+ RHR_SPACE_SHIP(diff, 0, odt->nanos)
2352
+ }
2353
+ return diff == 0 ? Qtrue : Qfalse;
2354
+ } else if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
2355
+ Data_Get_Struct(other, rhrd_t, o);
2356
+ return rhrd__spaceship(d, o) == 0 ? Qtrue : Qfalse;
2357
+ }
2358
+ return Qfalse;
2359
+ }
2360
+
2361
+ /* call-seq:
2362
+ * gregorian() -> Date
2363
+ *
2364
+ * This library does not support modifying the day of calendar
2365
+ * reform, so this always returns self.
2366
+ */
2367
+ static VALUE rhrd_gregorian(VALUE self) {
2368
+ return self;
2369
+ }
2370
+
2371
+ /* call-seq:
2372
+ * gregorian?() -> true
2373
+ *
2374
+ * This library always uses the Gregorian calendar, so this
2375
+ * always returns +true+.
2376
+ */
2377
+ static VALUE rhrd_gregorian_q(VALUE self) {
2378
+ return Qtrue;
2379
+ }
2380
+
2381
+ /* call-seq:
2382
+ * hash() -> Integer
2383
+ *
2384
+ * Return an Integer hash value for the receiver, such that an
2385
+ * equal date will have the same hash value.
2386
+ */
2387
+ static VALUE rhrd_hash(VALUE self) {
2388
+ rhrd_t *d;
2389
+ RHR_CACHED_IV(self, rhrd_id_hash)
2390
+ Data_Get_Struct(self, rhrd_t, d);
2391
+ RHR_FILL_JD(d)
2392
+ return rb_ivar_set(self, rhrd_id_hash, rb_funcall(LONG2NUM(d->jd), rhrd_id_hash, 0));
2393
+ }
2394
+
2395
+ /* call-seq:
2396
+ * inspect() -> String
2397
+ *
2398
+ * Return a developer-friendly string containing the civil
2399
+ * date for the receiver. Example:
2400
+ *
2401
+ * Date.civil(2009, 1, 2).inspect
2402
+ * # => "#<Date 2009-01-02>"
2403
+ */
2404
+ static VALUE rhrd_inspect(VALUE self) {
2405
+ VALUE s;
2406
+ rhrd_t *d;
2407
+ int len;
2408
+ Data_Get_Struct(self, rhrd_t, d);
2409
+ RHR_FILL_CIVIL(d)
2410
+
2411
+ s = rb_str_buf_new(128);
2412
+ len = snprintf(RSTRING_PTR(s), 128, "#<Date %04li-%02hhi-%02hhi>",
2413
+ d->year, d->month, d->day);
2414
+ if (len == -1 || len > 127) {
2415
+ rb_raise(rb_eNoMemError, "in Date#inspect (in snprintf)");
2416
+ }
2417
+
2418
+ RHR_RETURN_RESIZED_STR(s, len)
2419
+ }
2420
+
2421
+ /* call-seq:
2422
+ * jd() -> Integer
2423
+ *
2424
+ * Return the julian day number for the receiver as an +Integer+.
2425
+ *
2426
+ * Date.civil(2009, 1, 2).jd
2427
+ * # => 2454834
2428
+ */
2429
+ static VALUE rhrd_jd(VALUE self) {
2430
+ rhrd_t *d;
2431
+ Data_Get_Struct(self, rhrd_t, d);
2432
+ RHR_FILL_JD(d)
2433
+ return LONG2NUM(d->jd);
2434
+ }
2435
+
2436
+ /* call-seq:
2437
+ * julian?() -> false
2438
+ *
2439
+ * This library always uses the Gregorian calendar, so this
2440
+ * always returns +false+.
2441
+ */
2442
+ static VALUE rhrd_julian_q(VALUE self) {
2443
+ return Qfalse;
2444
+ }
2445
+
2446
+ /* call-seq:
2447
+ * ld() -> Integer
2448
+ *
2449
+ * Return the number of days since the Lilian Date (the day of calendar reform
2450
+ * in Italy).
2451
+ *
2452
+ * Date.civil(2009, 1, 2).ld
2453
+ * # => 155674
2454
+ */
2455
+ static VALUE rhrd_ld(VALUE self) {
2456
+ rhrd_t *d;
2457
+ Data_Get_Struct(self, rhrd_t, d);
2458
+ RHR_FILL_JD(d)
2459
+ return LONG2NUM(d->jd - RHR_JD_LD);
2460
+ }
2461
+
2462
+ /* call-seq:
2463
+ * leap?() -> true or false
2464
+ *
2465
+ * Return +true+ if the current year for this date is a leap year
2466
+ * in the Gregorian calendar, +false+ otherwise.
2467
+ *
2468
+ * Date.civil(2009, 1, 2).leap?
2469
+ * # => false
2470
+ * Date.civil(2008, 1, 2).leap?
2471
+ * # => true
2472
+ */
2473
+ static VALUE rhrd_leap_q(VALUE self) {
2474
+ rhrd_t *d;
2475
+ Data_Get_Struct(self, rhrd_t, d);
2476
+ RHR_FILL_CIVIL(d)
2477
+ return rhrd__leap_year(d->year) ? Qtrue : Qfalse;
2478
+ }
2479
+
2480
+ /* call-seq:
2481
+ * mjd() -> Integer
2482
+ *
2483
+ * Return the number of days since 1858-11-17.
2484
+ *
2485
+ * Date.civil(2009, 1, 2).mjd
2486
+ * # => 54833
2487
+ */
2488
+ static VALUE rhrd_mjd(VALUE self) {
2489
+ rhrd_t *d;
2490
+ Data_Get_Struct(self, rhrd_t, d);
2491
+ RHR_FILL_JD(d)
2492
+ return LONG2NUM(d->jd - RHR_JD_MJD);
2493
+ }
2494
+
2495
+ /* call-seq:
2496
+ * month() -> Integer
2497
+ *
2498
+ * Returns the number of the month as an +Integer+. Example:
2499
+ *
2500
+ * Date.civil(2009, 1, 2).month
2501
+ * # => 1
2502
+ */
2503
+ static VALUE rhrd_month(VALUE self) {
2504
+ rhrd_t *d;
2505
+ Data_Get_Struct(self, rhrd_t, d);
2506
+ RHR_FILL_CIVIL(d)
2507
+ return LONG2NUM(d->month);
2508
+ }
2509
+
2510
+ /* call-seq:
2511
+ * next() -> Date
2512
+ *
2513
+ * Returns the +Date+ after the receiver's date:
2514
+ *
2515
+ * Date.civil(2009, 1, 2).next
2516
+ * # => #<Date 2009-01-03>
2517
+ */
2518
+ static VALUE rhrd_next(VALUE self) {
2519
+ return rhrd__add_days(self, 1);
2520
+ }
2521
+
2522
+ /* call-seq:
2523
+ * new_start(sg=nil) -> Date
2524
+ *
2525
+ * Returns self. Ignores an argument if given.
2526
+ */
2527
+ static VALUE rhrd_new_start(int argc, VALUE *argv, VALUE self) {
2528
+ switch(argc) {
2529
+ case 0:
2530
+ case 1:
2531
+ break;
2532
+ default:
2533
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2534
+ break;
2535
+ }
2536
+
2537
+ return self;
2538
+ }
2539
+
2540
+ /* call-seq:
2541
+ * start() -> Integer
2542
+ *
2543
+ * Returns a number lower than the lowest julian date that can be
2544
+ * correctly handled. Because this library always uses the Gregorian
2545
+ * calendar, the day of calendar reform is chosen to be less than any
2546
+ * date that this library can handle.
2547
+ */
2548
+ static VALUE rhrd_start(VALUE self) {
2549
+ return rhrd_start_num;
2550
+ }
2551
+
2552
+ /* call-seq:
2553
+ * step(target, step=1){|date|} -> Date
2554
+ *
2555
+ * Yields +Date+ objects between the receiver and the +target+ date
2556
+ * (inclusive), with +step+ integer days between each yielded date.
2557
+ * +step+ can be negative, in which case the dates are yielded in
2558
+ * reverse chronological order. Returns self in all cases.
2559
+ *
2560
+ * If +target+ is equal to the receiver, yields self once regardless of
2561
+ * +step+. It +target+ is less than receiver and +step+ is nonnegative, or
2562
+ * +target+ is greater than receiver and +step+ is nonpositive, does not
2563
+ * yield.
2564
+ *
2565
+ * Date.civil(2009, 1, 2).step(Date.civil(2009, 1, 6), 2) do |date|
2566
+ * puts date
2567
+ * end
2568
+ * # Output:
2569
+ * # 2009-01-02
2570
+ * # 2009-01-04
2571
+ * # 2009-01-06
2572
+ */
2573
+ static VALUE rhrd_step(int argc, VALUE *argv, VALUE self) {
2574
+ rhrd_t *d, *n, *newd;
2575
+ rhrdt_t *ndt;
2576
+ long step, limit, current;
2577
+ VALUE rlimit, new;
2578
+ Data_Get_Struct(self, rhrd_t, d);
2579
+ RHR_FILL_JD(d)
2580
+
2581
+ rb_need_block();
2582
+ switch(argc) {
2583
+ case 1:
2584
+ step = 1;
2585
+ break;
2586
+ case 2:
2587
+ step = NUM2LONG(argv[1]);
2588
+ break;
2589
+ default:
2590
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 2", argc);
2591
+ break;
2592
+ }
2593
+
2594
+ rlimit = argv[0];
2595
+ if (RTEST(rb_obj_is_kind_of(rlimit, rb_cNumeric))) {
2596
+ limit = NUM2LONG(rlimit);
2597
+ } else if (RTEST((rb_obj_is_kind_of(rlimit, rhrdt_class)))) {
2598
+ Data_Get_Struct(rlimit, rhrdt_t, ndt);
2599
+ RHRDT_FILL_JD(ndt)
2600
+ limit = ndt->jd;
2601
+ } else if (RTEST((rb_obj_is_kind_of(rlimit, rhrd_class)))) {
2602
+ Data_Get_Struct(rlimit, rhrd_t, n);
2603
+ RHR_FILL_JD(n)
2604
+ limit = n->jd;
2605
+ } else {
2606
+ rb_raise(rb_eTypeError, "expected numeric or date");
2607
+ }
2608
+
2609
+ current = d->jd;
2610
+ if (limit > current) {
2611
+ if (step > 0) {
2612
+ while(limit >= current) {
2613
+ new = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, newd);
2614
+ newd->jd = current;
2615
+ RHR_CHECK_JD(newd)
2616
+ newd->flags = RHR_HAVE_JD;
2617
+ current += step;
2618
+ rb_yield(new);
2619
+ }
2620
+ }
2621
+ } else if (limit < current) {
2622
+ if (step < 0) {
2623
+ while(limit <= current) {
2624
+ new = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, newd);
2625
+ newd->jd = current;
2626
+ RHR_CHECK_JD(newd)
2627
+ newd->flags = RHR_HAVE_JD;
2628
+ current += step;
2629
+ rb_yield(new);
2630
+ }
2631
+ }
2632
+ } else {
2633
+ rb_yield(self);
2634
+ }
2635
+
2636
+ return self;
2637
+ }
2638
+
2639
+ /* call-seq:
2640
+ * strftime() -> String <br />
2641
+ * strftime(format) -> String
2642
+ *
2643
+ * If no argument is provided, returns a string in ISO8601 format, just like
2644
+ * +to_s+. If an argument is provided, uses it as a format string and returns
2645
+ * a +String+ based on the format. The following formats parts are supported:
2646
+ *
2647
+ * %a :: The abbreviated day name (e.g. Fri)
2648
+ * %A :: The full day name (e.g. Friday)
2649
+ * %b, %h :: The abbreviated month name (e.g. Jan)
2650
+ * %B :: The full month name (e.g. January)
2651
+ * %c :: A full date and time representation (e.g. Fri Jan 02 13:29:39 2009)
2652
+ * %C :: The century of the year (e.g. 20)
2653
+ * %d :: The day of the month, with a leading zero if necessary (e.g. 02)
2654
+ * %e :: The day of the month, with a leading space if necessary (e.g. 2)
2655
+ * %F :: An ISO8601 date representation (e.g. 2009-01-02)
2656
+ * %g :: The last 2 digits of the commercial week year (e.g. 09)
2657
+ * %G :: The commercial week year (e.g. 2009)
2658
+ * %H :: The hour of the day in 24 hour format, with a leading zero if necessary (e.g. 13)
2659
+ * %I :: The hour of the day in 12 hour format (e.g. 01)
2660
+ * %j :: The day of the year (e.g. 002)
2661
+ * %k :: The hour of the day in 24 hour format, with a leading space if necessary (e.g. 13)
2662
+ * %l :: The hour of the day in 12 hour format, with a leading space if necessary (e.g. 13)
2663
+ * %L :: The number of milliseconds in the fractional second, with leading zeros if necessary (e.g. 079)
2664
+ * %m :: The month of the year (e.g. 01)
2665
+ * %M :: The minute of the hour (e.g. 29)
2666
+ * %n :: A newline (e.g. "\n")
2667
+ * %N :: The number of nanoseconds in the fractional second, with leading zeros if necessary (e.g. 079013023)
2668
+ * %p :: The meridian indicator, upcased (e.g. PM)
2669
+ * %P :: The meridian indicator, downcased (e.g. pm)
2670
+ * %Q :: The number of milliseconds since the unix epoch (e.g. 1230902979079)
2671
+ * %r :: A full time representation in 12 hour format (e.g. 1:29:39 PM)
2672
+ * %R :: An hour and minute representation in 24 hour format (e.g. 13:29)
2673
+ * %s :: The number of seconds since the unix epoch (e.g. 1230902979)
2674
+ * %S :: The second of the minute (e.g. 39)
2675
+ * %t :: A tab (e.g. "\t")
2676
+ * %T, %X :: A full time representation in 24 hour format (e.g. 13:29:39)
2677
+ * %u :: The commercial week day (e.g. 5)
2678
+ * %U :: The week number of the current year, with Sunday as the first day of the first week (e.g. 0)
2679
+ * %v :: A full date representation (e.g. 2-Jan-2009)
2680
+ * %V :: The commercial week (e.g. 01)
2681
+ * %w :: The day of the week, with Sunday as 0 and Saturday as 6 (e.g. 5)
2682
+ * %W :: The week number of the current year, with Monday as the first day of the first week (e.g. 0)
2683
+ * %x, %D :: A full date representation in month/day/year format (e.g. 01/02/09)
2684
+ * %y :: The last two digits of the year (e.g. 09)
2685
+ * %Y :: The year (e.g. 2009)
2686
+ * %z :: The offset from UTC, without a colon (e.g. +0000)
2687
+ * %Z :: The offset from UTC, with a colon (e.g. +00:00)
2688
+ * %+ :: A full date and time representation, including the offset (e.g. Fri Jan 2 13:29:39 +00:00 2009)
2689
+ *
2690
+ * All other formats (e.g. %f, %%) are handled by removing the leading percent sign. All other text is
2691
+ * passed through literally.
2692
+ */
2693
+ static VALUE rhrd_strftime(int argc, VALUE *argv, VALUE self) {
2694
+ rhrd_t *d;
2695
+ rhrdt_t dt;
2696
+ VALUE r;
2697
+
2698
+ switch(argc) {
2699
+ case 0:
2700
+ return rhrd_to_s(self);
2701
+ case 1:
2702
+ r = rb_str_to_str(argv[0]);
2703
+ break;
2704
+ default:
2705
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2706
+ break;
2707
+ }
2708
+
2709
+ Data_Get_Struct(self, rhrd_t, d);
2710
+ RHR_FILL_CIVIL(d)
2711
+ RHR_FILL_JD(d)
2712
+ memset(&dt, 0, sizeof(rhrdt_t));
2713
+ dt.jd = d->jd;
2714
+ dt.year = d->year;
2715
+ dt.month = d->month;
2716
+ dt.day = d->day;
2717
+ dt.flags = RHR_HAVE_CIVIL | RHR_HAVE_JD;
2718
+ return rhrd__strftime(&dt, RSTRING_PTR(r), RSTRING_LEN(r));
2719
+ }
2720
+
2721
+ /* call-seq:
2722
+ * to_s() -> String
2723
+ *
2724
+ * Returns the receiver as an ISO8601 formatted string.
2725
+ *
2726
+ * Date.civil(2009, 1, 2).to_s
2727
+ * # => "2009-01-02"
2728
+ */
2729
+ static VALUE rhrd_to_s(VALUE self) {
2730
+ VALUE s;
2731
+ rhrd_t *d;
2732
+ int len;
2733
+ Data_Get_Struct(self, rhrd_t, d);
2734
+ RHR_FILL_CIVIL(d)
2735
+
2736
+ s = rb_str_buf_new(128);
2737
+ len = snprintf(RSTRING_PTR(s), 128, "%04li-%02hhi-%02hhi",
2738
+ d->year, d->month, d->day);
2739
+ if (len == -1 || len > 127) {
2740
+ rb_raise(rb_eNoMemError, "in Date#to_s (in snprintf)");
2741
+ }
2742
+
2743
+ RHR_RETURN_RESIZED_STR(s, len)
2744
+ }
2745
+
2746
+ /* call-seq:
2747
+ * upto(target){|date|} -> Date
2748
+ *
2749
+ * Equivalent to calling +step+ with the +target+ as the first argument.
2750
+ * Returns self.
2751
+ *
2752
+ * Date.civil(2009, 1, 1).upto(Date.civil(2009, 1, 2)) do |date|
2753
+ * puts date
2754
+ * end
2755
+ * # Output:
2756
+ * # 2009-01-01
2757
+ * # 2009-01-02
2758
+ */
2759
+ static VALUE rhrd_upto(VALUE self, VALUE other) {
2760
+ VALUE argv[1];
2761
+ argv[0] = other;
2762
+ return rhrd_step(1, argv, self);
2763
+ }
2764
+
2765
+ /* call-seq:
2766
+ * wday() -> Integer
2767
+ *
2768
+ * Returns the day of the week as an +Integer+, where Sunday
2769
+ * is 0 and Saturday is 6. Example:
2770
+ *
2771
+ * Date.civil(2009, 1, 2).wday
2772
+ * # => 5
2773
+ */
2774
+ static VALUE rhrd_wday(VALUE self) {
2775
+ rhrd_t *d;
2776
+ Data_Get_Struct(self, rhrd_t, d);
2777
+ RHR_FILL_JD(d)
2778
+ return LONG2NUM(rhrd__jd_to_wday(d->jd));
2779
+ }
2780
+
2781
+ /* call-seq:
2782
+ * yday() -> Integer
2783
+ *
2784
+ * Returns the day of the year as an +Integer+, where January
2785
+ * 1st is 1 and December 31 is 365 (or 366 if the year is a leap
2786
+ * year). Example:
2787
+ *
2788
+ * Date.civil(2009, 2, 2).yday
2789
+ * # => 33
2790
+ */
2791
+ static VALUE rhrd_yday(VALUE self) {
2792
+ rhrd_t *d;
2793
+ Data_Get_Struct(self, rhrd_t, d);
2794
+ RHR_FILL_CIVIL(d)
2795
+ return LONG2NUM(rhrd__ordinal_day(d->year, d->month, d->day));
2796
+ }
2797
+
2798
+ /* call-seq:
2799
+ * year() -> Integer
2800
+ *
2801
+ * Returns the year as an +Integer+. Example:
2802
+ *
2803
+ * Date.civil(2009, 1, 2).year
2804
+ * # => 2009
2805
+ */
2806
+ static VALUE rhrd_year(VALUE self) {
2807
+ rhrd_t *d;
2808
+ Data_Get_Struct(self, rhrd_t, d);
2809
+ RHR_FILL_CIVIL(d)
2810
+ return LONG2NUM(d->year);
2811
+ }
2812
+
2813
+ /* Ruby instance operator methods */
2814
+
2815
+ /* call-seq:
2816
+ * >>(n) -> Date
2817
+ *
2818
+ * Returns a +Date+ that is +n+ months after the receiver. +n+
2819
+ * can be negative, in which case it returns a +Date+ before
2820
+ * the receiver.
2821
+ *
2822
+ * Date.civil(2009, 1, 2) >> 2
2823
+ * # => #<Date 2009-01-02>
2824
+ * Date.civil(2009, 1, 2) >> -2
2825
+ * # => #<Date 2008-11-02>
2826
+ */
2827
+ static VALUE rhrd_op_right_shift(VALUE self, VALUE other) {
2828
+ return rhrd__add_months(self, NUM2LONG(other));
2829
+ }
2830
+
2831
+ /* call-seq:
2832
+ * <<(n) -> Date
2833
+ *
2834
+ * Returns a +Date+ that is +n+ months before the receiver. +n+
2835
+ * can be negative, in which case it returns a +Date+ after
2836
+ * the receiver.
2837
+ *
2838
+ * Date.civil(2009, 1, 2) << 2
2839
+ * # => #<Date 2008-11-02>
2840
+ * Date.civil(2009, 1, 2) << -2
2841
+ * # => #<Date 2009-01-02>
2842
+ */
2843
+ static VALUE rhrd_op_left_shift(VALUE self, VALUE other) {
2844
+ return rhrd__add_months(self, -NUM2LONG(other));
2845
+ }
2846
+
2847
+ /* call-seq:
2848
+ * +(n) -> Date
2849
+ *
2850
+ * Returns a +Date+ that is +n+ days after the receiver. +n+
2851
+ * can be negative, in which case it returns a +Date+ before
2852
+ * the receiver.
2853
+ *
2854
+ * Date.civil(2009, 1, 2) + 2
2855
+ * # => #<Date 2009-01-04>
2856
+ * Date.civil(2009, 1, 2) + -2
2857
+ * # => #<Date 2008-12-31>
2858
+ */
2859
+ static VALUE rhrd_op_plus(VALUE self, VALUE other) {
2860
+ return rhrd__add_days(self, NUM2LONG(other));
2861
+ }
2862
+
2863
+ /* call-seq:
2864
+ * -(n) -> Date <br />
2865
+ * -(date) -> Integer <br />
2866
+ * -(datetime) -> Float
2867
+ *
2868
+ * If a +Numeric+ argument is given, it is treated as an +Integer+,
2869
+ * and the number of days it represents is substracted from the
2870
+ * receiver to return a new +Date+ object. +n+ can be negative, in
2871
+ * which case the +Date+ returned will be after the receiver.
2872
+ *
2873
+ * If a +Date+ argument is given, returns the number of days
2874
+ * between the current date and the argument as an +Integer+.
2875
+ *
2876
+ * If a +DateTime+ argument is given, returns the number of days
2877
+ * between the current date and the argument as a +Float+, and
2878
+ * considers the receiver to be in the same time zone as the
2879
+ * argument.
2880
+ *
2881
+ * Other types of arguments raise a +TypeError+.
2882
+ *
2883
+ * Date.civil(2009, 1, 2) - 2
2884
+ * # => #<Date 2008-12-31>
2885
+ * Date.civil(2009, 1, 2) - Date.civil(2009, 1, 1)
2886
+ * # => 1
2887
+ * Date.civil(2009, 1, 2) - DateTime.civil(2009, 1, 3, 12)
2888
+ * # => -1.5
2889
+ */
2890
+ static VALUE rhrd_op_minus(VALUE self, VALUE other) {
2891
+ rhrd_t *d;
2892
+ rhrd_t *newd;
2893
+ rhrdt_t *newdt;
2894
+ Data_Get_Struct(self, rhrd_t, d);
2895
+
2896
+ if (RTEST(rb_obj_is_kind_of(other, rb_cNumeric))) {
2897
+ return rhrd__add_days(self, -NUM2LONG(other));
2898
+ }
2899
+ if (RTEST((rb_obj_is_kind_of(other, rhrdt_class)))) {
2900
+ Data_Get_Struct(other, rhrdt_t, newdt);
2901
+ RHR_FILL_JD(d)
2902
+ RHRDT_FILL_JD(newdt)
2903
+ RHRDT_FILL_NANOS(newdt)
2904
+ return rb_float_new(d->jd - (newdt->jd + newdt->nanos/RHR_NANOS_PER_DAYD));
2905
+ }
2906
+ if (RTEST((rb_obj_is_kind_of(other, rhrd_class)))) {
2907
+ Data_Get_Struct(other, rhrd_t, newd);
2908
+ RHR_FILL_JD(d)
2909
+ RHR_FILL_JD(newd)
2910
+ return LONG2NUM(rhrd__safe_add_long(d->jd, -newd->jd));
2911
+ }
2912
+ rb_raise(rb_eTypeError, "expected numeric or date");
2913
+ }
2914
+
2915
+ /* call-seq:
2916
+ * ===(other) -> true or false
2917
+ *
2918
+ * If +other+ is a +Date+, returns +true+ if +other+ is the
2919
+ * same date as the receiver, or +false+ otherwise.
2920
+ *
2921
+ * If +other+ is a +DateTime+, return +true+ if +other has the same
2922
+ * julian date as the receiver, or +false+ otherwise.
2923
+ *
2924
+ * If +other+ is a +Numeric+, convert it to an +Integer+ and return
2925
+ * +true+ if it is equal to the receiver's julian date, or +false+
2926
+ * otherwise.
2927
+ */
2928
+ static VALUE rhrd_op_relationship(VALUE self, VALUE other) {
2929
+ rhrd_t *d, *o;
2930
+ rhrdt_t *odt;
2931
+ long diff = 1;
2932
+ Data_Get_Struct(self, rhrd_t, d);
2933
+
2934
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
2935
+ Data_Get_Struct(other, rhrdt_t, odt);
2936
+ RHR_FILL_JD(d)
2937
+ RHRDT_FILL_JD(odt)
2938
+ diff = d->jd != odt->jd;
2939
+ } else if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
2940
+ Data_Get_Struct(other, rhrd_t, o);
2941
+ diff = rhrd__spaceship(d, o);
2942
+ } else if (RTEST((rb_obj_is_kind_of(other, rb_cNumeric)))) {
2943
+ diff = NUM2LONG(other);
2944
+ RHR_FILL_JD(d)
2945
+ RHR_SPACE_SHIP(diff, d->jd, diff)
2946
+ }
2947
+ return diff == 0 ? Qtrue : Qfalse;
2948
+ }
2949
+
2950
+ /* call-seq:
2951
+ * <=>(other) -> -1, 0, 1, or nil
2952
+ *
2953
+ * If +other+ is a +Date+, returns -1 if +other+ is before the
2954
+ * the receiver chronologically, 0 if +other+ is the same date as the receiver,
2955
+ * or 1 if +other+ is after the receiver chronologically.
2956
+ *
2957
+ * If +other+ is a +DateTime+, return 0 if +other+ has the same
2958
+ * julian date as the receiver and no fractional part, -1 if +other+ has a julian date
2959
+ * less than the receiver's, and 1 if +other+ has a julian date
2960
+ * greater than the receiver's or a julian date the same as the
2961
+ * receiver's and a fractional part.
2962
+ *
2963
+ * If +other+ is a +Numeric+, convert it to an integer and compare
2964
+ * it to the receiver's julian date.
2965
+ *
2966
+ * For an unrecognized type, return +nil+.
2967
+ */
2968
+ static VALUE rhrd_op_spaceship(VALUE self, VALUE other) {
2969
+ rhrd_t *d, *o;
2970
+ rhrdt_t *odt;
2971
+ long diff;
2972
+ Data_Get_Struct(self, rhrd_t, d);
2973
+
2974
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
2975
+ Data_Get_Struct(other, rhrdt_t, odt);
2976
+ RHR_FILL_JD(d)
2977
+ RHRDT_FILL_JD(odt)
2978
+ RHR_SPACE_SHIP(diff, d->jd, odt->jd)
2979
+ if (diff == 0) {
2980
+ RHRDT_FILL_NANOS(odt)
2981
+ RHR_SPACE_SHIP(diff, 0, odt->nanos)
2982
+ }
2983
+ return LONG2NUM(diff);
2984
+ } else if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
2985
+ Data_Get_Struct(other, rhrd_t, o);
2986
+ return LONG2NUM(rhrd__spaceship(d, o));
2987
+ } else if (RTEST((rb_obj_is_kind_of(other, rb_cNumeric)))) {
2988
+ diff = NUM2LONG(other);
2989
+ RHR_FILL_JD(d)
2990
+ RHR_SPACE_SHIP(diff, d->jd, diff)
2991
+ return LONG2NUM(diff);
2992
+ }
2993
+ return Qnil;
2994
+ }
2995
+
2996
+ #ifdef RUBY19
2997
+
2998
+ /* Ruby 1.9 helper methods */
2999
+
3000
+ /* Add n number of years to the given ruby Date object. n can
3001
+ * be negative to subtract years. Returns a new ruby Date
3002
+ * object */
3003
+ VALUE rhrd__add_years(VALUE self, long n) {
3004
+ rhrd_t *d;
3005
+ rhrd_t *newd;
3006
+ VALUE new;
3007
+ Data_Get_Struct(self, rhrd_t, d);
3008
+
3009
+ new = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, newd);
3010
+ RHR_FILL_CIVIL(d)
3011
+ newd->year = rhrd__safe_add_long(n, d->year);
3012
+ newd->month = d->month;
3013
+ if(d->month == 2 && d->day == 29) {
3014
+ newd->day = rhrd__leap_year(newd->year) ? 29 : 28;
3015
+ } else {
3016
+ newd->day = d->day;
3017
+ }
3018
+
3019
+ RHR_CHECK_CIVIL(newd)
3020
+ newd->flags = RHR_HAVE_CIVIL;
3021
+ return new;
3022
+ }
3023
+
3024
+ /* Return ruby true if the given date falls on the given
3025
+ * week day number, or ruby false otherwise. */
3026
+ VALUE rhrd__day_q(VALUE self, long day) {
3027
+ rhrd_t *d;
3028
+ Data_Get_Struct(self, rhrd_t, d);
3029
+ RHR_FILL_JD(d)
3030
+ return rhrd__jd_to_wday(d->jd) == day ? Qtrue : Qfalse;
3031
+ }
3032
+
3033
+ /* Ruby 1.9 class methods */
3034
+
3035
+ /* call-seq:
3036
+ * [ruby 1-9 only] <br />
3037
+ * httpdate() -> Date <br />
3038
+ * httpdate(str, sg=nil) -> Date
3039
+ *
3040
+ * If no argument is given, returns a +Date+ for julian day 0.
3041
+ * If an argument is given, it should be a string that is
3042
+ * parsed using +_httpdate+, returning a +Date+ or raising
3043
+ * an +ArgumentError+ if the string is not in a valid format
3044
+ * or the date it represents is not a valid date.
3045
+ * Ignores the 2nd argument.
3046
+ * Example:
3047
+ *
3048
+ * Date.httpdate("Fri, 02 Jan 2009 00:00:00 GMT")
3049
+ * # => #<Date 2009-01-02>
3050
+ */
3051
+ static VALUE rhrd_s_httpdate(int argc, VALUE *argv, VALUE klass) {
3052
+ rhrd_t *d;
3053
+ VALUE rd;
3054
+
3055
+ switch(argc) {
3056
+ case 0:
3057
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3058
+ d->flags = RHR_HAVE_JD;
3059
+ return rd;
3060
+ case 1:
3061
+ case 2:
3062
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__httpdate, 1, argv[0]));
3063
+ default:
3064
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3065
+ break;
3066
+ }
3067
+ }
3068
+
3069
+ /* call-seq:
3070
+ * [ruby 1-9 only] <br />
3071
+ * iso8601() -> Date <br />
3072
+ * iso8601(str, sg=nil) -> Date
3073
+ *
3074
+ * If no argument is given, returns a +Date+ for julian day 0.
3075
+ * If an argument is given, it should be a string that is
3076
+ * parsed using +_iso8601+, returning a +Date+ or raising
3077
+ * an +ArgumentError+ if the string is not in a valid format
3078
+ * or the date it represents is not a valid date.
3079
+ * Ignores the 2nd argument.
3080
+ * Example:
3081
+ *
3082
+ * Date.iso8601("2009-01-02")
3083
+ * # => #<Date 2009-01-02>
3084
+ */
3085
+ static VALUE rhrd_s_iso8601(int argc, VALUE *argv, VALUE klass) {
3086
+ rhrd_t *d;
3087
+ VALUE rd;
3088
+
3089
+ switch(argc) {
3090
+ case 0:
3091
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3092
+ d->flags = RHR_HAVE_JD;
3093
+ return rd;
3094
+ case 1:
3095
+ case 2:
3096
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__iso8601, 1, argv[0]));
3097
+ default:
3098
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3099
+ break;
3100
+ }
3101
+ }
3102
+
3103
+ /* call-seq:
3104
+ * [ruby 1-9 only] <br />
3105
+ * jisx0301() -> Date <br />
3106
+ * jisx0301(str, sg=nil) -> Date
3107
+ *
3108
+ * If no argument is given, returns a +Date+ for julian day 0.
3109
+ * If an argument is given, it should be a string that is
3110
+ * parsed using +_jisx0301+, returning a +Date+ or raising
3111
+ * an +ArgumentError+ if the string is not in a valid format
3112
+ * or the date it represents is not a valid date.
3113
+ * Ignores the 2nd argument.
3114
+ * Example:
3115
+ *
3116
+ * Date.iso8601("H21.01.02")
3117
+ * # => #<Date 2009-01-02>
3118
+ */
3119
+ static VALUE rhrd_s_jisx0301(int argc, VALUE *argv, VALUE klass) {
3120
+ rhrd_t *d;
3121
+ VALUE rd;
3122
+
3123
+ switch(argc) {
3124
+ case 0:
3125
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3126
+ d->flags = RHR_HAVE_JD;
3127
+ return rd;
3128
+ case 1:
3129
+ case 2:
3130
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__jisx0301, 1, argv[0]));
3131
+ default:
3132
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3133
+ break;
3134
+ }
3135
+ }
3136
+
3137
+ /* call-seq:
3138
+ * [ruby 1-9 only] <br />
3139
+ * rfc2822() -> Date <br />
3140
+ * rfc2822(str, sg=nil) -> Date
3141
+ *
3142
+ * If no argument is given, returns a +Date+ for julian day 0.
3143
+ * If an argument is given, it should be a string that is
3144
+ * parsed using +_rfc2822+, returning a +Date+ or raising
3145
+ * an +ArgumentError+ if the string is not in a valid format
3146
+ * or the date it represents is not a valid date.
3147
+ * Ignores the 2nd argument.
3148
+ * Example:
3149
+ *
3150
+ * Date.rfc2822("Fri, 2 Jan 2009 00:00:00 +0000")
3151
+ * # => #<Date 2009-01-02>
3152
+ */
3153
+ static VALUE rhrd_s_rfc2822(int argc, VALUE *argv, VALUE klass) {
3154
+ rhrd_t *d;
3155
+ VALUE rd;
3156
+
3157
+ switch(argc) {
3158
+ case 0:
3159
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3160
+ d->flags = RHR_HAVE_JD;
3161
+ return rd;
3162
+ case 1:
3163
+ case 2:
3164
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__rfc2822, 1, argv[0]));
3165
+ default:
3166
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3167
+ break;
3168
+ }
3169
+ }
3170
+
3171
+ /* call-seq:
3172
+ * [ruby 1-9 only] <br />
3173
+ * rfc3339() -> Date <br />
3174
+ * rfc3339(str, sg=nil) -> Date
3175
+ *
3176
+ * If no argument is given, returns a +Date+ for julian day 0.
3177
+ * If an argument is given, it should be a string that is
3178
+ * parsed using +_rfc3339+, returning a +Date+ or raising
3179
+ * an +ArgumentError+ if the string is not in a valid format
3180
+ * or the date it represents is not a valid date.
3181
+ * Ignores the 2nd argument.
3182
+ * Example:
3183
+ *
3184
+ * Date.rfc3339("2009-01-02T00:00:00+00:00")
3185
+ * # => #<Date 2009-01-02>
3186
+ */
3187
+ static VALUE rhrd_s_rfc3339(int argc, VALUE *argv, VALUE klass) {
3188
+ rhrd_t *d;
3189
+ VALUE rd;
3190
+
3191
+ switch(argc) {
3192
+ case 0:
3193
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3194
+ d->flags = RHR_HAVE_JD;
3195
+ return rd;
3196
+ case 1:
3197
+ case 2:
3198
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__rfc3339, 1, argv[0]));
3199
+ default:
3200
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3201
+ break;
3202
+ }
3203
+ }
3204
+
3205
+ /* call-seq:
3206
+ * [ruby 1-9 only] <br />
3207
+ * xmlschema() -> Date <br />
3208
+ * xmlschema(str, sg=nil) -> Date
3209
+ *
3210
+ * If no argument is given, returns a +Date+ for julian day 0.
3211
+ * If an argument is given, it should be a string that is
3212
+ * parsed using +_xmlschema+, returning a +Date+ or raising
3213
+ * an +ArgumentError+ if the string is not in a valid format
3214
+ * or the date it represents is not a valid date.
3215
+ * Ignores the 2nd argument.
3216
+ * Example:
3217
+ *
3218
+ * Date.xmlschema("2009-01-02")
3219
+ * # => #<Date 2009-01-02>
3220
+ */
3221
+ static VALUE rhrd_s_xmlschema(int argc, VALUE *argv, VALUE klass) {
3222
+ rhrd_t *d;
3223
+ VALUE rd;
3224
+
3225
+ switch(argc) {
3226
+ case 0:
3227
+ rd = Data_Make_Struct(klass, rhrd_t, NULL, free, d);
3228
+ d->flags = RHR_HAVE_JD;
3229
+ return rd;
3230
+ case 1:
3231
+ case 2:
3232
+ return rhrd__from_hash(rb_funcall(klass, rhrd_id__xmlschema, 1, argv[0]));
3233
+ default:
3234
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
3235
+ break;
3236
+ }
3237
+ }
3238
+
3239
+ /* Ruby 1.9 instance methods */
3240
+
3241
+ /* call-seq:
3242
+ * [ruby 1-9 only] <br />
3243
+ * httpdate() -> String
3244
+ *
3245
+ * Returns the receiver as a +String+ in HTTP format. Example:
3246
+ *
3247
+ * Date.civil(2009, 1, 2).httpdate
3248
+ * # => "Fri, 02 Jan 2009 00:00:00 GMT"
3249
+ */
3250
+ static VALUE rhrd_httpdate(VALUE self) {
3251
+ VALUE s;
3252
+ rhrd_t *d;
3253
+ int len;
3254
+ Data_Get_Struct(self, rhrd_t, d);
3255
+ RHR_FILL_CIVIL(d)
3256
+ RHR_FILL_JD(d)
3257
+
3258
+ s = rb_str_buf_new(128);
3259
+ len = snprintf(RSTRING_PTR(s), 128, "%s, %02hhi %s %04li 00:00:00 GMT",
3260
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
3261
+ d->day,
3262
+ rhrd__abbr_month_names[d->month],
3263
+ d->year);
3264
+ if (len == -1 || len > 127) {
3265
+ rb_raise(rb_eNoMemError, "in Date#httpdate (in snprintf)");
3266
+ }
3267
+
3268
+ RHR_RETURN_RESIZED_STR(s, len)
3269
+ }
3270
+
3271
+ /* call-seq:
3272
+ * [ruby 1-9 only] <br />
3273
+ * jisx0301() -> String
3274
+ *
3275
+ * Returns the receiver as a +String+ in JIS X 0301 format. Example:
3276
+ *
3277
+ * Date.civil(2009, 1, 2).jisx0301
3278
+ * # => "H21.01.02"
3279
+ */
3280
+ static VALUE rhrd_jisx0301(VALUE self) {
3281
+ VALUE s;
3282
+ rhrd_t *d;
3283
+ int len;
3284
+ char c;
3285
+ long year;
3286
+ Data_Get_Struct(self, rhrd_t, d);
3287
+ RHR_FILL_CIVIL(d)
3288
+ RHR_FILL_JD(d)
3289
+
3290
+ s = rb_str_buf_new(128);
3291
+ if (d->jd < 2405160) {
3292
+ len = snprintf(RSTRING_PTR(s), 128, "%04li-%02hhi-%02hhi", d->year, d->month, d->day);
3293
+ } else {
3294
+ if (d->jd >= 2447535) {
3295
+ c = 'H';
3296
+ year = d->year - 1988;
3297
+ } else if (d->jd >= 2424875) {
3298
+ c = 'S';
3299
+ year = d->year - 1925;
3300
+ } else if (d->jd >= 2419614) {
3301
+ c = 'T';
3302
+ year = d->year - 1911;
3303
+ } else {
3304
+ c = 'M';
3305
+ year = d->year - 1867;
3306
+ }
3307
+ len = snprintf(RSTRING_PTR(s), 128, "%c%02li.%02hhi.%02hhi", c, year, d->month, d->day);
3308
+ }
3309
+ if (len == -1 || len > 127) {
3310
+ rb_raise(rb_eNoMemError, "in Date#jisx0301 (in snprintf)");
3311
+ }
3312
+
3313
+ RHR_RETURN_RESIZED_STR(s, len)
3314
+ }
3315
+
3316
+ /* call-seq:
3317
+ * [ruby 1-9 only] <br />
3318
+ * next_day(n=1) -> Date
3319
+ *
3320
+ * Returns a +Date+ +n+ days after the receiver. If +n+ is negative,
3321
+ * returns a +Date+ before the receiver.
3322
+ *
3323
+ * Date.civil(2009, 1, 2).next_day
3324
+ * # => #<Date 2009-01-03>
3325
+ * Date.civil(2009, 1, 2).next_day(2)
3326
+ * # => #<Date 2009-01-04>
3327
+ */
3328
+ static VALUE rhrd_next_day(int argc, VALUE *argv, VALUE self) {
3329
+ long i;
3330
+
3331
+ switch(argc) {
3332
+ case 0:
3333
+ i = 1;
3334
+ break;
3335
+ case 1:
3336
+ i = NUM2LONG(argv[0]);
3337
+ break;
3338
+ default:
3339
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3340
+ break;
3341
+ }
3342
+
3343
+ return rhrd__add_days(self, i);
3344
+ }
3345
+
3346
+ /* call-seq:
3347
+ * [ruby 1-9 only] <br />
3348
+ * next_month(n=1) -> Date
3349
+ *
3350
+ * Returns a +Date+ +n+ months after the receiver. If +n+ is negative,
3351
+ * returns a +Date+ before the receiver.
3352
+ *
3353
+ * Date.civil(2009, 1, 2).next_month
3354
+ * # => #<Date 2009-02-02>
3355
+ * Date.civil(2009, 1, 2).next_month(2)
3356
+ * # => #<Date 2009-03-02>
3357
+ */
3358
+ static VALUE rhrd_next_month(int argc, VALUE *argv, VALUE self) {
3359
+ long i;
3360
+
3361
+ switch(argc) {
3362
+ case 0:
3363
+ i = 1;
3364
+ break;
3365
+ case 1:
3366
+ i = NUM2LONG(argv[0]);
3367
+ break;
3368
+ default:
3369
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3370
+ break;
3371
+ }
3372
+
3373
+ return rhrd__add_months(self, i);
3374
+ }
3375
+
3376
+ /* call-seq:
3377
+ * [ruby 1-9 only] <br />
3378
+ * next_year(n=1) -> Date
3379
+ *
3380
+ * Returns a +Date+ +n+ years after the receiver. If +n+ is negative,
3381
+ * returns a +Date+ before the receiver.
3382
+ *
3383
+ * Date.civil(2009, 1, 2).next_year
3384
+ * # => #<Date 2010-01-02>
3385
+ * Date.civil(2009, 1, 2).next_year(2)
3386
+ * # => #<Date 2011-01-02>
3387
+ */
3388
+ static VALUE rhrd_next_year(int argc, VALUE *argv, VALUE self) {
3389
+ long i;
3390
+
3391
+ switch(argc) {
3392
+ case 0:
3393
+ i = 1;
3394
+ break;
3395
+ case 1:
3396
+ i = NUM2LONG(argv[0]);
3397
+ break;
3398
+ default:
3399
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3400
+ break;
3401
+ }
3402
+
3403
+ return rhrd__add_years(self, i);
3404
+ }
3405
+
3406
+ /* call-seq:
3407
+ * [ruby 1-9 only] <br />
3408
+ * prev_day(n=1) -> Date
3409
+ *
3410
+ * Returns a +Date+ +n+ days before the receiver. If +n+ is negative,
3411
+ * returns a +Date+ after the receiver.
3412
+ *
3413
+ * Date.civil(2009, 1, 2).prev_day
3414
+ * # => #<Date 2009-01-01>
3415
+ * Date.civil(2009, 1, 2).prev_day(2)
3416
+ * # => #<Date 2008-12-31>
3417
+ */
3418
+ static VALUE rhrd_prev_day(int argc, VALUE *argv, VALUE self) {
3419
+ long i;
3420
+
3421
+ switch(argc) {
3422
+ case 0:
3423
+ i = -1;
3424
+ break;
3425
+ case 1:
3426
+ i = -NUM2LONG(argv[0]);
3427
+ break;
3428
+ default:
3429
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3430
+ break;
3431
+ }
3432
+
3433
+ return rhrd__add_days(self, i);
3434
+ }
3435
+
3436
+ /* call-seq:
3437
+ * [ruby 1-9 only] <br />
3438
+ * prev_month(n=1) -> Date
3439
+ *
3440
+ * Returns a +Date+ +n+ months before the receiver. If +n+ is negative,
3441
+ * returns a +Date+ after the receiver.
3442
+ *
3443
+ * Date.civil(2009, 1, 2).prev_month
3444
+ * # => #<Date 2008-12-02>
3445
+ * Date.civil(2009, 1, 2).prev_month(2)
3446
+ * # => #<Date 2008-11-02>
3447
+ */
3448
+ static VALUE rhrd_prev_month(int argc, VALUE *argv, VALUE self) {
3449
+ long i;
3450
+
3451
+ switch(argc) {
3452
+ case 0:
3453
+ i = -1;
3454
+ break;
3455
+ case 1:
3456
+ i = -NUM2LONG(argv[0]);
3457
+ break;
3458
+ default:
3459
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3460
+ break;
3461
+ }
3462
+
3463
+ return rhrd__add_months(self, i);
3464
+ }
3465
+
3466
+ /* call-seq:
3467
+ * [ruby 1-9 only] <br />
3468
+ * prev_year(n=1) -> Date
3469
+ *
3470
+ * Returns a +Date+ +n+ years before the receiver. If +n+ is negative,
3471
+ * returns a +Date+ after the receiver.
3472
+ *
3473
+ * Date.civil(2009, 1, 2).prev_year
3474
+ * # => #<Date 2008-01-02>
3475
+ * Date.civil(2009, 1, 2).prev_year(2)
3476
+ * # => #<Date 2007-01-02>
3477
+ */
3478
+ static VALUE rhrd_prev_year(int argc, VALUE *argv, VALUE self) {
3479
+ long i;
3480
+
3481
+ switch(argc) {
3482
+ case 0:
3483
+ i = -1;
3484
+ break;
3485
+ case 1:
3486
+ i = -NUM2LONG(argv[0]);
3487
+ break;
3488
+ default:
3489
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
3490
+ break;
3491
+ }
3492
+
3493
+ return rhrd__add_years(self, i);
3494
+ }
3495
+
3496
+ /* call-seq:
3497
+ * [ruby 1-9 only] <br />
3498
+ * rfc2822() -> String
3499
+ *
3500
+ * Returns the receiver as a +String+ in RFC2822 format. Example:
3501
+ *
3502
+ * Date.civil(2009, 1, 2).rfc2822
3503
+ * # => "Fri, 2 Jan 2009 00:00:00 +0000"
3504
+ */
3505
+ static VALUE rhrd_rfc2822(VALUE self) {
3506
+ VALUE s;
3507
+ rhrd_t *d;
3508
+ int len;
3509
+ Data_Get_Struct(self, rhrd_t, d);
3510
+ RHR_FILL_CIVIL(d)
3511
+ RHR_FILL_JD(d)
3512
+
3513
+ s = rb_str_buf_new(128);
3514
+ len = snprintf(RSTRING_PTR(s), 128, "%s, %hhi %s %04li 00:00:00 +0000",
3515
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
3516
+ d->day,
3517
+ rhrd__abbr_month_names[d->month],
3518
+ d->year);
3519
+ if (len == -1 || len > 127) {
3520
+ rb_raise(rb_eNoMemError, "in Date#rfc2822 (in snprintf)");
3521
+ }
3522
+
3523
+ RHR_RETURN_RESIZED_STR(s, len)
3524
+ }
3525
+
3526
+ /* call-seq:
3527
+ * [ruby 1-9 only] <br />
3528
+ * rfc3339() -> String
3529
+ *
3530
+ * Returns the receiver as a +String+ in RFC3339 format. Example:
3531
+ *
3532
+ * Date.civil(2009, 1, 2).rfc3339
3533
+ * # => "2009-01-02T00:00:00+00:00"
3534
+ */
3535
+ static VALUE rhrd_rfc3339(VALUE self) {
3536
+ VALUE s;
3537
+ rhrd_t *d;
3538
+ int len;
3539
+ Data_Get_Struct(self, rhrd_t, d);
3540
+ RHR_FILL_CIVIL(d)
3541
+
3542
+ s = rb_str_buf_new(128);
3543
+ len = snprintf(RSTRING_PTR(s), 128, "%04li-%02hhi-%02hhiT00:00:00+00:00", d->year, d->month, d->day);
3544
+ if (len == -1 || len > 127) {
3545
+ rb_raise(rb_eNoMemError, "in Date#rfc3339 (in snprintf)");
3546
+ }
3547
+
3548
+ RHR_RETURN_RESIZED_STR(s, len)
3549
+ }
3550
+
3551
+ /* call-seq:
3552
+ * [ruby 1-9 only] <br />
3553
+ * to_datetime() -> DateTime
3554
+ *
3555
+ * Returns a +DateTime+ equal to the receiver.
3556
+ *
3557
+ * Date.civil(2009, 1, 2).to_datetime
3558
+ * # => #<DateTime 2009-01-02T00:00:00+00:00>
3559
+ */
3560
+ static VALUE rhrd_to_datetime(VALUE self) {
3561
+ rhrd_t *d;
3562
+ rhrdt_t *dt;
3563
+ VALUE rdt = Data_Make_Struct(rhrdt_class, rhrdt_t, NULL, free, dt);
3564
+ Data_Get_Struct(self, rhrd_t, d);
3565
+
3566
+ if (RHR_HAS_CIVIL(d)) {
3567
+ dt->year = d->year;
3568
+ dt->month = d->month;
3569
+ dt->day = d->day;
3570
+ dt->flags |= RHR_HAVE_CIVIL;
3571
+ }
3572
+ if (RHR_HAS_JD(d)) {
3573
+ dt->jd = d->jd;
3574
+ dt->flags |= RHR_HAVE_JD;
3575
+ }
3576
+
3577
+ return rdt;
3578
+ }
3579
+
3580
+ /* call-seq:
3581
+ * [ruby 1-9 only] <br />
3582
+ * to_time() -> Time
3583
+ *
3584
+ * Returns a +Time+ in local time with the same year, month, and day
3585
+ * as the receiver.
3586
+ *
3587
+ * Date.civil(2009, 1, 2).to_time
3588
+ * # => 2009-01-02 00:00:00 -0800
3589
+ */
3590
+ static VALUE rhrd_to_time(VALUE self) {
3591
+ rhrd_t *d;
3592
+ Data_Get_Struct(self, rhrd_t, d);
3593
+ RHR_FILL_CIVIL(d)
3594
+ return rb_funcall(rb_cTime, rhrd_id_local, 3, LONG2NUM(d->year), LONG2NUM(d->month), LONG2NUM(d->day));
3595
+ }
3596
+
3597
+ /* call-seq:
3598
+ * [ruby 1-9 only] <br />
3599
+ * to_date() -> Date
3600
+ *
3601
+ * Returns a +Date+ with the same year, month, and day
3602
+ * as the receiver in local time.
3603
+ *
3604
+ * Time.local(2009, 1, 2).to_date
3605
+ * # => #<Date 2009-01-02>
3606
+ */
3607
+ static VALUE rhrd_time_to_date(VALUE self) {
3608
+ rhrd_t *d;
3609
+ VALUE rd;
3610
+ rd = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, d);
3611
+ d->jd = rhrd__unix_to_jd(NUM2LONG(rb_funcall(self, rhrd_id_to_i, 0)) + NUM2LONG(rb_funcall(self, rhrd_id_utc_offset, 0)));
3612
+ d->flags = RHR_HAVE_JD;
3613
+ RHR_CHECK_JD(d)
3614
+ return rd;
3615
+ }
3616
+
3617
+ /* call-seq:
3618
+ * [ruby 1-9 only] <br />
3619
+ * to_time() -> Time
3620
+ *
3621
+ * Returns a copy of the receiver in local time.
3622
+ *
3623
+ * Time.local(2009, 1, 2).to_time
3624
+ * # => 2009-01-02 00:00:00 -0800
3625
+ * Time.local(2009, 1, 2).getutc.to_time
3626
+ * # => 2009-01-02 00:00:00 -0800
3627
+ */
3628
+ static VALUE rhrd_time_to_time(VALUE self) {
3629
+ return rb_funcall(self, rhrd_id_getlocal, 0);
3630
+ }
3631
+
3632
+ /* Ruby 1.9 *day? instance methods */
3633
+
3634
+ /* call-seq:
3635
+ * [ruby 1-9 only] <br />
3636
+ * sunday?() -> true or false
3637
+ *
3638
+ * Returns +true+ if the receiver is a Sunday, +false+ otherwise.
3639
+ */
3640
+ static VALUE rhrd_sunday_q(VALUE self) {
3641
+ return rhrd__day_q(self, 0);
3642
+ }
3643
+
3644
+ /* call-seq:
3645
+ * [ruby 1-9 only] <br />
3646
+ * monday?() -> true or false
3647
+ *
3648
+ * Returns +true+ if the receiver is a Monday, +false+ otherwise.
3649
+ */
3650
+ static VALUE rhrd_monday_q(VALUE self) {
3651
+ return rhrd__day_q(self, 1);
3652
+ }
3653
+
3654
+ /* call-seq:
3655
+ * [ruby 1-9 only] <br />
3656
+ * tuesday?() -> true or false
3657
+ *
3658
+ * Returns +true+ if the receiver is a Tuesday, +false+ otherwise.
3659
+ */
3660
+ static VALUE rhrd_tuesday_q(VALUE self) {
3661
+ return rhrd__day_q(self, 2);
3662
+ }
3663
+
3664
+ /* call-seq:
3665
+ * [ruby 1-9 only] <br />
3666
+ * wednesday?() -> true or false
3667
+ *
3668
+ * Returns +true+ if the receiver is a Wednesday, +false+ otherwise.
3669
+ */
3670
+ static VALUE rhrd_wednesday_q(VALUE self) {
3671
+ return rhrd__day_q(self, 3);
3672
+ }
3673
+
3674
+ /* call-seq:
3675
+ * [ruby 1-9 only] <br />
3676
+ * thursday?() -> true or false
3677
+ *
3678
+ * Returns +true+ if the receiver is a Thursday, +false+ otherwise.
3679
+ */
3680
+ static VALUE rhrd_thursday_q(VALUE self) {
3681
+ return rhrd__day_q(self, 4);
3682
+ }
3683
+
3684
+ /* call-seq:
3685
+ * [ruby 1-9 only] <br />
3686
+ * friday?() -> true or false
3687
+ *
3688
+ * Returns +true+ if the receiver is a Friday, +false+ otherwise.
3689
+ */
3690
+ static VALUE rhrd_friday_q(VALUE self) {
3691
+ return rhrd__day_q(self, 5);
3692
+ }
3693
+
3694
+ /* call-seq:
3695
+ * [ruby 1-9 only] <br />
3696
+ * saturday?() -> true or false
3697
+ *
3698
+ * Returns +true+ if the receiver is a Saturday, +false+ otherwise.
3699
+ */
3700
+ static VALUE rhrd_saturday_q(VALUE self) {
3701
+ return rhrd__day_q(self, 6);
3702
+ }
3703
+
3704
+ #else
3705
+
3706
+ /* Ruby 1.8 class methods */
3707
+
3708
+ /* call-seq:
3709
+ * [ruby 1-8 only] <br />
3710
+ * ajd_to_amjd(ajd) -> Integer
3711
+ *
3712
+ * Converts the given astronomical julian date (+Integer+) into an
3713
+ * astronomical modified julian date.
3714
+ */
3715
+ static VALUE rhrd_s_ajd_to_amjd(VALUE klass, VALUE ajd) {
3716
+ return LONG2NUM(rhrd__safe_add_long(-RHR_JD_MJD, NUM2LONG(ajd)));
3717
+ }
3718
+
3719
+ /* call-seq:
3720
+ * [ruby 1-8 only] <br />
3721
+ * ajd_to_jd(ajd) -> [jd, Float(1)/2]
3722
+ *
3723
+ * Converts the given astronomical julian date (+Integer+) into an
3724
+ * an array of two elements, where the first element is the julian
3725
+ * date +Integer+ and the second is a +Float+ with value 0.5.
3726
+ */
3727
+ static VALUE rhrd_s_ajd_to_jd(int argc, VALUE *argv, VALUE klass) {
3728
+ switch(argc) {
3729
+ case 1:
3730
+ case 2:
3731
+ break;
3732
+ default:
3733
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 2", argc);
3734
+ break;
3735
+ }
3736
+
3737
+ return rb_ary_new3(2, argv[0], rb_float_new(0.5));
3738
+ }
3739
+
3740
+ /* call-seq:
3741
+ * [ruby 1-8 only] <br />
3742
+ * amjd_to_ajd(ajd) -> Integer
3743
+ *
3744
+ * Converts the given astronomical modified julian date (+Integer+) into an
3745
+ * astronomical julian date.
3746
+ */
3747
+ static VALUE rhrd_s_amjd_to_ajd(VALUE klass, VALUE amjd) {
3748
+ return LONG2NUM(rhrd__safe_add_long(RHR_JD_MJD - 1, NUM2LONG(amjd)));
3749
+ }
3750
+
3751
+ /* call-seq:
3752
+ * [ruby 1-8 only] <br />
3753
+ * civil_to_jd(year, month, day, sg=nil) -> Integer
3754
+ *
3755
+ * Converts the given year, month, and day into a julian date +Integer+.
3756
+ * Ignores the 4th argument.
3757
+ */
3758
+ static VALUE rhrd_s_civil_to_jd(int argc, VALUE *argv, VALUE klass) {
3759
+ rhrd_t d;
3760
+ memset(&d, 0, sizeof(rhrd_t));
3761
+
3762
+ switch(argc) {
3763
+ case 3:
3764
+ case 4:
3765
+ d.year = NUM2LONG(argv[0]);
3766
+ d.month = (unsigned char)NUM2LONG(argv[1]);
3767
+ d.day = (unsigned char)NUM2LONG(argv[2]);
3768
+ break;
3769
+ default:
3770
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
3771
+ break;
3772
+ }
3773
+ d.flags = RHR_HAVE_CIVIL;
3774
+ RHR_FILL_JD(&d)
3775
+
3776
+ return LONG2NUM(d.jd);
3777
+ }
3778
+
3779
+ /* call-seq:
3780
+ * [ruby 1-8 only] <br />
3781
+ * civil_to_jd(cwyear, cweek, cwday, sg=nil) -> Integer
3782
+ *
3783
+ * Converts the given cwyear, cweek, and cwday into a julian date +Integer+.
3784
+ * Ignores the 4th argument.
3785
+ */
3786
+ static VALUE rhrd_s_commercial_to_jd(int argc, VALUE *argv, VALUE klass) {
3787
+ long jd;
3788
+
3789
+ switch(argc) {
3790
+ case 3:
3791
+ case 4:
3792
+ jd = rhrd__commercial_to_jd(NUM2LONG(argv[0]), NUM2LONG(argv[1]), NUM2LONG(argv[2]));
3793
+ break;
3794
+ default:
3795
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 4", argc);
3796
+ break;
3797
+ }
3798
+
3799
+ return LONG2NUM(jd);
3800
+ }
3801
+
3802
+ /* call-seq:
3803
+ * [ruby 1-8 only] <br />
3804
+ * day_fraction_to_time(float) -> [hour, minute, second, sec_fraction]
3805
+ *
3806
+ * Converts the given float (which should be in the range [0.0, 1.0))
3807
+ * into an array of 4 elements: +hour+ (+Integer+), +minute+ (+Integer+),
3808
+ * +second+ (+Integer+), and +sec_fraction+ (+Float+). Note that
3809
+ * +sec_fraction+ is the fraction of the second as a fraction of the day,
3810
+ * so it will be in the range [0.0, 1.0/86400.0).
3811
+ */
3812
+ static VALUE rhrd_s_day_fraction_to_time(VALUE klass, VALUE rf) {
3813
+ double f;
3814
+ int h, m, s;
3815
+
3816
+ f = NUM2DBL(rf) * 24;
3817
+ h = floor(f);
3818
+ f = (f - h) * 60;
3819
+ m = floor(f);
3820
+ f = (f - m) * 60;
3821
+ s = floor(f);
3822
+ f = (f - s)/RHR_SECONDS_PER_DAY;
3823
+ return rb_ary_new3(4, LONG2NUM(h), LONG2NUM(m), LONG2NUM(s), rb_float_new(f));
3824
+ }
3825
+
3826
+ /* call-seq:
3827
+ * [ruby 1-8 only] <br />
3828
+ * gregorian?(jd, sg) -> true or false
3829
+ *
3830
+ * If +sg+ is +nil+ or +false+, returns +false+. If +sg+ is +Numeric+,
3831
+ * returns +true+ if +jd+ is greater than or equal to +sg+, and +false+
3832
+ * otherwise. If +sg+ is not +Numeric+, +nil+, or +false+, returns +true+.
3833
+ */
3834
+ static VALUE rhrd_s_gregorian_q(VALUE klass, VALUE jd, VALUE sg) {
3835
+ if (RTEST((rb_obj_is_kind_of(sg, rb_cNumeric)))) {
3836
+ return rb_funcall(jd, rhrd_id_op_gte, 1, sg);
3837
+ } else {
3838
+ return RTEST(sg) ? Qtrue : Qfalse;
3839
+ }
3840
+ }
3841
+
3842
+ /* call-seq:
3843
+ * [ruby 1-8 only] <br />
3844
+ * jd_to_ajd(jd, rf, of=nil) -> Integer
3845
+ *
3846
+ * Returns +jd+. Ignores the 2nd and 3rd arguments.
3847
+ */
3848
+ static VALUE rhrd_s_jd_to_ajd(int argc, VALUE *argv, VALUE klass) {
3849
+ switch(argc) {
3850
+ case 2:
3851
+ case 3:
3852
+ break;
3853
+ default:
3854
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
3855
+ break;
3856
+ }
3857
+ return argv[0];
3858
+ }
3859
+
3860
+ /* call-seq:
3861
+ * [ruby 1-8 only] <br />
3862
+ * jd_to_civil(jd, sg=nil) -> [year, month, day]
3863
+ *
3864
+ * Converts +jd+ to an array with 3 +Integer+ values: +year+, +month+,
3865
+ * and +day+. Ignores the 2nd argument.
3866
+ */
3867
+ static VALUE rhrd_s_jd_to_civil(int argc, VALUE *argv, VALUE klass) {
3868
+ rhrd_t d;
3869
+ memset(&d, 0, sizeof(rhrd_t));
3870
+
3871
+ switch(argc) {
3872
+ case 1:
3873
+ case 2:
3874
+ d.jd = NUM2LONG(argv[0]);
3875
+ break;
3876
+ default:
3877
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
3878
+ break;
3879
+ }
3880
+ RHR_FILL_CIVIL(&d)
3881
+ return rb_ary_new3(3, LONG2NUM(d.year), LONG2NUM(d.month), LONG2NUM(d.day));
3882
+ }
3883
+
3884
+ /* call-seq:
3885
+ * [ruby 1-8 only] <br />
3886
+ * jd_to_commercial(jd, sg=nil) -> [cwyear, cweek, cwday]
3887
+ *
3888
+ * Converts +jd+ to an array with 3 +Integer+ values: +cwyear+, +cweek+,
3889
+ * and +cwday+. Ignores the 2nd argument.
3890
+ */
3891
+ static VALUE rhrd_s_jd_to_commercial(int argc, VALUE *argv, VALUE klass) {
3892
+ rhrd_t d;
3893
+ memset(&d, 0, sizeof(rhrd_t));
3894
+
3895
+ switch(argc) {
3896
+ case 1:
3897
+ case 2:
3898
+ d.jd = NUM2LONG(argv[0]);
3899
+ break;
3900
+ default:
3901
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
3902
+ break;
3903
+ }
3904
+ rhrd__fill_commercial(&d);
3905
+ return rb_ary_new3(3, LONG2NUM(d.year), LONG2NUM(d.month), LONG2NUM(d.day));
3906
+ }
3907
+
3908
+ /* call-seq:
3909
+ * [ruby 1-8 only] <br />
3910
+ * jd_to_ld(jd) -> Integer
3911
+ *
3912
+ * Converts +jd+ to a Lilian Date (the number of days since the day of calendar
3913
+ * reform in Italy).
3914
+ */
3915
+ static VALUE rhrd_s_jd_to_ld(VALUE klass, VALUE jd) {
3916
+ return LONG2NUM(rhrd__safe_add_long(-RHR_JD_LD, NUM2LONG(jd)));
3917
+ }
3918
+
3919
+ /* call-seq:
3920
+ * [ruby 1-8 only] <br />
3921
+ * jd_to_mjd(jd) -> Integer
3922
+ *
3923
+ * Converts +jd+ to a modified julian date +Integer+.
3924
+ */
3925
+ static VALUE rhrd_s_jd_to_mjd(VALUE klass, VALUE jd) {
3926
+ return LONG2NUM(rhrd__safe_add_long(-RHR_JD_MJD, NUM2LONG(jd)));
3927
+ }
3928
+
3929
+ /* call-seq:
3930
+ * [ruby 1-8 only] <br />
3931
+ * jd_to_ordinal(jd, sg=nil) -> [year, yday]
3932
+ *
3933
+ * Converts +jd+ to an array with 2 +Integer+ values: +year+ and +yday+ (day of year).
3934
+ * Ignores the 2nd argument.
3935
+ */
3936
+ static VALUE rhrd_s_jd_to_ordinal(int argc, VALUE *argv, VALUE klass) {
3937
+ rhrd_t d;
3938
+ memset(&d, 0, sizeof(rhrd_t));
3939
+
3940
+ switch(argc) {
3941
+ case 1:
3942
+ case 2:
3943
+ d.jd = NUM2LONG(argv[0]);
3944
+ break;
3945
+ default:
3946
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
3947
+ break;
3948
+ }
3949
+ RHR_FILL_CIVIL(&d)
3950
+
3951
+ return rb_ary_new3(2, LONG2NUM(d.year), LONG2NUM(rhrd__ordinal_day(d.year, d.month, d.day)));
3952
+ }
3953
+
3954
+ /* call-seq:
3955
+ * [ruby 1-8 only] <br />
3956
+ * jd_to_wday(jd) -> Integer
3957
+ *
3958
+ * Converts +jd+ to an +Integer+ day of the week, where 0 represents Sunday
3959
+ * and 6 represents Saturday.
3960
+ */
3961
+ static VALUE rhrd_s_jd_to_wday(VALUE klass, VALUE jd) {
3962
+ return LONG2NUM(rhrd__jd_to_wday(NUM2LONG(jd)));
3963
+ }
3964
+
3965
+ /* call-seq:
3966
+ * [ruby 1-8 only] <br />
3967
+ * julian?(jd, sg) -> true or false
3968
+ *
3969
+ * If +sg+ is +nil+ or +false+, returns +true+. If +sg+ is +Numeric+,
3970
+ * returns +true+ if +jd+ is less than +sg+, and +false+
3971
+ * otherwise. If +sg+ is not +Numeric+, +nil+, or +false+, returns +false+.
3972
+ */
3973
+ static VALUE rhrd_s_julian_q(VALUE klass, VALUE jd, VALUE sg) {
3974
+ if (RTEST((rb_obj_is_kind_of(sg, rb_cNumeric)))) {
3975
+ return rb_funcall(jd, rhrd_id_op_lt, 1, sg);
3976
+ } else {
3977
+ return RTEST(sg) ? Qfalse : Qtrue;
3978
+ }
3979
+ }
3980
+
3981
+ /* call-seq:
3982
+ * [ruby 1-8 only] <br />
3983
+ * ld_to_jd(ld) -> Integer
3984
+ *
3985
+ * Converts +ld+ (a Lilian Date) to a julian day +Integer+.
3986
+ */
3987
+ static VALUE rhrd_s_ld_to_jd(VALUE klass, VALUE ld) {
3988
+ return LONG2NUM(rhrd__safe_add_long(RHR_JD_LD, NUM2LONG(ld)));
3989
+ }
3990
+
3991
+ /* call-seq:
3992
+ * [ruby 1-8 only] <br />
3993
+ * mjd_to_jd(mjd) -> Integer
3994
+ *
3995
+ * Converts a modified julian date number to a julian day +Integer+.
3996
+ */
3997
+ static VALUE rhrd_s_mjd_to_jd(VALUE klass, VALUE mjd) {
3998
+ return LONG2NUM(rhrd__safe_add_long(RHR_JD_MJD, NUM2LONG(mjd)));
3999
+ }
4000
+
4001
+ /* call-seq:
4002
+ * [ruby 1-8 only] <br />
4003
+ * ordinal_to_jd(year, yday, sg=nil) -> Integer
4004
+ *
4005
+ * Converts the given +year+ and +yday+ (day of year) into a julian day +Integer+.
4006
+ * Ignores the 3rd argument.
4007
+ */
4008
+ static VALUE rhrd_s_ordinal_to_jd(int argc, VALUE *argv, VALUE klass) {
4009
+ switch(argc) {
4010
+ case 2:
4011
+ case 3:
4012
+ return LONG2NUM(rhrd__ymd_to_jd(NUM2LONG(argv[0]), 1, NUM2LONG(argv[1])));
4013
+ break;
4014
+ default:
4015
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
4016
+ break;
4017
+ }
4018
+ }
4019
+
4020
+ /* call-seq:
4021
+ * [ruby 1-8 only] <br />
4022
+ * time_to_day_fraction(hour, minute, second) -> Float
4023
+ *
4024
+ * Converts the given +hour+, +minute+, and +second+ into a single +Float+ representing
4025
+ * the fraction of the day, such that 12 hours, 0 minutes, and 0 seconds would return
4026
+ * 0.5.
4027
+ */
4028
+ static VALUE rhrd_s_time_to_day_fraction(VALUE klass, VALUE h, VALUE m, VALUE s) {
4029
+ return rb_float_new(NUM2DBL(h)/24.0 + NUM2DBL(m)/RHR_MINUTES_PER_DAYD + NUM2DBL(s)/RHR_SECONDS_PER_DAYD);
4030
+ }
4031
+
4032
+ /* call-seq:
4033
+ * [ruby 1-8 only] <br />
4034
+ * valid_time?(hour, minute, second) -> Float
4035
+ *
4036
+ * Checks that the hour, minute, and second are a valid time. This handles negative
4037
+ * values for all 3 arguments, so that -10 minutes is treated as 50 minutes. It returns
4038
+ * a +Float+ representing the fraction of the day for the given values.
4039
+ */
4040
+ static VALUE rhrd_s_valid_time_q(VALUE klass, VALUE rh, VALUE rm, VALUE rs) {
4041
+ long h, m, s;
4042
+ h = NUM2LONG(rh);
4043
+ m = NUM2LONG(rm);
4044
+ s = NUM2LONG(rs);
4045
+ if (h < 0) {
4046
+ h += 24;
4047
+ }
4048
+ if (m < 0) {
4049
+ m += 60;
4050
+ }
4051
+ if (s < 0) {
4052
+ s += 60;
4053
+ }
4054
+ if (h < 0 || m < 0 || s < 0 || h > 24 || m > 59 || s > 59 || (h == 24 && m != 0 && s != 0)) {
4055
+ return Qnil;
4056
+ }
4057
+ return rb_float_new(h/24.0 + m/RHR_MINUTES_PER_DAYD + s/RHR_SECONDS_PER_DAYD);
4058
+ }
4059
+
4060
+ #endif
4061
+
4062
+ #include "datetime.c"
4063
+
4064
+ /* Ruby Library Initialization */
4065
+
4066
+ /* +Date+ is used to store a single date in the gregorian calendar.
4067
+ *
4068
+ * In general, +Date+ objects are created by calling one of the class
4069
+ * methods: +civil+, +parse+, +strptime+, +today+. Once created,
4070
+ * +Date+ objects are immutable. Operations that result in a separate
4071
+ * date (such as adding a number of days), always return a new +Date+
4072
+ * object.
4073
+ * */
4074
+ void Init_date_ext(void) {
4075
+ int i;
4076
+
4077
+ /* Setup static IDs and symbols */
4078
+
4079
+ rhrd_id_op_array = rb_intern("[]");
4080
+ rhrd_id_op_gte = rb_intern(">=");
4081
+ rhrd_id_op_lt = rb_intern("<");
4082
+ rhrd_id__parse = rb_intern("_parse");
4083
+ rhrd_id_cwday = rb_intern("cwday");
4084
+ rhrd_id_cweek = rb_intern("cweek");
4085
+ rhrd_id_cwyear = rb_intern("cwyear");
4086
+ rhrd_id_downcase = rb_intern("downcase");
4087
+ rhrd_id_getlocal = rb_intern("getlocal");
4088
+ rhrd_id_hash = rb_intern("hash");
4089
+ rhrd_id_length = rb_intern("length");
4090
+ rhrd_id_include_q = rb_intern("include?");
4091
+ rhrd_id_local = rb_intern("local");
4092
+ rhrd_id_localtime = rb_intern("localtime");
4093
+ rhrd_id_match = rb_intern("match");
4094
+ rhrd_id_now = rb_intern("now");
4095
+ rhrd_id_offset = rb_intern("offset");
4096
+ rhrd_id_slice = rb_intern("slice");
4097
+ rhrd_id_split = rb_intern("split");
4098
+ rhrd_id_sub_b = rb_intern("sub!");
4099
+ rhrd_id_to_i = rb_intern("to_i");
4100
+ #ifdef RUBY19
4101
+ rhrd_id_nsec = rb_intern("nsec");
4102
+ #else
4103
+ rhrd_id_usec = rb_intern("usec");
4104
+ #endif
4105
+ rhrd_id_utc = rb_intern("utc");
4106
+ rhrd_id_utc_offset = rb_intern("utc_offset");
4107
+
4108
+ #ifdef RUBY19
4109
+ rhrd_id__httpdate = rb_intern("_httpdate");
4110
+ rhrd_id__iso8601 = rb_intern("_iso8601");
4111
+ rhrd_id__jisx0301 = rb_intern("_jisx0301");
4112
+ rhrd_id__rfc2822 = rb_intern("_rfc2822");
4113
+ rhrd_id__rfc3339 = rb_intern("_rfc3339");
4114
+ rhrd_id__xmlschema = rb_intern("_xmlschema");
4115
+ #endif
4116
+
4117
+ rhrd_sym_cwday = ID2SYM(rb_intern("cwday"));
4118
+ rhrd_sym_cweek = ID2SYM(rb_intern("cweek"));
4119
+ rhrd_sym_cwyear = ID2SYM(rb_intern("cwyear"));
4120
+ rhrd_sym_hour = ID2SYM(rb_intern("hour"));
4121
+ #ifdef RUBY19
4122
+ rhrd_sym_leftover = ID2SYM(rb_intern("leftover"));
4123
+ #endif
4124
+ rhrd_sym_mday = ID2SYM(rb_intern("mday"));
4125
+ rhrd_sym_min = ID2SYM(rb_intern("min"));
4126
+ rhrd_sym_mon = ID2SYM(rb_intern("mon"));
4127
+ rhrd_sym_offset = ID2SYM(rb_intern("offset"));
4128
+ rhrd_sym_sec = ID2SYM(rb_intern("sec"));
4129
+ rhrd_sym_sec_fraction = ID2SYM(rb_intern("sec_fraction"));
4130
+ rhrd_sym_seconds = ID2SYM(rb_intern("seconds"));
4131
+ rhrd_sym_wday = ID2SYM(rb_intern("wday"));
4132
+ rhrd_sym_wnum0 = ID2SYM(rb_intern("wnum0"));
4133
+ rhrd_sym_wnum1 = ID2SYM(rb_intern("wnum1"));
4134
+ rhrd_sym_yday = ID2SYM(rb_intern("yday"));
4135
+ rhrd_sym_year = ID2SYM(rb_intern("year"));
4136
+ rhrd_sym_zone = ID2SYM(rb_intern("zone"));
4137
+
4138
+ /* Define classes*/
4139
+
4140
+ rhrd_class = rb_define_class("Date", rb_cObject);
4141
+ rb_undef_alloc_func(rhrd_class);
4142
+ rhrd_s_class = rb_singleton_class(rhrd_class);
4143
+
4144
+ /* Define methods for all ruby versions */
4145
+
4146
+ rb_define_method(rhrd_s_class, "_load", rhrd_s__load, 1);
4147
+ rb_define_method(rhrd_s_class, "_strptime", rhrd_s__strptime, -1);
4148
+ rb_define_method(rhrd_s_class, "civil", rhrd_s_civil, -1);
4149
+ rb_define_method(rhrd_s_class, "commercial", rhrd_s_commercial, -1);
4150
+ rb_define_method(rhrd_s_class, "gregorian_leap?", rhrd_s_gregorian_leap_q, 1);
4151
+ rb_define_method(rhrd_s_class, "jd", rhrd_s_jd, -1);
4152
+ rb_define_method(rhrd_s_class, "julian_leap?", rhrd_s_julian_leap_q, 1);
4153
+ rb_define_method(rhrd_s_class, "new!", rhrd_s_new_b, -1);
4154
+ rb_define_method(rhrd_s_class, "ordinal", rhrd_s_ordinal, -1);
4155
+ rb_define_method(rhrd_s_class, "parse", rhrd_s_parse, -1);
4156
+ rb_define_method(rhrd_s_class, "strptime", rhrd_s_strptime, -1);
4157
+ rb_define_method(rhrd_s_class, "today", rhrd_s_today, -1);
4158
+ rb_define_method(rhrd_s_class, "valid_civil?", rhrd_s_valid_civil_q, -1);
4159
+ rb_define_method(rhrd_s_class, "valid_commercial?", rhrd_s_valid_commercial_q, -1);
4160
+ rb_define_method(rhrd_s_class, "valid_jd?", rhrd_s_valid_jd_q, -1);
4161
+ rb_define_method(rhrd_s_class, "valid_ordinal?", rhrd_s_valid_ordinal_q, -1);
4162
+
4163
+ rb_define_alias(rhrd_s_class, "leap?", "gregorian_leap?");
4164
+ rb_define_alias(rhrd_s_class, "new", "civil");
4165
+ rb_define_alias(rhrd_s_class, "valid_date?", "valid_civil?");
4166
+
4167
+ rb_define_private_method(rhrd_s_class, "_ragel_parse", rhrd_s__ragel_parse, 1);
4168
+
4169
+ rb_define_method(rhrd_class, "_dump", rhrd__dump, 1);
4170
+ rb_define_method(rhrd_class, "asctime", rhrd_asctime, 0);
4171
+ rb_define_method(rhrd_class, "cwday", rhrd_cwday, 0);
4172
+ rb_define_method(rhrd_class, "cweek", rhrd_cweek, 0);
4173
+ rb_define_method(rhrd_class, "cwyear", rhrd_cwyear, 0);
4174
+ rb_define_method(rhrd_class, "day", rhrd_day, 0);
4175
+ rb_define_method(rhrd_class, "day_fraction", rhrd_day_fraction, 0);
4176
+ rb_define_method(rhrd_class, "downto", rhrd_downto, 1);
4177
+ rb_define_method(rhrd_class, "eql?", rhrd_eql_q, 1);
4178
+ rb_define_method(rhrd_class, "gregorian", rhrd_gregorian, 0);
4179
+ rb_define_method(rhrd_class, "gregorian?", rhrd_gregorian_q, 0);
4180
+ rb_define_method(rhrd_class, "hash", rhrd_hash, 0);
4181
+ rb_define_method(rhrd_class, "inspect", rhrd_inspect, 0);
4182
+ rb_define_method(rhrd_class, "jd", rhrd_jd, 0);
4183
+ rb_define_method(rhrd_class, "julian?", rhrd_julian_q, 0);
4184
+ rb_define_method(rhrd_class, "ld", rhrd_ld, 0);
4185
+ rb_define_method(rhrd_class, "leap?", rhrd_leap_q, 0);
4186
+ rb_define_method(rhrd_class, "mjd", rhrd_mjd, 0);
4187
+ rb_define_method(rhrd_class, "month", rhrd_month, 0);
4188
+ rb_define_method(rhrd_class, "next", rhrd_next, 0);
4189
+ rb_define_method(rhrd_class, "new_start", rhrd_new_start, -1);
4190
+ rb_define_method(rhrd_class, "start", rhrd_start, 0);
4191
+ rb_define_method(rhrd_class, "step", rhrd_step, -1);
4192
+ rb_define_method(rhrd_class, "strftime", rhrd_strftime, -1);
4193
+ rb_define_method(rhrd_class, "to_s", rhrd_to_s, 0);
4194
+ rb_define_method(rhrd_class, "upto", rhrd_upto, 1);
4195
+ rb_define_method(rhrd_class, "wday", rhrd_wday, 0);
4196
+ rb_define_method(rhrd_class, "yday", rhrd_yday, 0);
4197
+ rb_define_method(rhrd_class, "year", rhrd_year, 0);
4198
+
4199
+ rb_define_alias(rhrd_class, "ajd", "jd");
4200
+ rb_define_alias(rhrd_class, "amjd", "mjd");
4201
+ rb_define_alias(rhrd_class, "ctime", "asctime");
4202
+ rb_define_alias(rhrd_class, "england", "gregorian");
4203
+ rb_define_alias(rhrd_class, "italy", "gregorian");
4204
+ rb_define_alias(rhrd_class, "julian", "gregorian");
4205
+ rb_define_alias(rhrd_class, "mday", "day");
4206
+ rb_define_alias(rhrd_class, "mon", "month");
4207
+ rb_define_alias(rhrd_class, "succ", "next");
4208
+
4209
+ rb_define_method(rhrd_class, ">>", rhrd_op_right_shift, 1);
4210
+ rb_define_method(rhrd_class, "<<", rhrd_op_left_shift, 1);
4211
+ rb_define_method(rhrd_class, "+", rhrd_op_plus, 1);
4212
+ rb_define_method(rhrd_class, "-", rhrd_op_minus, 1);
4213
+ rb_define_method(rhrd_class, "===", rhrd_op_relationship, 1);
4214
+ rb_define_method(rhrd_class, "<=>", rhrd_op_spaceship, 1);
4215
+
4216
+ rb_funcall(rhrd_class, rb_intern("include"), 1, rb_mComparable);
4217
+
4218
+ /* Setup static constants */
4219
+
4220
+ rhrd_monthnames = rb_ary_new2(13);
4221
+ rhrd_abbr_monthnames = rb_ary_new2(13);
4222
+ rb_ary_push(rhrd_monthnames, Qnil);
4223
+ rb_ary_push(rhrd_abbr_monthnames, Qnil);
4224
+ for(i = 1; i < 13; i++) {
4225
+ rb_ary_push(rhrd_monthnames, rb_str_new2(rhrd__month_names[i]));
4226
+ rb_ary_push(rhrd_abbr_monthnames, rb_str_new2(rhrd__abbr_month_names[i]));
4227
+ }
4228
+
4229
+ rhrd_daynames = rb_ary_new2(7);
4230
+ rhrd_abbr_daynames = rb_ary_new2(7);
4231
+ for(i = 0; i < 7; i++) {
4232
+ rb_ary_push(rhrd_daynames, rb_str_new2(rhrd__day_names[i]));
4233
+ rb_ary_push(rhrd_abbr_daynames, rb_str_new2(rhrd__abbr_day_names[i]));
4234
+ }
4235
+
4236
+ rhrd_zones_hash = rb_hash_new();
4237
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("a"), LONG2NUM(3600));
4238
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("adt"), LONG2NUM(-10800));
4239
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("afghanistan"), LONG2NUM(16200));
4240
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ahst"), LONG2NUM(-36000));
4241
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("akdt"), LONG2NUM(-28800));
4242
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("akst"), LONG2NUM(-32400));
4243
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("alaskan"), LONG2NUM(-32400));
4244
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("arab"), LONG2NUM(10800));
4245
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("arabian"), LONG2NUM(14400));
4246
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("arabic"), LONG2NUM(10800));
4247
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("art"), LONG2NUM(-10800));
4248
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ast"), LONG2NUM(-14400));
4249
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("at"), LONG2NUM(-7200));
4250
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("atlantic"), LONG2NUM(-14400));
4251
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("aus central"), LONG2NUM(34200));
4252
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("aus eastern"), LONG2NUM(36000));
4253
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("azores"), LONG2NUM(-3600));
4254
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("b"), LONG2NUM(7200));
4255
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("brst"), LONG2NUM(-7200));
4256
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("brt"), LONG2NUM(-10800));
4257
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("bst"), LONG2NUM(3600));
4258
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("bt"), LONG2NUM(10800));
4259
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("c"), LONG2NUM(10800));
4260
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("canada central"), LONG2NUM(-21600));
4261
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cape verde"), LONG2NUM(-3600));
4262
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cat"), LONG2NUM(-36000));
4263
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("caucasus"), LONG2NUM(14400));
4264
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cct"), LONG2NUM(28800));
4265
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cdt"), LONG2NUM(-18000));
4266
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cen. australia"), LONG2NUM(34200));
4267
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central"), LONG2NUM(-21600));
4268
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central america"), LONG2NUM(-21600));
4269
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central asia"), LONG2NUM(21600));
4270
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central europe"), LONG2NUM(3600));
4271
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central european"), LONG2NUM(3600));
4272
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("central pacific"), LONG2NUM(39600));
4273
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cest"), LONG2NUM(7200));
4274
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cet"), LONG2NUM(3600));
4275
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("china"), LONG2NUM(28800));
4276
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("clst"), LONG2NUM(-10800));
4277
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("clt"), LONG2NUM(-14400));
4278
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("cst"), LONG2NUM(-21600));
4279
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("d"), LONG2NUM(14400));
4280
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("dateline"), LONG2NUM(-43200));
4281
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("e"), LONG2NUM(18000));
4282
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("e. africa"), LONG2NUM(10800));
4283
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("e. australia"), LONG2NUM(36000));
4284
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("e. europe"), LONG2NUM(7200));
4285
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("e. south america"), LONG2NUM(-10800));
4286
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("eadt"), LONG2NUM(39600));
4287
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("east"), LONG2NUM(36000));
4288
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("eastern"), LONG2NUM(-18000));
4289
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("eat"), LONG2NUM(10800));
4290
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("edt"), LONG2NUM(-14400));
4291
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("eest"), LONG2NUM(10800));
4292
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("eet"), LONG2NUM(7200));
4293
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("egypt"), LONG2NUM(7200));
4294
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ekaterinburg"), LONG2NUM(18000));
4295
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("est"), LONG2NUM(-18000));
4296
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("f"), LONG2NUM(21600));
4297
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("fiji"), LONG2NUM(43200));
4298
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("fle"), LONG2NUM(7200));
4299
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("fst"), LONG2NUM(7200));
4300
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("fwt"), LONG2NUM(3600));
4301
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("g"), LONG2NUM(25200));
4302
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("gmt"), LONG2NUM(0));
4303
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("greenland"), LONG2NUM(-10800));
4304
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("greenwich"), LONG2NUM(0));
4305
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("gst"), LONG2NUM(36000));
4306
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("gtb"), LONG2NUM(7200));
4307
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("h"), LONG2NUM(28800));
4308
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("hadt"), LONG2NUM(-32400));
4309
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("hast"), LONG2NUM(-36000));
4310
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("hawaiian"), LONG2NUM(-36000));
4311
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("hdt"), LONG2NUM(-32400));
4312
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("hst"), LONG2NUM(-36000));
4313
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("i"), LONG2NUM(32400));
4314
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("idle"), LONG2NUM(43200));
4315
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("idlw"), LONG2NUM(-43200));
4316
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("india"), LONG2NUM(19800));
4317
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("iran"), LONG2NUM(12600));
4318
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ist"), LONG2NUM(19800));
4319
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("jerusalem"), LONG2NUM(7200));
4320
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("jst"), LONG2NUM(32400));
4321
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("k"), LONG2NUM(36000));
4322
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("korea"), LONG2NUM(32400));
4323
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("kst"), LONG2NUM(32400));
4324
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("l"), LONG2NUM(39600));
4325
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("m"), LONG2NUM(43200));
4326
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("malay peninsula"), LONG2NUM(28800));
4327
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mdt"), LONG2NUM(-21600));
4328
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mest"), LONG2NUM(7200));
4329
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mesz"), LONG2NUM(7200));
4330
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("met"), LONG2NUM(3600));
4331
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mewt"), LONG2NUM(3600));
4332
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mexico"), LONG2NUM(-21600));
4333
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mez"), LONG2NUM(3600));
4334
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mid-atlantic"), LONG2NUM(-7200));
4335
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mountain"), LONG2NUM(-25200));
4336
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("msd"), LONG2NUM(14400));
4337
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("msk"), LONG2NUM(10800));
4338
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("mst"), LONG2NUM(-25200));
4339
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("myanmar"), LONG2NUM(23400));
4340
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("n"), LONG2NUM(-3600));
4341
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("n. central asia"), LONG2NUM(21600));
4342
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ndt"), LONG2NUM(-9000));
4343
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nepal"), LONG2NUM(20700));
4344
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("new zealand"), LONG2NUM(43200));
4345
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("newfoundland"), LONG2NUM(-12600));
4346
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("north asia"), LONG2NUM(25200));
4347
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("north asia east"), LONG2NUM(28800));
4348
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nst"), LONG2NUM(-12600));
4349
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nt"), LONG2NUM(-39600));
4350
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nzdt"), LONG2NUM(46800));
4351
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nzst"), LONG2NUM(43200));
4352
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("nzt"), LONG2NUM(43200));
4353
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("o"), LONG2NUM(-7200));
4354
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("p"), LONG2NUM(-10800));
4355
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("pacific"), LONG2NUM(-28800));
4356
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("pacific sa"), LONG2NUM(-14400));
4357
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("pdt"), LONG2NUM(-25200));
4358
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("pst"), LONG2NUM(-28800));
4359
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("q"), LONG2NUM(-14400));
4360
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("r"), LONG2NUM(-18000));
4361
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("romance"), LONG2NUM(3600));
4362
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("russian"), LONG2NUM(10800));
4363
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("s"), LONG2NUM(-21600));
4364
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sa eastern"), LONG2NUM(-10800));
4365
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sa pacific"), LONG2NUM(-18000));
4366
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sa western"), LONG2NUM(-14400));
4367
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("samoa"), LONG2NUM(-39600));
4368
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sast"), LONG2NUM(7200));
4369
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("se asia"), LONG2NUM(25200));
4370
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sgt"), LONG2NUM(28800));
4371
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("south africa"), LONG2NUM(7200));
4372
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sri lanka"), LONG2NUM(21600));
4373
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("sst"), LONG2NUM(7200));
4374
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("swt"), LONG2NUM(3600));
4375
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("t"), LONG2NUM(-25200));
4376
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("taipei"), LONG2NUM(28800));
4377
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("tasmania"), LONG2NUM(36000));
4378
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("tokyo"), LONG2NUM(32400));
4379
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("tonga"), LONG2NUM(46800));
4380
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("u"), LONG2NUM(-28800));
4381
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("us eastern"), LONG2NUM(-18000));
4382
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("us mountain"), LONG2NUM(-25200));
4383
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ut"), LONG2NUM(0));
4384
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("utc"), LONG2NUM(0));
4385
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("v"), LONG2NUM(-32400));
4386
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("vladivostok"), LONG2NUM(36000));
4387
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("w"), LONG2NUM(-36000));
4388
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("w. australia"), LONG2NUM(28800));
4389
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("w. central africa"), LONG2NUM(3600));
4390
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("w. europe"), LONG2NUM(3600));
4391
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("wadt"), LONG2NUM(28800));
4392
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("wast"), LONG2NUM(25200));
4393
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("wat"), LONG2NUM(3600));
4394
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("west"), LONG2NUM(3600));
4395
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("west asia"), LONG2NUM(18000));
4396
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("west pacific"), LONG2NUM(36000));
4397
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("wet"), LONG2NUM(0));
4398
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("x"), LONG2NUM(-39600));
4399
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("y"), LONG2NUM(-43200));
4400
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("yakutsk"), LONG2NUM(32400));
4401
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("ydt"), LONG2NUM(-28800));
4402
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("yst"), LONG2NUM(-32400));
4403
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("z"), LONG2NUM(0));
4404
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("zp4"), LONG2NUM(14400));
4405
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("zp5"), LONG2NUM(18000));
4406
+ rb_hash_aset(rhrd_zones_hash, rb_str_new2("zp6"), LONG2NUM(21600));
4407
+
4408
+ rhrd_start_num = LONG2NUM(RHR_JD_MIN - 1);
4409
+ rhrd_empty_string = rb_str_new("", 0);
4410
+ rhrd_string_colon = rb_str_new(":", 1);
4411
+
4412
+ /* Define some static regexps. The 1 for the options makes
4413
+ * it case insensitive, as I don't want to deal with including
4414
+ * the ruby regex header just to get it. */
4415
+ rhrd_zone_re = rb_reg_new(rhrd__zone_re_str, strlen(rhrd__zone_re_str), 1);
4416
+ rhrd_zone_dst_re = rb_reg_new(rhrd__zone_dst_re_str, strlen(rhrd__zone_dst_re_str), 1);
4417
+ rhrd_zone_sign_re = rb_reg_new(rhrd__zone_sign_re_str, strlen(rhrd__zone_sign_re_str), 1);
4418
+ rhrd_re_comma_period = rb_reg_new("[,.]", 4, 0);
4419
+
4420
+ /* Register global variables with Garbage collector, so users
4421
+ * who remove constants can't crash the interpreter. */
4422
+
4423
+ rb_global_variable(&rhrd_zones_hash);
4424
+ rb_global_variable(&rhrd_monthnames);
4425
+ rb_global_variable(&rhrd_abbr_monthnames);
4426
+ rb_global_variable(&rhrd_daynames);
4427
+ rb_global_variable(&rhrd_abbr_daynames);
4428
+ rb_global_variable(&rhrd_start_num);
4429
+ rb_global_variable(&rhrd_empty_string);
4430
+ rb_global_variable(&rhrd_string_colon);
4431
+ rb_global_variable(&rhrd_zone_re);
4432
+ rb_global_variable(&rhrd_zone_dst_re);
4433
+ rb_global_variable(&rhrd_zone_sign_re);
4434
+ rb_global_variable(&rhrd_re_comma_period);
4435
+
4436
+ /* Define constants accessible from ruby */
4437
+
4438
+ /* The julian day number for the day of calendar reform in Italy */
4439
+ rb_define_const(rhrd_class, "ITALY", LONG2NUM(RHR_JD_ITALY));
4440
+ /* The julian day number for the day of calendar reform in England */
4441
+ rb_define_const(rhrd_class, "ENGLAND", LONG2NUM(RHR_JD_ENGLAND));
4442
+ /* An integer lower than the lowest supported julian day number */
4443
+ rb_define_const(rhrd_class, "GREGORIAN", rhrd_start_num);
4444
+ /* An integer higher than the highest supported julian day number */
4445
+ rb_define_const(rhrd_class, "JULIAN", LONG2NUM(RHR_JD_MAX + 1));
4446
+
4447
+ /* A hash mapping lowercase time zone names to offsets
4448
+ * in seconds<br />ZONES['pst'] => -28800 */
4449
+ rb_define_const(rhrd_class, "ZONES", rhrd_zones_hash);
4450
+ /* An array of month names<br />MONTHNAMES[1] => 'January' */
4451
+ rb_define_const(rhrd_class, "MONTHNAMES", rhrd_monthnames);
4452
+ /* An array of abbreviated month names<br />ABBR_MONTHNAMES[1] => 'Jan' */
4453
+ rb_define_const(rhrd_class, "ABBR_MONTHNAMES", rhrd_abbr_monthnames);
4454
+ /* An array of day names<br />DAYNAMES[0] => 'Sunday' */
4455
+ rb_define_const(rhrd_class, "DAYNAMES", rhrd_daynames);
4456
+ /* An array of abbreviated day names<br />ABBR_DAYNAMES[0] => 'Sun' */
4457
+ rb_define_const(rhrd_class, "ABBR_DAYNAMES", rhrd_abbr_daynames);
4458
+
4459
+ #ifdef RUBY19
4460
+
4461
+ /* Define ruby 1.9 only methods */
4462
+
4463
+ rb_define_method(rhrd_s_class, "httpdate", rhrd_s_httpdate, -1);
4464
+ rb_define_method(rhrd_s_class, "iso8601", rhrd_s_iso8601, -1);
4465
+ rb_define_method(rhrd_s_class, "jisx0301", rhrd_s_jisx0301, -1);
4466
+ rb_define_method(rhrd_s_class, "rfc2822", rhrd_s_rfc2822, -1);
4467
+ rb_define_method(rhrd_s_class, "rfc3339", rhrd_s_rfc3339, -1);
4468
+ rb_define_method(rhrd_s_class, "xmlschema", rhrd_s_xmlschema, -1);
4469
+
4470
+ rb_define_alias(rhrd_s_class, "rfc822", "rfc2822");
4471
+
4472
+ rb_define_method(rhrd_class, "httpdate", rhrd_httpdate, 0);
4473
+ rb_define_method(rhrd_class, "jisx0301", rhrd_jisx0301, 0);
4474
+ rb_define_method(rhrd_class, "next_day", rhrd_next_day, -1);
4475
+ rb_define_method(rhrd_class, "next_month", rhrd_next_month, -1);
4476
+ rb_define_method(rhrd_class, "next_year", rhrd_next_year, -1);
4477
+ rb_define_method(rhrd_class, "prev_day", rhrd_prev_day, -1);
4478
+ rb_define_method(rhrd_class, "prev_month", rhrd_prev_month, -1);
4479
+ rb_define_method(rhrd_class, "prev_year", rhrd_prev_year, -1);
4480
+ rb_define_method(rhrd_class, "rfc2822", rhrd_rfc2822, 0);
4481
+ rb_define_method(rhrd_class, "rfc3339", rhrd_rfc3339, 0);
4482
+ rb_define_method(rhrd_class, "to_datetime", rhrd_to_datetime, 0);
4483
+ rb_define_method(rhrd_class, "to_time", rhrd_to_time, 0);
4484
+
4485
+ rb_define_alias(rhrd_class, "to_date", "gregorian");
4486
+ rb_define_alias(rhrd_class, "iso8601", "to_s");
4487
+ rb_define_alias(rhrd_class, "rfc822", "rfc2822");
4488
+ rb_define_alias(rhrd_class, "xmlschema", "to_s");
4489
+
4490
+ rb_define_method(rhrd_class, "sunday?", rhrd_sunday_q, 0);
4491
+ rb_define_method(rhrd_class, "monday?", rhrd_monday_q, 0);
4492
+ rb_define_method(rhrd_class, "tuesday?", rhrd_tuesday_q, 0);
4493
+ rb_define_method(rhrd_class, "wednesday?", rhrd_wednesday_q, 0);
4494
+ rb_define_method(rhrd_class, "thursday?", rhrd_thursday_q, 0);
4495
+ rb_define_method(rhrd_class, "friday?", rhrd_friday_q, 0);
4496
+ rb_define_method(rhrd_class, "saturday?", rhrd_saturday_q, 0);
4497
+
4498
+ rb_define_private_method(rhrd_s_class, "zone_to_diff", rhrd_s_zone_to_diff, 1);
4499
+
4500
+ rb_define_method(rb_cTime, "to_date", rhrd_time_to_date, 0);
4501
+ rb_define_method(rb_cTime, "to_time", rhrd_time_to_time, 0);
4502
+ #else
4503
+
4504
+ /* Define ruby 1.8 only methods */
4505
+
4506
+ rb_define_method(rhrd_s_class, "ajd_to_amjd", rhrd_s_ajd_to_amjd, 1);
4507
+ rb_define_method(rhrd_s_class, "ajd_to_jd", rhrd_s_ajd_to_jd, -1);
4508
+ rb_define_method(rhrd_s_class, "amjd_to_ajd", rhrd_s_amjd_to_ajd, 1);
4509
+ rb_define_method(rhrd_s_class, "civil_to_jd", rhrd_s_civil_to_jd, -1);
4510
+ rb_define_method(rhrd_s_class, "commercial_to_jd", rhrd_s_commercial_to_jd, -1);
4511
+ rb_define_method(rhrd_s_class, "day_fraction_to_time", rhrd_s_day_fraction_to_time, 1);
4512
+ rb_define_method(rhrd_s_class, "gregorian?", rhrd_s_gregorian_q, 2);
4513
+ rb_define_method(rhrd_s_class, "jd_to_ajd", rhrd_s_jd_to_ajd, -1);
4514
+ rb_define_method(rhrd_s_class, "jd_to_civil", rhrd_s_jd_to_civil, -1);
4515
+ rb_define_method(rhrd_s_class, "jd_to_commercial", rhrd_s_jd_to_commercial, -1);
4516
+ rb_define_method(rhrd_s_class, "jd_to_ld", rhrd_s_jd_to_ld, 1);
4517
+ rb_define_method(rhrd_s_class, "jd_to_mjd", rhrd_s_jd_to_mjd, 1);
4518
+ rb_define_method(rhrd_s_class, "jd_to_ordinal", rhrd_s_jd_to_ordinal, -1);
4519
+ rb_define_method(rhrd_s_class, "jd_to_wday", rhrd_s_jd_to_wday, 1);
4520
+ rb_define_method(rhrd_s_class, "julian?", rhrd_s_julian_q, 2);
4521
+ rb_define_method(rhrd_s_class, "ld_to_jd", rhrd_s_ld_to_jd, 1);
4522
+ rb_define_method(rhrd_s_class, "mjd_to_jd", rhrd_s_mjd_to_jd, 1);
4523
+ rb_define_method(rhrd_s_class, "ordinal_to_jd", rhrd_s_ordinal_to_jd, -1);
4524
+ rb_define_method(rhrd_s_class, "time_to_day_fraction", rhrd_s_time_to_day_fraction, 3);
4525
+ rb_define_method(rhrd_s_class, "valid_time?", rhrd_s_valid_time_q, 3);
4526
+ rb_define_method(rhrd_s_class, "zone_to_diff", rhrd_s_zone_to_diff, 1);
4527
+
4528
+ rb_define_alias(rhrd_s_class, "exist?", "valid_civil?");
4529
+ rb_define_alias(rhrd_s_class, "exist1?", "valid_jd?");
4530
+ rb_define_alias(rhrd_s_class, "exist2?", "valid_ordinal?");
4531
+ rb_define_alias(rhrd_s_class, "exist3?", "valid_civil?");
4532
+ rb_define_alias(rhrd_s_class, "existw?", "valid_commercial?");
4533
+ rb_define_alias(rhrd_s_class, "new0", "new!");
4534
+ rb_define_alias(rhrd_s_class, "new1", "jd");
4535
+ rb_define_alias(rhrd_s_class, "new2", "ordinal");
4536
+ rb_define_alias(rhrd_s_class, "new3", "civil");
4537
+ rb_define_alias(rhrd_s_class, "neww", "commercial");
4538
+ rb_define_alias(rhrd_s_class, "ns?", "gregorian?");
4539
+ rb_define_alias(rhrd_s_class, "os?", "julian?");
4540
+
4541
+ rb_define_alias(rhrd_class, "newsg", "new_start");
4542
+ rb_define_alias(rhrd_class, "ns?", "gregorian?");
4543
+ rb_define_alias(rhrd_class, "os?", "julian?");
4544
+ rb_define_alias(rhrd_class, "sg", "start");
4545
+ #endif
4546
+
4547
+ Init_datetime();
4548
+ }