home_run 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +19 -0
  3. data/README.rdoc +314 -0
  4. data/Rakefile +140 -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 +87 -0
  11. data/default.mspec +12 -0
  12. data/ext/date/format.rb +842 -0
  13. data/ext/date.rb +7 -0
  14. data/ext/date_ext.c +4548 -0
  15. data/ext/date_parser.c +367 -0
  16. data/ext/date_parser.rl +134 -0
  17. data/ext/datetime.c +2804 -0
  18. data/ext/extconf.rb +6 -0
  19. data/spec/date/accessor_spec.rb +176 -0
  20. data/spec/date/add_month_spec.rb +26 -0
  21. data/spec/date/add_spec.rb +23 -0
  22. data/spec/date/boat_spec.rb +38 -0
  23. data/spec/date/civil_spec.rb +147 -0
  24. data/spec/date/commercial_spec.rb +153 -0
  25. data/spec/date/constants_spec.rb +44 -0
  26. data/spec/date/conversions_spec.rb +246 -0
  27. data/spec/date/day_spec.rb +73 -0
  28. data/spec/date/downto_spec.rb +17 -0
  29. data/spec/date/eql_spec.rb +16 -0
  30. data/spec/date/format_spec.rb +52 -0
  31. data/spec/date/gregorian_spec.rb +52 -0
  32. data/spec/date/hash_spec.rb +11 -0
  33. data/spec/date/julian_spec.rb +129 -0
  34. data/spec/date/leap_spec.rb +19 -0
  35. data/spec/date/minus_month_spec.rb +25 -0
  36. data/spec/date/minus_spec.rb +51 -0
  37. data/spec/date/next_prev_spec.rb +108 -0
  38. data/spec/date/ordinal_spec.rb +83 -0
  39. data/spec/date/parse_spec.rb +442 -0
  40. data/spec/date/parsing_spec.rb +77 -0
  41. data/spec/date/relationship_spec.rb +28 -0
  42. data/spec/date/step_spec.rb +109 -0
  43. data/spec/date/strftime_spec.rb +223 -0
  44. data/spec/date/strptime_spec.rb +201 -0
  45. data/spec/date/succ_spec.rb +20 -0
  46. data/spec/date/today_spec.rb +15 -0
  47. data/spec/date/upto_spec.rb +17 -0
  48. data/spec/datetime/accessor_spec.rb +218 -0
  49. data/spec/datetime/add_month_spec.rb +26 -0
  50. data/spec/datetime/add_spec.rb +36 -0
  51. data/spec/datetime/boat_spec.rb +43 -0
  52. data/spec/datetime/constructor_spec.rb +142 -0
  53. data/spec/datetime/conversions_spec.rb +54 -0
  54. data/spec/datetime/day_spec.rb +73 -0
  55. data/spec/datetime/downto_spec.rb +39 -0
  56. data/spec/datetime/eql_spec.rb +17 -0
  57. data/spec/datetime/format_spec.rb +59 -0
  58. data/spec/datetime/hash_spec.rb +11 -0
  59. data/spec/datetime/leap_spec.rb +19 -0
  60. data/spec/datetime/minus_month_spec.rb +25 -0
  61. data/spec/datetime/minus_spec.rb +77 -0
  62. data/spec/datetime/next_prev_spec.rb +138 -0
  63. data/spec/datetime/now_spec.rb +18 -0
  64. data/spec/datetime/parse_spec.rb +390 -0
  65. data/spec/datetime/parsing_spec.rb +77 -0
  66. data/spec/datetime/relationship_spec.rb +28 -0
  67. data/spec/datetime/step_spec.rb +155 -0
  68. data/spec/datetime/strftime_spec.rb +118 -0
  69. data/spec/datetime/strptime_spec.rb +117 -0
  70. data/spec/datetime/succ_spec.rb +24 -0
  71. data/spec/datetime/upto_spec.rb +39 -0
  72. data/spec/spec_helper.rb +59 -0
  73. metadata +138 -0
data/ext/date_ext.c ADDED
@@ -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
+ }