Permalink
Dec 30, 2003
Jun 23, 2004
Jun 23, 2004
Jun 23, 2004
Jun 23, 2004
Jun 23, 2004
Jun 23, 2004
Jun 23, 2004
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Dec 27, 2003
Newer
100644
4992 lines (4456 sloc)
128 KB
36
static ID id_divmod, id_mul, id_submicro, id_nano_num, id_nano_den, id_offset;
37
static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift;
39
#define NDIV(x,y) (-(-((x)+1)/(y))-1)
40
#define NMOD(x,y) ((y)-(-((x)+1)%(y))-1)
41
#define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d))
44
static int
45
eq(VALUE x, VALUE y)
46
{
47
if (FIXNUM_P(x) && FIXNUM_P(y)) {
48
return x == y;
49
}
50
return RTEST(rb_funcall(x, id_eq, 1, y));
51
}
52
53
static int
57
if ((long)x < (long)y)
58
return -1;
59
if ((long)x > (long)y)
60
return 1;
61
return 0;
66
#define ne(x,y) (!eq((x),(y)))
67
#define lt(x,y) (cmp((x),(y)) < 0)
68
#define gt(x,y) (cmp((x),(y)) > 0)
69
#define le(x,y) (cmp((x),(y)) <= 0)
70
#define ge(x,y) (cmp((x),(y)) >= 0)
75
if (FIXNUM_P(x) && FIXNUM_P(y)) {
76
long l = FIX2LONG(x) + FIX2LONG(y);
77
if (FIXABLE(l)) return LONG2FIX(l);
78
return LONG2NUM(l);
80
if (TYPE(x) == T_BIGNUM) return rb_big_plus(x, y);
81
return rb_funcall(x, '+', 1, y);
87
if (FIXNUM_P(x) && FIXNUM_P(y)) {
88
long l = FIX2LONG(x) - FIX2LONG(y);
89
if (FIXABLE(l)) return LONG2FIX(l);
90
return LONG2NUM(l);
92
if (TYPE(x) == T_BIGNUM) return rb_big_minus(x, y);
93
return rb_funcall(x, '-', 1, y);
96
#if !(HAVE_LONG_LONG && SIZEOF_LONG * 2 <= SIZEOF_LONG_LONG)
97
static int
98
long_mul(long x, long y, long *z)
99
{
100
unsigned long a, b, c;
101
int s;
102
if (x == 0 || y == 0) {
103
*z = 0;
104
return 1;
105
}
106
if (x < 0) {
107
s = -1;
108
a = (unsigned long)-x;
109
}
110
else {
111
s = 1;
112
a = (unsigned long)x;
113
}
114
if (y < 0) {
115
s = -s;
116
b = (unsigned long)-y;
117
}
118
else {
119
b = (unsigned long)y;
120
}
123
if (s < 0) {
124
if (c <= (unsigned long)LONG_MAX + 1) {
125
*z = -(long)c;
126
return 1;
127
}
128
}
129
else {
130
if (c <= (unsigned long)LONG_MAX) {
131
*z = (long)c;
132
return 1;
133
}
134
}
135
}
136
return 0;
137
}
138
#endif
139
161
162
static VALUE
163
mod(VALUE x, VALUE y)
164
{
165
switch (TYPE(x)) {
166
case T_BIGNUM: return rb_big_modulo(x, y);
167
default: return rb_funcall(x, '%', 1, y);
168
}
169
}
170
171
#define neg(x) (sub(INT2FIX(0), (x)))
172
#define lshift(x,y) (rb_funcall((x), id_lshift, 1, (y)))
173
179
long a, b, c;
180
a = FIX2LONG(x);
181
b = FIX2LONG(y);
182
if (b == 0) rb_num_zerodiv();
183
c = a / b;
184
if (c * b == a) {
185
return LONG2NUM(c);
186
}
198
static void
199
divmodv(VALUE n, VALUE d, VALUE *q, VALUE *r)
200
{
201
VALUE tmp, ary;
202
tmp = rb_funcall(n, id_divmod, 1, d);
203
ary = rb_check_array_type(tmp);
204
if (NIL_P(ary)) {
205
rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
206
rb_obj_classname(tmp));
207
}
208
*q = rb_ary_entry(ary, 0);
209
*r = rb_ary_entry(ary, 1);
210
}
211
212
#if SIZEOF_LONG == 8
213
# define INT64toNUM(x) LONG2NUM(x)
214
# define UINT64toNUM(x) ULONG2NUM(x)
215
#elif defined(HAVE_LONG_LONG) && SIZEOF_LONG_LONG == 8
216
# define INT64toNUM(x) LL2NUM(x)
217
# define UINT64toNUM(x) ULL2NUM(x)
218
#endif
219
220
#if defined(HAVE_UINT64_T) && SIZEOF_LONG*2 <= SIZEOF_UINT64_T
221
typedef uint64_t uwideint_t;
222
typedef int64_t wideint_t;
223
typedef uint64_t WIDEVALUE;
224
typedef int64_t SIGNED_WIDEVALUE;
225
# define WIDEVALUE_IS_WIDER 1
226
# define UWIDEINT_MAX UINT64_MAX
227
# define WIDEINT_MAX INT64_MAX
228
# define WIDEINT_MIN INT64_MIN
229
# define FIXWINT_P(tv) ((tv) & 1)
230
# define FIXWVtoINT64(tv) RSHIFT((SIGNED_WIDEVALUE)(tv), 1)
231
# define INT64toFIXWV(wi) ((WIDEVALUE)((SIGNED_WIDEVALUE)(wi) << 1 | FIXNUM_FLAG))
232
# define FIXWV_MAX (((int64_t)1 << 62) - 1)
233
# define FIXWV_MIN (-((int64_t)1 << 62))
234
# define FIXWVABLE(wi) (POSFIXWVABLE(wi) && NEGFIXWVABLE(wi))
235
# define WINT2FIXWV(i) WIDEVAL_WRAP(INT64toFIXWV(i))
236
# define FIXWV2WINT(w) FIXWVtoINT64(WIDEVAL_GET(w))
237
#else
238
typedef unsigned long uwideint_t;
239
typedef long wideint_t;
240
typedef VALUE WIDEVALUE;
241
typedef SIGNED_VALUE SIGNED_WIDEVALUE;
242
# define WIDEVALUE_IS_WIDER 0
243
# define UWIDEINT_MAX ULONG_MAX
244
# define WIDEINT_MAX LONG_MAX
245
# define WIDEINT_MIN LONG_MIN
249
# define FIXWVABLE(i) FIXABLE(i)
250
# define WINT2FIXWV(i) WIDEVAL_WRAP(LONG2FIX(i))
251
# define FIXWV2WINT(w) FIX2LONG(WIDEVAL_GET(w))
252
#endif
253
254
#define POSFIXWVABLE(wi) ((wi) < FIXWV_MAX+1)
255
#define NEGFIXWVABLE(wi) ((wi) >= FIXWV_MIN)
256
#define FIXWV_P(w) FIXWINT_P(WIDEVAL_GET(w))
257
258
/* #define STRUCT_WIDEVAL */
259
#ifdef STRUCT_WIDEVAL
260
/* for type checking */
261
typedef struct {
262
WIDEVALUE value;
263
} wideval_t;
264
static inline wideval_t WIDEVAL_WRAP(WIDEVALUE v) { wideval_t w = { v }; return w; }
265
# define WIDEVAL_GET(w) ((w).value)
266
#else
267
typedef WIDEVALUE wideval_t;
268
# define WIDEVAL_WRAP(v) (v)
269
# define WIDEVAL_GET(w) (w)
270
#endif
271
272
#if WIDEVALUE_IS_WIDER
273
static inline wideval_t
274
wint2wv(wideint_t wi)
275
{
276
if (FIXWVABLE(wi))
277
return WINT2FIXWV(wi);
278
else
279
return WIDEVAL_WRAP(INT64toNUM(wi));
280
}
281
# define WINT2WV(wi) wint2wv(wi)
282
#else
283
# define WINT2WV(wi) WIDEVAL_WRAP(LONG2NUM(wi))
284
#endif
285
286
static inline VALUE
287
w2v(wideval_t w)
288
{
289
#if WIDEVALUE_IS_WIDER
290
if (FIXWV_P(w))
291
return INT64toNUM(FIXWV2WINT(w));
292
return (VALUE)WIDEVAL_GET(w);
293
#else
294
return WIDEVAL_GET(w);
295
#endif
296
}
297
298
#if WIDEVALUE_IS_WIDER
299
static int
300
bdigit_find_maxbit(BDIGIT d)
301
{
302
int res = 0;
303
if (d & ~(BDIGIT)0xffff) {
304
d >>= 16;
305
res += 16;
306
}
307
if (d & ~(BDIGIT)0xff) {
308
d >>= 8;
309
res += 8;
310
}
311
if (d & ~(BDIGIT)0xf) {
312
d >>= 4;
313
res += 4;
314
}
315
if (d & ~(BDIGIT)0x3) {
316
d >>= 2;
317
res += 2;
318
}
319
if (d & ~(BDIGIT)0x1) {
320
d >>= 1;
321
res += 1;
322
}
323
return res;
324
}
325
326
static VALUE
327
rb_big_abs_find_maxbit(VALUE big)
328
{
329
BDIGIT *ds = RBIGNUM_DIGITS(big);
330
BDIGIT d;
331
long len = RBIGNUM_LEN(big);
332
VALUE res;
333
while (0 < len && ds[len-1] == 0)
334
len--;
335
if (len == 0)
336
return Qnil;
337
res = mul(LONG2NUM(len-1), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT));
338
d = ds[len-1];
339
res = add(res, LONG2FIX(bdigit_find_maxbit(d)));
340
return res;
341
}
342
343
static VALUE
344
rb_big_abs_find_minbit(VALUE big)
345
{
346
BDIGIT *ds = RBIGNUM_DIGITS(big);
347
BDIGIT d;
348
long len = RBIGNUM_LEN(big);
349
long i;
350
VALUE res;
351
for (i = 0; i < len; i++)
352
if (ds[i])
353
break;
354
if (i == len)
355
return Qnil;
356
res = mul(LONG2NUM(i), INT2FIX(SIZEOF_BDIGITS * CHAR_BIT));
357
d = ds[i];
359
return res;
360
}
361
362
static wideval_t
363
v2w_bignum(VALUE v)
364
{
365
long len = RBIGNUM_LEN(v);
366
BDIGIT *ds;
367
wideval_t w;
368
VALUE maxbit;
369
ds = RBIGNUM_DIGITS(v);
370
w = WIDEVAL_WRAP(v);
371
maxbit = rb_big_abs_find_maxbit(v);
372
if (NIL_P(maxbit))
373
return WINT2FIXWV(0);
374
if (lt(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) ||
375
(eq(maxbit, INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)) &&
376
RBIGNUM_NEGATIVE_P(v) &&
377
eq(rb_big_abs_find_minbit(v), INT2FIX(sizeof(wideint_t) * CHAR_BIT - 2)))) {
378
wideint_t i;
379
i = 0;
380
while (len)
381
i = (i << sizeof(BDIGIT)*CHAR_BIT) | ds[--len];
382
if (RBIGNUM_NEGATIVE_P(v)) {
383
i = -i;
384
}
385
w = WINT2FIXWV(i);
386
}
387
return w;
388
}
389
#endif
390
391
static inline wideval_t
392
v2w(VALUE v)
393
{
394
#if WIDEVALUE_IS_WIDER
395
if (FIXNUM_P(v)) {
396
return WIDEVAL_WRAP((WIDEVALUE)(SIGNED_WIDEVALUE)(long)v);
397
}
398
else if (TYPE(v) == T_BIGNUM &&
399
RBIGNUM_LEN(v) * sizeof(BDIGIT) <= sizeof(WIDEVALUE)) {
400
return v2w_bignum(v);
401
}
402
#endif
403
return WIDEVAL_WRAP(v);
404
}
405
425
wideint_t a, b;
426
a = FIXWV2WINT(wx);
427
b = FIXWV2WINT(wy);
428
if (a < b)
429
return -1;
430
if (a > b)
431
return 1;
432
return 0;
435
x = w2v(wx);
436
y = w2v(wy);
437
return rb_cmpint(rb_funcall(x, id_cmp, 1, y), x, y);
440
#define wne(x,y) (!weq((x),(y)))
441
#define wlt(x,y) (wcmp((x),(y)) < 0)
442
#define wgt(x,y) (wcmp((x),(y)) > 0)
443
#define wle(x,y) (wcmp((x),(y)) <= 0)
444
#define wge(x,y) (wcmp((x),(y)) >= 0)
451
if (FIXWV_P(wx) && FIXWV_P(wy)) {
452
wideint_t r = FIXWV2WINT(wx) + FIXWV2WINT(wy);
457
x = w2v(wx);
458
if (TYPE(x) == T_BIGNUM) return v2w(rb_big_plus(x, w2v(wy)));
459
return v2w(rb_funcall(x, '+', 1, w2v(wy)));
467
if (FIXWV_P(wx) && FIXWV_P(wy)) {
468
wideint_t r = FIXWV2WINT(wx) - FIXWV2WINT(wy);
473
x = w2v(wx);
474
if (TYPE(x) == T_BIGNUM) return v2w(rb_big_minus(x, w2v(wy)));
475
return v2w(rb_funcall(x, '-', 1, w2v(wy)));
478
static int
479
wi_mul(wideint_t x, wideint_t y, wideint_t *z)
480
{
481
uwideint_t a, b, c;
482
int s;
483
if (x == 0 || y == 0) {
484
*z = 0;
485
return 1;
486
}
487
if (x < 0) {
488
s = -1;
489
a = (uwideint_t)-x;
490
}
491
else {
492
s = 1;
493
a = (uwideint_t)x;
494
}
495
if (y < 0) {
496
s = -s;
497
b = (uwideint_t)-y;
498
}
499
else {
500
b = (uwideint_t)y;
501
}
504
if (s < 0) {
505
if (c <= (uwideint_t)WIDEINT_MAX + 1) {
506
*z = -(wideint_t)c;
507
return 1;
508
}
509
}
510
else {
511
if (c <= (uwideint_t)WIDEINT_MAX) {
512
*z = (wideint_t)c;
513
return 1;
514
}
515
}
516
}
517
return 0;
518
}
519
526
wideint_t z;
527
if (wi_mul(FIXWV2WINT(wx), FIXWV2WINT(wy), &z))
528
return WINT2WV(z);
533
z = rb_funcall(x, '*', 1, w2v(wy));
534
if (TYPE(z) == T_RATIONAL && RRATIONAL(z)->den == INT2FIX(1)) {
535
z = RRATIONAL(z)->num;
536
}
537
return v2w(z);
545
if (FIXWV_P(wx) && FIXWV_P(wy)) {
546
wideint_t a, b, c;
547
a = FIXWV2WINT(wx);
548
b = FIXWV2WINT(wy);
558
ret = rb_funcall(x, id_quo, 1, y);
559
if (TYPE(ret) == T_RATIONAL &&
560
RRATIONAL(ret)->den == INT2FIX(1)) {
561
ret = RRATIONAL(ret)->num;
562
}
566
#define wmulquo(x,y,z) ((WIDEVAL_GET(y) == WIDEVAL_GET(z)) ? (x) : wquo(wmul((x),(y)),(z)))
567
#define wmulquoll(x,y,z) (((y) == (z)) ? (x) : wquo(wmul((x),WINT2WV(y)),WINT2WV(z)))
574
if (FIXWV_P(wn) && FIXWV_P(wd)) {
575
wideint_t n, d, q, r;
576
d = FIXWV2WINT(wd);
584
wideint_t xneg = -FIXWV2WINT(wn);
585
*wq = WINT2WV(xneg);
586
*wr = WINT2FIXWV(0);
597
q = ((-n) / (-d));
598
r = ((-n) % (-d));
599
if (r != 0) {
600
q -= 1;
601
r += d;
602
}
603
}
604
else { /* 0 < n */
605
q = -(n / (-d));
606
r = -(n % (-d));
607
}
608
}
609
else { /* 0 < d */
610
if (n < 0) {
611
q = -((-n) / d);
612
r = -((-n) % d);
613
if (r != 0) {
614
q -= 1;
615
r += d;
616
}
629
ary = rb_check_array_type(tmp);
630
if (NIL_P(ary)) {
631
rb_raise(rb_eTypeError, "unexpected divmod result: into %s",
632
rb_obj_classname(tmp));
633
}
638
static void
639
wmuldivmod(wideval_t wx, wideval_t wy, wideval_t wz, wideval_t *wq, wideval_t *wr)
640
{
641
if (WIDEVAL_GET(wy) == WIDEVAL_GET(wz)) {
642
*wq = wx;
643
*wr = WINT2FIXWV(0);
644
return;
645
}
646
wdivmod(wmul(wx,wy), wz, wq, wr);
647
}
648
649
static wideval_t
650
wdiv(wideval_t wx, wideval_t wy)
651
{
652
wideval_t q, r;
653
wdivmod(wx, wy, &q, &r);
654
return q;
655
}
656
657
static wideval_t
658
wmod(wideval_t wx, wideval_t wy)
659
{
660
wideval_t q, r;
661
wdivmod(wx, wy, &q, &r);
662
return r;
663
}
664
684
default:
685
if ((tmp = rb_check_funcall(v, rb_intern("to_r"), 0, NULL)) != Qundef) {
686
/* test to_int method availability to reject non-Numeric
687
* objects such as String, Time, etc which have to_r method. */
688
if (!rb_respond_to(v, rb_intern("to_int"))) goto typeerror;
696
goto typeerror;
697
}
698
699
t = TYPE(v);
700
switch (t) {
701
case T_FIXNUM:
702
case T_BIGNUM:
703
return v;
704
705
case T_RATIONAL:
706
if (RRATIONAL(v)->den == INT2FIX(1))
707
v = RRATIONAL(v)->num;
709
710
default:
711
typeerror:
712
rb_raise(rb_eTypeError, "can't convert %s into an exact number",
713
NIL_P(v) ? "nil" : rb_obj_classname(v));
718
/* time_t */
719
720
#ifndef TYPEOF_TIMEVAL_TV_SEC
721
# define TYPEOF_TIMEVAL_TV_SEC time_t
722
#endif
723
#ifndef TYPEOF_TIMEVAL_TV_USEC
724
# if INT_MAX >= 1000000
725
# define TYPEOF_TIMEVAL_TV_USEC int
726
# else
727
# define TYPEOF_TIMEVAL_TV_USEC long
728
# endif
729
#endif
730
731
#if SIZEOF_TIME_T == SIZEOF_LONG
732
typedef unsigned long unsigned_time_t;
733
#elif SIZEOF_TIME_T == SIZEOF_INT
734
typedef unsigned int unsigned_time_t;
735
#elif SIZEOF_TIME_T == SIZEOF_LONG_LONG
736
typedef unsigned LONG_LONG unsigned_time_t;
737
#else
738
# error cannot find integer type which size is same as time_t.
739
#endif
740
741
#define TIMET_MAX (~(time_t)0 <= 0 ? (time_t)((~(unsigned_time_t)0) >> 1) : (time_t)(~(unsigned_time_t)0))
742
#define TIMET_MIN (~(time_t)0 <= 0 ? (time_t)(((unsigned_time_t)1) << (sizeof(time_t) * CHAR_BIT - 1)) : (time_t)0)
743
780
b = TIME_SCALE;
781
c = a / b;
782
if (c * b == a) {
783
return DBL2NUM((double)c);
784
}
806
if (TIMET_MIN == 0) {
807
uwideint_t wi = (uwideint_t)t;
808
if (wi <= FIXWV_MAX) {
809
return WINT2FIXWV(wi);
810
}
811
}
812
else {
813
wideint_t wi = (wideint_t)t;
814
if (FIXWV_MIN <= wi && wi <= FIXWV_MAX) {
815
return WINT2FIXWV(wi);
816
}
817
}
818
#endif
819
return v2w(TIMET2NUM(t));
820
}
821
#define TIMET2WV(t) timet2wv(t)
822
823
static time_t
824
wv2timet(wideval_t w)
825
{
826
#if WIDEVALUE_IS_WIDER
827
if (FIXWV_P(w)) {
828
wideint_t wi = FIXWV2WINT(w);
829
if (TIMET_MIN == 0) {
830
if (wi < 0)
831
rb_raise(rb_eRangeError, "negative value to convert into `time_t'");
832
if (TIMET_MAX < (uwideint_t)wi)
833
rb_raise(rb_eRangeError, "too big to convert into `time_t'");
834
}
835
else {
836
if (wi < TIMET_MIN || TIMET_MAX < wi)
837
rb_raise(rb_eRangeError, "too big to convert into `time_t'");
838
}
839
return (time_t)wi;
845
846
VALUE rb_cTime;
847
static VALUE time_utc_offset _((VALUE));
848
849
static int obj2int(VALUE obj);
850
static VALUE obj2vint(VALUE obj);
851
static int month_arg(VALUE arg);
852
static void validate_utc_offset(VALUE utc_offset);
853
static void validate_vtm(struct vtm *vtm);
854
855
static VALUE time_gmtime(VALUE);
856
static VALUE time_localtime(VALUE);
857
static VALUE time_fixoff(VALUE);
858
859
static time_t timegm_noleapsecond(struct tm *tm);
860
static int tmcmp(struct tm *a, struct tm *b);
861
static int vtmcmp(struct vtm *a, struct vtm *b);
862
static const char *find_time_t(struct tm *tptr, int utc_p, time_t *tp);
863
864
static struct vtm *localtimew(wideval_t timew, struct vtm *result);
865
866
static int leap_year_p(long y);
870
#define rb_gmtime_r(t, tm) gmtime_r((t), (tm))
871
#define rb_localtime_r(t, tm) localtime_r((t), (tm))
893
#if defined __APPLE__ && defined __LP64__
894
if (*t != (time_t)(int)*t) return NULL;
895
#endif
896
result = rb_localtime_r(t, result);
897
#if defined(HAVE_MKTIME) && defined(LOCALTIME_OVERFLOW_PROBLEM)
898
if (result) {
903
# if defined(HAVE_STRUCT_TM_TM_GMTOFF)
904
gmtoff1 = result->tm_gmtoff;
905
# endif
912
}
913
#endif
914
return result;
915
}
916
#define LOCALTIME(tm, result) (tzset(),rb_localtime_r2((tm), &(result)))
917
918
#if !defined(HAVE_STRUCT_TM_TM_GMTOFF)
919
static struct tm *
920
rb_gmtime_r2(const time_t *t, struct tm *result)
921
{
922
result = rb_gmtime_r(t, result);
924
if (result) {
925
struct tm tmp = *result;
926
time_t t2 = timegm(&tmp);
927
if (*t != t2)
928
result = NULL;
936
static const int common_year_yday_offset[] = {
937
-1,
938
-1 + 31,
939
-1 + 31 + 28,
940
-1 + 31 + 28 + 31,
941
-1 + 31 + 28 + 31 + 30,
942
-1 + 31 + 28 + 31 + 30 + 31,
943
-1 + 31 + 28 + 31 + 30 + 31 + 30,
944
-1 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
945
-1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
946
-1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
947
-1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
948
-1 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
949
/* 1 2 3 4 5 6 7 8 9 10 11 */
950
};
951
static const int leap_year_yday_offset[] = {
952
-1,
953
-1 + 31,
954
-1 + 31 + 29,
955
-1 + 31 + 29 + 31,
956
-1 + 31 + 29 + 31 + 30,
957
-1 + 31 + 29 + 31 + 30 + 31,
958
-1 + 31 + 29 + 31 + 30 + 31 + 30,
959
-1 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
960
-1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
961
-1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
962
-1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
963
-1 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
964
/* 1 2 3 4 5 6 7 8 9 10 11 */
965
};
966
967
static const int common_year_days_in_month[] = {
968
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
969
};
970
static const int leap_year_days_in_month[] = {
971
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
972
};
973
978
int tm_yday = tm_mday;
979
980
if (leap_year_p(tm_year_mod400 + 1900))
981
tm_yday += leap_year_yday_offset[tm_mon];
982
else
983
tm_yday += common_year_yday_offset[tm_mon];
984
985
return tm_yday;
986
}
987
998
999
year1900 = sub(vtm->year, INT2FIX(1900));
1000
1001
divmodv(year1900, INT2FIX(400), &q400, &r400);
1002
year_mod400 = NUM2INT(r400);
1003
1005
1006
/*
1007
* `Seconds Since the Epoch' in SUSv3:
1008
* tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
1009
* (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
1010
* ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
1011
*/
1012
ret = LONG2NUM(vtm->sec
1013
+ vtm->min*60
1014
+ vtm->hour*3600);
1015
days_in400 = yday
1016
- 70*365
1017
+ DIV(year_mod400 - 69, 4)
1018
- DIV(year_mod400 - 1, 100)
1019
+ (year_mod400 + 299) / 400;
1020
vdays = LONG2NUM(days_in400);
1021
vdays = add(vdays, mul(q400, INT2FIX(97)));
1022
vdays = add(vdays, mul(year1900, INT2FIX(365)));
1023
wret = wadd(rb_time_magnify(v2w(ret)), wmul(rb_time_magnify(v2w(vdays)), WINT2FIXWV(86400)));
1027
}
1028
1029
static st_table *zone_table;
1030
1031
static const char *
1032
zone_str(const char *s)
1033
{
1034
st_data_t k, v;
1035
1036
if (!zone_table)
1037
zone_table = st_init_strtable();
1038
1039
k = (st_data_t)s;
1040
if (st_lookup(zone_table, k, &v)) {
1041
return (const char *)v;
1042
}
1043
s = strdup(s);
1044
k = (st_data_t)s;
1045
st_add_direct(zone_table, k, k);
1046
1047
return s;
1048
}
1049
1050
static void
1062
split_second(timew, &timew2, &vtm->subsecx);
1063
1064
wdivmod(timew2, WINT2FIXWV(86400), &w2, &w);
1065
timev = w2v(w2);
1066
v = w2v(w);
1067
1068
wday = NUM2INT(mod(timev, INT2FIX(7)));
1069
vtm->wday = (wday + 4) % 7;
1070
1071
n = NUM2INT(v);
1072
vtm->sec = n % 60; n = n / 60;
1073
vtm->min = n % 60; n = n / 60;
1074
vtm->hour = n;
1075
1076
/* 97 leap days in the 400 year cycle */
1077
divmodv(timev, INT2FIX(400*365 + 97), &timev, &v);
1078
vtm->year = mul(timev, INT2FIX(400));
1079
1080
/* n is the days in the 400 year cycle.
1081
* the start of the cycle is 1970-01-01. */
1082
1083
n = NUM2INT(v);
1084
y = 1970;
1085
1086
/* 30 years including 7 leap days (1972, 1976, ... 1996),
1087
* 31 days in January 2000 and
1089
* from 1970-01-01 to 2000-02-29 */
1090
if (30*365+7+31+29-1 <= n) {
1091
/* 2000-02-29 or after */
1092
if (n < 31*365+8) {
1093
/* 2000-02-29 to 2000-12-31 */
1094
y += 30;
1095
n -= 30*365+7;
1096
goto found;
1097
}
1098
else {
1099
/* 2001-01-01 or after */
1100
n -= 1;
1101
}
1102
}
1103
1104
x = n / (365*100 + 24);
1105
n = n % (365*100 + 24);
1106
y += x * 100;
1107
if (30*365+7+31+29-1 <= n) {
1108
if (n < 31*365+7) {
1109
y += 30;
1110
n -= 30*365+7;
1111
goto found;
1112
}
1113
else
1114
n += 1;
1115
}
1116
1117
x = n / (365*4 + 1);
1118
n = n % (365*4 + 1);
1119
y += x * 4;
1120
if (365*2+31+29-1 <= n) {
1121
if (n < 365*2+366) {
1122
y += 2;
1123
n -= 365*2;
1124
goto found;
1125
}
1126
else
1127
n -= 1;
1128
}
1129
1130
x = n / 365;
1131
n = n % 365;
1132
y += x;
1133
1134
found:
1135
vtm->yday = n+1;
1136
vtm->year = add(vtm->year, INT2NUM(y));
1137
1138
if (leap_year_p(y))
1139
yday_offset = leap_year_yday_offset;
1140
else
1141
yday_offset = common_year_yday_offset;
1142
1143
for (i = 0; i < 12; i++) {
1144
if (yday_offset[i] < n) {
1145
vtm->mon = i+1;
1146
vtm->mday = n - yday_offset[i];
1147
}
1148
else
1149
break;
1150
}
1151
1152
vtm->utc_offset = INT2FIX(0);
1153
vtm->zone = "UTC";
1154
}
1155
1156
static struct tm *
1157
gmtime_with_leapsecond(const time_t *timep, struct tm *result)
1158
{
1159
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1160
/* 4.4BSD counts leap seconds only with localtime, not with gmtime. */
1161
struct tm *t;
1162
int sign;
1166
if (t == NULL)
1167
return NULL;
1168
1169
/* subtract gmtoff */
1170
if (t->tm_gmtoff < 0) {
1171
sign = 1;
1172
gmtoff = -t->tm_gmtoff;
1173
}
1174
else {
1175
sign = -1;
1176
gmtoff = t->tm_gmtoff;
1177
}
1183
1184
gmtoff_sec *= sign;
1185
gmtoff_min *= sign;
1186
gmtoff_hour *= sign;
1187
1188
gmtoff_day = 0;
1189
1190
if (gmtoff_sec) {
1191
/* If gmtoff_sec == 0, don't change result->tm_sec.
1192
* It may be 60 which is a leap second. */
1193
result->tm_sec += gmtoff_sec;
1194
if (result->tm_sec < 0) {
1195
result->tm_sec += 60;
1196
gmtoff_min -= 1;
1197
}
1198
if (60 <= result->tm_sec) {
1199
result->tm_sec -= 60;
1200
gmtoff_min += 1;
1201
}
1202
}
1203
if (gmtoff_min) {
1204
result->tm_min += gmtoff_min;
1205
if (result->tm_min < 0) {
1206
result->tm_min += 60;
1207
gmtoff_hour -= 1;
1208
}
1209
if (60 <= result->tm_min) {
1210
result->tm_min -= 60;
1211
gmtoff_hour += 1;
1212
}
1213
}
1214
if (gmtoff_hour) {
1215
result->tm_hour += gmtoff_hour;
1216
if (result->tm_hour < 0) {
1217
result->tm_hour += 24;
1218
gmtoff_day = -1;
1219
}
1220
if (24 <= result->tm_hour) {
1221
result->tm_hour -= 24;
1222
gmtoff_day = 1;
1223
}
1224
}
1225
1226
if (gmtoff_day) {
1227
if (gmtoff_day < 0) {
1228
if (result->tm_yday == 0) {
1229
result->tm_mday = 31;
1230
result->tm_mon = 11; /* December */
1231
result->tm_year--;
1232
result->tm_yday = leap_year_p(result->tm_year + 1900) ? 365 : 364;
1233
}
1234
else if (result->tm_mday == 1) {
1235
const int *days_in_month = leap_year_p(result->tm_year + 1900) ?
1236
leap_year_days_in_month :
1237
common_year_days_in_month;
1238
result->tm_mon--;
1239
result->tm_mday = days_in_month[result->tm_mon];
1240
result->tm_yday--;
1241
}
1242
else {
1243
result->tm_mday--;
1244
result->tm_yday--;
1245
}
1246
result->tm_wday = (result->tm_wday + 6) % 7;
1247
}
1248
else {
1249
int leap = leap_year_p(result->tm_year + 1900);
1250
if (result->tm_yday == (leap ? 365 : 364)) {
1251
result->tm_year++;
1252
result->tm_mon = 0; /* January */
1253
result->tm_mday = 1;
1254
result->tm_yday = 0;
1255
}
1256
else if (result->tm_mday == (leap ? leap_year_days_in_month :
1257
common_year_days_in_month)[result->tm_mon]) {
1258
result->tm_mon++;
1259
result->tm_mday = 1;
1260
result->tm_yday++;
1261
}
1262
else {
1263
result->tm_mday++;
1264
result->tm_yday++;
1265
}
1266
result->tm_wday = (result->tm_wday + 1) % 7;
1267
}
1268
}
1269
result->tm_isdst = 0;
1270
result->tm_gmtoff = 0;
1271
#if defined(HAVE_TM_ZONE)
1273
#endif
1274
return result;
1275
#else
1276
return GMTIME(timep, *result);
1277
#endif
1278
}
1279
1280
static long this_year = 0;
1281
static time_t known_leap_seconds_limit;
1282
static int number_of_leap_seconds_known;
1283
1284
static void
1285
init_leap_second_info()
1286
{
1287
/*
1288
* leap seconds are determined by IERS.
1289
* It is announced 6 months before the leap second.
1290
* So no one knows leap seconds in the future after the next year.
1291
*/
1292
if (this_year == 0) {
1297
now = time(NULL);
1298
gmtime(&now);
1299
tm = gmtime_with_leapsecond(&now, &result);
1303
if (TIMET_MAX - now < (time_t)(366*86400))
1304
known_leap_seconds_limit = TIMET_MAX;
1310
1311
vtm.year = LONG2NUM(result.tm_year + 1900);
1312
vtm.mon = result.tm_mon + 1;
1313
vtm.mday = result.tm_mday;
1314
vtm.hour = result.tm_hour;
1315
vtm.min = result.tm_min;
1316
vtm.sec = result.tm_sec;
1322
number_of_leap_seconds_known = NUM2INT(w2v(wsub(TIMET2WV(known_leap_seconds_limit), rb_time_unmagnify(timew))));
1333
1334
/* The first leap second is 1972-06-30 23:59:60 UTC.
1335
* No leap seconds before. */
1348
tm.tm_mon = vtm->mon - 1;
1349
tm.tm_mday = vtm->mday;
1350
tm.tm_hour = vtm->hour;
1351
tm.tm_min = vtm->min;
1352
tm.tm_sec = vtm->sec;
1353
tm.tm_isdst = 0;
1354
1355
errmsg = find_time_t(&tm, 1, &t);
1356
if (errmsg)
1357
rb_raise(rb_eArgError, "%s", errmsg);
1385
if (!gmtime_with_leapsecond(&t, &tm))
1386
return NULL;
1387
1388
result->year = LONG2NUM((long)tm.tm_year + 1900);
1389
result->mon = tm.tm_mon + 1;
1390
result->mday = tm.tm_mday;
1391
result->hour = tm.tm_hour;
1392
result->min = tm.tm_min;
1393
result->sec = tm.tm_sec;
1395
result->utc_offset = INT2FIX(0);
1396
result->wday = tm.tm_wday;
1397
result->yday = tm.tm_yday+1;
1398
result->isdst = tm.tm_isdst;
1399
result->zone = "UTC";
1400
1401
return result;
1402
}
1403
1404
static struct tm *localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone);
1407
* The idea is come from Perl:
1408
* http://use.perl.org/articles/08/02/07/197204.shtml
1409
*
1410
* compat_common_month_table is generated by following program.
1411
* This table finds the last month which start the same day of a week.
1412
* The year 2037 is not used because
1413
* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=522949
1414
*
1416
*
1417
* require 'date'
1418
*
1419
* h = {}
1420
* 2036.downto(2010) {|y|
1421
* 1.upto(12) {|m|
1422
* next if m == 2 && y % 4 == 0
1423
* d = Date.new(y,m,1)
1424
* h[m] ||= {}
1425
* h[m][d.wday] ||= y
1428
*
1429
* 1.upto(12) {|m|
1430
* print "{"
1431
* 0.upto(6) {|w|
1432
* y = h[m][w]
1433
* print " #{y},"
1434
* }
1435
* puts "},"
1436
* }
1437
*
1438
*/
1439
static int compat_common_month_table[12][7] = {
1440
/* Sun Mon Tue Wed Thu Fri Sat */
1441
{ 2034, 2035, 2036, 2031, 2032, 2027, 2033 }, /* January */
1442
{ 2026, 2027, 2033, 2034, 2035, 2030, 2031 }, /* February */
1443
{ 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* March */
1444
{ 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* April */
1445
{ 2033, 2034, 2035, 2030, 2036, 2026, 2032 }, /* May */
1446
{ 2036, 2026, 2032, 2033, 2034, 2035, 2030 }, /* June */
1447
{ 2035, 2030, 2036, 2026, 2032, 2033, 2034 }, /* July */
1448
{ 2032, 2033, 2034, 2035, 2030, 2036, 2026 }, /* August */
1449
{ 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* September */
1450
{ 2034, 2035, 2030, 2036, 2026, 2032, 2033 }, /* October */
1451
{ 2026, 2032, 2033, 2034, 2035, 2030, 2036 }, /* November */
1452
{ 2030, 2036, 2026, 2032, 2033, 2034, 2035 }, /* December */
1453
};
1454
1455
/*
1456
* compat_leap_month_table is generated by following program.
1457
*
1462
* h = {}
1463
* 2037.downto(2010) {|y|
1464
* 1.upto(12) {|m|
1465
* next unless m == 2 && y % 4 == 0
1466
* d = Date.new(y,m,1)
1467
* h[m] ||= {}
1468
* h[m][d.wday] ||= y
1469
* }
1470
* }
1472
* 2.upto(2) {|m|
1473
* 0.upto(6) {|w|
1474
* y = h[m][w]
1475
* print " #{y},"
1476
* }
1477
* puts
1478
* }
1479
*/
1480
static int compat_leap_month_table[7] = {
1481
/* Sun Mon Tue Wed Thu Fri Sat */
1482
2032, 2016, 2028, 2012, 2024, 2036, 2020, /* February */
1483
};
1484
1485
static int
1486
calc_wday(int year, int month, int day)
1487
{
1488
int a, y, m;
1489
int wday;
1490
1491
a = (14 - month) / 12;
1492
y = year + 4800 - a;
1493
m = month + 12 * a - 3;
1494
wday = day + (153*m+2)/5 + 365*y + y/4 - y/100 + y/400 + 2;
1495
wday = wday % 7;
1496
return wday;
1497
}
1498
1499
static VALUE
1510
/* The first DST is at 1916 in German.
1511
* So we don't need to care DST before that. */
1512
if (lt(vtm_utc->year, INT2FIX(1916))) {
1513
VALUE off = INT2FIX(0);
1514
int isdst = 0;
1515
zone = "UTC";
1516
1518
# if SIZEOF_TIME_T <= 4
1519
/* 1901-12-13 20:45:52 UTC : The oldest time in 32-bit signed time_t. */
1520
# define THE_TIME_OLD_ENOUGH ((time_t)0x80000000)
1521
# else
1522
/* Since the Royal Greenwich Observatory was commissioned in 1675,
1523
no timezone defined using GMT at 1600. */
1524
# define THE_TIME_OLD_ENOUGH ((time_t)(1600-1970)*366*24*60*60)
1525
# endif
1526
if (localtime_with_gmtoff_zone((t = THE_TIME_OLD_ENOUGH, &t), &tm, &gmtoff, &zone)) {
1532
/* 1970-01-01 00:00:00 UTC : The Unix epoch - the oldest time in portable time_t. */
1533
if (localtime_with_gmtoff_zone((t = 0, &t), &tm, &gmtoff, &zone)) {
1534
off = LONG2FIX(gmtoff);
1535
isdst = tm.tm_isdst;
1536
}
1544
1545
/* It is difficult to guess future. */
1546
1547
vtm2 = *vtm_utc;
1548
1549
/* guess using a year before 2038. */
1550
y = NUM2INT(mod(vtm_utc->year, INT2FIX(400)));
1551
wday = calc_wday(y, vtm_utc->mon, 1);
1552
if (vtm_utc->mon == 2 && leap_year_p(y))
1553
vtm2.year = INT2FIX(compat_leap_month_table[wday]);
1554
else
1555
vtm2.year = INT2FIX(compat_common_month_table[vtm_utc->mon-1][wday]);
1556
1559
zone = "UTC";
1560
if (localtime_with_gmtoff_zone(&t, &tm, &gmtoff, &zone)) {
1561
if (isdst_ret)
1562
*isdst_ret = tm.tm_isdst;
1563
if (zone_ret)
1564
*zone_ret = zone;
1567
1568
{
1569
/* Use the current time offset as a last resort. */
1570
static time_t now = 0;
1571
static long now_gmtoff = 0;
1577
if (isdst_ret)
1578
*isdst_ret = tm.tm_isdst;
1579
if (zone_ret)
1580
*zone_ret = now_zone;
1581
return LONG2FIX(now_gmtoff);
1582
}
1583
}
1584
1585
static VALUE
1586
small_vtm_sub(struct vtm *vtm1, struct vtm *vtm2)
1587
{
1588
int off;
1589
1590
off = vtm1->sec - vtm2->sec;
1591
off += (vtm1->min - vtm2->min) * 60;
1592
off += (vtm1->hour - vtm2->hour) * 3600;
1593
if (ne(vtm1->year, vtm2->year))
1594
off += lt(vtm1->year, vtm2->year) ? -24*3600 : 24*3600;
1595
else if (vtm1->mon != vtm2->mon)
1596
off += vtm1->mon < vtm2->mon ? -24*3600 : 24*3600;
1597
else if (vtm1->mday != vtm2->mday)
1598
off += vtm1->mday < vtm2->mday ? -24*3600 : 24*3600;
1599
1600
return INT2FIX(off);
1601
}
1602
1610
struct vtm vtm1, vtm2;
1611
int n;
1612
1613
if (FIXNUM_P(vtm->year)) {
1614
long l = FIX2LONG(vtm->year) - 1900;
1615
if (l < INT_MIN || INT_MAX < l)
1616
goto no_localtime;
1618
}
1619
else {
1620
v = sub(vtm->year, INT2FIX(1900));
1621
if (lt(v, INT2NUM(INT_MIN)) || lt(INT2NUM(INT_MAX), v))
1622
goto no_localtime;
1623
tm.tm_year = NUM2INT(v);
1624
}
1625
1626
tm.tm_mon = vtm->mon-1;
1627
tm.tm_mday = vtm->mday;
1628
tm.tm_hour = vtm->hour;
1629
tm.tm_min = vtm->min;
1630
tm.tm_sec = vtm->sec;
1631
tm.tm_isdst = vtm->isdst;
1632
1633
if (find_time_t(&tm, 0, &t))
1634
goto no_localtime;
1663
timew1 = wadd(timew1, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm1))));
1664
timew2 = wadd(timew2, rb_time_magnify(v2w(small_vtm_sub(vtm, &vtm2))));
1686
localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, const char **zone)
1687
{
1688
struct tm tm;
1689
1690
if (LOCALTIME(t, tm)) {
1691
#if defined(HAVE_STRUCT_TM_TM_GMTOFF)
1692
*gmtoff = tm.tm_gmtoff;
1693
#else
1694
struct tm *u, *l;
1695
long off;
1701
if (l->tm_year != u->tm_year)
1702
off = l->tm_year < u->tm_year ? -1 : 1;
1703
else if (l->tm_mon != u->tm_mon)
1704
off = l->tm_mon < u->tm_mon ? -1 : 1;
1705
else if (l->tm_mday != u->tm_mday)
1706
off = l->tm_mday < u->tm_mday ? -1 : 1;
1707
else
1708
off = 0;
1709
off = off * 24 + l->tm_hour - u->tm_hour;
1710
off = off * 60 + l->tm_min - u->tm_min;
1711
off = off * 60 + l->tm_sec - u->tm_sec;
1712
*gmtoff = off;
1713
#endif
1714
1715
if (zone) {
1716
#if defined(HAVE_TM_ZONE)
1717
*zone = zone_str(tm.tm_zone);
1718
#elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT)
1719
/* this needs tzset or localtime, instead of localtime_r */
1720
*zone = zone_str(tzname[daylight && tm.tm_isdst]);
1721
#else
1722
{
1723
char buf[64];
1724
strftime(buf, sizeof(buf), "%Z", &tm);
1725
*zone = zone_str(buf);
1726
}
1727
#endif
1728
}
1729
1741
if (FIXWV_P(timew)) {
1742
wideint_t t = FIXWV2WINT(timew);
1743
if (t < TIME_SCALE * (wideint_t)TIMET_MIN ||
1744
TIME_SCALE * (1 + (wideint_t)TIMET_MAX) <= t)
1750
if (lt(timexv, mul(INT2FIX(TIME_SCALE), TIMET2NUM(TIMET_MIN))) ||
1751
le(mul(INT2FIX(TIME_SCALE), add(TIMET2NUM(TIMET_MAX), INT2FIX(1))), timexv))
1752
return 1;
1753
return 0;
1754
}
1755
1774
result->year = LONG2NUM((long)tm.tm_year + 1900);
1775
result->mon = tm.tm_mon + 1;
1776
result->mday = tm.tm_mday;
1777
result->hour = tm.tm_hour;
1778
result->min = tm.tm_min;
1779
result->sec = tm.tm_sec;
1781
result->wday = tm.tm_wday;
1782
result->yday = tm.tm_yday+1;
1783
result->isdst = tm.tm_isdst;
1784
result->utc_offset = LONG2NUM(gmtoff);
1812
#define GetTimeval(obj, tobj) ((tobj) = get_timeval(obj))
1813
#define GetNewTimeval(obj, tobj) ((tobj) = get_new_timeval(obj))
1818
#define TIME_UTC_P(tobj) ((tobj)->gmt == 1)
1819
#define TIME_SET_UTC(tobj) ((tobj)->gmt = 1)
1820
1821
#define TIME_LOCALTIME_P(tobj) ((tobj)->gmt == 0)
1822
#define TIME_SET_LOCALTIME(tobj) ((tobj)->gmt = 0)
1823
1824
#define TIME_FIXOFF_P(tobj) ((tobj)->gmt == 2)
1825
#define TIME_SET_FIXOFF(tobj, off) \
1826
((tobj)->gmt = 2, \
1827
(tobj)->vtm.utc_offset = (off), \
1828
(tobj)->vtm.zone = NULL)
1829
1830
#define TIME_COPY_GMT(tobj1, tobj2) \
1831
((tobj1)->gmt = (tobj2)->gmt, \
1832
(tobj1)->vtm.utc_offset = (tobj2)->vtm.utc_offset, \
1833
(tobj1)->vtm.zone = (tobj2)->vtm.zone)
1843
static void
1844
time_mark(void *ptr)
1845
{
1846
struct time_object *tobj = ptr;
1847
if (!tobj) return;
1861
static size_t
1862
time_memsize(const void *tobj)
1863
{
1864
return tobj ? sizeof(struct time_object) : 0;
1865
}
1866
1867
static const rb_data_type_t time_data_type = {
1868
"time",
1886
static struct time_object *
1887
get_timeval(VALUE obj)
1888
{
1889
struct time_object *tobj;
1890
TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
1891
if (!TIME_INIT_P(tobj)) {
1892
rb_raise(rb_eTypeError, "uninitialized %"PRIiVALUE, CLASS_OF(obj));
1893
}
1894
return tobj;
1895
}
1896
1897
static struct time_object *
1898
get_new_timeval(VALUE obj)
1899
{
1900
struct time_object *tobj;
1901
TypedData_Get_Struct(obj, struct time_object, &time_data_type, tobj);
1902
if (TIME_INIT_P(tobj)) {
1903
rb_raise(rb_eTypeError, "already initialized %"PRIiVALUE, CLASS_OF(obj));
1904
}
1905
return tobj;
1906
}
1907
1911
rb_check_frozen(time);
1912
if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
1913
rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
1914
}
1915
1942
static struct timespec *
1943
timew2timespec_exact(wideval_t timew, struct timespec *ts)
1944
{
1945
VALUE subsecx;
1946
wideval_t timew2;
1947
VALUE nsecv;
1948
1949
if (timew_out_of_timet_range(timew))
1950
return NULL;
1951
split_second(timew, &timew2, &subsecx);
1952
ts->tv_sec = WV2TIMET(timew2);
1953
nsecv = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
1954
if (!FIXNUM_P(nsecv))
1955
return NULL;
1956
ts->tv_nsec = NUM2LONG(nsecv);
1957
return ts;
1958
}
1959
1960
/*
1961
* Document-method: now
1962
*
1963
* Synonym for <code>Time.new</code>. Returns a +Time+ object
1997
static VALUE
1998
time_set_utc_offset(VALUE time, VALUE off)
1999
{
2000
struct time_object *tobj;
2001
off = num_exact(off);
2002
2003
time_modify(time);
2004
GetTimeval(time, tobj);
2005
2006
tobj->tm_got = 0;
2007
TIME_SET_FIXOFF(tobj, off);
2008
2009
return time;
2010
}
2011
2012
static void
2013
vtm_add_offset(struct vtm *vtm, VALUE off)
2014
{
2015
int sign;
2016
VALUE subsec, v;
2017
int sec, min, hour;
2018
int day;
2019
2020
vtm->utc_offset = sub(vtm->utc_offset, off);
2021
2023
sign = -1;
2024
off = neg(off);
2025
}
2026
else {
2027
sign = 1;
2028
}
2029
divmodv(off, INT2FIX(1), &off, &subsec);
2030
divmodv(off, INT2FIX(60), &off, &v);
2031
sec = NUM2INT(v);
2032
divmodv(off, INT2FIX(60), &off, &v);
2033
min = NUM2INT(v);
2034
divmodv(off, INT2FIX(24), &off, &v);
2035
hour = NUM2INT(v);
2036
2037
if (sign < 0) {
2038
subsec = neg(subsec);
2039
sec = -sec;
2040
min = -min;
2041
hour = -hour;
2042
}
2043
2044
day = 0;
2045
2046
if (!rb_equal(subsec, INT2FIX(0))) {
2048
if (lt(vtm->subsecx, INT2FIX(0))) {
2049
vtm->subsecx = add(vtm->subsecx, INT2FIX(TIME_SCALE));
2052
if (le(INT2FIX(TIME_SCALE), vtm->subsecx)) {
2053
vtm->subsecx = sub(vtm->subsecx, INT2FIX(TIME_SCALE));
2054
sec += 1;
2055
}
2056
goto not_zero_sec;
2057
}
2058
if (sec) {
2059
not_zero_sec:
2060
/* If sec + subsec == 0, don't change vtm->sec.
2061
* It may be 60 which is a leap second. */
2062
vtm->sec += sec;
2063
if (vtm->sec < 0) {
2064
vtm->sec += 60;
2065
min -= 1;
2066
}
2067
if (60 <= vtm->sec) {
2068
vtm->sec -= 60;
2069
min += 1;
2070
}
2071
}
2072
if (min) {
2073
vtm->min += min;
2074
if (vtm->min < 0) {
2075
vtm->min += 60;
2076
hour -= 1;
2077
}
2078
if (60 <= vtm->min) {
2079
vtm->min -= 60;
2080
hour += 1;
2081
}
2082
}
2083
if (hour) {
2084
vtm->hour += hour;
2085
if (vtm->hour < 0) {
2086
vtm->hour += 24;
2087
day = -1;
2088
}
2089
if (24 <= vtm->hour) {
2090
vtm->hour -= 24;
2091
day = 1;
2092
}
2093
}
2094
2095
if (day) {
2096
if (day < 0) {
2097
if (vtm->mon == 1 && vtm->mday == 1) {
2098
vtm->mday = 31;
2099
vtm->mon = 12; /* December */
2100
vtm->year = sub(vtm->year, INT2FIX(1));
2101
vtm->yday = leap_year_v_p(vtm->year) ? 365 : 364;
2102
}
2103
else if (vtm->mday == 1) {
2104
const int *days_in_month = leap_year_v_p(vtm->year) ?
2105
leap_year_days_in_month :
2106
common_year_days_in_month;
2107
vtm->mon--;
2108
vtm->mday = days_in_month[vtm->mon-1];
2109
vtm->yday--;
2110
}
2111
else {
2112
vtm->mday--;
2113
vtm->yday--;
2114
}
2115
vtm->wday = (vtm->wday + 6) % 7;
2116
}
2117
else {
2118
int leap = leap_year_v_p(vtm->year);
2119
if (vtm->mon == 12 && vtm->mday == 31) {
2120
vtm->year = add(vtm->year, INT2FIX(1));
2121
vtm->mon = 1; /* January */
2122
vtm->mday = 1;
2123
vtm->yday = 1;
2124
}
2125
else if (vtm->mday == (leap ? leap_year_days_in_month :
2126
common_year_days_in_month)[vtm->mon-1]) {
2127
vtm->mon++;
2128
vtm->mday = 1;
2129
vtm->yday++;
2130
}
2131
else {
2132
vtm->mday++;
2133
vtm->yday++;
2134
}
2135
vtm->wday = (vtm->wday + 1) % 7;
2136
}
2137
}
2138
}
2139
2140
static VALUE
2141
utc_offset_arg(VALUE arg)
2142
{
2143
VALUE tmp;
2144
if (!NIL_P(tmp = rb_check_string_type(arg))) {
2145
int n;
2146
char *s = RSTRING_PTR(tmp);
2147
if (!rb_enc_str_asciicompat_p(tmp) ||
2148
RSTRING_LEN(tmp) != 6 ||
2149
(s[0] != '+' && s[0] != '-') ||
2150
!ISDIGIT(s[1]) ||
2151
!ISDIGIT(s[2]) ||
2152
s[3] != ':' ||
2153
!ISDIGIT(s[4]) ||
2154
!ISDIGIT(s[5]))
2155
rb_raise(rb_eArgError, "\"+HH:MM\" or \"-HH:MM\" expected for utc_offset");
2156
n = (s[1] * 10 + s[2] - '0' * 11) * 3600;
2157
n += (s[4] * 10 + s[5] - '0' * 11) * 60;
2158
if (s[0] == '-')
2159
n = -n;
2160
return INT2FIX(n);
2161
}
2162
else {
2163
return num_exact(arg);
2164
}
2165
}
2166
2167
static VALUE
2168
time_init_1(int argc, VALUE *argv, VALUE time)
2169
{
2170
struct vtm vtm;
2171
VALUE v[7];
2172
struct time_object *tobj;
2173
2174
vtm.wday = -1;
2175
vtm.yday = 0;
2176
vtm.zone = "";
2177
2178
/* year mon mday hour min sec off */
2179
rb_scan_args(argc, argv, "16", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6]);
2180
2181
vtm.year = obj2vint(v[0]);
2182
2183
vtm.mon = NIL_P(v[1]) ? 1 : month_arg(v[1]);
2184
2193
if (!NIL_P(v[5])) {
2194
VALUE sec = num_exact(v[5]);
2195
VALUE subsec;
2196
divmodv(sec, INT2FIX(1), &sec, &subsec);
2197
vtm.sec = NUM2INT(sec);
2199
}
2200
2201
vtm.isdst = -1;
2202
vtm.utc_offset = Qnil;
2203
if (!NIL_P(v[6])) {
2204
VALUE arg = v[6];
2205
if (arg == ID2SYM(rb_intern("dst")))
2206
vtm.isdst = 1;
2207
else if (arg == ID2SYM(rb_intern("std")))
2208
vtm.isdst = 0;
2209
else
2210
vtm.utc_offset = utc_offset_arg(arg);
2211
}
2212
2213
validate_vtm(&vtm);
2214
2215
time_modify(time);
2220
2221
if (!NIL_P(vtm.utc_offset)) {
2222
VALUE off = vtm.utc_offset;
2223
vtm_add_offset(&vtm, neg(off));
2224
vtm.utc_offset = Qnil;
2230
return time_localtime(time);
2231
}
2232
}
2233
2234
2235
/*
2236
* call-seq:
2237
* Time.new -> time
2238
* Time.new(year, month=nil, day=nil, hour=nil, min=nil, sec=nil, utc_offset=nil) -> time
2239
*
2240
* Returns a <code>Time</code> object.
2241
*
2242
* It is initialized to the current system time if no argument.
2243
* <b>Note:</b> The object created will be created using the
2244
* resolution available on your system clock, and so may include
2245
* fractional seconds.
2246
*
2247
* If one or more arguments specified, the time is initialized
2248
* to the specified time.
2249
* _sec_ may have fraction if it is a rational.
2250
*
2251
* _utc_offset_ is the offset from UTC.
2252
* It is a string such as "+09:00" or a number of seconds such as 32400.
2253
*
2254
* a = Time.new #=> 2007-11-19 07:50:02 -0600
2255
* b = Time.new #=> 2007-11-19 07:50:02 -0600
2256
* a == b #=> false
2257
* "%.6f" % a.to_f #=> "1195480202.282373"
2258
* "%.6f" % b.to_f #=> "1195480202.283415"
2259
*
2260
* Time.new(2008,6,21, 13,30,0, "+09:00") #=> 2008-06-21 13:30:00 +0900
2261
*
2262
* # A trip for RubyConf 2007
2263
* t1 = Time.new(2007,11,1,15,25,0, "+09:00") # JST (Narita)
2264
* t2 = Time.new(2007,11,1,12, 5,0, "-05:00") # CDT (Minneapolis)
2265
* t3 = Time.new(2007,11,1,13,25,0, "-05:00") # CDT (Minneapolis)
2267
* t5 = Time.new(2007,11,5, 9,24,0, "-05:00") # EST (Charlotte)
2268
* t6 = Time.new(2007,11,5,11,21,0, "-05:00") # EST (Detroit)
2269
* t7 = Time.new(2007,11,5,13,45,0, "-05:00") # EST (Detroit)
2270
* t8 = Time.new(2007,11,6,17,10,0, "+09:00") # JST (Narita)
2271
* p((t2-t1)/3600.0) #=> 10.666666666666666
2272
* p((t4-t3)/3600.0) #=> 2.466666666666667
2273
* p((t6-t5)/3600.0) #=> 1.95
2274
* p((t8-t7)/3600.0) #=> 13.416666666666666
2275
*
2276
*/
2277
2278
static VALUE
2279
time_init(int argc, VALUE *argv, VALUE time)
2280
{
2281
if (argc == 0)
2282
return time_init_0(time);
2283
else
2284
return time_init_1(argc, argv, time);
2285
}
2286
2293
if (nsec >= 1000000000) { /* nsec positive overflow */
2294
tmp = sec + nsec / 1000000000;
2295
nsec %= 1000000000;
2296
if (sec > 0 && tmp < 0) {
2297
rb_raise(rb_eRangeError, "out of Time range");
2298
}
2299
sec = tmp;
2301
if (nsec < 0) { /* nsec negative overflow */
2302
tmp = sec + NDIV(nsec,1000000000); /* negative div */
2303
nsec = NMOD(nsec,1000000000); /* negative mod */
2304
if (sec < 0 && tmp > 0) {
2305
rb_raise(rb_eRangeError, "out of Time range");
2306
}
2307
sec = tmp;
2319
{
2320
struct timespec ts;
2321
time_overflow_p(&sec, &nsec);
2322
ts.tv_sec = sec;
2323
ts.tv_nsec = nsec;
2343
wideval_t timew;
2344
2345
if (usec >= 1000000) {
2346
long sec2 = usec / 1000000;
2347
if (sec > TIMET_MAX - sec2) {
2348
rb_raise(rb_eRangeError, "out of Time range");
2349
}
2350
usec -= sec2 * 1000000;
2351
sec += sec2;
2352
}
2353
else if (usec <= 1000000) {
2354
long sec2 = usec / 1000000;
2355
if (sec < -TIMET_MAX - sec2) {
2356
rb_raise(rb_eRangeError, "out of Time range");
2357
}
2358
usec -= sec2 * 1000000;
2359
sec += sec2;
2360
}
2361
2362
timew = nsec2timew(sec, usec * 1000);
2363
return time_new_timew(rb_cTime, timew);
2376
2377
if (!NIL_P(off)) {
2378
off = utc_offset_arg(off);
2379
validate_utc_offset(off);
2380
time_set_utc_offset(time, off);
2381
return time;
2382
}
2383
2384
return time;
2385
}
2386
2387
static struct timespec
2388
time_timespec(VALUE num, int interval)
2389
{
2390
struct timespec t;
2401
if (interval && t.tv_sec < 0)
2402
rb_raise(rb_eArgError, "%s must be positive", tstr);
2413
if (d >= 0) {
2414
t.tv_nsec = (int)(d*1e9+0.5);
2415
}
2416
else if ((t.tv_nsec = (int)(-d*1e9+0.5)) > 0) {
2417
t.tv_nsec = 1000000000 - t.tv_nsec;
2418
f -= 1;
2419
}
2429
if (interval && t.tv_sec < 0)
2430
rb_raise(rb_eArgError, "%s must be positive", tstr);
2435
i = INT2FIX(1);
2436
ary = rb_check_funcall(num, id_divmod, 1, &i);
2437
if (ary != Qundef && !NIL_P(ary = rb_check_array_type(ary))) {
2441
if (interval && t.tv_sec < 0)
2442
rb_raise(rb_eArgError, "%s must be positive", tstr);
2443
f = rb_funcall(f, id_mul, 1, INT2FIX(1000000000));
2444
t.tv_nsec = NUM2LONG(f);
2445
}
2446
else {
2447
rb_raise(rb_eTypeError, "can't convert %s into %s",
2448
rb_obj_classname(num), tstr);
2449
}
2455
static struct timeval
2456
time_timeval(VALUE num, int interval)
2457
{
2458
struct timespec ts;
2459
struct timeval tv;
2460
2461
ts = time_timespec(num, interval);
2491
struct timespec
2492
rb_time_timespec(VALUE time)
2493
{
2494
struct time_object *tobj;
2495
struct timespec t;
2496
2508
*
2509
* Creates a new time object for the current time.
2510
*
2511
* Time.now #=> 2009-06-24 12:39:54 +0900
2512
*/
2513
2514
static VALUE
2515
time_s_now(VALUE klass)
2516
{
2517
return rb_class_new_instance(0, NULL, klass);
2518
}
2519
2522
* Time.at(time) -> time
2523
* Time.at(seconds_with_frac) -> time
2524
* Time.at(seconds, microseconds_with_frac) -> time
2526
* Creates a new time object with the value given by <i>time</i>,
2527
* the given number of <i>seconds_with_frac</i>, or
2528
* <i>seconds</i> and <i>microseconds_with_frac</i> from the Epoch.
2529
* <i>seconds_with_frac</i> and <i>microseconds_with_frac</i>
2530
* can be Integer, Float, Rational, or other Numeric.
2531
* non-portable feature allows the offset to be negative on some systems.
2533
* Time.at(0) #=> 1969-12-31 18:00:00 -0600
2534
* Time.at(Time.at(0)) #=> 1969-12-31 18:00:00 -0600
2535
* Time.at(946702800) #=> 1999-12-31 23:00:00 -0600
2536
* Time.at(-284061600) #=> 1960-12-31 00:00:00 -0600
2537
* Time.at(946684800.2).usec #=> 200000
2538
* Time.at(946684800, 123456.789).nsec #=> 123456789
2569
"jan", "feb", "mar", "apr", "may", "jun",
2570
"jul", "aug", "sep", "oct", "nov", "dec",
2571
};
2572
2622
static int
2623
month_arg(VALUE arg)
2624
{
2625
int i, mon;
2626
2627
VALUE s = rb_check_string_type(arg);
2628
if (!NIL_P(s)) {
2629
mon = 0;
2630
for (i=0; i<12; i++) {
2631
if (RSTRING_LEN(s) == 3 &&
2632
STRCASECMP(months[i], RSTRING_PTR(s)) == 0) {
2633
mon = i+1;
2634
break;
2635
}
2636
}
2637
if (mon == 0) {
2638
char c = RSTRING_PTR(s)[0];
2639
2640
if ('0' <= c && c <= '9') {
2651
static void
2652
validate_utc_offset(VALUE utc_offset)
2653
{
2654
if (le(utc_offset, INT2FIX(-86400)) || ge(utc_offset, INT2FIX(86400)))
2655
rb_raise(rb_eArgError, "utc_offset out of range");
2656
}
2657
2658
static void
2659
validate_vtm(struct vtm *vtm)
2660
{
2661
if ( vtm->mon < 1 || vtm->mon > 12
2662
|| vtm->mday < 1 || vtm->mday > 31
2663
|| vtm->hour < 0 || vtm->hour > 24
2664
|| (vtm->hour == 24 && (vtm->min > 0 || vtm->sec > 0))
2665
|| vtm->min < 0 || vtm->min > 59
2666
|| vtm->sec < 0 || vtm->sec > 60
2676
2677
vtm->year = INT2FIX(0);
2678
vtm->mon = 0;
2679
vtm->mday = 0;
2680
vtm->hour = 0;
2681
vtm->min = 0;
2682
vtm->sec = 0;
2684
vtm->utc_offset = Qnil;
2685
vtm->wday = 0;
2686
vtm->yday = 0;
2687
vtm->isdst = 0;
2688
vtm->zone = "";
2690
if (argc == 10) {
2691
v[0] = argv[5];
2692
v[1] = argv[4];
2693
v[2] = argv[3];
2694
v[3] = argv[2];
2695
v[4] = argv[1];
2696
v[5] = argv[0];
2701
rb_scan_args(argc, argv, "17", &v[0],&v[1],&v[2],&v[3],&v[4],&v[5],&v[6],&v[7]);
2702
/* v[6] may be usec or zone (parsedate) */
2703
/* v[7] is wday (parsedate; ignored) */
2748
{
2749
long tm_year = tm->tm_year;
2750
int tm_yday = tm->tm_mday;
2751
if (leap_year_p(tm_year + 1900))
2755
2756
/*
2757
* `Seconds Since the Epoch' in SUSv3:
2758
* tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
2759
* (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
2760
* ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
2761
*/
2762
return tm->tm_sec + tm->tm_min*60 + tm->tm_hour*3600 +
2763
(time_t)(tm_yday +
2764
(tm_year-70)*365 +
2765
DIV(tm_year-69,4) -
2766
DIV(tm_year-1,100) +
2767
DIV(tm_year+299,400))*86400;
2775
#ifdef DEBUG_GUESSRANGE
2776
#define DEBUG_REPORT_GUESSRANGE fprintf(stderr, "find time guess range: %ld - %ld : %lu\n", guess_lo, guess_hi, (unsigned_time_t)(guess_hi-guess_lo))
2777
#else
2778
#define DEBUG_REPORT_GUESSRANGE
2779
#endif
2780
2781
#ifdef DEBUG_FIND_TIME_NUMGUESS
2782
#define DEBUG_FIND_TIME_NUMGUESS_INC find_time_numguess++,
2783
static unsigned long long find_time_numguess;
2784
2785
static VALUE find_time_numguess_getter(void)
2786
{
2787
return ULL2NUM(find_time_numguess);
2788
}
2804
#define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond((p), &result) : LOCALTIME((p), result)))
2811
#if defined(HAVE_MKTIME)
2812
tm0 = *tptr;
2813
if (!utc_p && (guess = mktime(&tm0)) != -1) {
2814
tm = GUESS(&guess);
2815
if (tm && tmcmp(tptr, tm) == 0) {
2816
goto found;
2817
}
2818
}
2819
#endif
2820
2821
tm0 = *tptr;
2822
if (tm0.tm_mon < 0) {
2823
tm0.tm_mon = 0;
2824
tm0.tm_mday = 1;
2825
tm0.tm_hour = 0;
2826
tm0.tm_min = 0;
2827
tm0.tm_sec = 0;
2828
}
2829
else if (11 < tm0.tm_mon) {
2830
tm0.tm_mon = 11;
2831
tm0.tm_mday = 31;
2832
tm0.tm_hour = 23;
2833
tm0.tm_min = 59;
2834
tm0.tm_sec = 60;
2835
}
2836
else if (tm0.tm_mday < 1) {
2837
tm0.tm_mday = 1;
2838
tm0.tm_hour = 0;
2839
tm0.tm_min = 0;
2840
tm0.tm_sec = 0;
2841
}
2842
else if ((d = (leap_year_p(1900 + tm0.tm_year) ?
2843
leap_year_days_in_month :
2844
common_year_days_in_month)[tm0.tm_mon]) < tm0.tm_mday) {
2845
tm0.tm_mday = d;
2846
tm0.tm_hour = 23;
2847
tm0.tm_min = 59;
2848
tm0.tm_sec = 60;
2849
}
2850
else if (tm0.tm_hour < 0) {
2851
tm0.tm_hour = 0;
2852
tm0.tm_min = 0;
2853
tm0.tm_sec = 0;
2854
}
2855
else if (23 < tm0.tm_hour) {
2856
tm0.tm_hour = 23;
2857
tm0.tm_min = 59;
2858
tm0.tm_sec = 60;
2859
}
2860
else if (tm0.tm_min < 0) {
2861
tm0.tm_min = 0;
2862
tm0.tm_sec = 0;
2863
}
2864
else if (59 < tm0.tm_min) {
2865
tm0.tm_min = 59;
2866
tm0.tm_sec = 60;
2867
}
2868
else if (tm0.tm_sec < 0) {
2869
tm0.tm_sec = 0;
2870
}
2871
else if (60 < tm0.tm_sec) {
2872
tm0.tm_sec = 60;
2873
}
2881
if (d < 0) {
2882
guess_hi = guess;
2883
guess -= 24 * 60 * 60;
2884
}
2885
else {
2886
guess_lo = guess;
2887
guess += 24 * 60 * 60;
2888
}
2922
guess = guess_lo / 2 + guess_hi / 2;
2923
if (guess <= guess_lo)
2924
guess = guess_lo + 1;
2925
else if (guess >= guess_hi)
2926
guess = guess_hi - 1;
2927
status = 1;
2928
}
2929
else {
2930
if (status == 1) {
2931
time_t guess0_hi = timegm_noleapsecond(&tm_hi);
2932
guess = guess_hi - (guess0_hi - guess0);
2935
status = 2;
2936
}
2937
else if (status == 2) {
2938
time_t guess0_lo = timegm_noleapsecond(&tm_lo);
2939
guess = guess_lo + (guess0 - guess0_lo);
2942
status = 0;
2943
}
2944
if (guess <= guess_lo || guess_hi <= guess) {
2945
/* Precious guess is invalid. try binary search. */
2946
#ifdef DEBUG_GUESSRANGE
2947
if (guess <= guess_lo) fprintf(stderr, "too small guess: %ld <= %ld\n", guess, guess_lo);
2948
if (guess_hi <= guess) fprintf(stderr, "too big guess: %ld <= %ld\n", guess_hi, guess);
2949
#endif
2971
if (!utc_p) {
2972
/* If localtime is nonmonotonic, another result may exist. */
2973
time_t guess2;
2974
if (find_dst) {
2975
guess2 = guess - 2 * 60 * 60;
2977
if (tm) {
2978
if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
2979
tptr->tm_min != tm->tm_min ||
2981
guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
2982
(tm->tm_min - tptr->tm_min) * 60 +
2983
(tm->tm_sec - tptr->tm_sec);
2984
if (tptr->tm_mday != tm->tm_mday)
2985
guess2 += 24 * 60 * 60;
2986
if (guess != guess2) {
3002
if (tm) {
3003
if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
3004
tptr->tm_min != tm->tm_min ||
3006
guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
3007
(tm->tm_min - tptr->tm_min) * 60 +
3008
(tm->tm_sec - tptr->tm_sec);
3009
if (tptr->tm_mday != tm->tm_mday)
3010
guess2 -= 24 * 60 * 60;
3011
if (guess != guess2) {
3031
/*
3032
* `Seconds Since the Epoch' in SUSv3:
3033
* tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
3034
* (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
3035
* ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
3036
*/
3037
3038
tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday);
3039
3040
*tp = guess_lo +
3041
((tptr->tm_year - tm_lo.tm_year) * 365 +
3042
((tptr->tm_year-69)/4) -
3043
((tptr->tm_year-1)/100) +
3044
((tptr->tm_year+299)/400) -
3045
((tm_lo.tm_year-69)/4) +
3046
((tm_lo.tm_year-1)/100) -
3047
((tm_lo.tm_year+299)/400) +
3048
tptr_tm_yday -
3049
tm_lo.tm_yday) * 86400 +
3050
(tptr->tm_hour - tm_lo.tm_hour) * 3600 +
3051
(tptr->tm_min - tm_lo.tm_min) * 60 +
3063
static int
3064
vtmcmp(struct vtm *a, struct vtm *b)
3065
{
3066
if (ne(a->year, b->year))
3067
return lt(a->year, b->year) ? -1 : 1;
3068
else if (a->mon != b->mon)
3069
return a->mon < b->mon ? -1 : 1;
3070
else if (a->mday != b->mday)
3071
return a->mday < b->mday ? -1 : 1;
3072
else if (a->hour != b->hour)
3073
return a->hour < b->hour ? -1 : 1;
3074
else if (a->min != b->min)
3075
return a->min < b->min ? -1 : 1;
3076
else if (a->sec != b->sec)
3077
return a->sec < b->sec ? -1 : 1;
3078
else if (ne(a->subsecx, b->subsecx))
3079
return lt(a->subsecx, b->subsecx) ? -1 : 1;
3084
static int
3085
tmcmp(struct tm *a, struct tm *b)
3086
{
3087
if (a->tm_year != b->tm_year)
3088
return a->tm_year < b->tm_year ? -1 : 1;
3089
else if (a->tm_mon != b->tm_mon)
3090
return a->tm_mon < b->tm_mon ? -1 : 1;
3091
else if (a->tm_mday != b->tm_mday)
3092
return a->tm_mday < b->tm_mday ? -1 : 1;
3093
else if (a->tm_hour != b->tm_hour)
3094
return a->tm_hour < b->tm_hour ? -1 : 1;
3095
else if (a->tm_min != b->tm_min)
3096
return a->tm_min < b->tm_min ? -1 : 1;
3097
else if (a->tm_sec != b->tm_sec)
3098
return a->tm_sec < b->tm_sec ? -1 : 1;
3099
else
3100
return 0;
3120
* Time.utc(year) -> time
3121
* Time.utc(year, month) -> time
3122
* Time.utc(year, month, day) -> time
3123
* Time.utc(year, month, day, hour) -> time
3124
* Time.utc(year, month, day, hour, min) -> time
3125
* Time.utc(year, month, day, hour, min, sec_with_frac) -> time
3126
* Time.utc(year, month, day, hour, min, sec, usec_with_frac) -> time
3127
* Time.utc(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3128
* Time.gm(year) -> time
3129
* Time.gm(year, month) -> time
3130
* Time.gm(year, month, day) -> time
3131
* Time.gm(year, month, day, hour) -> time
3132
* Time.gm(year, month, day, hour, min) -> time
3133
* Time.gm(year, month, day, hour, min, sec_with_frac) -> time
3134
* Time.gm(year, month, day, hour, min, sec, usec_with_frac) -> time
3135
* Time.gm(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3137
* Creates a time based on given values, interpreted as UTC (GMT). The
3138
* year must be specified. Other values default to the minimum value
3139
* for that field (and may be <code>nil</code> or omitted). Months may
3140
* be specified by numbers from 1 to 12, or by the three-letter English
3141
* month names. Hours are specified on a 24-hour clock (0..23). Raises
3142
* an <code>ArgumentError</code> if any values are out of range. Will
3143
* also accept ten arguments in the order output by
3144
* <code>Time#to_a</code>.
3147
* Time.utc(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3148
* Time.gm(2000,"jan",1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3158
* Time.local(year) -> time
3159
* Time.local(year, month) -> time
3160
* Time.local(year, month, day) -> time
3161
* Time.local(year, month, day, hour) -> time
3162
* Time.local(year, month, day, hour, min) -> time
3163
* Time.local(year, month, day, hour, min, sec_with_frac) -> time
3164
* Time.local(year, month, day, hour, min, sec, usec_with_frac) -> time
3165
* Time.local(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3166
* Time.mktime(year) -> time
3167
* Time.mktime(year, month) -> time
3168
* Time.mktime(year, month, day) -> time
3169
* Time.mktime(year, month, day, hour) -> time
3170
* Time.mktime(year, month, day, hour, min) -> time
3171
* Time.mktime(year, month, day, hour, min, sec_with_frac) -> time
3172
* Time.mktime(year, month, day, hour, min, sec, usec_with_frac) -> time
3173
* Time.mktime(sec, min, hour, day, month, year, wday, yday, isdst, tz) -> time
3175
* Same as <code>Time::gm</code>, but interprets the values in the
3176
* local time zone.
3236
*
3237
* Returns the value of <i>time</i> as a rational number of seconds
3238
* since the Epoch.
3239
*
3240
* t = Time.now
3242
*
3243
* This methods is intended to be used to get an accurate value
3244
* representing nanoseconds from the Epoch. You can use this
3245
* to convert time to another Epoch.
3246
*/
3247
3248
static VALUE
3249
time_to_r(VALUE time)
3250
{
3251
struct time_object *tobj;
3269
* t = Time.now #=> 2007-11-19 08:03:26 -0600
3270
* "%10.6f" % t.to_f #=> "1195481006.775195"
3271
* t.usec #=> 775195
3281
3282
w = wmod(tobj->timew, WINT2WV(TIME_SCALE));
3283
wmuldivmod(w, WINT2FIXWV(1000000), WINT2FIXWV(TIME_SCALE), &q, &r);
3284
return rb_to_int(w2v(q));
3294
* t = Time.now #=> 2007-11-17 15:18:03 +0900
3295
* "%10.9f" % t.to_f #=> "1195280283.536151409"
3296
* t.nsec #=> 536151406
3297
*
3298
* The lowest digit of to_f and nsec is different because
3299
* IEEE 754 double is not accurate enough to represent
3300
* nanoseconds from the Epoch.
3302
*/
3303
3304
static VALUE
3305
time_nsec(VALUE time)
3306
{
3307
struct time_object *tobj;
3308
3309
GetTimeval(time, tobj);
3310
return rb_to_int(w2v(wmulquoll(wmod(tobj->timew, WINT2WV(TIME_SCALE)), 1000000000, TIME_SCALE)));
3316
*
3317
* Returns just the fraction for <i>time</i>.
3318
*
3319
* The result is possibly rational.
3320
*
3321
* t = Time.now #=> 2009-03-26 22:33:12 +0900
3322
* "%10.9f" % t.to_f #=> "1238074392.940563917"
3323
* t.subsec #=> (94056401/100000000)
3324
*
3325
* The lowest digit of to_f and subsec is different because
3326
* IEEE 754 double is not accurate enough to represent
3327
* the rational.
3328
* The accurate value is returned by subsec.
3329
*/
3330
3331
static VALUE
3332
time_subsec(VALUE time)
3333
{
3334
struct time_object *tobj;
3335
3336
GetTimeval(time, tobj);
3346
* t = Time.now #=> 2007-11-19 08:12:12 -0600
3347
* t2 = t + 2592000 #=> 2007-12-19 08:12:12 -0600
3348
* t <=> t2 #=> -1
3349
* t2 <=> t #=> 1
3351
* t = Time.now #=> 2007-11-19 08:13:38 -0600
3352
* t2 = t + 0.1 #=> 2007-11-19 08:13:38 -0600
3353
* t.nsec #=> 98222999
3354
* t2.nsec #=> 198222999
3374
tmp = rb_funcall(time2, rb_intern("<=>"), 1, time1);
3375
if (NIL_P(tmp)) return Qnil;
3379
if (n == 0) return INT2FIX(0);
3380
if (n > 0) return INT2FIX(1);
3381
return INT2FIX(-1);
3384
/*
3385
* call-seq:
3386
* time.eql?(other_time)
3387
*
3388
* Return <code>true</code> if <i>time</i> and <i>other_time</i> are
3389
* both <code>Time</code> objects with the same seconds and fractional
3390
* seconds.
3391
*/
3392
3502
*
3503
* Converts <i>time</i> to local time (using the local time zone in
3504
* effect for this process) modifying the receiver.
3505
*
3506
* If _utc_offset_ is given, it is used instead of the local time.
3507
*
3508
* t = Time.utc(2000, "jan", 1, 20, 15, 1) #=> 2000-01-01 20:15:01 UTC
3509
* t.utc? #=> true
3510
*
3511
* t.localtime #=> 2000-01-01 14:15:01 -0600
3512
* t.utc? #=> false
3513
*
3514
* t.localtime("+09:00") #=> 2000-01-02 05:15:01 +0900
3515
* t.utc? #=> false
3516
*/
3517
3518
static VALUE
3519
time_localtime_m(int argc, VALUE *argv, VALUE time)
3520
{
3521
VALUE off;
3522
rb_scan_args(argc, argv, "01", &off);
3523
3524
if (!NIL_P(off)) {
3525
off = utc_offset_arg(off);
3526
validate_utc_offset(off);
3527
3528
time_set_utc_offset(time, off);
3529
return time_fixoff(time);
3530
}
3531
3532
return time_localtime(time);
3533
}
3534
3577
static VALUE
3578
time_fixoff(VALUE time)
3579
{
3580
struct time_object *tobj;
3581
struct vtm vtm;
3582
VALUE off;
3583
3584
GetTimeval(time, tobj);
3585
if (TIME_FIXOFF_P(tobj)) {
3586
if (tobj->tm_got)
3587
return time;
3588
}
3589
else {
3590
time_modify(time);
3591
}
3592
3593
if (TIME_FIXOFF_P(tobj))
3594
off = tobj->vtm.utc_offset;
3595
else
3596
off = INT2FIX(0);
3597
3599
rb_raise(rb_eArgError, "gmtime error");
3600
3601
tobj->vtm = vtm;
3602
vtm_add_offset(&tobj->vtm, off);
3603
3604
tobj->tm_got = 1;
3605
TIME_SET_FIXOFF(tobj, off);
3606
return time;
3607
}
3608
3614
* Returns a new <code>new_time</code> object representing <i>time</i> in
3615
* local time (using the local time zone in effect for this process).
3617
* If _utc_offset_ is given, it is used instead of the local time.
3618
*
3619
* t = Time.utc(2000,1,1,20,15,1) #=> 2000-01-01 20:15:01 UTC
3620
* t.utc? #=> true
3621
*
3625
*
3626
* j = t.getlocal("+09:00") #=> 2000-01-02 05:15:01 +0900
3627
* j.utc? #=> false
3628
* t == j #=> true
3634
VALUE off;
3635
rb_scan_args(argc, argv, "01", &off);
3636
3637
if (!NIL_P(off)) {
3638
off = utc_offset_arg(off);
3639
validate_utc_offset(off);
3640
3641
time = time_dup(time);
3642
time_set_utc_offset(time, off);
3643
return time_fixoff(time);
3644
}
3645
3654
* Returns a new <code>new_time</code> object representing <i>time</i> in
3655
* UTC.
3702
* <code>Time#strftime</code> with a format string of
3703
* ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>%z</code>''
3704
* for a local time and
3705
* ``<code>%Y-%m-%d</code> <code>%H:%M:%S</code> <code>UTC</code>''
3706
* for a UTC time.
3708
* Time.now.to_s #=> "2007-10-05 16:09:51 +0900"
3709
* Time.now.utc.to_s #=> "2007-10-05 07:09:51 UTC"
3719
return strftimev("%Y-%m-%d %H:%M:%S UTC", time);
3720
else
3721
return strftimev("%Y-%m-%d %H:%M:%S %z", time);
3730
result = time_new_timew(rb_cTime, wsub(tobj->timew, rb_time_magnify(v2w(offset))));
3732
result = time_new_timew(rb_cTime, wadd(tobj->timew, rb_time_magnify(v2w(offset))));
3737
else if (TIME_FIXOFF_P(tobj)) {
3738
VALUE off = tobj->vtm.utc_offset;
3739
GetTimeval(result, tobj);
3740
TIME_SET_FIXOFF(tobj, off);
3741
}
3749
* Addition---Adds some number of seconds (possibly fractional) to
3750
* <i>time</i> and returns that value as a new time.
3752
* t = Time.now #=> 2007-11-19 08:22:21 -0600
3753
* t + (60 * 60 * 24) #=> 2007-11-20 08:22:21 -0600
3773
* Difference---Returns a new time that represents the difference
3774
* between two times, or subtracts the given number of seconds in
3775
* <i>numeric</i> from <i>time</i>.
3777
* t = Time.now #=> 2007-11-19 08:23:10 -0600
3778
* t2 = t + 2592000 #=> 2007-12-19 08:23:10 -0600
3804
*
3805
* t = Time.now #=> 2007-11-19 08:23:57 -0600
3806
* t.succ #=> 2007-11-19 08:23:58 -0600
3828
*
3829
* Rounds sub seconds to a given precision in decimal digits (0 digits by default).
3830
* It returns a new time object.
3831
* _ndigits_ should be zero or positive integer.
3832
*
3833
* require 'time'
3834
*
3835
* t = Time.utc(2010,3,30, 5,43,"25.123456789".to_r)
3836
* p t.iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3837
* p t.round.iso8601(10) #=> "2010-03-30T05:43:25.0000000000Z"
3838
* p t.round(0).iso8601(10) #=> "2010-03-30T05:43:25.0000000000Z"
3839
* p t.round(1).iso8601(10) #=> "2010-03-30T05:43:25.1000000000Z"
3840
* p t.round(2).iso8601(10) #=> "2010-03-30T05:43:25.1200000000Z"
3841
* p t.round(3).iso8601(10) #=> "2010-03-30T05:43:25.1230000000Z"
3842
* p t.round(4).iso8601(10) #=> "2010-03-30T05:43:25.1235000000Z"
3843
* p t.round(5).iso8601(10) #=> "2010-03-30T05:43:25.1234600000Z"
3844
* p t.round(6).iso8601(10) #=> "2010-03-30T05:43:25.1234570000Z"
3845
* p t.round(7).iso8601(10) #=> "2010-03-30T05:43:25.1234568000Z"
3846
* p t.round(8).iso8601(10) #=> "2010-03-30T05:43:25.1234567900Z"
3847
* p t.round(9).iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3848
* p t.round(10).iso8601(10) #=> "2010-03-30T05:43:25.1234567890Z"
3849
*
3851
* p((t + 0.4).round.iso8601(3)) #=> "1999-12-31T23:59:59.000Z"
3852
* p((t + 0.49).round.iso8601(3)) #=> "1999-12-31T23:59:59.000Z"
3853
* p((t + 0.5).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3854
* p((t + 1.4).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3855
* p((t + 1.49).round.iso8601(3)) #=> "2000-01-01T00:00:00.000Z"
3856
* p((t + 1.5).round.iso8601(3)) #=> "2000-01-01T00:00:01.000Z"
3857
*
3858
* t = Time.utc(1999,12,31, 23,59,59)
3859
* p (t + 0.123456789).round(4).iso8601(6) #=> "1999-12-31T23:59:59.123500Z"
3860
*/
3861
3862
static VALUE
3863
time_round(int argc, VALUE *argv, VALUE time)
3864
{
3865
VALUE ndigits, v, a, b, den;
3866
long nd;
3867
struct time_object *tobj;
3868
3869
rb_scan_args(argc, argv, "01", &ndigits);
3870
3871
if (NIL_P(ndigits))
3872
ndigits = INT2FIX(0);
3873
else
3874
ndigits = rb_to_int(ndigits);
3875
3876
nd = NUM2LONG(ndigits);
3877
if (nd < 0)
3878
rb_raise(rb_eArgError, "negative ndigits given");
3879
3880
GetTimeval(time, tobj);
3882
3883
a = INT2FIX(1);
3884
b = INT2FIX(10);
3885
while (0 < nd) {
3886
if (nd & 1)
3887
a = mul(a, b);
3888
b = mul(b, b);
3889
nd = nd >> 1;
3890
}
3891
den = quo(INT2FIX(1), a);
3892
v = mod(v, den);
3893
if (lt(v, quo(den, INT2FIX(2))))
3894
return time_add(tobj, v, -1);
3895
else
3896
return time_add(tobj, sub(den, v), 1);
3897
}
3903
* Returns the second of the minute (0..60)<em>[Yes, seconds really can
3904
* range from zero to 60. This allows the system to inject leap seconds
3905
* every now and then to correct for the fact that years are not really
3906
* a convenient number of hours long.]</em> for <i>time</i>.
3969
* t = Time.now #=> 2007-11-19 08:27:03 -0600
3970
* t.day #=> 19
3971
* t.mday #=> 19
3991
* t = Time.now #=> 2007-11-19 08:27:30 -0600
3992
* t.mon #=> 11
3993
* t.month #=> 11
4030
* Returns an integer representing the day of the week, 0..6, with
4031
* Sunday == 0.
4033
* t = Time.now #=> 2007-11-20 02:35:35 -0600
4034
* t.wday #=> 2
4035
* t.sunday? #=> false
4036
* t.monday? #=> false
4037
* t.tuesday? #=> true
4038
* t.wednesday? #=> false
4039
* t.thursday? #=> false
4040
* t.friday? #=> false
4041
* t.saturday? #=> false
4054
#define wday_p(n) {\
4055
struct time_object *tobj;\
4056
GetTimeval(time, tobj);\
4067
* t = Time.local(1990, 4, 1) #=> 1990-04-01 00:00:00 -0600
4068
* t.sunday? #=> true
4069
*/
4070
4071
static VALUE
4072
time_sunday(VALUE time)
4073
{
4074
wday_p(0);
4075
}
4076
4077
/*
4078
* call-seq:
4083
* t = Time.local(2003, 8, 4) #=> 2003-08-04 00:00:00 -0500
4084
* p t.monday? #=> true
4085
*/
4086
4087
static VALUE
4088
time_monday(VALUE time)
4089
{
4090
wday_p(1);
4091
}
4092
4093
/*
4094
* call-seq:
4098
*
4099
* t = Time.local(1991, 2, 19) #=> 1991-02-19 00:00:00 -0600
4100
* p t.tuesday? #=> true
4101
*/
4102
4103
static VALUE
4104
time_tuesday(VALUE time)
4105
{
4106
wday_p(2);
4107
}
4108
4109
/*
4110
* call-seq:
4114
*
4115
* t = Time.local(1993, 2, 24) #=> 1993-02-24 00:00:00 -0600
4116
* p t.wednesday? #=> true
4117
*/
4118
4119
static VALUE
4120
time_wednesday(VALUE time)
4121
{
4122
wday_p(3);
4123
}
4124
4125
/*
4126
* call-seq:
4130
*
4131
* t = Time.local(1995, 12, 21) #=> 1995-12-21 00:00:00 -0600
4132
* p t.thursday? #=> true
4133
*/
4134
4135
static VALUE
4136
time_thursday(VALUE time)
4137
{
4138
wday_p(4);
4139
}
4140
4141
/*
4142
* call-seq:
4146
*
4147
* t = Time.local(1987, 12, 18) #=> 1987-12-18 00:00:00 -0600
4148
* t.friday? #=> true
4149
*/
4150
4151
static VALUE
4152
time_friday(VALUE time)
4153
{
4154
wday_p(5);
4155
}
4156
4157
/*
4158
* call-seq:
4162
*
4163
* t = Time.local(2006, 6, 10) #=> 2006-06-10 00:00:00 -0500
4164
* t.saturday? #=> true
4165
*/
4166
4167
static VALUE
4168
time_saturday(VALUE time)
4169
{
4170
wday_p(6);
4171
}
4172
4198
* Returns <code>true</code> if <i>time</i> occurs during Daylight
4199
* Saving Time in its time zone.
4204
* Time.local(2000, 1, 1).dst? #=> false
4205
* Time.local(2000, 7, 1).zone #=> "CDT"
4206
* Time.local(2000, 7, 1).isdst #=> true
4210
* Time.local(2000, 1, 1).zone #=> "JST"
4211
* Time.local(2000, 1, 1).isdst #=> false
4213
* Time.local(2000, 7, 1).zone #=> "JST"
4214
* Time.local(2000, 7, 1).isdst #=> false
4215
* Time.local(2000, 7, 1).dst? #=> false
4232
* Returns the name of the time zone used for <i>time</i>. As of Ruby
4233
* 1.8, returns ``UTC'' rather than ``GMT'' for UTC times.
4235
* t = Time.gm(2000, "jan", 1, 20, 15, 1)
4236
* t.zone #=> "UTC"
4237
* t = Time.local(2000, "jan", 1, 20, 15, 1)
4238
* t.zone #=> "CST"
4239
*/
4240
4259
* time.gmt_offset -> fixnum
4260
* time.gmtoff -> fixnum
4261
* time.utc_offset -> fixnum
4263
* Returns the offset in seconds between the timezone of <i>time</i>
4264
* and UTC.
4292
* Returns a ten-element <i>array</i> of values for <i>time</i>:
4293
* {<code>[ sec, min, hour, day, month, year, wday, yday, isdst, zone
4294
* ]</code>}. See the individual methods for an explanation of the
4295
* valid ranges of each value. The ten elements can be passed directly
4296
* to <code>Time::utc</code> or <code>Time::local</code> to create a
4297
* new <code>Time</code>.
4299
* t = Time.now #=> 2007-11-19 08:36:01 -0600
4300
* now = t.to_a #=> [1, 36, 8, 19, 11, 2007, 1, 323, false, "CST"]
4311
INT2FIX(tobj->vtm.sec),
4312
INT2FIX(tobj->vtm.min),
4313
INT2FIX(tobj->vtm.hour),
4314
INT2FIX(tobj->vtm.mday),
4315
INT2FIX(tobj->vtm.mon),
4316
tobj->vtm.year,
4317
INT2FIX(tobj->vtm.wday),
4318
INT2FIX(tobj->vtm.yday),
4319
tobj->vtm.isdst?Qtrue:Qfalse,
4323
size_t
4324
rb_strftime(char *s, size_t maxsize, const char *format,
4325
const struct vtm *vtm, VALUE timev,
4326
int gmt);
4327
4334
VALUE timev = Qnil;
4335
struct timespec ts;
4336
4337
if (!timew2timespec_exact(timew, &ts))
4338
timev = w2v(rb_time_unmagnify(timew));
4340
(*buf)[0] = '\0';
4341
flen = strlen(format);
4342
if (flen == 0) {
4343
return 0;
4344
}
4346
if (timev == Qnil)
4347
len = rb_strftime_timespec(*buf, SMALLBUF, format, vtm, &ts, gmt);
4348
else
4349
len = rb_strftime(*buf, SMALLBUF, format, vtm, timev, gmt);
4354
if (timev == Qnil)
4355
len = rb_strftime_timespec(*buf, size, format, vtm, &ts, gmt);
4356
else
4357
len = rb_strftime(*buf, size, format, vtm, timev, gmt);
4358
/*
4359
* buflen can be zero EITHER because there's not enough
4360
* room in the string, or because the control command
4361
* goes to the empty string. Make a reasonable guess that
4362
* if the buffer is 1024 times bigger than the length of the
4363
* format string, it's not failing for lack of room.
4364
*/
4375
static VALUE
4376
strftimev(const char *fmt, VALUE time)
4377
{
4378
struct time_object *tobj;
4379
char buffer[SMALLBUF], *buf = buffer;
4380
long len;
4381
VALUE str;
4382
4383
GetTimeval(time, tobj);
4386
str = rb_str_new(buf, len);
4387
if (buf != buffer) xfree(buf);
4388
return str;
4389
}
4390
4396
* string.
4397
* The directives begins with a percent (%) character.
4398
* Any text not listed as a directive will be passed through to the
4399
* output string.
4400
*
4401
* The directive consists of a percent (%) character,
4402
* zero or more flags, optional minimum field width,
4403
* optional modifier and a conversion specifier
4404
* as follows.
4405
*
4406
* %<flags><width><modifier><conversion>
4410
* _ use spaces for padding.
4411
* 0 use zeros for padding.
4412
* ^ upcase the result string.
4413
* # change case.
4414
* : use colons for %z.
4415
*
4416
* The minimum field width specifies the minimum width.
4417
*
4418
* The modifier is "E" and "O".
4424
* %Y - Year with century (can be negative, 4 digits at least)
4425
* -0001, 0000, 1995, 2009, 14292, etc.
4440
* %e - Day of the month, blank-padded ( 1..31)
4441
*
4442
* %j - Day of the year (001..366)
4445
* %H - Hour of the day, 24-hour clock, zero-padded (00..23)
4446
* %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
4447
* %I - Hour of the day, 12-hour clock, zero-padded (01..12)
4449
* %P - Meridian indicator, lowercase (``am'' or ``pm'')
4450
* %p - Meridian indicator, uppercase (``AM'' or ``PM'')
4456
* %L - Millisecond of the second (000..999)
4457
* %N - Fractional seconds digits, default is 9 digits (nanosecond)
4458
* %3N millisecond (3 digits)
4459
* %6N microsecond (6 digits)
4460
* %9N nanosecond (9 digits)
4463
* Time zone:
4464
* %z - Time zone as hour and minute offset from UTC (e.g. +0900)
4465
* %:z - hour and minute offset from UTC with a colon (e.g. +09:00)
4466
* %::z - hour, minute and second offset from UTC (e.g. +09:00:00)
4474
* %u - Day of the week (Monday is 1, 1..7)
4475
* %w - Day of the week (Sunday is 0, 0..6)
4477
* ISO 8601 week-based year and week number:
4478
* The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
4479
* The days in the year before the first week are in the last week of
4480
* the previous year.
4481
* %G - The week-based year
4482
* %g - The last 2 digits of the week-based year (00..99)
4483
* %V - Week number of the week-based year (01..53)
4486
* The week 1 of YYYY starts with a Sunday or Monday (according to %U
4487
* or %W). The days in the year before the first week are in week 0.
4488
* %U - Week number of the year. The week starts with Sunday. (00..53)
4489
* %W - Week number of the year. The week starts with Monday. (00..53)
4491
* Seconds since the Epoch:
4492
* %s - Number of seconds since 1970-01-01 00:00:00 UTC.
4506
* %r - 12-hour time (%I:%M:%S %p)
4507
* %R - 24-hour time (%H:%M)
4508
* %T - 24-hour time (%H:%M:%S)
4510
* This method is similar to strftime() function defined in ISO C and POSIX.
4511
* Several directives (%a, %A, %b, %B, %c, %p, %r, %x, %X, %E*, %O* and %Z)
4512
* are locale dependent in the function.
4513
* However this method is locale independent since Ruby 1.9.
4514
* So, the result may differ even if a same format string is used in other
4515
* systems such as C.
4519
* Examples:
4520
*
4521
* t = Time.new(2007,11,19,8,37,48,"-06:00") #=> 2007-11-19 08:37:48 -0600
4522
* t.strftime("Printed on %m/%d/%Y") #=> "Printed on 11/19/2007"
4523
* t.strftime("at %I:%M%p") #=> "at 08:37AM"
4526
* %Y%m%d => 20071119 Calendar date (basic)
4527
* %F => 2007-11-19 Calendar date (extended)
4528
* %Y-%m => 2007-11 Calendar date, reduced accuracy, specific month
4529
* %Y => 2007 Calendar date, reduced accuracy, specific year
4530
* %C => 20 Calendar date, reduced accuracy, specific century
4531
* %Y%j => 2007323 Ordinal date (basic)
4532
* %Y-%j => 2007-323 Ordinal date (extended)
4533
* %GW%V%u => 2007W471 Week date (basic)
4534
* %G-W%V-%u => 2007-W47-1 Week date (extended)
4535
* %GW%V => 2007W47 Week date, reduced accuracy, specific week (basic)
4536
* %G-W%V => 2007-W47 Week date, reduced accuracy, specific week (extended)
4537
* %H%M%S => 083748 Local time (basic)
4538
* %T => 08:37:48 Local time (extended)
4539
* %H%M => 0837 Local time, reduced accuracy, specific minute (basic)
4540
* %H:%M => 08:37 Local time, reduced accuracy, specific minute (extended)
4541
* %H => 08 Local time, reduced accuracy, specific hour
4542
* %H%M%S,%L => 083748,000 Local time with decimal fraction, comma as decimal sign (basic)
4543
* %T,%L => 08:37:48,000 Local time with decimal fraction, comma as decimal sign (extended)
4544
* %H%M%S.%L => 083748.000 Local time with decimal fraction, full stop as decimal sign (basic)
4545
* %T.%L => 08:37:48.000 Local time with decimal fraction, full stop as decimal sign (extended)
4546
* %H%M%S%z => 083748-0600 Local time and the difference from UTC (basic)
4547
* %T%:z => 08:37:48-06:00 Local time and the difference from UTC (extended)
4548
* %Y%m%dT%H%M%S%z => 20071119T083748-0600 Date and time of day for calendar date (basic)
4549
* %FT%T%:z => 2007-11-19T08:37:48-06:00 Date and time of day for calendar date (extended)
4550
* %Y%jT%H%M%S%z => 2007323T083748-0600 Date and time of day for ordinal date (basic)
4551
* %Y-%jT%T%:z => 2007-323T08:37:48-06:00 Date and time of day for ordinal date (extended)
4552
* %GW%V%uT%H%M%S%z => 2007W471T083748-0600 Date and time of day for week date (basic)
4553
* %G-W%V-%uT%T%:z => 2007-W47-1T08:37:48-06:00 Date and time of day for week date (extended)
4554
* %Y%m%dT%H%M => 20071119T0837 Calendar date and local time (basic)
4555
* %FT%R => 2007-11-19T08:37 Calendar date and local time (extended)
4556
* %Y%jT%H%MZ => 2007323T0837Z Ordinal date and UTC of day (basic)
4557
* %Y-%jT%RZ => 2007-323T08:37Z Ordinal date and UTC of day (extended)
4558
* %GW%V%uT%H%M%z => 2007W471T0837-0600 Week date and local time and difference from UTC (basic)
4559
* %G-W%V-%uT%R%:z => 2007-W47-1T08:37-06:00 Week date and local time and difference from UTC (extended)
4575
if (!rb_enc_str_asciicompat_p(format)) {
4576
rb_raise(rb_eArgError, "format should have ASCII compatible encoding");
4577
}
4581
if (len == 0) {
4582
rb_warning("strftime called with empty format string");
4583
}
4597
for (fmt = p; p < pe && !*p; ++p);
4598
if (p > fmt) rb_str_cat(str, fmt, p - fmt);
4633
4634
if (FIXNUM_P(vtm.year)) {
4635
year = FIX2LONG(vtm.year);
4636
if (year < 1900 || 1900+0xffff < year)
4645
nano = mulquo(subsecx, INT2FIX(1000000000), INT2FIX(TIME_SCALE));
4646
divmodv(nano, INT2FIX(1), &v, &subnano);
4653
p = 0x1UL << 31 | /* 1 */
4654
TIME_UTC_P(tobj) << 30 | /* 1 */
4655
(year-1900) << 14 | /* 16 */
4656
(vtm.mon-1) << 10 | /* 4 */
4657
vtm.mday << 5 | /* 5 */
4658
vtm.hour; /* 5 */
4659
s = vtm.min << 26 | /* 6 */
4660
vtm.sec << 20 | /* 6 */
4676
rb_ivar_set(str, id_nano_num, RRATIONAL(nano)->num);
4677
rb_ivar_set(str, id_nano_den, RRATIONAL(nano)->den);
4678
}
4679
else {
4680
rb_ivar_set(str, id_nano_num, nano);
4681
rb_ivar_set(str, id_nano_den, INT2FIX(1));
4682
}
4683
}
4684
if (nsec) { /* submicro is only for Ruby 1.9.1 compatibility */
4685
/*
4686
* submicro is formatted in fixed-point packed BCD (without sign).
4687
* It represent digits under microsecond.
4688
* For nanosecond resolution, 3 digits (2 bytes) are used.
4689
* However it can be longer.
4690
* Extra digits are ignored for loading.
4691
*/
4692
char buf[2];
4693
int len = (int)sizeof(buf);
4694
buf[1] = (char)((nsec % 10) << 4);
4703
if (!TIME_UTC_P(tobj)) {
4704
VALUE off = time_utc_offset(time), div, mod;
4705
divmodv(off, INT2FIX(1), &div, &mod);
4706
if (rb_equal(mod, INT2FIX(0)))
4707
off = rb_Integer(div);
4708
rb_ivar_set(str, id_offset, off);
4709
}
4752
#define get_attr(attr, iffound) \
4753
attr = rb_attr_get(str, id_##attr); \
4754
if (!NIL_P(attr)) { \
4755
data = id_##attr; \
4756
iffound; \
4757
st_delete(rb_generic_ivar_table(str), &data, 0); \
4759
4760
get_attr(nano_num, {});
4761
get_attr(nano_den, {});
4762
get_attr(submicro, {});
4763
get_attr(offset, validate_utc_offset(offset));
4764
#undef get_attr
4765
4788
timew = wadd(rb_time_magnify(TIMET2WV(sec)), wmulquoll(WINT2FIXWV(usec), TIME_SCALE, 1000000));
4792
gmt = (int)((p >> 30) & 0x1);
4793
4794
vtm.year = INT2FIX(((int)(p >> 14) & 0xffff) + 1900);
4795
vtm.mon = ((int)(p >> 10) & 0xf) + 1;
4796
vtm.mday = (int)(p >> 5) & 0x1f;
4797
vtm.hour = (int) p & 0x1f;
4798
vtm.min = (int)(s >> 26) & 0x3f;
4799
vtm.sec = (int)(s >> 20) & 0x3f;
4800
vtm.utc_offset = INT2FIX(0);
4801
vtm.yday = vtm.wday = 0;
4802
vtm.isdst = 0;
4803
vtm.zone = "";
4804
4808
4809
vtm.subsecx = mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000));
4810
if (nano_num != Qnil) {
4811
VALUE nano = quo(num_exact(nano_num), num_exact(nano_den));
4812
vtm.subsecx = add(vtm.subsecx, mulquo(nano, INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
4813
}
4814
else if (submicro != Qnil) { /* for Ruby 1.9.1 compatibility */
4822
if (10 <= (digit = ptr[0] >> 4)) goto end_submicro;
4823
nsec += digit * 100;
4824
if (10 <= (digit = ptr[0] & 0xf)) goto end_submicro;
4825
nsec += digit * 10;
4831
vtm.subsecx = add(vtm.subsecx, mulquo(LONG2FIX(nsec), INT2FIX(TIME_SCALE), LONG2FIX(1000000000)));
4841
if (gmt) {
4842
TIME_SET_UTC(tobj);
4843
}
4844
else if (!NIL_P(offset)) {
4845
time_set_utc_offset(time, offset);
4846
time_fixoff(time);
4847
}
4870
* stored internally as the number of seconds with fraction since
4871
* the <em>Epoch</em>, January 1, 1970 00:00 UTC.
4872
* Also see the library modules <code>Date</code>.
4873
* The <code>Time</code> class treats GMT (Greenwich Mean Time) and
4874
* UTC (Coordinated Universal Time)<em>[Yes, UTC really does stand for
4875
* Coordinated Universal Time. There was a committee involved.]</em>
4876
* as equivalent. GMT is the older way of referring to these
4881
* this fact when comparing times with each other---times that are
4882
* apparently equal when displayed may be different when compared.
4883
*/
4884
4891
id_eq = rb_intern("==");
4892
id_ne = rb_intern("!=");
4893
id_quo = rb_intern("quo");
4894
id_div = rb_intern("div");
4895
id_cmp = rb_intern("<=>");
4896
id_lshift = rb_intern("<<");
4897
id_divmod = rb_intern("divmod");
4898
id_mul = rb_intern("*");
4899
id_submicro = rb_intern("submicro");
4904
rb_cTime = rb_define_class("Time", rb_cObject);
4905
rb_include_module(rb_cTime, rb_mComparable);
4906
4910
rb_define_singleton_method(rb_cTime, "utc", time_s_mkutc, -1);
4911
rb_define_singleton_method(rb_cTime, "gm", time_s_mkutc, -1);
4912
rb_define_singleton_method(rb_cTime, "local", time_s_mktime, -1);
4913
rb_define_singleton_method(rb_cTime, "mktime", time_s_mktime, -1);
4914
4915
rb_define_method(rb_cTime, "to_i", time_to_i, 0);
4916
rb_define_method(rb_cTime, "to_f", time_to_f, 0);
4918
rb_define_method(rb_cTime, "<=>", time_cmp, 1);
4919
rb_define_method(rb_cTime, "eql?", time_eql, 1);
4920
rb_define_method(rb_cTime, "hash", time_hash, 0);
4928
rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
4929
rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
4930
4931
rb_define_method(rb_cTime, "ctime", time_asctime, 0);
4932
rb_define_method(rb_cTime, "asctime", time_asctime, 0);
4933
rb_define_method(rb_cTime, "to_s", time_to_s, 0);
4934
rb_define_method(rb_cTime, "inspect", time_to_s, 0);
4935
rb_define_method(rb_cTime, "to_a", time_to_a, 0);
4936
4937
rb_define_method(rb_cTime, "+", time_plus, 1);
4938
rb_define_method(rb_cTime, "-", time_minus, 1);
4939
4943
rb_define_method(rb_cTime, "sec", time_sec, 0);
4944
rb_define_method(rb_cTime, "min", time_min, 0);
4945
rb_define_method(rb_cTime, "hour", time_hour, 0);
4946
rb_define_method(rb_cTime, "mday", time_mday, 0);
4947
rb_define_method(rb_cTime, "day", time_mday, 0);
4948
rb_define_method(rb_cTime, "mon", time_mon, 0);
4949
rb_define_method(rb_cTime, "month", time_mon, 0);
4950
rb_define_method(rb_cTime, "year", time_year, 0);
4951
rb_define_method(rb_cTime, "wday", time_wday, 0);
4952
rb_define_method(rb_cTime, "yday", time_yday, 0);
4953
rb_define_method(rb_cTime, "isdst", time_isdst, 0);
4956
rb_define_method(rb_cTime, "gmtoff", time_utc_offset, 0);
4957
rb_define_method(rb_cTime, "gmt_offset", time_utc_offset, 0);
4958
rb_define_method(rb_cTime, "utc_offset", time_utc_offset, 0);
4960
rb_define_method(rb_cTime, "utc?", time_utc_p, 0);
4961
rb_define_method(rb_cTime, "gmt?", time_utc_p, 0);
4963
rb_define_method(rb_cTime, "sunday?", time_sunday, 0);
4964
rb_define_method(rb_cTime, "monday?", time_monday, 0);
4965
rb_define_method(rb_cTime, "tuesday?", time_tuesday, 0);
4966
rb_define_method(rb_cTime, "wednesday?", time_wednesday, 0);
4967
rb_define_method(rb_cTime, "thursday?", time_thursday, 0);
4968
rb_define_method(rb_cTime, "friday?", time_friday, 0);
4969
rb_define_method(rb_cTime, "saturday?", time_saturday, 0);
4970
4971
rb_define_method(rb_cTime, "tv_sec", time_to_i, 0);
4972
rb_define_method(rb_cTime, "tv_usec", time_usec, 0);
4973
rb_define_method(rb_cTime, "usec", time_usec, 0);
4974
rb_define_method(rb_cTime, "tv_nsec", time_nsec, 0);
4975
rb_define_method(rb_cTime, "nsec", time_nsec, 0);
4983
#if 0
4984
/* Time will support marshal_dump and marshal_load in the future (1.9 maybe) */
4985
rb_define_method(rb_cTime, "marshal_dump", time_mdump, 0);
4986
rb_define_method(rb_cTime, "marshal_load", time_mload, 1);
4987
#endif
4990
rb_define_virtual_variable("$find_time_numguess", find_time_numguess_getter, NULL);
4991
#endif

