FAR struct tm *gmtime_r(FAR const time_t *timer, FAR struct tm *result) { time_t epoch; time_t jdn; int year; int month; int day; int hour; int min; int sec; /* Get the seconds since the EPOCH */ epoch = *timer; sdbg("timer=%d\n", (int)epoch); /* Convert to days, hours, minutes, and seconds since the EPOCH */ jdn = epoch / SEC_PER_DAY; epoch -= SEC_PER_DAY * jdn; hour = epoch / SEC_PER_HOUR; epoch -= SEC_PER_HOUR * hour; min = epoch / SEC_PER_MIN; epoch -= SEC_PER_MIN * min; sec = epoch; sdbg("hour=%d min=%d sec=%d\n", (int)hour, (int)min, (int)sec); /* Convert the days since the EPOCH to calendar day */ clock_utc2calendar(jdn, &year, &month, &day); sdbg("jdn=%d year=%d month=%d day=%d\n", (int)jdn, (int)year, (int)month, (int)day); /* Then return the struct tm contents */ result->tm_year = (int)year - 1900; /* Relative to 1900 */ result->tm_mon = (int)month - 1; /* zero-based */ result->tm_mday = (int)day; /* one-based */ result->tm_hour = (int)hour; result->tm_min = (int)min; result->tm_sec = (int)sec; #if defined(CONFIG_TIME_EXTENDED) result->tm_wday = clock_dayoftheweek(day, month, year); result->tm_yday = day + clock_daysbeforemonth(result->tm_mon, clock_isleapyear(year)); result->tm_isdst = 0; #endif return result; }
time_t mktime(const struct tm *tp) { unsigned int days; /* Years since epoch in units of days (ignoring leap years). */ days = (tp->tm_year - 70) * 365; /* Add in the extra days for the leap years prior to the current year. */ days += (tp->tm_year - 69) >> 2; /* Add in the days up to the beginning of this month. */ days += (time_t)clock_daysbeforemonth(tp->tm_mon, clock_isleapyear(tp->tm_year + 1900)); /* Add in the days since the beginning of this month (days are 1-based). */ days += tp->tm_mday - 1; /* Then convert the seconds and add in hours, minutes, and seconds */ return ((days * 24 + tp->tm_hour) * 60 + tp->tm_min) * 60 + tp->tm_sec; }
time_t clock_calendar2utc(int year, int month, int day) { time_t days; /* Years since epoch in units of days (ignoring leap years). */ days = (year - EPOCH_YEAR) * 365; /* Add in the extra days for the leap years prior to the current year. */ days += (year - EPOCH_YEAR - 1) >> 2; /* Add in the days up to the beginning of this month. */ days += (time_t)clock_daysbeforemonth(month, clock_isleapyear(year)); /* Add in the days since the beginning of this month (days are 1-based). */ days += day - 1; /* Then convert the seconds and add in hours, minutes, and seconds */ return days; }
static void clock_utc2calendar(time_t days, int *year, int *month, int *day) { int value; int min; int max; int tmp; bool leapyear; /* There is one leap year every four years, so we can get close with the * following: */ value = days / (4*365 + 1); /* Number of 4-years periods since the epoch*/ days -= value * (4*365 + 1); /* Remaining days */ value <<= 2; /* Years since the epoch */ /* Then we will brute force the next 0-3 years */ for (;;) { /* Is this year a leap year (we'll need this later too) */ leapyear = clock_isleapyear(value + 1970); /* Get the number of days in the year */ tmp = (leapyear ? 366 : 365); /* Do we have that many days? */ if (days >= tmp) { /* Yes.. bump up the year */ value++; days -= tmp; } else { /* Nope... then go handle months */ break; } } /* At this point, value has the year and days has number days into this year */ *year = 1970 + value; /* Handle the month (zero based) */ min = 0; max = 11; do { /* Get the midpoint */ value = (min + max) >> 1; /* Get the number of days that occurred before the beginning of the month * following the midpoint. */ tmp = clock_daysbeforemonth(value + 1, leapyear); /* Does the number of days before this month that equal or exceed the * number of days we have remaining? */ if (tmp > days) { /* Yes.. then the month we want is somewhere from 'min' and to the * midpoint, 'value'. Could it be the midpoint? */ tmp = clock_daysbeforemonth(value, leapyear); if (tmp > days) { /* No... The one we want is somewhere between min and value-1 */ max = value - 1; } else { /* Yes.. 'value' contains the month that we want */ break; } } else { /* No... The one we want is somwhere between value+1 and max */ min = value + 1; } /* If we break out of the loop because min == max, then we want value * to be equal to min == max. */ value = min; } while (min < max); /* The selected month number is in value. Subtract the number of days in the * selected month */ days -= clock_daysbeforemonth(value, leapyear); /* At this point, value has the month into this year (zero based) and days has * number of days into this month (zero based) */ *month = value + 1; /* 1-based */ *day = days + 1; /* 1-based */ }
size_t strftime(FAR char *s, size_t max, FAR const char *format, FAR const struct tm *tm) { FAR const char *str; FAR char *dest = s; int chleft = max; int value; int len; while (*format && chleft > 0) { /* Just copy regular characters */ if (*format != '%') { *dest++ = *format++; chleft--; continue; } /* Handle the format character */ format++; len = 0; switch (*format++) { /* %a: A three-letter abbreviation for the day of the week. */ /* %A: The full name for the day of the week. */ case 'a': case 'A': { len = snprintf(dest, chleft, "Day"); /* Not supported */ } break; /* %h: Equivalent to %b */ case 'h': /* %b: The abbreviated month name according to the current locale. */ case 'b': { if (tm->tm_mon < 12) { str = g_abbrevmonthname[tm->tm_mon]; len = snprintf(dest, chleft, "%s", str); } } break; /* %B: The full month name according to the current locale. */ case 'B': { if (tm->tm_mon < 12) { str = g_monthname[tm->tm_mon]; len = snprintf(dest, chleft, "%s", str); } } break; /* %y: The year as a decimal number without a century (range 00 to 99). */ case 'y': { len = snprintf(dest, chleft, "%02d", tm->tm_year % 100); } break; /* %C: The century number (year/100) as a 2-digit integer. */ case 'C': { len = snprintf(dest, chleft, "%02d", tm->tm_year / 100); } break; /* %d: The day of the month as a decimal number (range 01 to 31). */ case 'd': { len = snprintf(dest, chleft, "%02d", tm->tm_mday); } break; /* %e: Like %d, the day of the month as a decimal number, but a leading * zero is replaced by a space. */ case 'e': { len = snprintf(dest, chleft, "%2d", tm->tm_mday); } break; /* %H: The hour as a decimal number using a 24-hour clock (range 00 to 23). */ case 'H': { len = snprintf(dest, chleft, "%02d", tm->tm_hour); } break; /* %I: The hour as a decimal number using a 12-hour clock (range 01 to 12). */ case 'I': { len = snprintf(dest, chleft, "%02d", tm->tm_hour % 12); } break; /* %j: The day of the year as a decimal number (range 001 to 366). */ case 'j': { if (tm->tm_mon < 12) { value = clock_daysbeforemonth(tm->tm_mon, clock_isleapyear(tm->tm_year)) + tm->tm_mday; len = snprintf(dest, chleft, "%03d", value); } } break; /* %k: The hour (24-hour clock) as a decimal number (range 0 to 23); * single digits are preceded by a blank. */ case 'k': { len = snprintf(dest, chleft, "%2d", tm->tm_hour); } break; /* %l: The hour (12-hour clock) as a decimal number (range 1 to 12); * single digits are preceded by a blank. */ case 'l': { len = snprintf(dest, chleft, "%2d", tm->tm_hour % 12); } break; /* %m: The month as a decimal number (range 01 to 12). */ case 'm': { len = snprintf(dest, chleft, "%02d", tm->tm_mon + 1); } break; /* %M: The minute as a decimal number (range 00 to 59). */ case 'M': { len = snprintf(dest, chleft, "%02d", tm->tm_min); } break; /* %n: A newline character. */ case 'n': { *dest = '\n'; len = 1; } break; /* %p: Either "AM" or "PM" according to the given time value. */ case 'p': { if (tm->tm_hour >= 12) { str = "PM"; } else { str = "AM"; } len = snprintf(dest, chleft, "%s", str); } break; /* %P: Like %p but in lowercase: "am" or "pm" */ case 'P': { if (tm->tm_hour >= 12) { str = "pm"; } else { str = "am"; } len = snprintf(dest, chleft, "%s", str); } break; /* %s: The number of seconds since the Epoch, that is, since 1970-01-01 * 00:00:00 UTC. Hmmm... mktime argume is not 'const'. */ case 's': { len = snprintf(dest, chleft, "%d", mktime((FAR struct tm *)tm)); } break; /* %S: The second as a decimal number (range 00 to 60). (The range is * up to 60 to allow for occasional leap seconds.) */ case 'S': { len = snprintf(dest, chleft, "%02d", tm->tm_sec); } break; /* %t: A tab character. */ case 't': { *dest = '\t'; len = 1; } break; /* %Y: The year as a decimal number including the century. */ case 'Y': { len = snprintf(dest, chleft, "%04d", tm->tm_year + 1900); } break; /* %%: A literal '%' character. */ case '%': { *dest = '%'; len = 1; } break; } /* Update counts and pointers */ dest += len; chleft -= len; } /* We get here because either we have reached the end of the format string * or because there is no more space in the user-provided buffer and the * resulting string has been truncated. * * Is there space remaining in the user-provided buffer for the NUL * terminator? */ if (chleft > 0) { /* Yes, append terminating NUL byte */ *dest = '\0'; /* And return the number of bytes in the resulting string (excluding * the NUL terminator). */ return max - chleft; } /* The string was truncated and/or not properly terminated. Return * zero. */ return 0; }