diff options
author | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-06-10 12:38:05 +0000 |
---|---|---|
committer | akr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-06-10 12:38:05 +0000 |
commit | cce257dead688a55ea6c33d3e540ba8af9f27b7a (patch) | |
tree | 687ac701320611cbf96ed27d659b78aed5bf6b19 /time.c | |
parent | 3c6fac490d2f4f221ef0cd577f79f8eeb60b7dba (diff) |
* time.c (find_time_t): always outerpolate from past.
[ruby-core:30672] reported by Benoit Daloze.
backport r28238 from trunk.
* time.c (calc_tm_yday): extracted from timegmw_noleapsecond.
backport r28236 from trunk.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_2@28254 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'time.c')
-rw-r--r-- | time.c | 65 |
1 files changed, 44 insertions, 21 deletions
@@ -30,6 +30,7 @@ static ID id_eq, id_ne, id_quo, id_div, id_cmp, id_lshift; #define NDIV(x,y) (-(-((x)+1)/(y))-1) #define NMOD(x,y) ((y)-(-((x)+1)%(y))-1) #define DIV(n,d) ((n)<0 ? NDIV((n),(d)) : (n)/(d)) +#define MOD(n,d) ((n)<0 ? NMOD((n),(d)) : (n)%(d)) static int eq(VALUE x, VALUE y) @@ -933,13 +934,29 @@ static const int leap_year_days_in_month[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +static int +calc_tm_yday(long tm_year, int tm_mon, int tm_mday) +{ + int tm_year_mod400; + int tm_yday = tm_mday; + + tm_year_mod400 = MOD(tm_year, 400); + + if (leap_year_p(tm_year_mod400 + 1900)) + tm_yday += leap_year_yday_offset[tm_mon]; + else + tm_yday += common_year_yday_offset[tm_mon]; + + return tm_yday; +} + static wideval_t timegmw_noleapsecond(struct vtm *vtm) { VALUE year1900; VALUE q400, r400; int year_mod400; - int yday = vtm->mday; + int yday; long days_in400; VALUE vdays, ret; wideval_t wret; @@ -949,10 +966,7 @@ timegmw_noleapsecond(struct vtm *vtm) divmodv(year1900, INT2FIX(400), &q400, &r400); year_mod400 = NUM2INT(r400); - if (leap_year_p(year_mod400 + 1900)) - yday += leap_year_yday_offset[vtm->mon-1]; - else - yday += common_year_yday_offset[vtm->mon-1]; + yday = calc_tm_yday(year_mod400, vtm->mon-1, vtm->mday); /* * `Seconds Since the Epoch' in SUSv3: @@ -2660,6 +2674,7 @@ find_time_t(struct tm *tptr, int utc_p, time_t *tp) int find_dst; struct tm result; int status; + int tptr_tm_yday; #define GUESS(p) (DEBUG_FIND_TIME_NUMGUESS_INC (utc_p ? gmtime_with_leapsecond(p, &result) : LOCALTIME(p, result))) @@ -2887,22 +2902,30 @@ find_time_t(struct tm *tptr, int utc_p, time_t *tp) } } /* Given argument has no corresponding time_t. Let's outerpolation. */ - if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) { - *tp = guess_lo + - (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 + - (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 + - (tptr->tm_min - tm_lo.tm_min) * 60 + - (tptr->tm_sec - tm_lo.tm_sec); - return NULL; - } - else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) { - *tp = guess_hi + - (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 + - (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 + - (tptr->tm_min - tm_hi.tm_min) * 60 + - (tptr->tm_sec - tm_hi.tm_sec); - return NULL; - } + /* + * `Seconds Since the Epoch' in SUSv3: + * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 + + * (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 - + * ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400 + */ + + tptr_tm_yday = calc_tm_yday(tptr->tm_year, tptr->tm_mon, tptr->tm_mday); + + *tp = guess_lo + + ((tptr->tm_year - tm_lo.tm_year) * 365 + + ((tptr->tm_year-69)/4) - + ((tptr->tm_year-1)/100) + + ((tptr->tm_year+299)/400) - + ((tm_lo.tm_year-69)/4) + + ((tm_lo.tm_year-1)/100) - + ((tm_lo.tm_year+299)/400) + + tptr_tm_yday - + tm_lo.tm_yday) * 86400 + + (tptr->tm_hour - tm_lo.tm_hour) * 3600 + + (tptr->tm_min - tm_lo.tm_min) * 60 + + (tptr->tm_sec - tm_lo.tm_sec); + + return NULL; out_of_range: return "time out of range"; |