home_run 0.9.0-x86-mswin32

Sign up to get free protection for your applications and to get access to all the features.
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
+ }