home_run 0.9.0-x86-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. data/CHANGELOG +3 -0
  2. data/LICENSE +19 -0
  3. data/README.rdoc +314 -0
  4. data/Rakefile +135 -0
  5. data/bench/cpu_bench.rb +279 -0
  6. data/bench/dt_garbage_bench.rb +11 -0
  7. data/bench/dt_mem_bench.rb +14 -0
  8. data/bench/garbage_bench.rb +11 -0
  9. data/bench/mem_bench.rb +14 -0
  10. data/bin/home_run +91 -0
  11. data/default.mspec +12 -0
  12. data/ext/1.8/date_ext.so +0 -0
  13. data/ext/1.9/date_ext.so +0 -0
  14. data/ext/date.rb +7 -0
  15. data/ext/date/format.rb +842 -0
  16. data/ext/date_ext.c +4548 -0
  17. data/ext/date_parser.c +367 -0
  18. data/ext/date_parser.rl +134 -0
  19. data/ext/datetime.c +2804 -0
  20. data/ext/extconf.rb +6 -0
  21. data/spec/date/accessor_spec.rb +176 -0
  22. data/spec/date/add_month_spec.rb +26 -0
  23. data/spec/date/add_spec.rb +23 -0
  24. data/spec/date/boat_spec.rb +38 -0
  25. data/spec/date/civil_spec.rb +147 -0
  26. data/spec/date/commercial_spec.rb +153 -0
  27. data/spec/date/constants_spec.rb +44 -0
  28. data/spec/date/conversions_spec.rb +246 -0
  29. data/spec/date/day_spec.rb +73 -0
  30. data/spec/date/downto_spec.rb +17 -0
  31. data/spec/date/eql_spec.rb +16 -0
  32. data/spec/date/format_spec.rb +52 -0
  33. data/spec/date/gregorian_spec.rb +52 -0
  34. data/spec/date/hash_spec.rb +11 -0
  35. data/spec/date/julian_spec.rb +129 -0
  36. data/spec/date/leap_spec.rb +19 -0
  37. data/spec/date/minus_month_spec.rb +25 -0
  38. data/spec/date/minus_spec.rb +51 -0
  39. data/spec/date/next_prev_spec.rb +108 -0
  40. data/spec/date/ordinal_spec.rb +83 -0
  41. data/spec/date/parse_spec.rb +442 -0
  42. data/spec/date/parsing_spec.rb +77 -0
  43. data/spec/date/relationship_spec.rb +28 -0
  44. data/spec/date/step_spec.rb +109 -0
  45. data/spec/date/strftime_spec.rb +223 -0
  46. data/spec/date/strptime_spec.rb +201 -0
  47. data/spec/date/succ_spec.rb +20 -0
  48. data/spec/date/today_spec.rb +15 -0
  49. data/spec/date/upto_spec.rb +17 -0
  50. data/spec/datetime/accessor_spec.rb +218 -0
  51. data/spec/datetime/add_month_spec.rb +26 -0
  52. data/spec/datetime/add_spec.rb +36 -0
  53. data/spec/datetime/boat_spec.rb +43 -0
  54. data/spec/datetime/constructor_spec.rb +142 -0
  55. data/spec/datetime/conversions_spec.rb +54 -0
  56. data/spec/datetime/day_spec.rb +73 -0
  57. data/spec/datetime/downto_spec.rb +39 -0
  58. data/spec/datetime/eql_spec.rb +17 -0
  59. data/spec/datetime/format_spec.rb +59 -0
  60. data/spec/datetime/hash_spec.rb +11 -0
  61. data/spec/datetime/leap_spec.rb +19 -0
  62. data/spec/datetime/minus_month_spec.rb +25 -0
  63. data/spec/datetime/minus_spec.rb +77 -0
  64. data/spec/datetime/next_prev_spec.rb +138 -0
  65. data/spec/datetime/now_spec.rb +18 -0
  66. data/spec/datetime/parse_spec.rb +390 -0
  67. data/spec/datetime/parsing_spec.rb +77 -0
  68. data/spec/datetime/relationship_spec.rb +28 -0
  69. data/spec/datetime/step_spec.rb +155 -0
  70. data/spec/datetime/strftime_spec.rb +118 -0
  71. data/spec/datetime/strptime_spec.rb +117 -0
  72. data/spec/datetime/succ_spec.rb +24 -0
  73. data/spec/datetime/upto_spec.rb +39 -0
  74. data/spec/spec_helper.rb +59 -0
  75. metadata +154 -0
@@ -0,0 +1,2804 @@
1
+
2
+ /* Helper methods */
3
+
4
+ /* Identical for rhrd__valid_civil, but for rhrdt_t. Not very
5
+ * DRY, but the arguments get modified by the method and then
6
+ * used to populate the rhrdt_t. Because the rhrd_t field structure
7
+ * has a different layout from the rhrdt_t field structure, you
8
+ * need separate functions (no duck typing in C). */
9
+ int rhrdt__valid_civil(rhrdt_t *dt, long year, long month, long day) {
10
+ if (month < 0 && month >= -12) {
11
+ month += 13;
12
+ }
13
+ if (month < 1 || month > 12) {
14
+ return 0;
15
+ }
16
+
17
+ if (day < 0) {
18
+ if (month == 2) {
19
+ day += rhrd__leap_year(year) ? 30 : 29;
20
+ } else {
21
+ day += rhrd_days_in_month[month] + 1;
22
+ }
23
+ }
24
+ if (day < 1 || day > 28) {
25
+ if (day > 31 || day <= 0) {
26
+ return 0;
27
+ } else if (month == 2) {
28
+ if (rhrd__leap_year(year)) {
29
+ if (day > 29) {
30
+ return 0;
31
+ }
32
+ } else if (day > 28) {
33
+ return 0;
34
+ }
35
+ } else if (day > rhrd_days_in_month[month]) {
36
+ return 0;
37
+ }
38
+ }
39
+
40
+ if(!rhrd__valid_civil_limits(year, month, day)) {
41
+ return 0;
42
+ }
43
+
44
+ dt->year = year;
45
+ dt->month = (unsigned char)month;
46
+ dt->day = (unsigned char)day;
47
+ dt->flags |= RHR_HAVE_CIVIL;
48
+ return 1;
49
+ }
50
+
51
+ /* Check if the given offset is valid. If so, set the offset field
52
+ * in the rhrdt_t and return 1. Otherwise, return 0. */
53
+ int rhrdt__valid_offset(rhrdt_t *dt, double offset) {
54
+ if (offset < RHR_MIN_OFFSET_FRACT || offset > RHR_MAX_OFFSET_FRACT) {
55
+ return 0;
56
+ }
57
+
58
+ dt->offset = lround(offset * 1440);
59
+ return 1;
60
+ }
61
+
62
+ /* Check if the time information consistutes a valid time. If not, return
63
+ * 0. If so, fill in the fields in the rhrdt_t and return 1. This handles
64
+ * wrap around for negative hour, minute, and second arguments, and handles
65
+ * an hour of 24 with no minute or second value as the 0th hour of the next
66
+ * day, so either the julian day or civil day fields in the rhrdt_t should
67
+ * be filled out before calling this method. */
68
+ int rhrdt__valid_time(rhrdt_t *dt, long h, long m, long s, double offset) {
69
+ if (h < 0) {
70
+ h += 24;
71
+ }
72
+ if (m < 0) {
73
+ m += 60;
74
+ }
75
+ if (s < 0) {
76
+ s += 60;
77
+ }
78
+
79
+ if (h == 24 && m == 0 && s == 0) {
80
+ RHRDT_FILL_JD(dt)
81
+ dt->jd++;
82
+ dt->flags &= ~RHR_HAVE_CIVIL;
83
+ h = 0;
84
+ } else if (h < 0 || m < 0 || s < 0 || h > 23 || m > 59 || s > 59) {
85
+ return 0;
86
+ }
87
+ if(!rhrdt__valid_offset(dt, offset)) {
88
+ return 0;
89
+ }
90
+
91
+ dt->hour = h;
92
+ dt->minute = m;
93
+ dt->second = s;
94
+ dt->flags |= RHR_HAVE_HMS;
95
+ return 1;
96
+ }
97
+
98
+ /* Same as rhrd__civil_to_jd for rhrdt_t. */
99
+ void rhrdt__civil_to_jd(rhrdt_t *d) {
100
+ d->jd = rhrd__ymd_to_jd(d->year, d->month, d->day);
101
+ d->flags |= RHR_HAVE_JD;
102
+ }
103
+
104
+ /* Same as rhrd__jd_to_civil for rhrdt_t. */
105
+ void rhrdt__jd_to_civil(rhrdt_t *date) {
106
+ long x, a, b, c, d, e;
107
+ x = (long)floor((date->jd - 1867216.25) / 36524.25);
108
+ a = date->jd + 1 + x - (long)floor(x / 4.0);
109
+ b = a + 1524;
110
+ c = (long)floor((b - 122.1) / 365.25);
111
+ d = (long)floor(365.25 * c);
112
+ e = (long)floor((b - d) / 30.6001);
113
+ date->day = b - d - (long)floor(30.6001 * e);
114
+ if (e <= 13) {
115
+ date->month = e - 1;
116
+ date->year = c - 4716;
117
+ } else {
118
+ date->month = e - 13;
119
+ date->year = c - 4715;
120
+ }
121
+ date->flags |= RHR_HAVE_CIVIL;
122
+ }
123
+
124
+ /* Using the stored nanos field, fill in the hour, minute,
125
+ * and second fields for the rhrdt_t. This assumes the
126
+ * nanos field has already been filled in. */
127
+ void rhrdt__nanos_to_hms(rhrdt_t *d) {
128
+ unsigned int seconds;
129
+ seconds = d->nanos/RHR_NANOS_PER_SECOND;
130
+ d->hour = seconds/RHR_SECONDS_PER_HOUR;
131
+ d->minute = (seconds % RHR_SECONDS_PER_HOUR)/60;
132
+ d->second = seconds % 60;
133
+ d->flags |= RHR_HAVE_HMS;
134
+ }
135
+
136
+ /* Using the stored hour, minute, and second fields, fill in
137
+ * the nanos field for th rhrdt_t. This assumes the hour, minute
138
+ * and second fields have already been filled in. */
139
+ void rhrdt__hms_to_nanos(rhrdt_t *d) {
140
+ d->nanos = (d->hour*RHR_SECONDS_PER_HOUR + d->minute*60 + d->second)*RHR_NANOS_PER_SECOND;
141
+ d->flags |= RHR_HAVE_NANOS;
142
+ }
143
+
144
+ /* Same as rhrd__valid_commercial, for rhrdt_t. */
145
+ int rhrdt__valid_commercial(rhrdt_t *d, long cwyear, long cweek, long cwday) {
146
+ rhrd_t n;
147
+ memset(&n, 0, sizeof(rhrd_t));
148
+
149
+ if (cwday < 0) {
150
+ if (cwday < -8) {
151
+ return 0;
152
+ }
153
+ cwday += 8;
154
+ }
155
+ if (cweek < 0) {
156
+ if (cweek < -53) {
157
+ return 0;
158
+ }
159
+ n.jd = rhrd__commercial_to_jd(cwyear + 1, 1, 1) + cweek * 7;
160
+ rhrd__fill_commercial(&n);
161
+ if (n.year != cwyear) {
162
+ return 0;
163
+ }
164
+ cweek = n.month;
165
+ memset(&n, 0, sizeof(rhrd_t));
166
+ }
167
+
168
+ n.jd = rhrd__commercial_to_jd(cwyear, cweek, cwday);
169
+ rhrd__fill_commercial(&n);
170
+ if(cwyear != n.year || cweek != n.month || cwday != n.day) {
171
+ return 0;
172
+ }
173
+
174
+ if ((n.jd > RHR_JD_MAX) || (n.jd < RHR_JD_MIN)) {
175
+ return 0;
176
+ }
177
+
178
+ d->jd = n.jd;
179
+ d->flags = RHR_HAVE_JD;
180
+ return 1;
181
+ }
182
+
183
+ /* Same as rhrd__valid_ordinal, for rhrdt_t. */
184
+ int rhrdt__valid_ordinal(rhrdt_t *d, long year, long yday) {
185
+ int leap;
186
+ long month, day;
187
+
188
+ leap = rhrd__leap_year(year);
189
+ if (yday < 0) {
190
+ if (leap) {
191
+ yday += 367;
192
+ } else {
193
+ yday += 366;
194
+ }
195
+ }
196
+ if (yday < 1 || yday > (leap ? 366 : 365)) {
197
+ return 0;
198
+ }
199
+ if (leap) {
200
+ month = rhrd_leap_yday_to_month[yday];
201
+ if (yday > 60) {
202
+ day = yday - rhrd_cumulative_days_in_month[month] - 1;
203
+ } else {
204
+ day = yday - rhrd_cumulative_days_in_month[month];
205
+ }
206
+ } else {
207
+ month = rhrd_yday_to_month[yday];
208
+ day = yday - rhrd_cumulative_days_in_month[month];
209
+ }
210
+
211
+ if(!rhrd__valid_civil_limits(year, month, day)) {
212
+ return 0;
213
+ }
214
+
215
+ d->year = year;
216
+ d->month = (unsigned char)month;
217
+ d->day = (unsigned char)day;
218
+ d->flags |= RHR_HAVE_CIVIL;
219
+ return 1;
220
+ }
221
+
222
+ /* Fill the rhrdt_t with the current time information. On
223
+ * ruby 1.9, this is accurate to nanoseconds if the platform
224
+ * supports it, while on ruby 1.8 is is accurate to microseconds.
225
+ * On Windows, it's only accurate to within about 15 milliseconds. */
226
+ void rhrdt__now(rhrdt_t * dt) {
227
+ long t;
228
+ long offset;
229
+ VALUE rt;
230
+ rt = rb_funcall(rb_cTime, rhrd_id_now, 0);
231
+ offset = NUM2LONG(rb_funcall(rt, rhrd_id_utc_offset, 0));
232
+ t = NUM2LONG(rb_funcall(rt, rhrd_id_to_i, 0)) + offset;
233
+ dt->jd = rhrd__unix_to_jd(t);
234
+ #ifdef RUBY19
235
+ dt->nanos = rhrd__mod(t, RHR_SECONDS_PER_DAY) * RHR_NANOS_PER_SECOND + NUM2LONG(rb_funcall(rt, rhrd_id_nsec, 0));
236
+ #else
237
+ dt->nanos = rhrd__mod(t, RHR_SECONDS_PER_DAY) * RHR_NANOS_PER_SECOND + NUM2LONG(rb_funcall(rt, rhrd_id_usec, 0)) * 1000;
238
+ #endif
239
+ dt->offset = offset/60;
240
+ dt->flags |= RHR_HAVE_JD | RHR_HAVE_NANOS;
241
+ RHR_CHECK_JD(dt);
242
+ }
243
+
244
+ /* Return a new ruby DateTime object using the given jd, nanos,
245
+ * and offset. The offset should already be in minutes-from-UTC
246
+ * format. This handles negative nanos or nanos greater than
247
+ * the number per day by subtracting from or adding to the jd.
248
+ * It should ensure that the stored nanos value is in the range
249
+ * [0, RHR_NANOS_PER_DAY). */
250
+ VALUE rhrdt__from_jd_nanos(long jd, long long nanos, short offset) {
251
+ long t;
252
+ rhrdt_t *dt;
253
+ VALUE new;
254
+ new = Data_Make_Struct(rhrdt_class, rhrdt_t, NULL, free, dt);
255
+
256
+ if (nanos < 0) {
257
+ t = nanos/RHR_NANOS_PER_DAY - 1;
258
+ nanos -= t * RHR_NANOS_PER_DAY;
259
+ jd += t;
260
+ } else if (nanos >= RHR_NANOS_PER_DAY) {
261
+ t = nanos/RHR_NANOS_PER_DAY;
262
+ nanos -= t * RHR_NANOS_PER_DAY;
263
+ jd += t;
264
+ }
265
+ dt->jd = jd;
266
+ dt->nanos = nanos;
267
+ dt->offset = offset;
268
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS;
269
+ return new;
270
+ }
271
+
272
+ /* Similar to rhrd__spaceship. Unlike that, we
273
+ * don't try to speed up by checking which fields
274
+ * are already stored, we just fill the jd and
275
+ * nanos fields for both and compare them.*/
276
+ long rhrdt__spaceship(rhrdt_t *dt, rhrdt_t *odt) {
277
+ RHRDT_FILL_JD(dt)
278
+ RHRDT_FILL_JD(odt)
279
+ RHRDT_FILL_NANOS(dt)
280
+ RHRDT_FILL_NANOS(odt)
281
+ if (dt->jd == odt->jd) {
282
+ if (dt->nanos == odt->nanos) {
283
+ return 0;
284
+ } else if (dt->nanos < odt->nanos) {
285
+ return -1;
286
+ }
287
+ return 1;
288
+ } else if (dt->jd < odt->jd) {
289
+ return -1;
290
+ }
291
+ return 1;
292
+ }
293
+
294
+ /* Similar to rhrd__add_days, but n is a double in
295
+ * order to handle fractional days. */
296
+ VALUE rhrdt__add_days(VALUE self, double n) {
297
+ long l;
298
+ long long nanos;
299
+ rhrdt_t *dt;
300
+ Data_Get_Struct(self, rhrdt_t, dt);
301
+ RHRDT_FILL_JD(dt)
302
+ RHRDT_FILL_NANOS(dt)
303
+ l = floor(n);
304
+ nanos = llround((n - l) * RHR_NANOS_PER_DAY);
305
+ return rhrdt__from_jd_nanos(rhrd__safe_add_long(dt->jd, l), dt->nanos + nanos, dt->offset);
306
+ }
307
+
308
+ /* Similar to rhrd__add_months, but for ruby DateTime
309
+ * values. */
310
+ VALUE rhrdt__add_months(VALUE self, long n) {
311
+ rhrdt_t *d;
312
+ rhrdt_t *newd;
313
+ VALUE new;
314
+ long x;
315
+ Data_Get_Struct(self, rhrdt_t, d);
316
+
317
+ new = Data_Make_Struct(rhrdt_class, rhrdt_t, NULL, free, newd);
318
+ RHRDT_FILL_CIVIL(d)
319
+ memcpy(newd, d, sizeof(rhrdt_t));
320
+
321
+ n = rhrd__safe_add_long(n, (long)(d->month));
322
+ if(n > 1 && n <= 12) {
323
+ newd->year = d->year;
324
+ newd->month = n;
325
+ } else {
326
+ x = n / 12;
327
+ n = n % 12;
328
+ if (n <= 0) {
329
+ newd->year = d->year + x - 1;
330
+ newd->month = n + 12;
331
+ } else {
332
+ newd->year = d->year + x;
333
+ newd->month = (unsigned char)n;
334
+ }
335
+ }
336
+ x = rhrd__days_in_month(newd->year, newd->month);
337
+ newd->day = (unsigned char)(d->day > x ? x : d->day);
338
+ RHR_CHECK_CIVIL(newd)
339
+ newd->flags &= ~RHR_HAVE_JD;
340
+ return new;
341
+ }
342
+
343
+ /* Similar to rhrd__fill_from_hash for rhrdt_t, except instead of
344
+ * returning 1 or 0, this raises ruby ArgumentErrors. */
345
+ void rhrdt__fill_from_hash(rhrdt_t *dt, VALUE hash) {
346
+ rhrd_t d;
347
+ long hour = 0;
348
+ long minute = 0;
349
+ long second = 0;
350
+ long offset = 0;
351
+ long long nanos = 0;
352
+ long long time_set = 0;
353
+ int r;
354
+ VALUE rhour, rmin, rsec, runix, roffset, rsecf;
355
+
356
+ if (!RTEST(hash)) {
357
+ rb_raise(rb_eArgError, "invalid date");
358
+ }
359
+
360
+ roffset = rb_hash_aref(hash, rhrd_sym_offset);
361
+ if (RTEST(roffset)) {
362
+ offset = NUM2LONG(roffset);
363
+ }
364
+
365
+ rsecf = rb_hash_aref(hash, rhrd_sym_sec_fraction);
366
+ if (RTEST(rsecf)) {
367
+ nanos = llround(NUM2DBL(rsecf) * RHR_NANOS_PER_SECOND);
368
+ }
369
+
370
+ runix = rb_hash_aref(hash, rhrd_sym_seconds);
371
+ if (RTEST(runix)) {
372
+ time_set = NUM2LL(runix);
373
+ dt->jd = rhrd__unix_to_jd(time_set);
374
+ time_set = rhrd__modll(time_set, RHR_SECONDS_PER_DAY);
375
+ dt->nanos = time_set*RHR_NANOS_PER_SECOND + nanos;
376
+ dt->hour = time_set/RHR_SECONDS_PER_HOUR;
377
+ dt->minute = (time_set - dt->hour * RHR_SECONDS_PER_HOUR)/60;
378
+ dt->second = rhrd__mod(time_set, 60);
379
+ offset /= 60;
380
+ if (offset > RHR_MAX_OFFSET_MINUTES || offset < RHR_MIN_OFFSET_MINUTES) {
381
+ rb_raise(rb_eArgError, "invalid offset: %ld minutes", offset);
382
+ }
383
+ RHR_CHECK_JD(dt);
384
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
385
+ return;
386
+ } else {
387
+ rhour = rb_hash_aref(hash, rhrd_sym_hour);
388
+ rmin = rb_hash_aref(hash, rhrd_sym_min);
389
+ rsec = rb_hash_aref(hash, rhrd_sym_sec);
390
+
391
+ if (RTEST(rhour)) {
392
+ time_set = 1;
393
+ hour = NUM2LONG(rhour);
394
+ }
395
+ if (RTEST(rmin)) {
396
+ time_set = 1;
397
+ minute = NUM2LONG(rmin);
398
+ }
399
+ if (RTEST(rsec)) {
400
+ time_set = 1;
401
+ second = NUM2LONG(rsec);
402
+ }
403
+ }
404
+
405
+ memset(&d, 0, sizeof(rhrd_t));
406
+ r = rhrd__fill_from_hash(&d, hash);
407
+ if(r > 0) {
408
+ /* bad date info */
409
+ rb_raise(rb_eArgError, "invalid date");
410
+ } else if (r < 0) {
411
+ if (time_set) {
412
+ /* time info but no date info, assume current date */
413
+ rhrd__today(&d);
414
+ } else {
415
+ /* no time or date info */
416
+ rb_raise(rb_eArgError, "invalid date");
417
+ }
418
+ }
419
+
420
+ if(RHR_HAS_JD(&d)) {
421
+ dt->jd = d.jd;
422
+ dt->flags |= RHR_HAVE_JD;
423
+ }
424
+ if(RHR_HAS_CIVIL(&d)) {
425
+ dt->year = d.year;
426
+ dt->month = d.month;
427
+ dt->day = d.day;
428
+ dt->flags |= RHR_HAVE_CIVIL;
429
+ }
430
+ if(time_set) {
431
+ rhrdt__valid_time(dt, hour, minute, second, offset/RHR_SECONDS_PER_DAYD);
432
+ if(nanos) {
433
+ RHRDT_FILL_NANOS(dt)
434
+ dt->nanos += nanos;
435
+ }
436
+ } else if (offset) {
437
+ if(!rhrdt__valid_offset(dt, offset/RHR_SECONDS_PER_DAYD)){
438
+ rb_raise(rb_eArgError, "invalid date");
439
+ }
440
+ }
441
+ }
442
+
443
+ /* Return a new ruby DateTime object with the same
444
+ * absolute time as the given one, but with a different
445
+ * offset. */
446
+ VALUE rhrdt__new_offset(VALUE self, double offset) {
447
+ rhrdt_t *dt;
448
+ long offset_min;
449
+
450
+ if(offset < RHR_MIN_OFFSET_FRACT || offset > RHR_MAX_OFFSET_FRACT) {
451
+ rb_raise(rb_eArgError, "invalid offset (%f)", offset);
452
+ }
453
+ offset_min = lround(offset * 1440.0);
454
+ Data_Get_Struct(self, rhrdt_t, dt);
455
+ RHRDT_FILL_JD(dt)
456
+ RHRDT_FILL_NANOS(dt)
457
+ return rhrdt__from_jd_nanos(dt->jd, dt->nanos - (dt->offset - offset_min)*RHR_NANOS_PER_MINUTE, offset_min);
458
+ }
459
+
460
+ /* Class methods */
461
+
462
+ /* call-seq:
463
+ * _load(string) -> DateTime
464
+ *
465
+ * Unmarshal a dumped +DateTime+ object. Not generally called directly,
466
+ * usually called by <tt>Marshal.load</tt>.
467
+ *
468
+ * Note that this does not handle the marshalling format used by
469
+ * the stdlib's +DateTime+, it only handles marshalled versions of
470
+ * this library's +DateTime+ objects.
471
+ */
472
+ static VALUE rhrdt_s__load(VALUE klass, VALUE string) {
473
+ rhrdt_t * d;
474
+ long x;
475
+ VALUE ary, rd;
476
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
477
+
478
+ ary = rb_marshal_load(string);
479
+ if (!RTEST(rb_obj_is_kind_of(ary, rb_cArray)) || RARRAY_LEN(ary) != 3) {
480
+ rb_raise(rb_eTypeError, "incompatible marshal file format");
481
+ }
482
+
483
+ d->jd = NUM2LONG(rb_ary_entry(ary, 0));
484
+ RHR_CHECK_JD(d)
485
+
486
+ d->nanos = NUM2LL(rb_ary_entry(ary, 1));
487
+ if (d->nanos < 0 || d->nanos >= RHR_NANOS_PER_DAY) {
488
+ rb_raise(rb_eArgError, "invalid nanos: %lld", d->nanos);
489
+ }
490
+
491
+ x = NUM2LONG(rb_ary_entry(ary, 2));
492
+ if (x > RHR_MAX_OFFSET_MINUTES || x < RHR_MIN_OFFSET_MINUTES) {
493
+ rb_raise(rb_eArgError, "invalid offset: %ld minutes", x);
494
+ }
495
+ d->offset = x;
496
+
497
+ d->flags = RHR_HAVE_JD | RHR_HAVE_NANOS;
498
+ return rd;
499
+ }
500
+
501
+ /* call-seq:
502
+ * _strptime(string, format='%FT%T%z') -> Hash or nil
503
+ *
504
+ * Attemps to parse the string using the given format, returning
505
+ * a hash if there is a match (or +nil+ if no match).
506
+ *
507
+ * +_strptime+ supports the same formats that <tt>DateTime#strftime</tt> does.
508
+ */
509
+ static VALUE rhrdt_s__strptime(int argc, VALUE *argv, VALUE klass) {
510
+ const char * fmt_str = "%FT%T%z";
511
+ long fmt_len = 7;
512
+ VALUE r;
513
+
514
+ switch(argc) {
515
+ case 2:
516
+ r = rb_str_to_str(argv[1]);
517
+ fmt_str = RSTRING_PTR(r);
518
+ fmt_len = RSTRING_LEN(r);
519
+ case 1:
520
+ break;
521
+ default:
522
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
523
+ break;
524
+ }
525
+
526
+ return rhrd__strptime(argv[0], fmt_str, fmt_len);
527
+ }
528
+
529
+ /* call-seq:
530
+ * civil() -> DateTime <br />
531
+ * civil(year, month=1, day=1, hour=0, minute=0, second=0, offset=0, sg=nil) -> DateTime
532
+ *
533
+ * If no arguments are given, returns a +DateTime+ for julian day 0.
534
+ * Otherwise, returns a +DateTime+ for the year, month, day, hour, minute, second
535
+ * and offset given.
536
+ * Raises an +ArgumentError+ for invalid dates or times.
537
+ * Ignores the 8th argument.
538
+ */
539
+ static VALUE rhrdt_s_civil(int argc, VALUE *argv, VALUE klass) {
540
+ rhrdt_t *dt;
541
+ long year;
542
+ long month = 1;
543
+ long day = 1;
544
+ long hour = 0;
545
+ long minute = 0;
546
+ long second = 0;
547
+ double offset = 0.0;
548
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
549
+
550
+ switch(argc) {
551
+ case 0:
552
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
553
+ return rdt;
554
+ case 8:
555
+ case 7:
556
+ offset = NUM2DBL(argv[6]);
557
+ case 6:
558
+ second = NUM2LONG(argv[5]);
559
+ case 5:
560
+ minute = NUM2LONG(argv[4]);
561
+ case 4:
562
+ hour = NUM2LONG(argv[3]);
563
+ case 3:
564
+ day = NUM2LONG(argv[2]);
565
+ case 2:
566
+ month = NUM2LONG(argv[1]);
567
+ case 1:
568
+ year = NUM2LONG(argv[0]);
569
+ break;
570
+ default:
571
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 8", argc);
572
+ break;
573
+ }
574
+
575
+ if (!rhrdt__valid_civil(dt, year, month, day)) {
576
+ RHR_CHECK_CIVIL(dt)
577
+ rb_raise(rb_eArgError, "invalid date (year: %li, month: %li, day: %li)", year, month, day);
578
+ }
579
+ if (!rhrdt__valid_time(dt, hour, minute, second, offset)) {
580
+ rb_raise(rb_eArgError, "invalid time (hour: %li, minute: %li, second: %li, offset: %f)", hour, minute, second, offset);
581
+ }
582
+
583
+ return rdt;
584
+ }
585
+
586
+ /* call-seq:
587
+ * commercial() -> DateTime <br />
588
+ * commercial(cwyear, cweek=41, cwday=5, hour=0, minute=0, second=0, offset=0, sg=nil) -> DateTime [ruby 1-8] <br />
589
+ * commercial(cwyear, cweek=1, cwday=1, hour=0, minute=0, second=0, offset=0, sg=nil) -> DateTime [ruby 1-9]
590
+ *
591
+ * If no arguments are given:
592
+ * * ruby 1.8: returns a +DateTime+ for 1582-10-15 (the Day of Calendar Reform in Italy)
593
+ * * ruby 1.9: returns a +DateTime+ for julian day 0
594
+ *
595
+ * Otherwise, returns a +DateTime+ for the commercial week year, commercial week,
596
+ * commercial week day, hour, minute, second, and offset given.
597
+ * Raises an +ArgumentError+ for invalid dates or times.
598
+ * Ignores the 8th argument.
599
+ */
600
+ static VALUE rhrdt_s_commercial(int argc, VALUE *argv, VALUE klass) {
601
+ rhrdt_t *dt;
602
+ long cwyear = RHR_DEFAULT_CWYEAR;
603
+ long cweek = RHR_DEFAULT_CWEEK;
604
+ long cwday = RHR_DEFAULT_CWDAY;
605
+ long hour = 0;
606
+ long minute = 0;
607
+ long second = 0;
608
+ double offset = 0.0;
609
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
610
+
611
+ switch(argc) {
612
+ case 8:
613
+ case 7:
614
+ offset = NUM2DBL(argv[6]);
615
+ case 6:
616
+ second = NUM2LONG(argv[5]);
617
+ case 5:
618
+ minute = NUM2LONG(argv[4]);
619
+ case 4:
620
+ hour = NUM2LONG(argv[3]);
621
+ case 3:
622
+ cwday = NUM2LONG(argv[2]);
623
+ case 2:
624
+ cweek = NUM2LONG(argv[1]);
625
+ case 1:
626
+ cwyear = NUM2LONG(argv[0]);
627
+ #ifdef RUBY19
628
+ break;
629
+ case 0:
630
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
631
+ return rdt;
632
+ #else
633
+ case 0:
634
+ break;
635
+ #endif
636
+ default:
637
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 8", argc);
638
+ break;
639
+ }
640
+ if(!rhrdt__valid_commercial(dt, cwyear, cweek, cwday)) {
641
+ RHR_CHECK_JD(dt)
642
+ rb_raise(rb_eArgError, "invalid date (cwyear: %li, cweek: %li, cwday: %li)", cwyear, cweek, cwday);
643
+ }
644
+ if (!rhrdt__valid_time(dt, hour, minute, second, offset)) {
645
+ rb_raise(rb_eArgError, "invalid time (hour: %li, minute: %li, second: %li, offset: %f)", hour, minute, second, offset);
646
+ }
647
+
648
+ return rdt;
649
+ }
650
+
651
+ /* call-seq:
652
+ * jd(jd=0, hour=0, minute=0, second=0, offset=0, sg=nil) -> DateTime
653
+ *
654
+ * Returns a +DateTime+ for the julian day number,
655
+ * hour, minute, second, and offset given.
656
+ * Raises +ArgumentError+ for invalid times.
657
+ * Ignores the 6th argument.
658
+ */
659
+ static VALUE rhrdt_s_jd(int argc, VALUE *argv, VALUE klass) {
660
+ rhrdt_t *dt;
661
+ long hour = 0;
662
+ long minute = 0;
663
+ long second = 0;
664
+ double offset = 0.0;
665
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
666
+
667
+ switch(argc) {
668
+ case 0:
669
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
670
+ return rdt;
671
+ case 6:
672
+ case 5:
673
+ offset = NUM2DBL(argv[4]);
674
+ case 4:
675
+ second = NUM2LONG(argv[3]);
676
+ case 3:
677
+ minute = NUM2LONG(argv[2]);
678
+ case 2:
679
+ hour = NUM2LONG(argv[1]);
680
+ case 1:
681
+ dt->jd = NUM2LONG(argv[0]);
682
+ break;
683
+ default:
684
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 6", argc);
685
+ break;
686
+ }
687
+
688
+ RHR_CHECK_JD(dt)
689
+ dt->flags = RHR_HAVE_JD;
690
+ if (!rhrdt__valid_time(dt, hour, minute, second, offset)) {
691
+ rb_raise(rb_eArgError, "invalid time (hour: %li, minute: %li, second: %li, offset: %f)", hour, minute, second, offset);
692
+ }
693
+
694
+ return rdt;
695
+ }
696
+
697
+ /* call-seq:
698
+ * new!(ajd=0, offset=0, sg=nil) -> DateTime
699
+ *
700
+ * Returns a +DateTime+ for the astronomical julian day number and offset given.
701
+ * To include a fractional day, +ajd+ can be a +Float+. The date is assumed
702
+ * to be based at noon UTC, so if +ajd+ is an +Integer+ and +offset+ is 0,
703
+ * the hour will be 12.
704
+ * Ignores the 3rd argument. Example:
705
+ *
706
+ * DateTime.new!(2422222).to_s
707
+ * # => "1919-09-20T12:00:00+00:00"
708
+ * DateTime.new!(2422222.5).to_s
709
+ * # => "1919-09-21T00:00:00+00:00"
710
+ * DateTime.new!(2422222, 0.5).to_s
711
+ * # => "1919-09-21T00:00:00+12:00"
712
+ * DateTime.new!(2422222.5, 0.5).to_s
713
+ * # => "1919-09-21T12:00:00+12:00"
714
+ */
715
+ static VALUE rhrdt_s_new_b(int argc, VALUE *argv, VALUE klass) {
716
+ double offset = 0;
717
+ rhrdt_t *dt;
718
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
719
+
720
+ switch(argc) {
721
+ case 0:
722
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
723
+ return rdt;
724
+ case 2:
725
+ case 3:
726
+ offset = NUM2DBL(argv[1]);
727
+ if (!rhrdt__valid_offset(dt, offset)) {
728
+ rb_raise(rb_eArgError, "invalid offset (%f)", offset);
729
+ }
730
+ case 1:
731
+ offset += NUM2DBL(argv[0]) + 0.5;
732
+ dt->jd = offset;
733
+ dt->nanos = (offset - dt->jd)*RHR_NANOS_PER_DAY;
734
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS;
735
+ break;
736
+ default:
737
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 3", argc);
738
+ break;
739
+ }
740
+
741
+ RHR_CHECK_JD(dt)
742
+ return rdt;
743
+ }
744
+
745
+ /* call-seq:
746
+ * now(sg=nil) -> DateTime
747
+ *
748
+ * Returns a +DateTime+ representing the current local date
749
+ * and time.
750
+ * Ignores an argument if given.
751
+ */
752
+ static VALUE rhrdt_s_now(int argc, VALUE *argv, VALUE klass) {
753
+ rhrdt_t *dt;
754
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
755
+
756
+ switch(argc) {
757
+ case 0:
758
+ case 1:
759
+ break;
760
+ default:
761
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
762
+ break;
763
+ }
764
+
765
+ rhrdt__now(dt);
766
+ return rdt;
767
+ }
768
+
769
+ /* call-seq:
770
+ * ordinal() -> DateTime <br />
771
+ * ordinal(year, yday=1, hour=0, minute=0, second=0, offset=0, sg=nil) -> DateTime
772
+ *
773
+ * If no arguments are given, returns a +DateTime+ for julian day 0.
774
+ * Otherwise, returns a +DateTime+ for the year, day of year,
775
+ * hour, minute, second, and offset given.
776
+ * Raises an +ArgumentError+ for invalid dates.
777
+ * Ignores the 7th argument.
778
+ */
779
+ static VALUE rhrdt_s_ordinal(int argc, VALUE *argv, VALUE klass) {
780
+ long year;
781
+ long day = 1;
782
+ long hour = 0;
783
+ long minute = 0;
784
+ long second = 0;
785
+ double offset = 0.0;
786
+ rhrdt_t *dt;
787
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
788
+
789
+ switch(argc) {
790
+ case 7:
791
+ case 6:
792
+ offset = NUM2DBL(argv[5]);
793
+ case 5:
794
+ second = NUM2LONG(argv[4]);
795
+ case 4:
796
+ minute = NUM2LONG(argv[3]);
797
+ case 3:
798
+ hour = NUM2LONG(argv[2]);
799
+ case 2:
800
+ day = NUM2LONG(argv[1]);
801
+ case 1:
802
+ year = NUM2LONG(argv[0]);
803
+ break;
804
+ case 0:
805
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
806
+ return rdt;
807
+ default:
808
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 7", argc);
809
+ break;
810
+ }
811
+
812
+ if(!rhrdt__valid_ordinal(dt, year, day)) {
813
+ RHR_CHECK_JD(dt)
814
+ rb_raise(rb_eArgError, "invalid date (year: %li, yday: %li)", year, day);
815
+ }
816
+ if (!rhrdt__valid_time(dt, hour, minute, second, offset)) {
817
+ rb_raise(rb_eArgError, "invalid time (hour: %li, minute: %li, second: %li, offset: %f)", hour, minute, second, offset);
818
+ }
819
+ return rdt;
820
+ }
821
+
822
+ /* call-seq:
823
+ * parse() -> DateTime <br />
824
+ * parse(string, comp=true, sg=nil) -> DateTime
825
+ *
826
+ * If no arguments are given, returns a +DateTime+ for julian day 0.
827
+ * Otherwise returns a +DateTime+ for the date represented by the given
828
+ * +string+. Raises an +ArgumentError+ if the string was not in
829
+ * a recognized format, or if the recognized format represents
830
+ * an invalid date or time.
831
+ * If +comp+ is true, expands 2-digit years to 4-digits years.
832
+ * Ignores the 3rd argument.
833
+ */
834
+ static VALUE rhrdt_s_parse(int argc, VALUE *argv, VALUE klass) {
835
+ rhrdt_t *dt;
836
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
837
+
838
+ switch(argc) {
839
+ case 0:
840
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
841
+ return rdt;
842
+ case 1:
843
+ rhrdt__fill_from_hash(dt, rb_funcall(klass, rhrd_id__parse, 1, argv[0]));
844
+ break;
845
+ case 2:
846
+ case 3:
847
+ rhrdt__fill_from_hash(dt, rb_funcall(klass, rhrd_id__parse, 2, argv[0], argv[1]));
848
+ break;
849
+ default:
850
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 3)", argc);
851
+ break;
852
+ }
853
+
854
+ return rdt;
855
+ }
856
+
857
+ /* call-seq:
858
+ * strptime() -> DateTime <br />
859
+ * strptime(string, format="%FT%T%z", sg=nil) -> DateTime
860
+ *
861
+ * If no arguments are given, returns a +DateTime+ for julian day 0.
862
+ * Other returns a +DateTime+ for the date and time represented by the given
863
+ * +string+, parsed using the given +format+.
864
+ * Raises an +ArgumentError+ if the string did not match the format
865
+ * given, or if it did match and it represented an invalid date or time.
866
+ * Ignores the 3rd argument.
867
+ */
868
+ static VALUE rhrdt_s_strptime(int argc, VALUE *argv, VALUE klass) {
869
+ rhrdt_t *dt;
870
+ VALUE rdt = Data_Make_Struct(klass, rhrdt_t, NULL, free, dt);
871
+
872
+ switch(argc) {
873
+ case 0:
874
+ dt->flags = RHR_HAVE_JD | RHR_HAVE_NANOS | RHR_HAVE_HMS;
875
+ return rdt;
876
+ case 3:
877
+ argc = 2;
878
+ case 1:
879
+ case 2:
880
+ break;
881
+ default:
882
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 3)", argc);
883
+ break;
884
+ }
885
+
886
+ rhrdt__fill_from_hash(dt, rhrdt_s__strptime(argc, argv, klass));
887
+ return rdt;
888
+ }
889
+
890
+ /* Instance methods */
891
+
892
+ /* call-seq:
893
+ * _dump(limit) -> String
894
+ *
895
+ * Returns a marshalled representation of the receiver as a +String+.
896
+ * Generally not called directly, usually called by <tt>Marshal.dump</tt>.
897
+ */
898
+ static VALUE rhrdt__dump(VALUE self, VALUE limit) {
899
+ rhrdt_t *d;
900
+ Data_Get_Struct(self, rhrdt_t, d);
901
+ RHRDT_FILL_JD(d)
902
+ RHRDT_FILL_NANOS(d)
903
+ return rb_marshal_dump(rb_ary_new3(3, LONG2NUM(d->jd), LL2NUM(d->nanos), LONG2NUM(d->offset)), LONG2NUM(NUM2LONG(limit) - 1));
904
+ }
905
+
906
+ /* call-seq:
907
+ * ajd() -> Float
908
+ *
909
+ * Returns the date and time represented by the receiver as a
910
+ * astronomical julian day +Float+.
911
+ */
912
+ static VALUE rhrdt_ajd(VALUE self) {
913
+ rhrdt_t *d;
914
+ Data_Get_Struct(self, rhrdt_t, d);
915
+ RHRDT_FILL_JD(d)
916
+ RHRDT_FILL_NANOS(d)
917
+ return rb_float_new(d->jd + d->nanos/RHR_NANOS_PER_DAYD - d->offset/1440.0 - 0.5);
918
+ }
919
+
920
+ /* call-seq:
921
+ * amjd() -> Float
922
+ *
923
+ * Returns the date and time represented by the receiver as a
924
+ * astronomical modified julian day +Float+.
925
+ */
926
+ static VALUE rhrdt_amjd(VALUE self) {
927
+ rhrdt_t *d;
928
+ Data_Get_Struct(self, rhrdt_t, d);
929
+ RHRDT_FILL_JD(d)
930
+ RHRDT_FILL_NANOS(d)
931
+ return rb_float_new(d->jd + d->nanos/RHR_NANOS_PER_DAYD - d->offset/1440.0 - RHR_JD_MJD);
932
+ }
933
+
934
+ /* call-seq:
935
+ * asctime() -> String
936
+ *
937
+ * Returns a string representation of the receiver. Example:
938
+ *
939
+ * DateTime.civil(2009, 1, 2, 3, 4, 5).asctime
940
+ * # => "Fri Jan 2 03:04:05 2009"
941
+ */
942
+ static VALUE rhrdt_asctime(VALUE self) {
943
+ VALUE s;
944
+ rhrdt_t *d;
945
+ int len;
946
+ Data_Get_Struct(self, rhrdt_t, d);
947
+ RHRDT_FILL_CIVIL(d)
948
+ RHRDT_FILL_JD(d)
949
+ RHRDT_FILL_HMS(d)
950
+
951
+ s = rb_str_buf_new(128);
952
+ len = snprintf(RSTRING_PTR(s), 128, "%s %s %2hhi %02hhi:%02hhi:%02hhi %04li",
953
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
954
+ rhrd__abbr_month_names[d->month],
955
+ d->day, d->hour, d->minute, d->second,
956
+ d->year);
957
+ if (len == -1 || len > 127) {
958
+ rb_raise(rb_eNoMemError, "in DateTime#asctime (in snprintf)");
959
+ }
960
+
961
+ RHR_RETURN_RESIZED_STR(s, len)
962
+ }
963
+
964
+ /* call-seq:
965
+ * cwday() -> Integer
966
+ *
967
+ * Returns the commercial week day as an +Integer+. Example:
968
+ *
969
+ * DateTime.civil(2009, 1, 2).cwday
970
+ * # => 5
971
+ * DateTime.civil(2010, 1, 2).cwday
972
+ * # => 6
973
+ */
974
+ static VALUE rhrdt_cwday(VALUE self) {
975
+ rhrdt_t *d;
976
+ rhrd_t n;
977
+ RHR_CACHED_IV(self, rhrd_id_cwday)
978
+ memset(&n, 0, sizeof(rhrd_t));
979
+ Data_Get_Struct(self, rhrdt_t, d);
980
+ RHRDT_FILL_JD(d)
981
+ n.jd = d->jd;
982
+ rhrd__fill_commercial(&n);
983
+ rhrd__set_cw_ivs(self, &n);
984
+ return LONG2NUM(n.day);
985
+ }
986
+
987
+ /* call-seq:
988
+ * cweek() -> Integer
989
+ *
990
+ * Returns the commercial week as an +Integer+. Example:
991
+ *
992
+ * DateTime.civil(2009, 1, 2).cweek
993
+ * # => 1
994
+ * DateTime.civil(2010, 1, 2).cweek
995
+ * # => 53
996
+ */
997
+ static VALUE rhrdt_cweek(VALUE self) {
998
+ rhrdt_t *d;
999
+ rhrd_t n;
1000
+ RHR_CACHED_IV(self, rhrd_id_cweek)
1001
+ memset(&n, 0, sizeof(rhrd_t));
1002
+ Data_Get_Struct(self, rhrdt_t, d);
1003
+ RHRDT_FILL_JD(d)
1004
+ n.jd = d->jd;
1005
+ rhrd__fill_commercial(&n);
1006
+ rhrd__set_cw_ivs(self, &n);
1007
+ return LONG2NUM(n.month);
1008
+ }
1009
+
1010
+ /* call-seq:
1011
+ * cwyear() -> Integer
1012
+ *
1013
+ * Returns the commercial week year as an +Integer+. Example:
1014
+ *
1015
+ * DateTime.civil(2009, 1, 2).cwyear
1016
+ * # => 2009
1017
+ * DateTime.civil(2010, 1, 2).cwyear
1018
+ * # => 2009
1019
+ */
1020
+ static VALUE rhrdt_cwyear(VALUE self) {
1021
+ rhrdt_t *d;
1022
+ rhrd_t n;
1023
+ RHR_CACHED_IV(self, rhrd_id_cwyear)
1024
+ memset(&n, 0, sizeof(rhrd_t));
1025
+ Data_Get_Struct(self, rhrdt_t, d);
1026
+ RHRDT_FILL_JD(d)
1027
+ n.jd = d->jd;
1028
+ rhrd__fill_commercial(&n);
1029
+ rhrd__set_cw_ivs(self, &n);
1030
+ return LONG2NUM(n.year);
1031
+ }
1032
+
1033
+ /* call-seq:
1034
+ * day() -> Integer
1035
+ *
1036
+ * Returns the day of the month as an +Integer+. Example:
1037
+ *
1038
+ * DateTime.civil(2009, 1, 2).day
1039
+ * # => 2
1040
+ */
1041
+ static VALUE rhrdt_day(VALUE self) {
1042
+ rhrdt_t *dt;
1043
+ Data_Get_Struct(self, rhrdt_t, dt);
1044
+ RHRDT_FILL_CIVIL(dt)
1045
+ return LONG2NUM(dt->day);
1046
+ }
1047
+
1048
+ /* call-seq:
1049
+ * day_fraction() -> Float
1050
+ *
1051
+ * Returns the fraction of the day as a +Float+. Example:
1052
+ *
1053
+ * DateTime.civil(2009, 1, 2).day_fraction
1054
+ * # => 0.0
1055
+ * DateTime.civil(2009, 1, 2, 12).day_fraction
1056
+ * # => 0.5
1057
+ * DateTime.civil(2009, 1, 2, 6).day_fraction
1058
+ * # => 0.25
1059
+ */
1060
+ static VALUE rhrdt_day_fraction(VALUE self) {
1061
+ rhrdt_t *dt;
1062
+ Data_Get_Struct(self, rhrdt_t, dt);
1063
+ RHRDT_FILL_NANOS(dt)
1064
+ return rb_float_new(dt->nanos/RHR_NANOS_PER_DAYD);
1065
+ }
1066
+
1067
+ /* call-seq:
1068
+ * downto(target){|datetime|} -> DateTime
1069
+ *
1070
+ * Equivalent to calling +step+ with the +target+ as the first argument
1071
+ * and <tt>-1</tt> as the second argument. Returns self.
1072
+ *
1073
+ * DateTime.civil(2009, 1, 2).downto(DateTime.civil(2009, 1, 1)) do |datetime|
1074
+ * puts datetime
1075
+ * end
1076
+ * # Output:
1077
+ * # 2009-01-02T00:00:00+00:00
1078
+ * # 2009-01-01T00:00:00+00:00
1079
+ */
1080
+ static VALUE rhrdt_downto(VALUE self, VALUE other) {
1081
+ VALUE argv[2];
1082
+ argv[0] = other;
1083
+ argv[1] = INT2FIX(-1);
1084
+ return rhrdt_step(2, argv, self);
1085
+ }
1086
+
1087
+ /* call-seq:
1088
+ * eql?(datetime) -> true or false
1089
+ *
1090
+ * Returns true only if the +datetime+ given is the same date and time as the receiver.
1091
+ * If +date+ is an instance of +Date+, returns +true+ only if +date+ is
1092
+ * for the same date as the receiver and the receiver has no fractional component.
1093
+ * Otherwise, returns +false+. Example:
1094
+ *
1095
+ * DateTime.civil(2009, 1, 2, 12).eql?(DateTime.civil(2009, 1, 2, 12))
1096
+ * # => true
1097
+ * DateTime.civil(2009, 1, 2, 12).eql?(DateTime.civil(2009, 1, 2, 11))
1098
+ * # => false
1099
+ * DateTime.civil(2009, 1, 2).eql?(Date.civil(2009, 1, 2))
1100
+ * # => true
1101
+ * DateTime.civil(2009, 1, 2, 1).eql?(Date.civil(2009, 1, 2))
1102
+ * # => false
1103
+ */
1104
+ static VALUE rhrdt_eql_q(VALUE self, VALUE other) {
1105
+ rhrdt_t *dt, *odt;
1106
+ rhrd_t *o;
1107
+ long diff;
1108
+
1109
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
1110
+ self = rhrdt__new_offset(self, 0);
1111
+ other = rhrdt__new_offset(other, 0);
1112
+ Data_Get_Struct(self, rhrdt_t, dt);
1113
+ Data_Get_Struct(other, rhrdt_t, odt);
1114
+ return rhrdt__spaceship(dt, odt) == 0 ? Qtrue : Qfalse;
1115
+ } else if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
1116
+ Data_Get_Struct(self, rhrdt_t, dt);
1117
+ Data_Get_Struct(other, rhrd_t, o);
1118
+ RHRDT_FILL_JD(dt)
1119
+ RHR_FILL_JD(o)
1120
+ RHR_SPACE_SHIP(diff, dt->jd, o->jd)
1121
+ if (diff == 0) {
1122
+ RHRDT_FILL_NANOS(dt)
1123
+ RHR_SPACE_SHIP(diff, dt->nanos, 0)
1124
+ }
1125
+ return diff == 0 ? Qtrue : Qfalse;
1126
+ }
1127
+ return Qfalse;
1128
+ }
1129
+
1130
+ /* call-seq:
1131
+ * hash() -> Integer
1132
+ *
1133
+ * Return an +Integer+ hash value for the receiver, such that an
1134
+ * equal date and time will have the same hash value.
1135
+ */
1136
+ static VALUE rhrdt_hash(VALUE self) {
1137
+ rhrdt_t *d;
1138
+ RHR_CACHED_IV(self, rhrd_id_hash)
1139
+ Data_Get_Struct(rhrdt__new_offset(self, 0), rhrdt_t, d);
1140
+ return rb_ivar_set(self, rhrd_id_hash, rb_funcall(rb_ary_new3(2, LONG2NUM(d->jd), LL2NUM(d->nanos)), rhrd_id_hash, 0));
1141
+ }
1142
+
1143
+ /* call-seq:
1144
+ * hour() -> Integer
1145
+ *
1146
+ * Returns the hour of the day as an +Integer+. Example:
1147
+ *
1148
+ * DateTime.civil(2009, 1, 2, 12, 13, 14).hour
1149
+ * # => 12
1150
+ */
1151
+ static VALUE rhrdt_hour(VALUE self) {
1152
+ rhrdt_t *dt;
1153
+ Data_Get_Struct(self, rhrdt_t, dt);
1154
+ RHRDT_FILL_HMS(dt)
1155
+ return LONG2NUM(dt->hour);
1156
+ }
1157
+
1158
+ /* call-seq:
1159
+ * inspect() -> String
1160
+ *
1161
+ * Return a developer-friendly string containing the civil
1162
+ * date and time for the receiver. Example:
1163
+ *
1164
+ * DateTime.civil(2009, 1, 2, 3, 4, 5, 0.5).inspect
1165
+ * # => "#<DateTime 2009-01-02T03:04:05+12:00>"
1166
+ */
1167
+ static VALUE rhrdt_inspect(VALUE self) {
1168
+ VALUE s;
1169
+ rhrdt_t *dt;
1170
+ int len;
1171
+ Data_Get_Struct(self, rhrdt_t, dt);
1172
+ RHRDT_FILL_CIVIL(dt)
1173
+ RHRDT_FILL_HMS(dt)
1174
+
1175
+ s = rb_str_buf_new(128);
1176
+ len = snprintf(RSTRING_PTR(s), 128, "#<DateTime %04li-%02hhi-%02hhiT%02hhi:%02hhi:%02hhi%+03i:%02i>",
1177
+ dt->year, dt->month, dt->day, dt->hour, dt->minute, dt->second, dt->offset/60, abs(dt->offset % 60));
1178
+ if (len == -1 || len > 127) {
1179
+ rb_raise(rb_eNoMemError, "in DateTime#inspect (in snprintf)");
1180
+ }
1181
+
1182
+ RHR_RETURN_RESIZED_STR(s, len)
1183
+ }
1184
+
1185
+ /* call-seq:
1186
+ * jd() -> Integer
1187
+ *
1188
+ * Return the julian day number for the receiver as an +Integer+.
1189
+ *
1190
+ * DateTime.civil(2009, 1, 2).jd
1191
+ * # => 2454834
1192
+ */
1193
+ static VALUE rhrdt_jd(VALUE self) {
1194
+ rhrdt_t *d;
1195
+ Data_Get_Struct(self, rhrdt_t, d);
1196
+ RHRDT_FILL_JD(d)
1197
+ return LONG2NUM(d->jd);
1198
+ }
1199
+
1200
+ /* call-seq:
1201
+ * ld() -> Integer
1202
+ *
1203
+ * Return the number of days since the Lilian Date (the day of calendar reform
1204
+ * in Italy).
1205
+ *
1206
+ * DateTime.civil(2009, 1, 2).ld
1207
+ * # => 155674
1208
+ */
1209
+ static VALUE rhrdt_ld(VALUE self) {
1210
+ rhrdt_t *d;
1211
+ Data_Get_Struct(self, rhrdt_t, d);
1212
+ RHRDT_FILL_JD(d)
1213
+ return LONG2NUM(d->jd - RHR_JD_LD);
1214
+ }
1215
+
1216
+ /* call-seq:
1217
+ * leap?() -> true or false
1218
+ *
1219
+ * Return +true+ if the current year for this date is a leap year
1220
+ * in the Gregorian calendar, +false+ otherwise.
1221
+ *
1222
+ * DateTime.civil(2009, 1, 2).leap?
1223
+ * # => false
1224
+ * DateTime.civil(2008, 1, 2).leap?
1225
+ * # => true
1226
+ */
1227
+ static VALUE rhrdt_leap_q(VALUE self) {
1228
+ rhrdt_t *d;
1229
+ Data_Get_Struct(self, rhrdt_t, d);
1230
+ RHRDT_FILL_CIVIL(d)
1231
+ return rhrd__leap_year(d->year) ? Qtrue : Qfalse;
1232
+ }
1233
+
1234
+ /* call-seq:
1235
+ * min() -> Integer
1236
+ *
1237
+ * Returns the minute of the hour as an +Integer+. Example:
1238
+ *
1239
+ * DateTime.civil(2009, 1, 2, 12, 13, 14).min
1240
+ * # => 13
1241
+ */
1242
+ static VALUE rhrdt_min(VALUE self) {
1243
+ rhrdt_t *dt;
1244
+ Data_Get_Struct(self, rhrdt_t, dt);
1245
+ RHRDT_FILL_HMS(dt)
1246
+ return LONG2NUM(dt->minute);
1247
+ }
1248
+
1249
+ /* call-seq:
1250
+ * mjd() -> Integer
1251
+ *
1252
+ * Return the number of days since 1858-11-17.
1253
+ *
1254
+ * DateTime.civil(2009, 1, 2).mjd
1255
+ * # => 54833
1256
+ */
1257
+ static VALUE rhrdt_mjd(VALUE self) {
1258
+ rhrdt_t *d;
1259
+ Data_Get_Struct(self, rhrdt_t, d);
1260
+ RHRDT_FILL_JD(d)
1261
+ return LONG2NUM(d->jd - RHR_JD_MJD);
1262
+ }
1263
+
1264
+ /* call-seq:
1265
+ * month() -> Integer
1266
+ *
1267
+ * Returns the number of the month as an +Integer+. Example:
1268
+ *
1269
+ * DateTime.civil(2009, 1, 2).month
1270
+ * # => 1
1271
+ */
1272
+ static VALUE rhrdt_month(VALUE self) {
1273
+ rhrdt_t *dt;
1274
+ Data_Get_Struct(self, rhrdt_t, dt);
1275
+ RHRDT_FILL_CIVIL(dt)
1276
+ return LONG2NUM(dt->month);
1277
+ }
1278
+
1279
+ /* call-seq:
1280
+ * new_offset() -> DateTime
1281
+ *
1282
+ * Returns a +DateTime+ with the same absolute time as the current
1283
+ * time, but a potentially different local time. The returned value will
1284
+ * be equal to the receiver.
1285
+ * Raises +ArgumentError+ if an invalid offset is specified.
1286
+ * Example:
1287
+ *
1288
+ * DateTime.civil(2009, 1, 2).new_offset(0.5)
1289
+ * # => #<DateTime 2009-01-02T12:00:00+12:00>
1290
+ * DateTime.civil(2009, 1, 2).new_offset(0.5)
1291
+ * # => #<DateTime 2009-01-01T12:00:00-12:00>
1292
+ */
1293
+ static VALUE rhrdt_new_offset(int argc, VALUE *argv, VALUE self) {
1294
+ double offset;
1295
+
1296
+ switch(argc) {
1297
+ case 0:
1298
+ offset = 0;
1299
+ break;
1300
+ case 1:
1301
+ if (RTEST(rb_obj_is_kind_of(argv[0], rb_cString))) {
1302
+ offset = NUM2LONG(rhrd_s_zone_to_diff(self, argv[0]))/RHR_SECONDS_PER_DAYD;
1303
+ } else {
1304
+ offset = NUM2DBL(argv[0]);
1305
+ }
1306
+ break;
1307
+ default:
1308
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
1309
+ break;
1310
+ }
1311
+ return rhrdt__new_offset(self, offset);
1312
+ }
1313
+
1314
+ /* call-seq:
1315
+ * next() -> DateTime
1316
+ *
1317
+ * Returns the +DateTime+ after the receiver's date. If the receiver
1318
+ * has a fractional day component, the result will have the same
1319
+ * fractional day component.
1320
+ *
1321
+ * DateTime.civil(2009, 1, 2, 12).next
1322
+ * # => #<DateTime 2009-01-03T12:00:00+00:00>
1323
+ */
1324
+ static VALUE rhrdt_next(VALUE self) {
1325
+ return rhrdt__add_days(self, 1);
1326
+ }
1327
+
1328
+ /* call-seq:
1329
+ * offset() -> Float
1330
+ *
1331
+ * Returns a +Float+ representing the offset from UTC as a fraction
1332
+ * of the day, where 0.5 would be 12 hours ahead of UTC ("+12:00"),
1333
+ * and -0.5 would be 12 hours behind UTC ("-12:00").
1334
+ *
1335
+ * DateTime.civil(2009, 1, 2, 12, 13, 14, -0.5).offset
1336
+ * # => -0.5
1337
+ */
1338
+ static VALUE rhrdt_offset(VALUE self) {
1339
+ rhrdt_t *dt;
1340
+ RHR_CACHED_IV(self, rhrd_id_offset)
1341
+ Data_Get_Struct(self, rhrdt_t, dt);
1342
+ return rb_ivar_set(self, rhrd_id_offset, rb_float_new(dt->offset/1440.0));
1343
+ }
1344
+
1345
+ /* call-seq:
1346
+ * sec() -> Integer
1347
+ *
1348
+ * Returns the second of the minute as an +Integer+. Example:
1349
+ *
1350
+ * DateTime.civil(2009, 1, 2, 12, 13, 14).sec
1351
+ * # => 14
1352
+ */
1353
+ static VALUE rhrdt_sec(VALUE self) {
1354
+ rhrdt_t *dt;
1355
+ Data_Get_Struct(self, rhrdt_t, dt);
1356
+ RHRDT_FILL_HMS(dt)
1357
+ return LONG2NUM(dt->second);
1358
+ }
1359
+
1360
+ /* call-seq:
1361
+ * sec_fraction() -> Float
1362
+ *
1363
+ * Returns a +Float+ representing the fraction of the second as a
1364
+ * fraction of the day, which will always be in the range [0.0, 1/86400.0).
1365
+ *
1366
+ * (DateTime.civil(2009, 1, 2, 12, 13, 14) + (1.5/86400)).sec_fraction
1367
+ * # => 0.000005787037
1368
+ */
1369
+ static VALUE rhrdt_sec_fraction(VALUE self) {
1370
+ rhrdt_t *dt;
1371
+ Data_Get_Struct(self, rhrdt_t, dt);
1372
+ RHRDT_FILL_NANOS(dt)
1373
+ return rb_float_new((dt->nanos % RHR_NANOS_PER_SECOND)/RHR_NANOS_PER_DAYD);
1374
+ }
1375
+
1376
+ /* call-seq:
1377
+ * step(target, step=1){|datetime|} -> DateTime
1378
+ *
1379
+ * Yields +DateTime+ objects between the receiver and the +target+ date
1380
+ * (inclusive), with +step+ days between each yielded date.
1381
+ * +step+ may be a an +Integer+, in which case whole days are added,
1382
+ * or it can be a +Float+, in which case fractional days are added.
1383
+ * +step+ can be negative, in which case the dates are yielded in
1384
+ * reverse chronological order. Returns self in all cases.
1385
+ *
1386
+ * If +target+ is equal to the receiver, yields self once regardless of
1387
+ * +step+. It +target+ is less than receiver and +step+ is nonnegative, or
1388
+ * +target+ is greater than receiver and +step+ is nonpositive, does not
1389
+ * yield.
1390
+ *
1391
+ * DateTime.civil(2009, 1, 2).step(DateTime.civil(2009, 1, 6), 2) do |datetime|
1392
+ * puts datetime
1393
+ * end
1394
+ * # Output:
1395
+ * # 2009-01-02T00:00:00+00:00
1396
+ * # 2009-01-04T00:00:00+00:00
1397
+ * # 2009-01-06T00:00:00+00:00
1398
+ * #
1399
+ */
1400
+ static VALUE rhrdt_step(int argc, VALUE *argv, VALUE self) {
1401
+ rhrdt_t *d, *ndt, *d0;
1402
+ rhrd_t *nd;
1403
+ double step, limit;
1404
+ long long step_nanos, limit_nanos, current_nanos;
1405
+ long step_jd, limit_jd, current_jd;
1406
+ VALUE rlimit, new;
1407
+ Data_Get_Struct(self, rhrdt_t, d);
1408
+ Data_Get_Struct(rhrdt__new_offset(self, 0), rhrdt_t, d0);
1409
+
1410
+ rb_need_block();
1411
+ switch(argc) {
1412
+ case 1:
1413
+ step_nanos = 0;
1414
+ step_jd = 1;
1415
+ break;
1416
+ case 2:
1417
+ step = NUM2DBL(argv[1]);
1418
+ step_jd = floor(step);
1419
+ step_nanos = llround((step - step_jd)*RHR_NANOS_PER_DAY);
1420
+ break;
1421
+ default:
1422
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 2", argc);
1423
+ break;
1424
+ }
1425
+
1426
+ rlimit = argv[0];
1427
+ if (RTEST(rb_obj_is_kind_of(rlimit, rb_cNumeric))) {
1428
+ limit = NUM2DBL(rlimit);
1429
+ limit_jd = floor(limit);
1430
+ limit_nanos = llround((limit - limit_jd)*RHR_NANOS_PER_DAY);
1431
+ } else if (RTEST((rb_obj_is_kind_of(rlimit, rhrdt_class)))) {
1432
+ rlimit = rhrdt__new_offset(rlimit, 0);
1433
+ Data_Get_Struct(rlimit, rhrdt_t, ndt);
1434
+ RHRDT_FILL_JD(ndt)
1435
+ RHRDT_FILL_NANOS(ndt)
1436
+ limit_jd = ndt->jd;
1437
+ limit_nanos = ndt->nanos;
1438
+ } else if (RTEST((rb_obj_is_kind_of(rlimit, rhrd_class)))) {
1439
+ Data_Get_Struct(rlimit, rhrd_t, nd);
1440
+ RHR_FILL_JD(nd)
1441
+ limit_jd = nd->jd;
1442
+ limit_nanos = d->offset*RHR_NANOS_PER_MINUTE;
1443
+ if (limit_nanos < 0) {
1444
+ limit_jd--;
1445
+ limit_nanos += RHR_NANOS_PER_DAY;
1446
+ }
1447
+ } else {
1448
+ rb_raise(rb_eTypeError, "expected numeric or date");
1449
+ }
1450
+
1451
+ current_jd = d0->jd;
1452
+ current_nanos = d0->nanos;
1453
+ new = rhrdt__from_jd_nanos(current_jd, current_nanos, d->offset);
1454
+ if (limit_jd > current_jd || (limit_jd == current_jd && limit_nanos > current_nanos)) {
1455
+ if (step_jd > 0 || (step_jd == 0 && step_nanos > 0)) {
1456
+ while (limit_jd > current_jd || (limit_jd == current_jd && limit_nanos >= current_nanos)) {
1457
+ rb_yield(new);
1458
+ new = rhrdt__from_jd_nanos(current_jd + step_jd, current_nanos + step_nanos, d->offset);
1459
+ Data_Get_Struct(new, rhrdt_t, ndt);
1460
+ current_jd = ndt->jd;
1461
+ current_nanos = ndt->nanos;
1462
+ }
1463
+ }
1464
+ } else if (limit_jd < current_jd || (limit_jd == current_jd && limit_nanos < current_nanos)) {
1465
+ if (step_jd < 0 || (step_jd == 0 && step_nanos < 0)) {
1466
+ while (limit_jd < current_jd || (limit_jd == current_jd && limit_nanos <= current_nanos)) {
1467
+ rb_yield(new);
1468
+ new = rhrdt__from_jd_nanos(current_jd + step_jd, current_nanos + step_nanos, d->offset);
1469
+ Data_Get_Struct(new, rhrdt_t, ndt);
1470
+ current_jd = ndt->jd;
1471
+ current_nanos = ndt->nanos;
1472
+ }
1473
+ }
1474
+ } else {
1475
+ rb_yield(self);
1476
+ }
1477
+
1478
+ return self;
1479
+ }
1480
+
1481
+ /* call-seq:
1482
+ * strftime() -> String <br />
1483
+ * strftime(format) -> String
1484
+ *
1485
+ * If no argument is provided, returns a string in ISO8601 format, just like
1486
+ * +to_s+. If an argument is provided, uses it as a format string and returns
1487
+ * a +String+ based on the format. See <tt>Date#strftime</tt> for the supported
1488
+ * formats.
1489
+ */
1490
+ static VALUE rhrdt_strftime(int argc, VALUE *argv, VALUE self) {
1491
+ rhrdt_t* dt;
1492
+ VALUE r;
1493
+
1494
+ switch(argc) {
1495
+ case 0:
1496
+ return rhrdt_to_s(self);
1497
+ case 1:
1498
+ r = rb_str_to_str(argv[0]);
1499
+ break;
1500
+ default:
1501
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
1502
+ break;
1503
+ }
1504
+
1505
+ Data_Get_Struct(self, rhrdt_t, dt);
1506
+ RHRDT_FILL_CIVIL(dt)
1507
+ RHRDT_FILL_JD(dt)
1508
+ RHRDT_FILL_HMS(dt)
1509
+ RHRDT_FILL_NANOS(dt)
1510
+ return rhrd__strftime(dt, RSTRING_PTR(r), RSTRING_LEN(r));
1511
+ }
1512
+
1513
+ /* call-seq:
1514
+ * to_s() -> String
1515
+ *
1516
+ * Returns the receiver as an ISO8601 formatted string.
1517
+ *
1518
+ * DateTime.civil(2009, 1, 2, 12, 13, 14, 0.5).to_s
1519
+ * # => "2009-01-02T12:13:14+12:00"
1520
+ */
1521
+ static VALUE rhrdt_to_s(VALUE self) {
1522
+ VALUE s;
1523
+ rhrdt_t *dt;
1524
+ int len;
1525
+ Data_Get_Struct(self, rhrdt_t, dt);
1526
+ RHRDT_FILL_CIVIL(dt)
1527
+ RHRDT_FILL_HMS(dt)
1528
+
1529
+ s = rb_str_buf_new(128);
1530
+ len = snprintf(RSTRING_PTR(s), 128, "%04li-%02hhi-%02hhiT%02hhi:%02hhi:%02hhi%+03i:%02i",
1531
+ dt->year, dt->month, dt->day, dt->hour, dt->minute, dt->second, dt->offset/60, abs(dt->offset % 60));
1532
+ if (len == -1 || len > 127) {
1533
+ rb_raise(rb_eNoMemError, "in DateTime#to_s (in snprintf)");
1534
+ }
1535
+
1536
+ RHR_RETURN_RESIZED_STR(s, len)
1537
+ }
1538
+
1539
+ /* call-seq:
1540
+ * upto(target){|datetime|} -> DateTime
1541
+ *
1542
+ * Equivalent to calling +step+ with the +target+ as the first argument. Returns self.
1543
+ *
1544
+ * DateTime.civil(2009, 1, 1).upto(DateTime.civil(2009, 1, 2)) do |datetime|
1545
+ * puts datetime
1546
+ * end
1547
+ * # Output:
1548
+ * # 2009-01-01T00:00:00+00:00
1549
+ * # 2009-01-02T00:00:00+00:00
1550
+ */
1551
+ static VALUE rhrdt_upto(VALUE self, VALUE other) {
1552
+ VALUE argv[1];
1553
+ argv[0] = other;
1554
+ return rhrdt_step(1, argv, self);
1555
+ }
1556
+
1557
+ /* call-seq:
1558
+ * wday() -> Integer
1559
+ *
1560
+ * Returns the day of the week as an +Integer+, where Sunday
1561
+ * is 0 and Saturday is 6. Example:
1562
+ *
1563
+ * DateTime.civil(2009, 1, 2).wday
1564
+ * # => 5
1565
+ */
1566
+ static VALUE rhrdt_wday(VALUE self) {
1567
+ rhrdt_t *d;
1568
+ Data_Get_Struct(self, rhrdt_t, d);
1569
+ RHRDT_FILL_JD(d)
1570
+ return LONG2NUM(rhrd__jd_to_wday(d->jd));
1571
+ }
1572
+
1573
+ /* call-seq:
1574
+ * yday() -> Integer
1575
+ *
1576
+ * Returns the day of the year as an +Integer+, where January
1577
+ * 1st is 1 and December 31 is 365 (or 366 if the year is a leap
1578
+ * year). Example:
1579
+ *
1580
+ * DateTime.civil(2009, 2, 2).yday
1581
+ * # => 33
1582
+ */
1583
+ static VALUE rhrdt_yday(VALUE self) {
1584
+ rhrdt_t *d;
1585
+ Data_Get_Struct(self, rhrdt_t, d);
1586
+ RHRDT_FILL_CIVIL(d)
1587
+ return LONG2NUM(rhrd__ordinal_day(d->year, d->month, d->day));
1588
+ }
1589
+
1590
+ /* call-seq:
1591
+ * year() -> Integer
1592
+ *
1593
+ * Returns the year as an +Integer+. Example:
1594
+ *
1595
+ * DateTime.civil(2009, 1, 2).year
1596
+ * # => 2009
1597
+ */
1598
+ static VALUE rhrdt_year(VALUE self) {
1599
+ rhrdt_t *dt;
1600
+ Data_Get_Struct(self, rhrdt_t, dt);
1601
+ RHRDT_FILL_CIVIL(dt)
1602
+ return LONG2NUM(dt->year);
1603
+ }
1604
+
1605
+ /* call-seq:
1606
+ * zone() -> String
1607
+ *
1608
+ * Returns the time zone as a formatted string. This always uses
1609
+ * a numeric representation based on the offset, as +DateTime+ instances
1610
+ * do not keep information about named timezones.
1611
+ *
1612
+ * DateTime.civil(2009, 1, 2, 12, 13, 14, 0.5).zone
1613
+ * # => "+12:00"
1614
+ */
1615
+ static VALUE rhrdt_zone(VALUE self) {
1616
+ VALUE s;
1617
+ rhrdt_t *dt;
1618
+ int len;
1619
+ Data_Get_Struct(self, rhrdt_t, dt);
1620
+
1621
+ s = rb_str_buf_new(128);
1622
+ len = snprintf(RSTRING_PTR(s), 128, "%+03i:%02i", dt->offset/60, abs(dt->offset % 60));
1623
+ if (len == -1 || len > 127) {
1624
+ rb_raise(rb_eNoMemError, "in DateTime#zone (in snprintf)");
1625
+ }
1626
+
1627
+ RHR_RETURN_RESIZED_STR(s, len)
1628
+ }
1629
+
1630
+ /* Ruby instance operator methods */
1631
+
1632
+ /* call-seq:
1633
+ * >>(n) -> DateTime
1634
+ *
1635
+ * Returns a +DateTime+ that is +n+ months after the receiver. +n+
1636
+ * can be negative, in which case it returns a +DateTime+ before
1637
+ * the receiver.
1638
+ *
1639
+ * DateTime.civil(2009, 1, 2) >> 2
1640
+ * # => #<DateTime 2009-03-02T00:00:00+00:00>
1641
+ * DateTime.civil(2009, 1, 2) >> -2
1642
+ * # => #<DateTime 2008-11-02T00:00:00+00:00>
1643
+ */
1644
+ static VALUE rhrdt_op_right_shift(VALUE self, VALUE other) {
1645
+ return rhrdt__add_months(self, NUM2LONG(other));
1646
+ }
1647
+
1648
+ /* call-seq:
1649
+ * <<(n) -> DateTime
1650
+ *
1651
+ * Returns a +DateTime+ that is +n+ months before the receiver. +n+
1652
+ * can be negative, in which case it returns a +DateTime+ after
1653
+ * the receiver.
1654
+ *
1655
+ * DateTime.civil(2009, 1, 2) << 2
1656
+ * # => #<DateTime 2008-11-02T00:00:00+00:00>
1657
+ * DateTime.civil(2009, 1, 2) << -2
1658
+ * # => #<DateTime 2009-03-02T00:00:00+00:00>
1659
+ */
1660
+ static VALUE rhrdt_op_left_shift(VALUE self, VALUE other) {
1661
+ return rhrdt__add_months(self, -NUM2LONG(other));
1662
+ }
1663
+
1664
+ /* call-seq:
1665
+ * +(n) -> DateTime
1666
+ *
1667
+ * Returns a +DateTime+ that is +n+ days after the receiver. +n+
1668
+ * can be negative, in which case it returns a +DateTime+ before
1669
+ * the receiver. +n+ can be a +Float+ including a fractional part,
1670
+ * in which case it is added as a partial day.
1671
+ *
1672
+ * DateTime.civil(2009, 1, 2, 6, 0, 0) + 2
1673
+ * # => #<DateTime 2009-01-04T06:00:00+00:00>
1674
+ * DateTime.civil(2009, 1, 2, 6, 0, 0) + -2
1675
+ * # => #<DateTime 2008-12-31T06:00:00+00:00>
1676
+ * DateTime.civil(2009, 1, 2, 6, 0, 0) + 0.5
1677
+ * # => #<DateTime 2009-01-02T18:00:00+00:00>
1678
+ */
1679
+ static VALUE rhrdt_op_plus(VALUE self, VALUE other) {
1680
+ return rhrdt__add_days(self, NUM2DBL(other));
1681
+ }
1682
+
1683
+ /* call-seq:
1684
+ * -(n) -> DateTime <br />
1685
+ * -(date) -> Float <br />
1686
+ * -(datetime) -> Float
1687
+ *
1688
+ * If a +Numeric+ argument is given, it is treated as an +Float+,
1689
+ * and the number of days it represents is substracted from the
1690
+ * receiver to return a new +DateTime+ object. +n+ can be negative, in
1691
+ * which case the +DateTime+ returned will be after the receiver.
1692
+ *
1693
+ * If a +Date+ argument is given, returns the number of days
1694
+ * between the current date and the argument as an +Float+. If
1695
+ * the receiver has no fractional component, will return a +Float+
1696
+ * with no fractional component. The +Date+ argument is assumed to
1697
+ * have the same time zone offset as the receiver.
1698
+ *
1699
+ * If a +DateTime+ argument is given, returns the number of days
1700
+ * between the receiver and the argument as a +Float+. This
1701
+ * handles differences in the time zone offsets between the
1702
+ * receiver and the argument.
1703
+ *
1704
+ * Other types of arguments raise a +TypeError+.
1705
+ *
1706
+ * DateTime.civil(2009, 1, 2) - 2
1707
+ * # => #<DateTime 2008-12-31T00:00:00+00:00>
1708
+ * DateTime.civil(2009, 1, 2) - 2.5
1709
+ * # => #<DateTime 2008-12-30T12:00:00+00:00>
1710
+ * DateTime.civil(2009, 1, 2) - Date.civil(2009, 1, 1)
1711
+ * # => 1.0
1712
+ * DateTime.civil(2009, 1, 2, 12, 0, 0) - Date.civil(2009, 1, 1)
1713
+ * # => 1.5
1714
+ * DateTime.civil(2009, 1, 2, 12, 0, 0, 0.5) - Date.civil(2009, 1, 1)
1715
+ * # => 1.5
1716
+ * DateTime.civil(2009, 1, 2) - DateTime.civil(2009, 1, 3, 12)
1717
+ * # => -1.5
1718
+ * DateTime.civil(2009, 1, 2, 0, 0, 0, 0.5) - DateTime.civil(2009, 1, 3, 12, 0, 0, -0.5)
1719
+ * # => -2.5
1720
+ */
1721
+ static VALUE rhrdt_op_minus(VALUE self, VALUE other) {
1722
+ rhrdt_t *dt;
1723
+ rhrdt_t *newdt;
1724
+ rhrd_t *newd;
1725
+
1726
+ if (RTEST(rb_obj_is_kind_of(other, rb_cNumeric))) {
1727
+ Data_Get_Struct(self, rhrdt_t, dt);
1728
+ return rhrdt__add_days(self, -NUM2DBL(other));
1729
+ }
1730
+ if (RTEST((rb_obj_is_kind_of(other, rhrdt_class)))) {
1731
+ self = rhrdt__new_offset(self, 0);
1732
+ other = rhrdt__new_offset(other, 0);
1733
+ Data_Get_Struct(self, rhrdt_t, dt);
1734
+ Data_Get_Struct(other, rhrdt_t, newdt);
1735
+ RHRDT_FILL_JD(dt)
1736
+ RHRDT_FILL_NANOS(dt)
1737
+ RHRDT_FILL_JD(newdt)
1738
+ RHRDT_FILL_NANOS(newdt)
1739
+ if (dt->nanos == newdt->nanos) {
1740
+ return rb_float_new(dt->jd - newdt->jd);
1741
+ } else if (dt->jd == newdt->jd)
1742
+ return rb_float_new((dt->nanos - newdt->nanos)/RHR_NANOS_PER_DAYD);
1743
+ else {
1744
+ return rb_float_new((dt->jd - newdt->jd) + (dt->nanos - newdt->nanos)/RHR_NANOS_PER_DAYD);
1745
+ }
1746
+ }
1747
+ if (RTEST((rb_obj_is_kind_of(other, rhrd_class)))) {
1748
+ Data_Get_Struct(self, rhrdt_t, dt);
1749
+ Data_Get_Struct(other, rhrd_t, newd);
1750
+ RHRDT_FILL_JD(dt)
1751
+ RHRDT_FILL_NANOS(dt)
1752
+ RHR_FILL_JD(newd)
1753
+ return rb_float_new((dt->jd - newd->jd) + dt->nanos/RHR_NANOS_PER_DAYD);
1754
+ }
1755
+ rb_raise(rb_eTypeError, "expected numeric or date");
1756
+ }
1757
+
1758
+ /* call-seq:
1759
+ * ===(other) -> true or false
1760
+ *
1761
+ * If +other+ is a +Date+, returns +true+ if +other+ is the
1762
+ * same date as the receiver, or +false+ otherwise.
1763
+ *
1764
+ * If +other+ is a +DateTime+, return +true+ if +other has the same
1765
+ * julian date as the receiver, or +false+ otherwise.
1766
+ *
1767
+ * If +other+ is a +Numeric+, convert it to an +Integer+ and return
1768
+ * +true+ if it is equal to the receiver's julian date, or +false+
1769
+ * otherwise.
1770
+ */
1771
+ static VALUE rhrdt_op_relationship(VALUE self, VALUE other) {
1772
+ rhrdt_t *dt, *odt;
1773
+ rhrd_t *o;
1774
+ long jd;
1775
+
1776
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
1777
+ Data_Get_Struct(other, rhrdt_t, odt);
1778
+ RHRDT_FILL_JD(odt)
1779
+ jd = odt->jd;
1780
+ } else if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
1781
+ Data_Get_Struct(other, rhrd_t, o);
1782
+ RHR_FILL_JD(o)
1783
+ jd = o->jd;
1784
+ } else if (RTEST((rb_obj_is_kind_of(other, rb_cNumeric)))) {
1785
+ jd = NUM2LONG(other);
1786
+ } else {
1787
+ return Qfalse;
1788
+ }
1789
+
1790
+ Data_Get_Struct(self, rhrdt_t, dt);
1791
+ RHRDT_FILL_JD(dt)
1792
+ return dt->jd == jd ? Qtrue : Qfalse;
1793
+ }
1794
+
1795
+ /* call-seq:
1796
+ * <=>(other) -> -1, 0, 1, or nil
1797
+ *
1798
+ * If +other+ is a +DateTime+, returns -1 if the absolute date and time of
1799
+ * +other+ is before the absolute time of the receiver chronologically,
1800
+ * 0 if +other+ is the same absolute date and time as the receiver,
1801
+ * or 1 if the absolute date and time of +other+ is before the receiver
1802
+ * chronologically. Absolute date and time in this case means after taking
1803
+ * account the time zone offset.
1804
+ *
1805
+ * If +other+ is a +Date+, return 0 if +other+ has the same
1806
+ * julian date as the receiver and the receiver has no fractional part,
1807
+ * 1 if +other+ has a julian date greater than the receiver's, or
1808
+ * -1 if +other+ has a julian date less than the receiver's or
1809
+ * a julian date the same as the receiver's and the receiver has a
1810
+ * fractional part.
1811
+ *
1812
+ * If +other+ is a +Numeric+, convert it to an +Float+ and compare
1813
+ * it to the receiver's julian date plus the fractional part.
1814
+ *
1815
+ * For an unrecognized type, return +nil+.
1816
+ */
1817
+ static VALUE rhrdt_op_spaceship(VALUE self, VALUE other) {
1818
+ rhrdt_t *dt, *odt;
1819
+ rhrd_t *od;
1820
+ double diff;
1821
+ int res;
1822
+
1823
+ if (RTEST(rb_obj_is_kind_of(other, rhrdt_class))) {
1824
+ self = rhrdt__new_offset(self, 0);
1825
+ other = rhrdt__new_offset(other, 0);
1826
+ Data_Get_Struct(self, rhrdt_t, dt);
1827
+ Data_Get_Struct(other, rhrdt_t, odt);
1828
+ return LONG2NUM(rhrdt__spaceship(dt, odt));
1829
+ }
1830
+ if (RTEST(rb_obj_is_kind_of(other, rhrd_class))) {
1831
+ Data_Get_Struct(self, rhrdt_t, dt);
1832
+ Data_Get_Struct(other, rhrd_t, od);
1833
+ RHRDT_FILL_JD(dt)
1834
+ RHR_FILL_JD(od)
1835
+ RHR_SPACE_SHIP(res, dt->jd, od->jd)
1836
+ if (res == 0) {
1837
+ RHRDT_FILL_NANOS(dt)
1838
+ RHR_SPACE_SHIP(res, dt->nanos, 0)
1839
+ }
1840
+ return LONG2NUM(res);
1841
+ }
1842
+ if (RTEST((rb_obj_is_kind_of(other, rb_cNumeric)))) {
1843
+ Data_Get_Struct(self, rhrdt_t, dt);
1844
+ diff = NUM2DBL(other);
1845
+ RHRDT_FILL_JD(dt)
1846
+ RHR_SPACE_SHIP(res, dt->jd, (long)diff)
1847
+ if (res == 0) {
1848
+ RHRDT_FILL_NANOS(dt)
1849
+ RHR_SPACE_SHIP(res, dt->nanos, llround((diff - floor(diff)) * RHR_NANOS_PER_DAY))
1850
+ }
1851
+ return LONG2NUM(res);
1852
+ }
1853
+ return Qnil;
1854
+ }
1855
+
1856
+ #ifdef RUBY19
1857
+
1858
+ /* Ruby 1.9 helper methods */
1859
+
1860
+ /* Same as rhrd__add_years, but for ruby DateTime values. */
1861
+ VALUE rhrdt__add_years(VALUE self, long n) {
1862
+ rhrdt_t *d;
1863
+ rhrdt_t *newd;
1864
+ VALUE new;
1865
+ Data_Get_Struct(self, rhrdt_t, d);
1866
+
1867
+ new = Data_Make_Struct(rhrdt_class, rhrdt_t, NULL, free, newd);
1868
+ RHRDT_FILL_CIVIL(d)
1869
+ memcpy(newd, d, sizeof(rhrdt_t));
1870
+
1871
+ newd->year = rhrd__safe_add_long(n, d->year);
1872
+ if(d->month == 2 && d->day == 29 && !rhrd__leap_year(newd->year)) {
1873
+ newd->day = 28;
1874
+ }
1875
+
1876
+ RHR_CHECK_CIVIL(newd)
1877
+ newd->flags &= ~RHR_HAVE_JD;
1878
+ return new;
1879
+ }
1880
+
1881
+ /* Same as rhrd__day_q, but for ruby DateTime values. */
1882
+ VALUE rhrdt__day_q(VALUE self, long day) {
1883
+ rhrdt_t *d;
1884
+ Data_Get_Struct(self, rhrdt_t, d);
1885
+ RHRDT_FILL_JD(d)
1886
+ return rhrd__jd_to_wday(d->jd) == day ? Qtrue : Qfalse;
1887
+ }
1888
+
1889
+ /* Add i given fractional second decimal places to the string,
1890
+ * starting at the given offset len in the string. */
1891
+ long rhrdt__add_iso_time_format(rhrdt_t *dt, char *str, long len, long i) {
1892
+ int l;
1893
+
1894
+ RHRDT_FILL_HMS(dt)
1895
+
1896
+ if (i < 1) {
1897
+ i = 0;
1898
+ } else if (i > 9) {
1899
+ i = 9;
1900
+ }
1901
+
1902
+ l = snprintf(str + len, 128 - len, "T%02hhi:%02hhi:%02hhi", dt->hour, dt->minute, dt->second);
1903
+ if (l == -1 || l > 127) {
1904
+ rb_raise(rb_eNoMemError, "in DateTime formatting method (in snprintf)");
1905
+ }
1906
+ len += l;
1907
+
1908
+ if (i) {
1909
+ RHRDT_FILL_NANOS(dt)
1910
+ l = snprintf(str + len, 128 - len, ".%09lli", dt->nanos % RHR_NANOS_PER_SECOND);
1911
+ if (l == -1 || l > 127) {
1912
+ rb_raise(rb_eNoMemError, "in DateTime formatting method (in snprintf)");
1913
+ }
1914
+ len += i + 1;
1915
+ }
1916
+
1917
+ l = snprintf(str + len, 128 - len, "%+03i:%02i", dt->offset/60, abs(dt->offset % 60));
1918
+ if (l == -1 || l > 127) {
1919
+ rb_raise(rb_eNoMemError, "in DateTime formatting method (in snprintf)");
1920
+ }
1921
+
1922
+ return len + l;
1923
+ }
1924
+
1925
+ /* Ruby 1.9 class methods */
1926
+
1927
+ /* call-seq:
1928
+ * [ruby 1-9 only] <br />
1929
+ * httpdate() -> DateTime <br />
1930
+ * httpdate(str, sg=nil) -> DateTime
1931
+ *
1932
+ * If no argument is given, returns a +DateTime+ for julian day 0.
1933
+ * If an argument is given, it should be a string that is
1934
+ * parsed using +_httpdate+, returning a +DateTime+ or raising
1935
+ * an +ArgumentError+ if the string is not in a valid format
1936
+ * or the datetime it represents is not a valid date or time.
1937
+ * Ignores the 2nd argument.
1938
+ * Example:
1939
+ *
1940
+ * DateTime.httpdate("Fri, 02 Jan 2009 03:04:05 GMT")
1941
+ * # => #<DateTime 2009-01-02T03:04:05+00:00>
1942
+ */
1943
+ static VALUE rhrdt_s_httpdate(int argc, VALUE *argv, VALUE klass) {
1944
+ rhrdt_t *d;
1945
+ VALUE rd;
1946
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
1947
+
1948
+ switch(argc) {
1949
+ case 0:
1950
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
1951
+ return rd;
1952
+ case 1:
1953
+ case 2:
1954
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__httpdate, 1, argv[0]));
1955
+ return rd;
1956
+ default:
1957
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
1958
+ break;
1959
+ }
1960
+ }
1961
+
1962
+ /* call-seq:
1963
+ * [ruby 1-9 only] <br />
1964
+ * iso8601() -> DateTime <br />
1965
+ * iso8601(str, sg=nil) -> DateTime
1966
+ *
1967
+ * If no argument is given, returns a +DateTime+ for julian day 0.
1968
+ * If an argument is given, it should be a string that is
1969
+ * parsed using +_iso8601+, returning a +DateTime+ or raising
1970
+ * an +ArgumentError+ if the string is not in a valid format
1971
+ * or the datetime it represents is not a valid date or time.
1972
+ * Ignores the 2nd argument.
1973
+ * Example:
1974
+ *
1975
+ * DateTime.iso8601("2009-01-02T03:04:05+12:00")
1976
+ * # => #<DateTime 2009-01-02T03:04:05+12:00>
1977
+ */
1978
+ static VALUE rhrdt_s_iso8601(int argc, VALUE *argv, VALUE klass) {
1979
+ rhrdt_t *d;
1980
+ VALUE rd;
1981
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
1982
+
1983
+ switch(argc) {
1984
+ case 0:
1985
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
1986
+ return rd;
1987
+ case 1:
1988
+ case 2:
1989
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__iso8601, 1, argv[0]));
1990
+ return rd;
1991
+ default:
1992
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
1993
+ break;
1994
+ }
1995
+ }
1996
+
1997
+ /* call-seq:
1998
+ * [ruby 1-9 only] <br />
1999
+ * jisx0301() -> DateTime <br />
2000
+ * jisx0301(str, sg=nil) -> DateTime
2001
+ *
2002
+ * If no argument is given, returns a +DateTime+ for julian day 0.
2003
+ * If an argument is given, it should be a string that is
2004
+ * parsed using +_jisx0301+, returning a +DateTime+ or raising
2005
+ * an +ArgumentError+ if the string is not in a valid format
2006
+ * or the datetime it represents is not a valid date or time.
2007
+ * Ignores the 2nd argument.
2008
+ * Example:
2009
+ *
2010
+ * DateTime.iso8601("H21.01.02T03:04:05+12:00")
2011
+ * # => #<DateTime 2009-01-02T03:04:05+12:00>
2012
+ */
2013
+ static VALUE rhrdt_s_jisx0301(int argc, VALUE *argv, VALUE klass) {
2014
+ rhrdt_t *d;
2015
+ VALUE rd;
2016
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
2017
+
2018
+ switch(argc) {
2019
+ case 0:
2020
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
2021
+ return rd;
2022
+ case 1:
2023
+ case 2:
2024
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__jisx0301, 1, argv[0]));
2025
+ return rd;
2026
+ default:
2027
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
2028
+ break;
2029
+ }
2030
+ }
2031
+
2032
+ /* call-seq:
2033
+ * [ruby 1-9 only] <br />
2034
+ * rfc2822() -> DateTime <br />
2035
+ * rfc2822(str, sg=nil) -> DateTime
2036
+ *
2037
+ * If no argument is given, returns a +DateTime+ for julian day 0.
2038
+ * If an argument is given, it should be a string that is
2039
+ * parsed using +_rfc2822+, returning a +DateTime+ or raising
2040
+ * an +ArgumentError+ if the string is not in a valid format
2041
+ * or the datetime it represents is not a valid date or time.
2042
+ * Ignores the 2nd argument.
2043
+ * Example:
2044
+ *
2045
+ * DateTime.rfc2822("Fri, 2 Jan 2009 03:04:05 +1200")
2046
+ * # => #<DateTime 2009-01-02T03:04:05+12:00>
2047
+ */
2048
+ static VALUE rhrdt_s_rfc2822(int argc, VALUE *argv, VALUE klass) {
2049
+ rhrdt_t *d;
2050
+ VALUE rd;
2051
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
2052
+
2053
+ switch(argc) {
2054
+ case 0:
2055
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
2056
+ return rd;
2057
+ case 1:
2058
+ case 2:
2059
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__rfc2822, 1, argv[0]));
2060
+ return rd;
2061
+ default:
2062
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
2063
+ break;
2064
+ }
2065
+ }
2066
+
2067
+ /* call-seq:
2068
+ * [ruby 1-9 only] <br />
2069
+ * rfc3339() -> DateTime <br />
2070
+ * rfc3339(str, sg=nil) -> DateTime
2071
+ *
2072
+ * If no argument is given, returns a +DateTime+ for julian day 0.
2073
+ * If an argument is given, it should be a string that is
2074
+ * parsed using +_rfc3339+, returning a +DateTime+ or raising
2075
+ * an +ArgumentError+ if the string is not in a valid format
2076
+ * or the datetime it represents is not a valid date or time.
2077
+ * Ignores the 2nd argument.
2078
+ * Example:
2079
+ *
2080
+ * DateTime.rfc3339("2009-01-02T03:04:05+12:00")
2081
+ * # => #<DateTime 2009-01-02T03:04:05+12:00>
2082
+ */
2083
+ static VALUE rhrdt_s_rfc3339(int argc, VALUE *argv, VALUE klass) {
2084
+ rhrdt_t *d;
2085
+ VALUE rd;
2086
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
2087
+
2088
+ switch(argc) {
2089
+ case 0:
2090
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
2091
+ return rd;
2092
+ case 1:
2093
+ case 2:
2094
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__rfc3339, 1, argv[0]));
2095
+ return rd;
2096
+ default:
2097
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
2098
+ break;
2099
+ }
2100
+ }
2101
+
2102
+ /* call-seq:
2103
+ * [ruby 1-9 only] <br />
2104
+ * xmlschema() -> DateTime <br />
2105
+ * xmlschema(str, sg=nil) -> DateTime
2106
+ *
2107
+ * If no argument is given, returns a +DateTime+ for julian day 0.
2108
+ * If an argument is given, it should be a string that is
2109
+ * parsed using +_xmlschema+, returning a +DateTime+ or raising
2110
+ * an +ArgumentError+ if the string is not in a valid format
2111
+ * or the datetime it represents is not a valid date or time.
2112
+ * Ignores the 2nd argument.
2113
+ * Example:
2114
+ *
2115
+ * DateTime.xmlschema("2009-01-02T03:04:05+12:00")
2116
+ * # => #<DateTime 2009-01-02T03:04:05+12:00>
2117
+ */
2118
+ static VALUE rhrdt_s_xmlschema(int argc, VALUE *argv, VALUE klass) {
2119
+ rhrdt_t *d;
2120
+ VALUE rd;
2121
+ rd = Data_Make_Struct(klass, rhrdt_t, NULL, free, d);
2122
+
2123
+ switch(argc) {
2124
+ case 0:
2125
+ d->flags = RHR_HAVE_JD | RHR_HAVE_HMS | RHR_HAVE_NANOS;
2126
+ return rd;
2127
+ case 1:
2128
+ case 2:
2129
+ rhrdt__fill_from_hash(d, rb_funcall(klass, rhrd_id__xmlschema, 1, argv[0]));
2130
+ return rd;
2131
+ default:
2132
+ rb_raise(rb_eArgError, "wrong number of arguments (%i for 2)", argc);
2133
+ break;
2134
+ }
2135
+ }
2136
+
2137
+ /* Ruby 1.9 instance methods */
2138
+
2139
+ /* call-seq:
2140
+ * [ruby 1-9 only] <br />
2141
+ * httpdate() -> String
2142
+ *
2143
+ * Returns the receiver as a +String+ in HTTP format. Example:
2144
+ *
2145
+ * DateTime.civil(2009, 1, 2, 3, 4, 5).httpdate
2146
+ * # => "Fri, 02 Jan 2009 03:04:05 GMT"
2147
+ */
2148
+ static VALUE rhrdt_httpdate(VALUE self) {
2149
+ VALUE s;
2150
+ rhrdt_t *d;
2151
+ int len;
2152
+ s = rhrdt__new_offset(self, 0);
2153
+ Data_Get_Struct(s, rhrdt_t, d);
2154
+ RHRDT_FILL_JD(d)
2155
+ RHRDT_FILL_CIVIL(d)
2156
+ RHRDT_FILL_HMS(d)
2157
+
2158
+ s = rb_str_buf_new(128);
2159
+ len = snprintf(RSTRING_PTR(s), 128, "%s, %02hhi %s %04li %02hhi:%02hhi:%02hhi GMT",
2160
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
2161
+ d->day,
2162
+ rhrd__abbr_month_names[d->month],
2163
+ d->year, d->hour, d->minute, d->second);
2164
+ if (len == -1 || len > 127) {
2165
+ rb_raise(rb_eNoMemError, "in DateTime#httpdate (in snprintf)");
2166
+ }
2167
+
2168
+ RHR_RETURN_RESIZED_STR(s, len)
2169
+ }
2170
+
2171
+ /* call-seq:
2172
+ * [ruby 1-9 only] <br />
2173
+ * iso8601(n=0) -> String
2174
+ *
2175
+ * Returns the receiver as a +String+ in ISO8601 format.
2176
+ * If an argument is given, it should be an +Integer+ representing
2177
+ * the number of decimal places to use for the fractional seconds.
2178
+ * Example:
2179
+ *
2180
+ * DateTime.civil(2009, 1, 2, 3, 4, 5, 0.5).iso8601
2181
+ * # => "2009-01-02T03:04:05+12:00"
2182
+ * DateTime.civil(2009, 1, 2, 3, 4, 5, 0.5).iso8601(4)
2183
+ * # => "2009-01-02T03:04:05.0000+12:00"
2184
+ */
2185
+ static VALUE rhrdt_iso8601(int argc, VALUE *argv, VALUE self) {
2186
+ long i;
2187
+ VALUE s;
2188
+ rhrdt_t *dt;
2189
+ char * str;
2190
+ int len;
2191
+ Data_Get_Struct(self, rhrdt_t, dt);
2192
+ RHRDT_FILL_CIVIL(dt)
2193
+
2194
+ switch(argc) {
2195
+ case 1:
2196
+ i = NUM2LONG(argv[0]);
2197
+ break;
2198
+ case 0:
2199
+ i = 0;
2200
+ break;
2201
+ default:
2202
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2203
+ break;
2204
+ }
2205
+
2206
+ s = rb_str_buf_new(128);
2207
+ str = RSTRING_PTR(s);
2208
+
2209
+ len = snprintf(str, 128, "%04li-%02hhi-%02hhi", dt->year, dt->month, dt->day);
2210
+ if (len == -1 || len > 127) {
2211
+ rb_raise(rb_eNoMemError, "in DateTime#to_s (in snprintf)");
2212
+ }
2213
+
2214
+ len = rhrdt__add_iso_time_format(dt, str, len, i);
2215
+ RHR_RETURN_RESIZED_STR(s, len)
2216
+ }
2217
+
2218
+ /* call-seq:
2219
+ * [ruby 1-9 only] <br />
2220
+ * jisx0301(n=0) -> String
2221
+ *
2222
+ * Returns the receiver as a +String+ in JIS X 0301 format.
2223
+ * If an argument is given, it should be an +Integer+ representing
2224
+ * the number of decimal places to use for the fractional seconds.
2225
+ * Example:
2226
+ *
2227
+ * Date.civil(2009, 1, 2, 3, 4, 5, 0.5).jisx0301
2228
+ * # => "H21.01.02T03:04:05+12:00"
2229
+ * Date.civil(2009, 1, 2, 3, 4, 5, 0.5).jisx0301(4)
2230
+ * # => "H21.01.02T03:04:05.0000+12:00"
2231
+ */
2232
+ static VALUE rhrdt_jisx0301(int argc, VALUE *argv, VALUE self) {
2233
+ VALUE s;
2234
+ rhrdt_t *d;
2235
+ int len;
2236
+ int i;
2237
+ char c;
2238
+ char * str;
2239
+ long year;
2240
+ Data_Get_Struct(self, rhrdt_t, d);
2241
+ RHRDT_FILL_CIVIL(d)
2242
+ RHRDT_FILL_JD(d)
2243
+
2244
+ switch(argc) {
2245
+ case 1:
2246
+ i = NUM2LONG(argv[0]);
2247
+ break;
2248
+ case 0:
2249
+ i = 0;
2250
+ break;
2251
+ default:
2252
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2253
+ break;
2254
+ }
2255
+
2256
+ s = rb_str_buf_new(128);
2257
+ str = RSTRING_PTR(s);
2258
+
2259
+ if (d->jd < 2405160) {
2260
+ len = snprintf(str, 128, "%04li-%02hhi-%02hhi", d->year, d->month, d->day);
2261
+ } else {
2262
+ if (d->jd >= 2447535) {
2263
+ c = 'H';
2264
+ year = d->year - 1988;
2265
+ } else if (d->jd >= 2424875) {
2266
+ c = 'S';
2267
+ year = d->year - 1925;
2268
+ } else if (d->jd >= 2419614) {
2269
+ c = 'T';
2270
+ year = d->year - 1911;
2271
+ } else {
2272
+ c = 'M';
2273
+ year = d->year - 1867;
2274
+ }
2275
+ len = snprintf(RSTRING_PTR(s), 128, "%c%02li.%02hhi.%02hhi", c, year, d->month, d->day);
2276
+ }
2277
+ if (len == -1 || len > 127) {
2278
+ rb_raise(rb_eNoMemError, "in DateTime#jisx0301 (in snprintf)");
2279
+ }
2280
+
2281
+ len = rhrdt__add_iso_time_format(d, str, len, i);
2282
+ RHR_RETURN_RESIZED_STR(s, len)
2283
+ }
2284
+
2285
+ /* call-seq:
2286
+ * [ruby 1-9 only] <br />
2287
+ * next_day(n=1) -> DateTime
2288
+ *
2289
+ * Returns a +DateTime+ +n+ days after the receiver. If +n+ is negative,
2290
+ * returns a +DateTime+ before the receiver.
2291
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2292
+ *
2293
+ * DateTime.civil(2009, 1, 2, 12).next_day
2294
+ * # => #<DateTime 2009-01-03T12:00:00+00:00>
2295
+ * DateTime.civil(2009, 1, 2, 12).next_day(2)
2296
+ * # => #<DateTime 2009-01-04T12:00:00+00:00>
2297
+ */
2298
+ static VALUE rhrdt_next_day(int argc, VALUE *argv, VALUE self) {
2299
+ long i;
2300
+
2301
+ switch(argc) {
2302
+ case 0:
2303
+ i = 1;
2304
+ break;
2305
+ case 1:
2306
+ i = NUM2LONG(argv[0]);
2307
+ break;
2308
+ default:
2309
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2310
+ break;
2311
+ }
2312
+
2313
+ return rhrdt__add_days(self, i);
2314
+ }
2315
+
2316
+ /* call-seq:
2317
+ * [ruby 1-9 only] <br />
2318
+ * next_month(n=1) -> DateTime
2319
+ *
2320
+ * Returns a +DateTime+ +n+ months after the receiver. If +n+ is negative,
2321
+ * returns a +DateTime+ before the receiver.
2322
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2323
+ *
2324
+ * DateTime.civil(2009, 1, 2, 12).next_month
2325
+ * # => #<DateTime 2009-02-02T12:00:00+00:00>
2326
+ * DateTime.civil(2009, 1, 2, 12).next_month(2)
2327
+ * # => #<DateTime 2009-03-02T12:00:00+00:00>
2328
+ */
2329
+ static VALUE rhrdt_next_month(int argc, VALUE *argv, VALUE self) {
2330
+ long i;
2331
+
2332
+ switch(argc) {
2333
+ case 0:
2334
+ i = 1;
2335
+ break;
2336
+ case 1:
2337
+ i = NUM2LONG(argv[0]);
2338
+ break;
2339
+ default:
2340
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2341
+ break;
2342
+ }
2343
+
2344
+ return rhrdt__add_months(self, i);
2345
+ }
2346
+
2347
+ /* call-seq:
2348
+ * [ruby 1-9 only] <br />
2349
+ * next_year(n=1) -> DateTime
2350
+ *
2351
+ * Returns a +DateTime+ +n+ years after the receiver. If +n+ is negative,
2352
+ * returns a +DateTime+ before the receiver.
2353
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2354
+ *
2355
+ * DateTime.civil(2009, 1, 2, 12).next_year
2356
+ * # => #<DateTime 2010-01-02T12:00:00+00:00>
2357
+ * DateTime.civil(2009, 1, 2, 12).next_year(2)
2358
+ * # => #<DateTime 2011-01-02T12:00:00+00:00>
2359
+ */
2360
+ static VALUE rhrdt_next_year(int argc, VALUE *argv, VALUE self) {
2361
+ long i;
2362
+
2363
+ switch(argc) {
2364
+ case 0:
2365
+ i = 1;
2366
+ break;
2367
+ case 1:
2368
+ i = NUM2LONG(argv[0]);
2369
+ break;
2370
+ default:
2371
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2372
+ break;
2373
+ }
2374
+
2375
+ return rhrdt__add_years(self, i);
2376
+ }
2377
+
2378
+ /* call-seq:
2379
+ * [ruby 1-9 only] <br />
2380
+ * prev_day(n=1) -> DateTime
2381
+ *
2382
+ * Returns a +DateTime+ +n+ days before the receiver. If +n+ is negative,
2383
+ * returns a +DateTime+ after the receiver.
2384
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2385
+ *
2386
+ * DateTime.civil(2009, 1, 2, 12).prev_day
2387
+ * # => #<DateTime 2009-01-01T12:00:00+00:00>
2388
+ * DateTime.civil(2009, 1, 2, 12).prev_day(2)
2389
+ * # => #<DateTime 2008-12-31T12:00:00+00:00>
2390
+ */
2391
+ static VALUE rhrdt_prev_day(int argc, VALUE *argv, VALUE self) {
2392
+ long i;
2393
+
2394
+ switch(argc) {
2395
+ case 0:
2396
+ i = -1;
2397
+ break;
2398
+ case 1:
2399
+ i = -NUM2LONG(argv[0]);
2400
+ break;
2401
+ default:
2402
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2403
+ break;
2404
+ }
2405
+
2406
+ return rhrdt__add_days(self, i);
2407
+ }
2408
+
2409
+ /* call-seq:
2410
+ * [ruby 1-9 only] <br />
2411
+ * prev_month(n=1) -> DateTime
2412
+ *
2413
+ * Returns a +DateTime+ +n+ months before the receiver. If +n+ is negative,
2414
+ * returns a +DateTime+ after the receiver.
2415
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2416
+ *
2417
+ * DateTime.civil(2009, 1, 2, 12).prev_month
2418
+ * # => #<DateTime 2008-12-02T12:00:00+00:00>
2419
+ * DateTime.civil(2009, 1, 2, 12).prev_month(2)
2420
+ * # => #<DateTime 2008-11-02T12:00:00+00:00>
2421
+ */
2422
+ static VALUE rhrdt_prev_month(int argc, VALUE *argv, VALUE self) {
2423
+ long i;
2424
+
2425
+ switch(argc) {
2426
+ case 0:
2427
+ i = -1;
2428
+ break;
2429
+ case 1:
2430
+ i = -NUM2LONG(argv[0]);
2431
+ break;
2432
+ default:
2433
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2434
+ break;
2435
+ }
2436
+
2437
+ return rhrdt__add_months(self, i);
2438
+ }
2439
+
2440
+ /* call-seq:
2441
+ * [ruby 1-9 only] <br />
2442
+ * prev_year(n=1) -> DateTime
2443
+ *
2444
+ * Returns a +DateTime+ +n+ years before the receiver. If +n+ is negative,
2445
+ * returns a +DateTime+ after the receiver.
2446
+ * The new +DateTime+ is returned with the same fractional part and offset as the receiver.
2447
+ *
2448
+ * DateTime.civil(2009, 1, 2, 12).prev_year
2449
+ * # => #<DateTime 2008-01-02T12:00:00+00:00>
2450
+ * DateTime.civil(2009, 1, 2, 12).prev_year(2)
2451
+ * # => #<DateTime 2007-01-02T12:00:00+00:00>
2452
+ */
2453
+ static VALUE rhrdt_prev_year(int argc, VALUE *argv, VALUE self) {
2454
+ long i;
2455
+
2456
+ switch(argc) {
2457
+ case 0:
2458
+ i = -1;
2459
+ break;
2460
+ case 1:
2461
+ i = -NUM2LONG(argv[0]);
2462
+ break;
2463
+ default:
2464
+ rb_raise(rb_eArgError, "wrong number of arguments: %i for 1", argc);
2465
+ break;
2466
+ }
2467
+
2468
+ return rhrdt__add_years(self, i);
2469
+ }
2470
+
2471
+ /* call-seq:
2472
+ * [ruby 1-9 only] <br />
2473
+ * rfc2822() -> String
2474
+ *
2475
+ * Returns the receiver as a +String+ in RFC2822 format. Example:
2476
+ *
2477
+ * DateTime.civil(2009, 1, 2, 3, 4, 5, 0.5).rfc2822
2478
+ * # => "Fri, 2 Jan 2009 03:04:05 +1200"
2479
+ */
2480
+ static VALUE rhrdt_rfc2822(VALUE self) {
2481
+ VALUE s;
2482
+ rhrdt_t *d;
2483
+ int len;
2484
+ Data_Get_Struct(self, rhrdt_t, d);
2485
+ RHRDT_FILL_CIVIL(d)
2486
+ RHRDT_FILL_JD(d)
2487
+ RHRDT_FILL_HMS(d)
2488
+
2489
+ s = rb_str_buf_new(128);
2490
+ len = snprintf(RSTRING_PTR(s), 128, "%s, %hhi %s %04li %02hhi:%02hhi:%02hhi %+03i%02i",
2491
+ rhrd__abbr_day_names[rhrd__jd_to_wday(d->jd)],
2492
+ d->day,
2493
+ rhrd__abbr_month_names[d->month],
2494
+ d->year, d->hour, d->minute, d->second, d->offset/60, abs(d->offset % 60));
2495
+ if (len == -1 || len > 127) {
2496
+ rb_raise(rb_eNoMemError, "in DateTime#rfc2822 (in snprintf)");
2497
+ }
2498
+
2499
+ RHR_RETURN_RESIZED_STR(s, len)
2500
+ }
2501
+
2502
+ /* call-seq:
2503
+ * [ruby 1-9 only] <br />
2504
+ * to_date() -> Date
2505
+ *
2506
+ * Returns a +Date+ with the same date as the receiver, ignoring
2507
+ * any fractional parts or offsets.
2508
+ *
2509
+ * DateTime.civil(2009, 1, 2, 12).to_date
2510
+ * # => #<Date 2009-01-02>
2511
+ */
2512
+ static VALUE rhrdt_to_date(VALUE self) {
2513
+ rhrd_t *d;
2514
+ rhrdt_t *dt;
2515
+ VALUE rd = Data_Make_Struct(rhrd_class, rhrd_t, NULL, free, d);
2516
+ Data_Get_Struct(self, rhrdt_t, dt);
2517
+
2518
+ if (RHR_HAS_CIVIL(dt)) {
2519
+ d->year = dt->year;
2520
+ d->month = dt->month;
2521
+ d->day = dt->day;
2522
+ d->flags |= RHR_HAVE_CIVIL;
2523
+ }
2524
+ if (RHR_HAS_JD(dt)) {
2525
+ d->jd = dt->jd;
2526
+ d->flags |= RHR_HAVE_JD;
2527
+ }
2528
+
2529
+ return rd;
2530
+ }
2531
+
2532
+ /* call-seq:
2533
+ * [ruby 1-9 only] <br />
2534
+ * to_time() -> Time
2535
+ *
2536
+ * Returns a +Time+ in local time with the same year, month, day,
2537
+ * hour, minute, and second as the receiver (in absoute time).
2538
+ *
2539
+ * DateTime.civil(2009, 1, 2, 5).to_time
2540
+ * # => 2009-01-01 21:00:00 -0800
2541
+ */
2542
+ static VALUE rhrdt_to_time(VALUE self) {
2543
+ long h, m, s;
2544
+ rhrdt_t *dt;
2545
+ Data_Get_Struct(self, rhrdt_t, dt);
2546
+ RHRDT_FILL_JD(dt)
2547
+ RHRDT_FILL_NANOS(dt)
2548
+ self = rhrdt__from_jd_nanos(dt->jd, dt->nanos - dt->offset * RHR_NANOS_PER_MINUTE, 0);
2549
+ Data_Get_Struct(self, rhrdt_t, dt);
2550
+ RHRDT_FILL_CIVIL(dt)
2551
+ RHRDT_FILL_HMS(dt)
2552
+
2553
+ s = dt->nanos/RHR_NANOS_PER_SECOND;
2554
+ h = s/RHR_SECONDS_PER_HOUR;
2555
+ m = (s % RHR_SECONDS_PER_HOUR) / 60;
2556
+ return rb_funcall(rb_funcall(rb_cTime, rhrd_id_utc, 6, LONG2NUM(dt->year), LONG2NUM(dt->month), LONG2NUM(dt->day), LONG2NUM(h), LONG2NUM(m), rb_float_new(s % 60 + (dt->nanos % RHR_NANOS_PER_SECOND)/RHR_NANOS_PER_SECONDD)), rhrd_id_localtime, 0);
2557
+ }
2558
+
2559
+ /* call-seq:
2560
+ * [ruby 1-9 only] <br />
2561
+ * to_datetime() -> DateTime
2562
+ *
2563
+ * Returns a +DateTime+ with the same year, month, day,
2564
+ * hour, minute, and second as the receiver in local time.
2565
+ *
2566
+ * Time.local(2009, 1, 2, 12).to_datetime
2567
+ * # => #<DateTime 2009-01-02T12:00:00-08:00>
2568
+ */
2569
+ static VALUE rhrdt_time_to_datetime(VALUE self) {
2570
+ rhrdt_t *dt;
2571
+ VALUE rd;
2572
+ long t, offset;
2573
+ rd = Data_Make_Struct(rhrdt_class, rhrdt_t, NULL, free, dt);
2574
+
2575
+ offset = NUM2LONG(rb_funcall(self, rhrd_id_utc_offset, 0));
2576
+ t = NUM2LONG(rb_funcall(self, rhrd_id_to_i, 0)) + offset;
2577
+ dt->jd = rhrd__unix_to_jd(t);
2578
+ #ifdef RUBY19
2579
+ dt->nanos = rhrd__mod(t, RHR_SECONDS_PER_DAY) * RHR_NANOS_PER_SECOND + NUM2LONG(rb_funcall(self, rhrd_id_nsec, 0));
2580
+ #else
2581
+ dt->nanos = rhrd__mod(t, RHR_SECONDS_PER_DAY) * RHR_NANOS_PER_SECOND + NUM2LONG(rb_funcall(self, rhrd_id_usec, 0)) * 1000;
2582
+ #endif
2583
+ dt->offset = offset/60;
2584
+ dt->flags |= RHR_HAVE_JD | RHR_HAVE_NANOS;
2585
+ RHR_CHECK_JD(dt);
2586
+ return rd;
2587
+ }
2588
+
2589
+ /* 1.9 day? instance methods */
2590
+
2591
+ /* call-seq:
2592
+ * [ruby 1-9 only] <br />
2593
+ * sunday?() -> true or false
2594
+ *
2595
+ * Returns +true+ if the receiver is a Sunday, +false+ otherwise.
2596
+ */
2597
+ static VALUE rhrdt_sunday_q(VALUE self) {
2598
+ return rhrdt__day_q(self, 0);
2599
+ }
2600
+
2601
+ /* call-seq:
2602
+ * [ruby 1-9 only] <br />
2603
+ * monday?() -> true or false
2604
+ *
2605
+ * Returns +true+ if the receiver is a Monday, +false+ otherwise.
2606
+ */
2607
+ static VALUE rhrdt_monday_q(VALUE self) {
2608
+ return rhrdt__day_q(self, 1);
2609
+ }
2610
+
2611
+ /* call-seq:
2612
+ * [ruby 1-9 only] <br />
2613
+ * tuesday?() -> true or false
2614
+ *
2615
+ * Returns +true+ if the receiver is a Tuesday, +false+ otherwise.
2616
+ */
2617
+ static VALUE rhrdt_tuesday_q(VALUE self) {
2618
+ return rhrdt__day_q(self, 2);
2619
+ }
2620
+
2621
+ /* call-seq:
2622
+ * [ruby 1-9 only] <br />
2623
+ * wednesday?() -> true or false
2624
+ *
2625
+ * Returns +true+ if the receiver is a Wednesday, +false+ otherwise.
2626
+ */
2627
+ static VALUE rhrdt_wednesday_q(VALUE self) {
2628
+ return rhrdt__day_q(self, 3);
2629
+ }
2630
+
2631
+ /* call-seq:
2632
+ * [ruby 1-9 only] <br />
2633
+ * thursday?() -> true or false
2634
+ *
2635
+ * Returns +true+ if the receiver is a Thursday, +false+ otherwise.
2636
+ */
2637
+ static VALUE rhrdt_thursday_q(VALUE self) {
2638
+ return rhrdt__day_q(self, 4);
2639
+ }
2640
+
2641
+ /* call-seq:
2642
+ * [ruby 1-9 only] <br />
2643
+ * friday?() -> true or false
2644
+ *
2645
+ * Returns +true+ if the receiver is a Friday, +false+ otherwise.
2646
+ */
2647
+ static VALUE rhrdt_friday_q(VALUE self) {
2648
+ return rhrdt__day_q(self, 5);
2649
+ }
2650
+
2651
+ /* call-seq:
2652
+ * [ruby 1-9 only] <br />
2653
+ * saturday?() -> true or false
2654
+ *
2655
+ * Returns +true+ if the receiver is a Saturday, +false+ otherwise.
2656
+ */
2657
+ static VALUE rhrdt_saturday_q(VALUE self) {
2658
+ return rhrdt__day_q(self, 6);
2659
+ }
2660
+
2661
+ #endif
2662
+
2663
+ /* Library initialization */
2664
+
2665
+ /* +DateTime+ is used to store a single point in time. It consists of
2666
+ * three main parts:
2667
+ *
2668
+ * * A single date in the gregorian calendar (similar to +Date+)
2669
+ * * A time component (hour, minute, second, fractional second)
2670
+ * * A time zone offset in minutes from UTC
2671
+ *
2672
+ * In general, +DateTime+ objects are created by calling one of the class
2673
+ * methods: +civil+, +parse+, +strptime+, +now+. Once created,
2674
+ * +DateTime+ objects are immutable. Operations that result in a separate
2675
+ * datetime (such as adding a number of days), always return a new +DateTime+
2676
+ * object.
2677
+ * */
2678
+ void Init_datetime(void) {
2679
+
2680
+ /* Define class */
2681
+
2682
+ rhrdt_class = rb_define_class("DateTime", rhrd_class);
2683
+ rb_undef_alloc_func(rhrdt_class);
2684
+ rhrdt_s_class = rb_singleton_class(rhrdt_class);
2685
+
2686
+ /* Define methods for all ruby versions*/
2687
+
2688
+ rb_undef(rhrdt_s_class, rb_intern("today"));
2689
+ rb_define_method(rhrdt_s_class, "_load", rhrdt_s__load, 1);
2690
+ rb_define_method(rhrdt_s_class, "_strptime", rhrdt_s__strptime, -1);
2691
+ rb_define_method(rhrdt_s_class, "civil", rhrdt_s_civil, -1);
2692
+ rb_define_method(rhrdt_s_class, "commercial", rhrdt_s_commercial, -1);
2693
+ rb_define_method(rhrdt_s_class, "jd", rhrdt_s_jd, -1);
2694
+ rb_define_method(rhrdt_s_class, "new!", rhrdt_s_new_b, -1);
2695
+ rb_define_method(rhrdt_s_class, "now", rhrdt_s_now, -1);
2696
+ rb_define_method(rhrdt_s_class, "ordinal", rhrdt_s_ordinal, -1);
2697
+ rb_define_method(rhrdt_s_class, "parse", rhrdt_s_parse, -1);
2698
+ rb_define_method(rhrdt_s_class, "strptime", rhrdt_s_strptime, -1);
2699
+
2700
+ rb_define_alias(rhrdt_s_class, "new", "civil");
2701
+
2702
+ rb_define_method(rhrdt_class, "_dump", rhrdt__dump, 1);
2703
+ rb_define_method(rhrdt_class, "ajd", rhrdt_ajd, 0);
2704
+ rb_define_method(rhrdt_class, "amjd", rhrdt_amjd, 0);
2705
+ rb_define_method(rhrdt_class, "asctime", rhrdt_asctime, 0);
2706
+ rb_define_method(rhrdt_class, "cwday", rhrdt_cwday, 0);
2707
+ rb_define_method(rhrdt_class, "cweek", rhrdt_cweek, 0);
2708
+ rb_define_method(rhrdt_class, "cwyear", rhrdt_cwyear, 0);
2709
+ rb_define_method(rhrdt_class, "day", rhrdt_day, 0);
2710
+ rb_define_method(rhrdt_class, "day_fraction", rhrdt_day_fraction, 0);
2711
+ rb_define_method(rhrdt_class, "downto", rhrdt_downto, 1);
2712
+ rb_define_method(rhrdt_class, "eql?", rhrdt_eql_q, 1);
2713
+ rb_define_method(rhrdt_class, "hash", rhrdt_hash, 0);
2714
+ rb_define_method(rhrdt_class, "hour", rhrdt_hour, 0);
2715
+ rb_define_method(rhrdt_class, "inspect", rhrdt_inspect, 0);
2716
+ rb_define_method(rhrdt_class, "jd", rhrdt_jd, 0);
2717
+ rb_define_method(rhrdt_class, "ld", rhrdt_ld, 0);
2718
+ rb_define_method(rhrdt_class, "leap?", rhrdt_leap_q, 0);
2719
+ rb_define_method(rhrdt_class, "min", rhrdt_min, 0);
2720
+ rb_define_method(rhrdt_class, "mjd", rhrdt_mjd, 0);
2721
+ rb_define_method(rhrdt_class, "month", rhrdt_month, 0);
2722
+ rb_define_method(rhrdt_class, "new_offset", rhrdt_new_offset, -1);
2723
+ rb_define_method(rhrdt_class, "next", rhrdt_next, 0);
2724
+ rb_define_method(rhrdt_class, "offset", rhrdt_offset, 0);
2725
+ rb_define_method(rhrdt_class, "sec", rhrdt_sec, 0);
2726
+ rb_define_method(rhrdt_class, "sec_fraction", rhrdt_sec_fraction, 0);
2727
+ rb_define_method(rhrdt_class, "step", rhrdt_step, -1);
2728
+ rb_define_method(rhrdt_class, "strftime", rhrdt_strftime, -1);
2729
+ rb_define_method(rhrdt_class, "to_s", rhrdt_to_s, 0);
2730
+ rb_define_method(rhrdt_class, "upto", rhrdt_upto, 1);
2731
+ rb_define_method(rhrdt_class, "wday", rhrdt_wday, 0);
2732
+ rb_define_method(rhrdt_class, "yday", rhrdt_yday, 0);
2733
+ rb_define_method(rhrdt_class, "year", rhrdt_year, 0);
2734
+ rb_define_method(rhrdt_class, "zone", rhrdt_zone, 0);
2735
+
2736
+ rb_define_method(rhrdt_class, ">>", rhrdt_op_right_shift, 1);
2737
+ rb_define_method(rhrdt_class, "<<", rhrdt_op_left_shift, 1);
2738
+ rb_define_method(rhrdt_class, "+", rhrdt_op_plus, 1);
2739
+ rb_define_method(rhrdt_class, "-", rhrdt_op_minus, 1);
2740
+ rb_define_method(rhrdt_class, "===", rhrdt_op_relationship, 1);
2741
+ rb_define_method(rhrdt_class, "<=>", rhrdt_op_spaceship, 1);
2742
+
2743
+ rb_define_alias(rhrdt_class, "ctime", "asctime");
2744
+ rb_define_alias(rhrdt_class, "mday", "day");
2745
+ rb_define_alias(rhrdt_class, "mon", "month");
2746
+ rb_define_alias(rhrdt_class, "succ", "next");
2747
+
2748
+ #ifdef RUBY19
2749
+
2750
+ /* Define methods for ruby 1.9 */
2751
+
2752
+ rb_define_method(rhrdt_s_class, "httpdate", rhrdt_s_httpdate, -1);
2753
+ rb_define_method(rhrdt_s_class, "iso8601", rhrdt_s_iso8601, -1);
2754
+ rb_define_method(rhrdt_s_class, "jisx0301", rhrdt_s_jisx0301, -1);
2755
+ rb_define_method(rhrdt_s_class, "rfc2822", rhrdt_s_rfc2822, -1);
2756
+ rb_define_method(rhrdt_s_class, "rfc3339", rhrdt_s_rfc3339, -1);
2757
+ rb_define_method(rhrdt_s_class, "xmlschema", rhrdt_s_xmlschema, -1);
2758
+
2759
+ rb_define_alias(rhrdt_s_class, "rfc822", "rfc2822");
2760
+
2761
+ rb_define_method(rhrdt_class, "httpdate", rhrdt_httpdate, 0);
2762
+ rb_define_method(rhrdt_class, "iso8601", rhrdt_iso8601, -1);
2763
+ rb_define_method(rhrdt_class, "jisx0301", rhrdt_jisx0301, -1);
2764
+ rb_define_method(rhrdt_class, "next_day", rhrdt_next_day, -1);
2765
+ rb_define_method(rhrdt_class, "next_month", rhrdt_next_month, -1);
2766
+ rb_define_method(rhrdt_class, "next_year", rhrdt_next_year, -1);
2767
+ rb_define_method(rhrdt_class, "prev_day", rhrdt_prev_day, -1);
2768
+ rb_define_method(rhrdt_class, "prev_month", rhrdt_prev_month, -1);
2769
+ rb_define_method(rhrdt_class, "prev_year", rhrdt_prev_year, -1);
2770
+ rb_define_method(rhrdt_class, "rfc2822", rhrdt_rfc2822, 0);
2771
+ rb_define_method(rhrdt_class, "to_date", rhrdt_to_date, 0);
2772
+ rb_define_method(rhrdt_class, "to_time", rhrdt_to_time, 0);
2773
+
2774
+ rb_define_alias(rhrdt_class, "minute", "min");
2775
+ rb_define_alias(rhrdt_class, "rfc3339", "iso8601");
2776
+ rb_define_alias(rhrdt_class, "rfc822", "rfc2822");
2777
+ rb_define_alias(rhrdt_class, "second", "sec");
2778
+ rb_define_alias(rhrdt_class, "second_fraction", "sec_fraction");
2779
+ rb_define_alias(rhrdt_class, "to_datetime", "gregorian");
2780
+ rb_define_alias(rhrdt_class, "xmlschema", "iso8601");
2781
+
2782
+ rb_define_method(rhrdt_class, "sunday?", rhrdt_sunday_q, 0);
2783
+ rb_define_method(rhrdt_class, "monday?", rhrdt_monday_q, 0);
2784
+ rb_define_method(rhrdt_class, "tuesday?", rhrdt_tuesday_q, 0);
2785
+ rb_define_method(rhrdt_class, "wednesday?", rhrdt_wednesday_q, 0);
2786
+ rb_define_method(rhrdt_class, "thursday?", rhrdt_thursday_q, 0);
2787
+ rb_define_method(rhrdt_class, "friday?", rhrdt_friday_q, 0);
2788
+ rb_define_method(rhrdt_class, "saturday?", rhrdt_saturday_q, 0);
2789
+
2790
+ rb_define_method(rb_cTime, "to_datetime", rhrdt_time_to_datetime, 0);
2791
+ #else
2792
+
2793
+ /* Define methods for ruby 1.8 */
2794
+
2795
+ rb_define_alias(rhrdt_s_class, "new0", "new!");
2796
+ rb_define_alias(rhrdt_s_class, "new1", "jd");
2797
+ rb_define_alias(rhrdt_s_class, "new2", "ordinal");
2798
+ rb_define_alias(rhrdt_s_class, "new3", "civil");
2799
+ rb_define_alias(rhrdt_s_class, "neww", "commercial");
2800
+
2801
+ rb_define_alias(rhrdt_class, "newof", "new_offset");
2802
+ rb_define_alias(rhrdt_class, "of", "offset");
2803
+ #endif
2804
+ }