struct tm *gmtime_r(const time_t *timep, struct tm *r) { time_t i; register time_t work=*timep%(SPD); r->tm_sec=work%60; work/=60; r->tm_min=work%60; r->tm_hour=work/60; work=*timep/(SPD); r->tm_wday=(4+work)%7; for (i=1970; ; ++i) { register time_t k=__isleap(i)?366:365; if (work>=k) work-=k; else break; } r->tm_year=i-1900; r->tm_yday=work; r->tm_mday=1; if (__isleap(i) && (work>58)) { if (work==59) r->tm_mday=2; /* 29.2. */ work-=1; } for (i=11; i && (__spm[i]>work); --i) ; r->tm_mon=i; r->tm_mday+=work-__spm[i]; return r; }
void rtctime_gmtime (const int32 stamp, struct rtc_tm *r) { int32_t i; int32_t work = stamp % (SPD); r->tm_sec = work % 60; work /= 60; r->tm_min = work % 60; r->tm_hour = work / 60; work = stamp / (SPD); r->tm_wday = (4 + work) % 7; for (i = 1970; ; ++i) { int32_t k = __isleap (i) ? 366 : 365; if (work >= k) { work -= k; } else { break; } } r->tm_year = i - 1900; r->tm_yday = work; r->tm_mday = 1; if (__isleap (i) && (work > 58)) { if (work == 59) r->tm_mday = 2; /* 29.2. */ work -= 1; } for (i = 11; i && (__spm[i] > work); --i) ; r->tm_mon = i; r->tm_mday += work - __spm[i]; }
/* Compute the `struct tm' representation of *T, offset OFFSET seconds east of UTC, and store year, yday, mon, mday, wday, hour, min, sec into *TP. Return nonzero if successful. */ int __offtime (const time_t *t, long int offset, struct tm *tp) { time_t days, rem, y; const unsigned short int *ip; days = *t / SECS_PER_DAY; rem = *t % SECS_PER_DAY; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } tp->tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tp->tm_min = rem / 60; tp->tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ tp->tm_wday = (4 + days) % 7; if (tp->tm_wday < 0) tp->tm_wday += 7; y = 1970; #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ time_t yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } tp->tm_year = y - 1900; if (tp->tm_year != y - 1900) { /* The year cannot be represented due to overflow. */ __set_errno (EOVERFLOW); return 0; } tp->tm_yday = days; ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int) ip[y]; --y) continue; days -= ip[y]; tp->tm_mon = y; tp->tm_mday = days + 1; return 1; }
/** * Convert UNIX timestamp to date/time * Based on code from GNU C Library */ void date_from_timestamp(uint32_t timestamp, DateTimeT *date_time) { uint16_t y; int16_t days; uint32_t rem; days = timestamp / SECS_PER_DAY; rem = timestamp % SECS_PER_DAY; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } date_time->hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; date_time->min = rem / 60; date_time->sec = rem % 60; /* January 1, 1970 was a Thursday. */ date_time->wday = (4 + days) % 7; if (date_time->wday < 0){ date_time->wday += 7; } y = 1970; #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ uint16_t yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } date_time->year = y - 1900; if (date_time->year != y - 1900) { /* The year cannot be represented due to overflow. */ return; } const uint16_t *ip = __mon_yday[__isleap(y)]; for (y = 11; days < (uint16_t)ip[y]; --y){ continue; } days -= ip[y]; date_time->mon = y; date_time->mday = days + 1; }
s32 dev_rtc_date_to_days(struct DATE Dt, u32 *days) { u32 i; u32 j; if((Dt.year<YEAR_STA) || (Dt.year>year_LAST)) { return -1; } if((Dt.mon>12) || (Dt.mon == 0) || (0 == Dt.day)) { return -1; } if(__isleap(Dt.year)) { if(Dt.day>Month_day_Max_L[Dt.mon]) { return -1; } } else { if(Dt.day>Month_day_Max_C[Dt.mon]) { return -1; } } //计算年---->天 j = 0; for(i=YEAR_STA; i<Dt.year; i++) { if(__isleap(i)) { //闰年 j += 366; } else { j += 365; } } //计算月转天 if(__isleap(Dt.year)) { //闰年LeapYear j += Month_day_Accu_L[Dt.mon-1]; } else { j += Month_day_Accu_C[Dt.mon-1]; } //天 *days = j+(Dt.day-1); return 0; }
/* Compute the `struct tm' representation of *T, offset OFFSET seconds east of UTC, and store year, yday, mon, mday, wday, hour, min, sec into *TP. Return nonzero if successful. */ int offtime (unsigned long t, efi_time_t *tp) { const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; long int days, rem, y; const unsigned short int *ip; days = t / SECS_PER_DAY; rem = t % SECS_PER_DAY; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } tp->hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tp->minute = rem / 60; tp->second = rem % 60; /* January 1, 1970 was a Thursday. */ y = 1970; # define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) # define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) # define __isleap(year) \ ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ long int yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } tp->year = y; ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int) ip[y]; --y) continue; days -= ip[y]; tp->month = y + 1; tp->day = days + 1; return 1; }
struct tm gmtime(unsigned long t) { struct tm tbuf; long days, rem; int y; const unsigned short int *ip; y = 1970; #if BITS_PER_LONG >= 64 /* Allow the concept of time before 1970. 64-bit only; for 32-bit * time after 2038 seems more important than time before 1970. */ while ( t & (1UL<<39) ) { y -= 400; t += ((unsigned long)(365 * 303 + 366 * 97)) * SECS_PER_DAY; } t &= (1UL << 40) - 1; #endif days = t / SECS_PER_DAY; rem = t % SECS_PER_DAY; tbuf.tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tbuf.tm_min = rem / 60; tbuf.tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ tbuf.tm_wday = (4 + days) % 7; if ( tbuf.tm_wday < 0 ) tbuf.tm_wday += 7; while ( days >= (rem = __isleap(y) ? 366 : 365) ) { ++y; days -= rem; } while ( days < 0 ) { --y; days += __isleap(y) ? 366 : 365; } tbuf.tm_year = y - 1900; tbuf.tm_yday = days; ip = (const unsigned short int *)__mon_lengths[__isleap(y)]; for ( y = 0; days >= ip[y]; ++y ) days -= ip[y]; tbuf.tm_mon = y; tbuf.tm_mday = days + 1; tbuf.tm_isdst = -1; return tbuf; }
/** * time64_to_tm - converts the calendar time to local broken-down time * * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, * Coordinated Universal Time (UTC). * @offset offset seconds adding to totalsecs. * @result pointer to struct tm variable to receive broken-down time */ void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) { long days, rem, y; int remainder; const unsigned short *ip; days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder); rem = remainder; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } result->tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; result->tm_min = rem / 60; result->tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ result->tm_wday = (4 + days) % 7; if (result->tm_wday < 0) result->tm_wday += 7; y = 1970; while (days < 0 || days >= (__isleap(y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ long yg = y + math_div(days, 365); /* Adjust DAYS and Y to match the guessed year. */ days -= (yg - y) * 365 + leaps_between(y, yg); y = yg; } result->tm_year = y - 1900; result->tm_yday = days; ip = __mon_yday[__isleap(y)]; for (y = 11; days < ip[y]; y--) continue; days -= ip[y]; result->tm_mon = y; result->tm_mday = days + 1; }
void __tm_conv(struct tm *tmbuf, time_t * pt, long offset) { register int y; long days; /* This breaks but not for a while 8) */ long rem; unsigned char *ip; days = *pt / SECS_PER_DAY; rem = *pt % SECS_PER_DAY; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; --days; } /* FIXME: speed - we should probably do some of this with ifs and powers of 2 down as a trade against size */ while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } tmbuf->tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tmbuf->tm_min = rem / 60; tmbuf->tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ tmbuf->tm_wday = (4 + days) % 7; if (tmbuf->tm_wday < 0) tmbuf->tm_wday += 7; y = 1970; while (days >= (rem = __isleap(y) ? 366 : 365)) { ++y; days -= rem; } while (days < 0) { --y; days += __isleap(y) ? 366 : 365; } tmbuf->tm_year = y - 1900; tmbuf->tm_yday = days; ip = __mon_lengths[__isleap(y)]; y = 0; while (days >= ip[y]) days -= ip[y++]; tmbuf->tm_mon = y; tmbuf->tm_mday = days + 1; /* Until we do DST flagging */ tmbuf->tm_isdst = 0; }
time_t timegm(struct tm *const t) { register time_t day; register time_t i; register time_t years = t->tm_year - 70; if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } if (t->tm_hour>24) { t->tm_mday += t->tm_hour/24; t->tm_hour%=24; } if (t->tm_mon>12) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } while (t->tm_mday>__spm[1+t->tm_mon]) { if (t->tm_mon==1 && __isleap(t->tm_year+1900)) { --t->tm_mday; } t->tm_mday-=__spm[t->tm_mon]; ++t->tm_mon; if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; } } if (t->tm_year < 70) return (time_t) -1; /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ day = years * 365 + (years + 1) / 4; /* After 2100 we have to substract 3 leap years for every 400 years This is not intuitive. Most mktime implementations do not support dates after 2059, anyway, so we might leave this out for it's bloat. */ if ((years -= 131) >= 0) { years /= 100; day -= (years >> 2) * 3 + 1; if ((years &= 3) == 3) years--; day -= years; }
/* Returns 1 if MDAY is a valid day of the month in month MON of year YEAR, and 0 if it is not. */ static int check_mday (int year, int mon, int mday) { switch (mon) { case 0: case 2: case 4: case 6: case 7: case 9: case 11: if (mday >= 1 && mday <= 31) return 1; break; case 3: case 5: case 8: case 10: if (mday >= 1 && mday <= 30) return 1; break; case 1: if (mday >= 1 && mday <= (__isleap (year) ? 29 : 28)) return 1; break; } return 0; }
/* Compute an EFI_TIME representation of a GRUB's mtime_t */ VOID GrubTimeToEfiTime(const INT32 t, EFI_TIME *tp) { INT32 days, rem, y; const unsigned short int *ip; days = t / SECS_PER_DAY; rem = t % SECS_PER_DAY; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } tp->Hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tp->Minute = rem / 60; tp->Second = rem % 60; y = 1970; while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ INT32 yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ((yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } tp->Year = y; ip = __mon_yday[__isleap(y)]; for (y = 11; days < (long int) ip[y]; --y) continue; days -= ip[y]; tp->Month = y + 1; tp->Day = days + 1; }
struct tm gmtime(unsigned long t) { struct tm tbuf; long days, rem; int y; const unsigned short int *ip; days = t / SECS_PER_DAY; rem = t % SECS_PER_DAY; tbuf.tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tbuf.tm_min = rem / 60; tbuf.tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ tbuf.tm_wday = (4 + days) % 7; if ( tbuf.tm_wday < 0 ) tbuf.tm_wday += 7; y = 1970; while ( days >= (rem = __isleap(y) ? 366 : 365) ) { ++y; days -= rem; } while ( days < 0 ) { --y; days += __isleap(y) ? 366 : 365; } tbuf.tm_year = y - 1900; tbuf.tm_yday = days; ip = (const unsigned short int *)__mon_lengths[__isleap(y)]; for ( y = 0; days >= ip[y]; ++y ) days -= ip[y]; tbuf.tm_mon = y; tbuf.tm_mday = days + 1; tbuf.tm_isdst = -1; return tbuf; }
/* week_number computes * the ISO 8601 week number as a decimal number * [01,53]. In the ISO 8601 week-based system, weeks * begin on a Monday and week 1 of the year is the * week that includes both January 4th and the first * Thursday of the year. If the first Monday of * January is the 2nd, 3rd, or 4th, the preceding * days are part of the last week of the preceding * year. */ static int week_number(struct tm *tp) { int year = tp->tm_year + TM_YEAR_BASE; int days = week_days (tp->tm_yday, tp->tm_wday); if (days < 0) { /* This ISO week belongs to the previous year. */ year--; days = week_days (tp->tm_yday + (365 + __isleap(year)), tp->tm_wday); } else { int d = week_days (tp->tm_yday - (365 + __isleap(year)), tp->tm_wday); if (0 <= d) { /* This ISO week belongs to the next year. */ year++; days = d; } } return ( (int)days / 7 + 1); }
void eTimeCorrectionEditWindow::monthChanged( eListBoxEntryText *e ) { if ( e ) { const unsigned char monthdays[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; int month = (int)e->getKey(); cday->clear(); int days = monthdays[month]; if ( month == 1 && __isleap( (int)cyear->getCurrent()->getKey()) ) days++; for ( int i = 1; i <= days ; i++ ) new eListBoxEntryText( *cday, eString().sprintf("%02d", i), (void*)i); cday->setCurrent( (void*) 1 ); } }
time_t __buildtime(struct tm* tm) { time_t res; int leap, daysInMonth; // Out-of-range inputs make little sense, fail on them. // Note: this introduces incompatibility with the C standard. if ( tm->tm_sec < 0 || tm->tm_sec > 59 || tm->tm_min < 0 || tm->tm_min > 59 || tm->tm_hour < 0 || tm->tm_hour > 23 || tm->tm_mday < 1 || tm->tm_mday > 31 || tm->tm_mon < 0 || tm->tm_mon > 11 || tm->tm_year < 70 || tm->tm_year > 70+135 ) return (time_t)-1; leap = __isleap(1900 + tm->tm_year); daysInMonth = (tm->tm_mon == 1) ? 28 + leap: // february 30 + ((0xAD5 >> tm->tm_mon) & 1); // all other months if (tm->tm_mday > daysInMonth) // fail here as well return (time_t)-1; tm->tm_yday = __DaysSinceJan1st[leap][tm->tm_mon] + tm->tm_mday - 1; res = tm->tm_sec + tm->tm_min * SECONDS_PER_MINUTE + tm->tm_hour * (time_t)SECONDS_PER_HOUR + tm->tm_yday * SECONDS_PER_DAY + (tm->tm_year - 70) * SECONDS_PER_YEAR; // Now account for extra days in the leap years between 1970 and given year: // add a day every 4 years starting in 1973, // subtract a day back out every 100 years starting in 2001, and // add a day back in every 400 years starting in 2001: res += ((tm->tm_year-69)>>2) * (time_t)SECONDS_PER_DAY - ((tm->tm_year-1)/100) * (time_t)SECONDS_PER_DAY + ((tm->tm_year+299)/400) * (time_t)SECONDS_PER_DAY; tm->tm_wday = (res / SECONDS_PER_DAY + 4) % 7; return res; }
s32 dev_rtc_sec_to_date(struct DATE *Dt, struct TIME *Tm, u32 sec) { u32 i,j; u32 days; const UINT32 *ap; days = (sec/SecsPerDay); //处理时间 i = (sec%SecsPerDay); Tm->hour = (i/SecsPerHour); i = (i%SecsPerHour); Tm->min = (i/SecsPerMin); Tm->sec = (i%SecsPerMin); // uart_printf("dev_rtc_sec_to_date:days=%d\r\n", days); //处理周 Dt->dow = dev_rtc_days_accu_dow(days); // uart_printf("dows=%d\r\n", Dt->dow); //处理日期 //处理年 i = YEAR_STA; while(1) { if(__isleap(i)) { //闰年 j = 366; } else { j = 365; } if(days>=j) { days -= j; i ++; } else { break; } } Dt->year = i; //处理月 if(__isleap(i)) { ap = Month_day_Accu_L; } else { ap = Month_day_Accu_C; } for(i=1; i<13; i++) { if(days < ap[i]) { Dt->mon = i; days -= ap[i-1]; break; } } if(i>=13)return (-1); //天 Dt->day = days+1; return 0; }
/* Compute the `struct tm' representation of *T, offset OFFSET seconds east of UTC, and store year, yday, mon, mday, wday, hour, min, sec into *TP. Return nonzero if successful. */ bool timestamp_to_time (uint32_t timestamp, uint16_t offset, struct time_struct *tm) { const unsigned short int __mon_yday[2][13] = { /* Normal years. */ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, /* Leap years. */ { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } }; uint32_t days, rem, y; const unsigned short int *ip; days = timestamp / SECS_PER_DAY; rem = timestamp % SECS_PER_DAY; rem += offset; while (rem < 0) { rem += SECS_PER_DAY; --days; } while (rem >= SECS_PER_DAY) { rem -= SECS_PER_DAY; ++days; } tm->tm_hour = rem / SECS_PER_HOUR; rem %= SECS_PER_HOUR; tm->tm_min = rem / 60; tm->tm_sec = rem % 60; /* January 1, 1970 was a Thursday. */ tm->tm_wday = (4 + days) % 7; if (tm->tm_wday < 0) tm->tm_wday += 7; y = 1970; #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0)) #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) while (days < 0 || days >= (__isleap (y) ? 366 : 365)) { /* Guess a corrected year, assuming 365 days per year. */ long int yg = y + days / 365 - (days % 365 < 0); /* Adjust DAYS and Y to match the guessed year. */ days -= ( (yg - y) * 365 + LEAPS_THRU_END_OF (yg - 1) - LEAPS_THRU_END_OF (y - 1)); y = yg; } tm->tm_year = y - 1900; if (tm->tm_year != y - 1900) { /* The year cannot be represented due to overflow. */ //__set_errno (EOVERFLOW); return false; } tm->tm_yday = days; ip = __mon_yday[__isleap (y) ]; for (y = 11; days < (long int) ip[y]; --y) continue; days -= ip[y]; tm->tm_mon = y; tm->tm_mday = days + 1; return true; }
char * strptime_internal (const char *rp, const char *fmt, struct tm *tm, enum locale_status *decided) { const char *rp_backup; int cnt; size_t val; int have_I, is_pm; int century, want_century; int have_wday, want_xday; int have_yday; int have_mon, have_mday; have_I = is_pm = 0; century = -1; want_century = 0; have_wday = want_xday = have_yday = have_mon = have_mday = 0; while (*fmt != '\0') { /* A white space in the format string matches 0 more or white space in the input string. */ if (isspace (*fmt)) { while (isspace (*rp)) ++rp; ++fmt; continue; } /* Any character but `%' must be matched by the same character in the iput string. */ if (*fmt != '%') { match_char (*fmt++, *rp++); continue; } ++fmt; /* We need this for handling the `E' modifier. */ start_over: /* Make back up of current processing pointer. */ rp_backup = rp; switch (*fmt++) { case '%': /* Match the `%' character itself. */ match_char ('%', *rp++); break; case 'a': case 'A': /* Match day of week. */ for (cnt = 0; cnt < 7; ++cnt) { if (*decided != loc && (match_string (weekday_name[cnt], rp) || match_string (ab_weekday_name[cnt], rp))) { *decided = raw; break; } } if (cnt == 7) /* Does not match a weekday name. */ return NULL; tm->tm_wday = cnt; have_wday = 1; break; case 'b': case 'B': case 'h': /* Match month name. */ for (cnt = 0; cnt < 12; ++cnt) { if (match_string (month_name[cnt], rp) || match_string (ab_month_name[cnt], rp)) { *decided = raw; break; } } if (cnt == 12) /* Does not match a month name. */ return NULL; tm->tm_mon = cnt; want_xday = 1; break; case 'c': /* Match locale's date and time format. */ return strptime_internal (rp, "%x %X", tm, decided); break; case 'C': /* Match century number. */ get_number (0, 99, 2); century = val; want_xday = 1; break; case 'd': case 'e': /* Match day of month. */ get_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'F': if (!recursive ("%Y-%m-%d")) return NULL; want_xday = 1; break; case 'x': { char *pic; unsigned int loc; char winpic[100]; int ret; loc = GetThreadLocale(); GetLocaleInfo(loc, LOCALE_SSHORTDATE, winpic, 100); conv_winpic(winpic, &pic); ret = recursive(pic); free(pic); if (!ret) return NULL; want_xday = 1; } break; case 'D': /* Match standard day format. */ if (!recursive ("%m/%d/%y")) return NULL; want_xday = 1; break; case 'k': case 'H': /* Match hour in 24-hour clock. */ get_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock. */ get_number (1, 12, 2); tm->tm_hour = val % 12; have_I = 1; break; case 'j': /* Match day number of year. */ get_number (1, 366, 3); tm->tm_yday = val - 1; have_yday = 1; break; case 'm': /* Match number of month. */ get_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minute. */ get_number (0, 59, 2); tm->tm_min = val; break; case 'n': case 't': /* Match any white space. */ while (isspace (*rp)) ++rp; break; case 'p': /* Match locale's equivalent of AM/PM. */ if (!match_string (am_pm[0], rp)) { if (match_string (am_pm[1], rp)) { is_pm = 1; } else { return NULL; } } break; case 'r': return strptime_internal (rp, "%x %X", tm, decided); break; case 'R': if (!recursive ("%H:%M")) return NULL; break; case 's': { /* The number of seconds may be very high so we cannot use the `get_number' macro. Instead read the number character for character and construct the result while doing this. */ time_t secs = 0; if (*rp < '0' || *rp > '9') /* We need at least one digit. */ return NULL; do { secs *= 10; secs += *rp++ - '0'; } while (*rp >= '0' && *rp <= '9'); if ((tm = localtime (&secs)) == NULL) /* Error in function. */ return NULL; } break; case 'S': get_number (0, 61, 2); tm->tm_sec = val; break; case 'X': { char *pic; unsigned int loc; char winpic[100]; int ret; loc = GetThreadLocale(); GetLocaleInfo(loc, LOCALE_STIMEFORMAT, winpic, 100); conv_winpic(winpic, &pic); ret = recursive(pic); free(pic); if (!ret) return NULL; } break; case 'T': return strptime_internal (rp, "%H:%M:%S", tm, decided); break; case 'u': get_number (1, 7, 1); tm->tm_wday = val % 7; have_wday = 1; break; case 'g': get_number (0, 99, 2); /* XXX This cannot determine any field in TM. */ break; case 'G': if (*rp < '0' || *rp > '9') return NULL; /* XXX Ignore the number since we would need some more information to compute a real date. */ do ++rp; while (*rp >= '0' && *rp <= '9'); break; case 'U': case 'V': case 'W': get_number (0, 53, 2); /* XXX This cannot determine any field in TM without some information. */ break; case 'w': /* Match number of weekday. */ get_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': /* Match year within century. */ get_number (0, 99, 2); /* The "Year 2000: The Millennium Rollover" paper suggests that values in the range 69-99 refer to the twentieth century. */ tm->tm_year = val >= 69 ? val : val + 100; /* Indicate that we want to use the century, if specified. */ want_century = 1; want_xday = 1; break; case 'Y': /* Match year including century number. */ get_number (0, 9999, 4); tm->tm_year = val - 1900; want_century = 0; want_xday = 1; break; case 'Z': /* XXX How to handle this? */ break; case 'E': /* We have no information about the era format. Just use the normal format. */ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' && *fmt != 'x' && *fmt != 'X') /* This is an invalid format. */ return NULL; goto start_over; case 'O': switch (*fmt++) { case 'd': case 'e': /* Match day of month using alternate numeric symbols. */ get_alt_number (1, 31, 2); tm->tm_mday = val; have_mday = 1; want_xday = 1; break; case 'H': /* Match hour in 24-hour clock using alternate numeric symbols. */ get_alt_number (0, 23, 2); tm->tm_hour = val; have_I = 0; break; case 'I': /* Match hour in 12-hour clock using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_hour = val - 1; have_I = 1; break; case 'm': /* Match month using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_mon = val - 1; have_mon = 1; want_xday = 1; break; case 'M': /* Match minutes using alternate numeric symbols. */ get_alt_number (0, 59, 2); tm->tm_min = val; break; case 'S': /* Match seconds using alternate numeric symbols. */ get_alt_number (0, 61, 2); tm->tm_sec = val; break; case 'U': case 'V': case 'W': get_alt_number (0, 53, 2); /* XXX This cannot determine any field in TM without further information. */ break; case 'w': /* Match number of weekday using alternate numeric symbols. */ get_alt_number (0, 6, 1); tm->tm_wday = val; have_wday = 1; break; case 'y': /* Match year within century using alternate numeric symbols. */ get_alt_number (0, 99, 2); tm->tm_year = val >= 69 ? val : val + 100; want_xday = 1; break; default: return NULL; } break; default: return NULL; } } if (have_I && is_pm) tm->tm_hour += 12; if (century != -1) { if (want_century) tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; else /* Only the century, but not the year. Strange, but so be it. */ tm->tm_year = (century - 19) * 100; } if (want_xday && !have_wday) { if ( !(have_mon && have_mday) && have_yday) { /* we don't have tm_mon and/or tm_mday, compute them */ int t_mon = 0; while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) t_mon++; if (!have_mon) tm->tm_mon = t_mon - 1; if (!have_mday) tm->tm_mday = tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1; } day_of_the_week (tm); } if (want_xday && !have_yday) day_of_the_year (tm); return (char *) rp; }
static char * __strptime_internal (const char *rp, const char *fmt, struct tm *tmp, void *statep) { const char *rp_backup; const char *rp_longest; int cnt; int cnt_longest; size_t val; #ifdef _NL_CURRENT size_t num_eras; struct era_entry *era = NULL; #endif enum ptime_locale_status { nott, loc, raw } decided_longest; struct __strptime_state { unsigned int have_I : 1; unsigned int have_wday : 1; unsigned int have_yday : 1; unsigned int have_mon : 1; unsigned int have_mday : 1; unsigned int have_uweek : 1; unsigned int have_wweek : 1; unsigned int is_pm : 1; unsigned int want_century : 1; unsigned int want_era : 1; unsigned int want_xday : 1; enum ptime_locale_status decided : 2; signed char week_no; signed char century; int era_cnt; } s; struct tm tmb; struct tm *tm; if (statep == NULL) { memset (&s, 0, sizeof (s)); s.century = -1; s.era_cnt = -1; #ifdef _NL_CURRENT s.decided = nott; #else s.decided = raw; #endif tm = tmp; } else { s = *(struct __strptime_state *) statep; tmb = *tmp; tm = &tmb; } while (*fmt != '\0') { /* A white space in the format string matches 0 more or white space in the input string. */ if (isspace (*fmt)) { while (isspace (*rp)) ++rp; ++fmt; continue; } /* Any character but `%' must be matched by the same character in the iput string. */ if (*fmt != '%') { match_char (*fmt++, *rp++); continue; } ++fmt; if (statep != NULL) { /* In recursive calls silently discard strftime modifiers. */ while (*fmt == '-' || *fmt == '_' || *fmt == '0' || *fmt == '^' || *fmt == '#') ++fmt; /* And field width. */ while (*fmt >= '0' && *fmt <= '9') ++fmt; } #ifndef _NL_CURRENT /* We need this for handling the `E' modifier. */ start_over: #endif /* Make back up of current processing pointer. */ rp_backup = rp; switch (*fmt++) { case '%': /* Match the `%' character itself. */ match_char ('%', *rp++); break; case 'a': case 'A': /* Match day of week. */ rp_longest = NULL; decided_longest = s.decided; cnt_longest = -1; for (cnt = 0; cnt < 7; ++cnt) { const char *trp; #ifdef _NL_CURRENT if (s.decided !=raw) { trp = rp; if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), trp) && trp > rp_longest) { rp_longest = trp; cnt_longest = cnt; if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), weekday_name[cnt])) decided_longest = loc; } trp = rp; if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), trp) && trp > rp_longest) { rp_longest = trp; cnt_longest = cnt; if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), ab_weekday_name[cnt])) decided_longest = loc; } } #endif if (s.decided != loc && (((trp = rp, match_string (weekday_name[cnt], trp)) && trp > rp_longest) || ((trp = rp, match_string (ab_weekday_name[cnt], rp)) && trp > rp_longest))) { rp_longest = trp; cnt_longest = cnt; decided_longest = raw; } } if (rp_longest == NULL) /* Does not match a weekday name. */ return NULL; rp = rp_longest; s.decided = decided_longest; tm->tm_wday = cnt_longest; s.have_wday = 1; break; case 'b': case 'B': case 'h': /* Match month name. */ rp_longest = NULL; decided_longest = s.decided; cnt_longest = -1; for (cnt = 0; cnt < 12; ++cnt) { const char *trp; #ifdef _NL_CURRENT if (s.decided !=raw) { trp = rp; if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), trp) && trp > rp_longest) { rp_longest = trp; cnt_longest = cnt; if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), month_name[cnt])) decided_longest = loc; } trp = rp; if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), trp) && trp > rp_longest) { rp_longest = trp; cnt_longest = cnt; if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), ab_month_name[cnt])) decided_longest = loc; } } #endif if (s.decided != loc && (((trp = rp, match_string (month_name[cnt], trp)) && trp > rp_longest) || ((trp = rp, match_string (ab_month_name[cnt], trp)) && trp > rp_longest))) { rp_longest = trp; cnt_longest = cnt; decided_longest = raw; } } if (rp_longest == NULL) /* Does not match a month name. */ return NULL; rp = rp_longest; s.decided = decided_longest; tm->tm_mon = cnt_longest; s.have_mon = 1; s.want_xday = 1; break; case 'c': /* Match locale's date and time format. */ #ifdef _NL_CURRENT if (s.decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) s.decided = loc; s.want_xday = 1; break; } s.decided = raw; } #endif if (!recursive (HERE_D_T_FMT)) return NULL; s.want_xday = 1; break; case 'C': /* Match century number. */ #ifdef _NL_CURRENT match_century: #endif get_number (0, 99, 2); s.century = val; s.want_xday = 1; break; case 'd': case 'e': /* Match day of month. */ get_number (1, 31, 2); tm->tm_mday = val; s.have_mday = 1; s.want_xday = 1; break; case 'F': if (!recursive ("%Y-%m-%d")) return NULL; s.want_xday = 1; break; case 'x': #ifdef _NL_CURRENT if (s.decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) s.decided = loc; s.want_xday = 1; break; } s.decided = raw; } #endif /* Fall through. */ case 'D': /* Match standard day format. */ if (!recursive (HERE_D_FMT)) return NULL; s.want_xday = 1; break; case 'k': case 'H': /* Match hour in 24-hour clock. */ get_number (0, 23, 2); tm->tm_hour = val; s.have_I = 0; break; case 'l': /* Match hour in 12-hour clock. GNU extension. */ case 'I': /* Match hour in 12-hour clock. */ get_number (1, 12, 2); tm->tm_hour = val % 12; s.have_I = 1; break; case 'j': /* Match day number of year. */ get_number (1, 366, 3); tm->tm_yday = val - 1; s.have_yday = 1; break; case 'm': /* Match number of month. */ get_number (1, 12, 2); tm->tm_mon = val - 1; s.have_mon = 1; s.want_xday = 1; break; case 'M': /* Match minute. */ get_number (0, 59, 2); tm->tm_min = val; break; case 'n': case 't': /* Match any white space. */ while (isspace (*rp)) ++rp; break; case 'p': /* Match locale's equivalent of AM/PM. */ #ifdef _NL_CURRENT if (s.decided != raw) { if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) s.decided = loc; s.is_pm = 0; break; } if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) { if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) s.decided = loc; s.is_pm = 1; break; } s.decided = raw; } #endif if (!match_string (HERE_AM_STR, rp)) { if (match_string (HERE_PM_STR, rp)) s.is_pm = 1; else return NULL; } else s.is_pm = 0; break; case 'r': #ifdef _NL_CURRENT if (s.decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (s.decided == nott && strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), HERE_T_FMT_AMPM)) s.decided = loc; break; } s.decided = raw; } #endif if (!recursive (HERE_T_FMT_AMPM)) return NULL; break; case 'R': if (!recursive ("%H:%M")) return NULL; break; case 's': { /* The number of seconds may be very high so we cannot use the `get_number' macro. Instead read the number character for character and construct the result while doing this. */ time_t secs = 0; if (*rp < '0' || *rp > '9') /* We need at least one digit. */ return NULL; do { secs *= 10; secs += *rp++ - '0'; } while (*rp >= '0' && *rp <= '9'); if (localtime_r (&secs, tm) == NULL) /* Error in function. */ return NULL; } break; case 'S': get_number (0, 61, 2); tm->tm_sec = val; break; case 'X': #ifdef _NL_CURRENT if (s.decided != raw) { if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) s.decided = loc; break; } s.decided = raw; } #endif /* Fall through. */ case 'T': if (!recursive (HERE_T_FMT)) return NULL; break; case 'u': get_number (1, 7, 1); tm->tm_wday = val % 7; s.have_wday = 1; break; case 'g': get_number (0, 99, 2); /* XXX This cannot determine any field in TM. */ break; case 'G': if (*rp < '0' || *rp > '9') return NULL; /* XXX Ignore the number since we would need some more information to compute a real date. */ do ++rp; while (*rp >= '0' && *rp <= '9'); break; case 'U': get_number (0, 53, 2); s.week_no = val; s.have_uweek = 1; break; case 'W': get_number (0, 53, 2); s.week_no = val; s.have_wweek = 1; break; case 'V': get_number (0, 53, 2); /* XXX This cannot determine any field in TM without some information. */ break; case 'w': /* Match number of weekday. */ get_number (0, 6, 1); tm->tm_wday = val; s.have_wday = 1; break; case 'y': #ifdef _NL_CURRENT match_year_in_century: #endif /* Match year within century. */ get_number (0, 99, 2); /* The "Year 2000: The Millennium Rollover" paper suggests that values in the range 69-99 refer to the twentieth century. */ tm->tm_year = val >= 69 ? val : val + 100; /* Indicate that we want to use the century, if specified. */ s.want_century = 1; s.want_xday = 1; break; case 'Y': /* Match year including century number. */ get_number (0, 9999, 4); tm->tm_year = val - 1900; s.want_century = 0; s.want_xday = 1; break; case 'Z': /* XXX How to handle this? */ break; case 'z': /* We recognize two formats: if two digits are given, these specify hours. If fours digits are used, minutes are also specified. */ { val = 0; while (*rp == ' ') ++rp; if (*rp != '+' && *rp != '-') return NULL; rp++; int n = 0; while (n < 4 && *rp >= '0' && *rp <= '9') { val = val * 10 + *rp++ - '0'; ++n; } if (n == 2) val *= 100; else if (n != 4) /* Only two or four digits recognized. */ return NULL; else { /* We have to convert the minutes into decimal. */ if (val % 100 >= 60) return NULL; val = (val / 100) * 100 + ((val % 100) * 50) / 30; } if (val > 1200) return NULL; } break; case 'E': #ifdef _NL_CURRENT switch (*fmt++) { case 'c': /* Match locale's alternate date and time format. */ if (s.decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_T_FMT); if (!recursive (fmt)) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_T_FMT)) s.decided = loc; s.want_xday = 1; break; } s.decided = raw; } /* The C locale has no era information, so use the normal representation. */ if (!recursive (HERE_D_T_FMT)) return NULL; s.want_xday = 1; break; case 'C': if (s.decided != raw) { if (s.era_cnt >= 0) { era = _nl_select_era_entry (s.era_cnt); if (era != NULL && match_string (era->era_name, rp)) { s.decided = loc; break; } else return NULL; } num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (s.era_cnt = 0; s.era_cnt < (int) num_eras; ++s.era_cnt, rp = rp_backup) { era = _nl_select_era_entry (s.era_cnt); if (era != NULL && match_string (era->era_name, rp)) { s.decided = loc; break; } } if (s.era_cnt != (int) num_eras) break; s.era_cnt = -1; if (s.decided == loc) return NULL; s.decided = raw; } /* The C locale has no era information, so use the normal representation. */ goto match_century; case 'y': if (s.decided != raw) { get_number(0, 9999, 4); tm->tm_year = val; s.want_era = 1; s.want_xday = 1; s.want_century = 1; if (s.era_cnt >= 0) { assert (s.decided == loc); era = _nl_select_era_entry (s.era_cnt); bool match = false; if (era != NULL) { int delta = ((tm->tm_year - era->offset) * era->absolute_direction); match = (delta >= 0 && delta < (((int64_t) era->stop_date[0] - (int64_t) era->start_date[0]) * era->absolute_direction)); } if (! match) return NULL; break; } num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (s.era_cnt = 0; s.era_cnt < (int) num_eras; ++s.era_cnt) { era = _nl_select_era_entry (s.era_cnt); if (era != NULL) { int delta = ((tm->tm_year - era->offset) * era->absolute_direction); if (delta >= 0 && delta < (((int64_t) era->stop_date[0] - (int64_t) era->start_date[0]) * era->absolute_direction)) { s.decided = loc; break; } } } if (s.era_cnt != (int) num_eras) break; s.era_cnt = -1; if (s.decided == loc) return NULL; s.decided = raw; } goto match_year_in_century; case 'Y': if (s.decided != raw) { num_eras = _NL_CURRENT_WORD (LC_TIME, _NL_TIME_ERA_NUM_ENTRIES); for (s.era_cnt = 0; s.era_cnt < (int) num_eras; ++s.era_cnt, rp = rp_backup) { era = _nl_select_era_entry (s.era_cnt); if (era != NULL && recursive (era->era_format)) break; } if (s.era_cnt == (int) num_eras) { s.era_cnt = -1; if (s.decided == loc) return NULL; else rp = rp_backup; } else { s.decided = loc; s.era_cnt = -1; break; } s.decided = raw; } get_number (0, 9999, 4); tm->tm_year = val - 1900; s.want_century = 0; s.want_xday = 1; break; case 'x': if (s.decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, D_FMT); if (!recursive (fmt)) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_D_FMT)) s.decided = loc; break; } s.decided = raw; } if (!recursive (HERE_D_FMT)) return NULL; break; case 'X': if (s.decided != raw) { const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); if (*fmt == '\0') fmt = _NL_CURRENT (LC_TIME, T_FMT); if (!recursive (fmt)) { if (s.decided == loc) return NULL; else rp = rp_backup; } else { if (strcmp (fmt, HERE_T_FMT)) s.decided = loc; break; } s.decided = raw; } if (!recursive (HERE_T_FMT)) return NULL; break; default: return NULL; } break; #else /* We have no information about the era format. Just use the normal format. */ if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' && *fmt != 'x' && *fmt != 'X') /* This is an illegal format. */ return NULL; goto start_over; #endif case 'O': switch (*fmt++) { case 'd': case 'e': /* Match day of month using alternate numeric symbols. */ get_alt_number (1, 31, 2); tm->tm_mday = val; s.have_mday = 1; s.want_xday = 1; break; case 'H': /* Match hour in 24-hour clock using alternate numeric symbols. */ get_alt_number (0, 23, 2); tm->tm_hour = val; s.have_I = 0; break; case 'I': /* Match hour in 12-hour clock using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_hour = val % 12; s.have_I = 1; break; case 'm': /* Match month using alternate numeric symbols. */ get_alt_number (1, 12, 2); tm->tm_mon = val - 1; s.have_mon = 1; s.want_xday = 1; break; case 'M': /* Match minutes using alternate numeric symbols. */ get_alt_number (0, 59, 2); tm->tm_min = val; break; case 'S': /* Match seconds using alternate numeric symbols. */ get_alt_number (0, 61, 2); tm->tm_sec = val; break; case 'U': get_alt_number (0, 53, 2); s.week_no = val; s.have_uweek = 1; break; case 'W': get_alt_number (0, 53, 2); s.week_no = val; s.have_wweek = 1; break; case 'V': get_alt_number (0, 53, 2); /* XXX This cannot determine any field in TM without further information. */ break; case 'w': /* Match number of weekday using alternate numeric symbols. */ get_alt_number (0, 6, 1); tm->tm_wday = val; s.have_wday = 1; break; case 'y': /* Match year within century using alternate numeric symbols. */ get_alt_number (0, 99, 2); tm->tm_year = val >= 69 ? val : val + 100; s.want_xday = 1; break; default: return NULL; } break; default: return NULL; } } if (statep != NULL) { /* Recursive invocation, returning success, so update parent's struct tm and state. */ *(struct __strptime_state *) statep = s; *tmp = tmb; return (char *) rp; } if (s.have_I && s.is_pm) tm->tm_hour += 12; if (s.century != -1) { if (s.want_century) tm->tm_year = tm->tm_year % 100 + (s.century - 19) * 100; else /* Only the century, but not the year. Strange, but so be it. */ tm->tm_year = (s.century - 19) * 100; } if (s.want_xday && !s.have_wday) { if ( !(s.have_mon && s.have_mday) && s.have_yday) { /* We don't have tm_mon and/or tm_mday, compute them. */ int t_mon = 0; while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) t_mon++; if (!s.have_mon) tm->tm_mon = t_mon - 1; if (!s.have_mday) tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); s.have_mon = 1; s.have_mday = 1; } /* Don't crash in day_of_the_week if tm_mon is uninitialized. */ if (s.have_mon || (unsigned) tm->tm_mon <= 11) day_of_the_week (tm); } if (s.want_xday && !s.have_yday && (s.have_mon || (unsigned) tm->tm_mon <= 11)) day_of_the_year (tm); if ((s.have_uweek || s.have_wweek) && s.have_wday) { int save_wday = tm->tm_wday; int save_mday = tm->tm_mday; int save_mon = tm->tm_mon; int w_offset = s.have_uweek ? 0 : 1; tm->tm_mday = 1; tm->tm_mon = 0; day_of_the_week (tm); if (s.have_mday) tm->tm_mday = save_mday; if (s.have_mon) tm->tm_mon = save_mon; if (!s.have_yday) tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7 + (s.week_no - 1) *7 + save_wday - w_offset); if (!s.have_mday || !s.have_mon) { int t_mon = 0; while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) t_mon++; if (!s.have_mon) tm->tm_mon = t_mon - 1; if (!s.have_mday) tm->tm_mday = (tm->tm_yday - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); } tm->tm_wday = save_wday; } return (char *) rp; }
/* Compute the day of the year. */ static void day_of_the_year (struct tm *tm) { tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] + (tm->tm_mday - 1)); }
/* Days since 1970 is 365 * number of years + number of leap years since 1970 */ day = years * 365 + (years + 1) / 4; /* After 2100 we have to substract 3 leap years for every 400 years This is not intuitive. Most mktime implementations do not support dates after 2059, anyway, so we might leave this out for it's bloat. */ if ((years -= 131) >= 0) { years /= 100; day -= (years >> 2) * 3 + 1; if ((years &= 3) == 3) years--; day -= years; } day += t->tm_yday = __spm [t->tm_mon] + t->tm_mday-1 + ( __isleap (t->tm_year+1900) & (t->tm_mon > 1) ); /* day is now the number of days since 'Jan 1 1970' */ i = 7; t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ i = 24; day *= i; i = 60; return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; } time_t mktime(register struct tm* const t) { time_t x=timegm(t); struct timezone tz; gettimeofday(0, &tz);
int dysize (int year) { return __isleap (year) ? 366 : 365; }
char* strptime(const char* s,const char* format, struct tm* tm) { int i,j; register time_t day; while (*format) { switch (*format) { case ' ': case '\t': /* match zero or more white space in input string */ while (isblank(*s)) ++s; ++format; break; case '%': ++format; switch (*format) { case '%': if (*s=='%') ++s; else return 0; break; case 'a': case 'A': /* weekday; we just skip */ for (i=0; i<3; ++i) if (isalpha(*s)) ++s; break; case 'b': case 'B': case 'h': for (i=0; i<12; ++i) { if (strncasecmp(s,months[i],j=strlen(months[i]))) if (strncasecmp(s,months[i],j=3)) j=0; if (j) break; } if (!j) return 0; s+=j; tm->tm_mon=i; break; case 'c': s=strptime(s,"%b %a %d %k:%M:%S %Z %Y",tm); break; case 'C': i=getint(&s,2); if (i==-1) return 0; tm->tm_year=(tm->tm_year%100)+(i*100); break; case 'd': case 'e': i=getint(&s,2); if (i==-1 || i>31) return 0; tm->tm_mday=i; break; case 'D': s=strptime(s,"%m/%d/%y",tm); break; case 'H': case 'k': i=getint(&s,2); if (i==-1 || i>23) return 0; tm->tm_hour=i; break; case 'I': case 'l': i=getint(&s,2); if (i==-1 || i>12) return 0; tm->tm_hour=(tm->tm_hour/12)*12+i; break; case 'j': getint(&s,3); /* not used */ break; case 'm': i=getint(&s,2); if (i<=0 || i>12) return 0; tm->tm_mon=i-1; break; case 'M': i=getint(&s,2); if (i==-1 || i>59) return 0; tm->tm_min=i; break; case 'n': case 't': while (isblank(*s)) ++s; break; case 'p': case 'P': if (*s=='p' || *s=='P') tm->tm_hour=(tm->tm_hour%12)+12; s+=2; break; case 'r': s=strptime(s,"%I:%M:%S %p",tm); break; case 'R': s=strptime(s,"%H:%M",tm); break; case 'S': i=getint(&s,2); if (i==-1 || i>60) return 0; tm->tm_sec=i; break; case 'T': s=strptime(s,"%H:%M:%S",tm); break; case 'U': case 'W': if (getint(&s,2)==-1) return 0; break; case 'w': if (*s<'0' || *s>'6') return 0; ++s; break; case 'x': s=strptime(s,"%b %a %d",tm); break; case 'X': s=strptime(s,"%k:%M:%S",tm); break; case 'y': i=getint(&s,2); if (i<0) return 0; tm->tm_year=(i<69)?i+100:i; break; case 'Y': i=getint(&s,4); if (i==-1) return 0; tm->tm_year=i-1900; break; case 'Z': /* time zone. Not sure what I'm expected to do here. We'll just * skip to the next whitespace */ while (*s!=' ' && *s!='\t') ++s; break; } ++format; break; default: if (*s != *format) return 0; ++format; ++s; break; } } day = (tm->tm_year - 70) * 365 + (tm->tm_year - 69) / 4; day += tm->tm_yday = __spm [tm->tm_mon] + tm->tm_mday-1 + (__isleap (tm->tm_year+1900) & (tm->tm_mon > 1)); tm->tm_wday = (day + 4) % 7; return (char*)s; }
/* After 2100 we have to substract 3 leap years for every 400 years This is not intuitive. Most mktime implementations do not support dates after 2059, anyway, so we might leave this out for it's bloat. */ if (years >= 131) { years -= 131; years /= 100; day -= (years >> 2) * 3 + 1; if ((years &= 3) == 3) years--; day -= years; } day += t->tm_yday = __spm[t->tm_mon] + t->tm_mday - 1 + (__isleap(t->tm_year + TM_YEAR_BASE) & (t->tm_mon > 1)); /* day is now the number of days since 'Jan 1 1970' */ i = 7; t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ i = 24; day *= i; i = 60; return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; } static void num2str(char *c, int i) { c[0] = i / 10 + '0'; c[1] = i % 10 + '0';