diff options
Diffstat (limited to 'mrbgems/mruby-time/src/time.c')
| -rw-r--r-- | mrbgems/mruby-time/src/time.c | 40 |
1 files changed, 29 insertions, 11 deletions
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index 8903c522a..081e84c1c 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -4,6 +4,7 @@ ** See Copyright Notice in mruby.h */ +#include <math.h> #include <stdio.h> #include <time.h> #include "mruby.h" @@ -80,7 +81,7 @@ gettimeofday(struct timeval *tv, void *tz) t.u64 -= UI64(116444736000000000); /* Unix epoch bias */ t.u64 /= 10; /* to microseconds */ tv->tv_sec = (time_t)(t.u64 / (1000 * 1000)); - tv->tv_usec = t.u64 % 1000 * 1000; + tv->tv_usec = t.u64 % (1000 * 1000); } return 0; } @@ -200,20 +201,23 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(struct mrb_time)); - tm->sec = (time_t)sec; if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) { goto out_of_range; } - else if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { + if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) { + goto out_of_range; + } + tm->sec = (time_t)sec; + if ((sec > 0 && tm->sec < 0) || (sec < 0 && (double)tm->sec > sec)) { out_of_range: mrb_raisef(mrb, E_ARGUMENT_ERROR, "%S out of Time range", mrb_float_value(mrb, sec)); } - tm->usec = (time_t)((sec - tm->sec) * 1.0e6 + usec); + tm->usec = (time_t)llround((sec - tm->sec) * 1.0e6 + usec); while (tm->usec < 0) { tm->sec--; tm->usec += 1000000; } - while (tm->usec > 1000000) { + while (tm->usec >= 1000000) { tm->sec++; tm->usec -= 1000000; } @@ -235,7 +239,17 @@ current_mrb_time(mrb_state *mrb) struct mrb_time *tm; tm = (struct mrb_time *)mrb_malloc(mrb, sizeof(*tm)); -#ifdef NO_GETTIMEOFDAY +#if defined(TIME_UTC) + { + struct timespec ts; + if (timespec_get(&ts, TIME_UTC) == 0) { + mrb_free(mrb, tm); + mrb_raise(mrb, E_RUNTIME_ERROR, "timespec_get() failed for unknown reasons"); + } + tm->sec = ts.tv_sec; + tm->usec = ts.tv_nsec / 1000; + } +#elif defined(NO_GETTIMEOFDAY) { static time_t last_sec = 0, last_usec = 0; @@ -561,8 +575,7 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self) if (tm) { mrb_free(mrb, tm); } - DATA_TYPE(self) = &mrb_time_type; - DATA_PTR(self) = NULL; + mrb_data_init(self, NULL, &mrb_time_type); n = mrb_get_args(mrb, "|iiiiiii", &ayear, &amonth, &aday, &ahour, &amin, &asec, &ausec); @@ -572,7 +585,7 @@ mrb_time_initialize(mrb_state *mrb, mrb_value self) else { tm = time_mktime(mrb, ayear, amonth, aday, ahour, amin, asec, ausec, MRB_TIMEZONE_LOCAL); } - DATA_PTR(self) = tm; + mrb_data_init(self, tm, &mrb_time_type); return self; } @@ -589,8 +602,7 @@ mrb_time_initialize_copy(mrb_state *mrb, mrb_value copy) mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } if (!DATA_PTR(copy)) { - DATA_PTR(copy) = mrb_malloc(mrb, sizeof(struct mrb_time)); - DATA_TYPE(copy) = &mrb_time_type; + mrb_data_init(copy, mrb_malloc(mrb, sizeof(struct mrb_time)), &mrb_time_type); } *(struct mrb_time *)DATA_PTR(copy) = *(struct mrb_time *)DATA_PTR(src); return copy; @@ -673,6 +685,9 @@ mrb_time_to_i(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + if (tm->sec > MRB_INT_MAX || tm->sec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->sec); + } return mrb_fixnum_value((mrb_int)tm->sec); } @@ -684,6 +699,9 @@ mrb_time_usec(mrb_state *mrb, mrb_value self) struct mrb_time *tm; tm = DATA_GET_PTR(mrb, self, &mrb_time_type, struct mrb_time); + if (tm->usec > MRB_INT_MAX || tm->usec < MRB_INT_MIN) { + return mrb_float_value(mrb, (mrb_float)tm->usec); + } return mrb_fixnum_value((mrb_int)tm->usec); } |
