136 lines
2.9 KiB
C
136 lines
2.9 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <time.h>
|
|
|
|
/*
|
|
* asctime/ctime: the fixed-format "Www Mmm dd hh:mm:ss yyyy\n" rendering
|
|
* (26 bytes including the terminating NUL). Both functions are thin layers
|
|
* over a single buffer writer: asctime renders a broken-down time directly,
|
|
* ctime renders localtime(t). Per POSIX the conversion fails (NULL) when
|
|
* the calendar year lies outside [1000, 9999], which is also what keeps the
|
|
* fixed 26-byte layout exact.
|
|
*/
|
|
|
|
static const char *const wd_abbr[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
|
static const char *const mon_abbr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
|
|
/*
|
|
* Render tm into buf (26 bytes: 24 + '\n' + '\0'). Returns buf, or NULL
|
|
* when the year is outside the representable range (the buffer is then
|
|
* left untouched, matching the POSIX contract).
|
|
*/
|
|
static char *
|
|
asctime_write(const struct tm *tm, char *buf)
|
|
{
|
|
int year = tm->tm_year + 1900;
|
|
int wd = tm->tm_wday;
|
|
int mo = tm->tm_mon;
|
|
int mday = tm->tm_mday;
|
|
const char *s;
|
|
char *p = buf;
|
|
|
|
if (year < 1000 || year > 9999)
|
|
{
|
|
return NULL;
|
|
}
|
|
if (wd < 0)
|
|
{
|
|
wd = 7 - (-wd) % 7;
|
|
if (wd == 7)
|
|
{
|
|
wd = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wd %= 7;
|
|
}
|
|
if (mo < 0)
|
|
{
|
|
mo = 12 - (-mo) % 12;
|
|
if (mo == 12)
|
|
{
|
|
mo = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mo %= 12;
|
|
}
|
|
|
|
s = wd_abbr[wd];
|
|
while (*s != '\0')
|
|
{
|
|
*p++ = *s++;
|
|
}
|
|
*p++ = ' ';
|
|
s = mon_abbr[mo];
|
|
while (*s != '\0')
|
|
{
|
|
*p++ = *s++;
|
|
}
|
|
*p++ = ' ';
|
|
if (mday < 10)
|
|
{
|
|
*p++ = ' ';
|
|
}
|
|
*p++ = (char)('0' + (mday / 10) % 10);
|
|
*p++ = (char)('0' + mday % 10);
|
|
*p++ = ' ';
|
|
*p++ = (char)('0' + (tm->tm_hour / 10) % 10);
|
|
*p++ = (char)('0' + tm->tm_hour % 10);
|
|
*p++ = ':';
|
|
*p++ = (char)('0' + (tm->tm_min / 10) % 10);
|
|
*p++ = (char)('0' + tm->tm_min % 10);
|
|
*p++ = ':';
|
|
*p++ = (char)('0' + (tm->tm_sec / 10) % 10);
|
|
*p++ = (char)('0' + tm->tm_sec % 10);
|
|
*p++ = ' ';
|
|
*p++ = (char)('0' + (year / 1000) % 10);
|
|
*p++ = (char)('0' + (year / 100) % 10);
|
|
*p++ = (char)('0' + (year / 10) % 10);
|
|
*p++ = (char)('0' + year % 10);
|
|
*p++ = '\n';
|
|
*p = '\0';
|
|
return buf;
|
|
}
|
|
|
|
char *
|
|
asctime(const struct tm *tm) // NOLINT(concurrency-mt-unsafe)
|
|
{
|
|
static char asctime_buf[26];
|
|
|
|
return asctime_write(tm, asctime_buf);
|
|
}
|
|
|
|
char *
|
|
ctime(const time_t *timer)
|
|
{
|
|
return asctime(localtime(timer));
|
|
}
|
|
|
|
#if VLIBC_LEVEL_GE(2)
|
|
|
|
char *
|
|
asctime_r(const struct tm *tm, char *buf)
|
|
{
|
|
return asctime_write(tm, buf);
|
|
}
|
|
|
|
char *
|
|
ctime_r(const time_t *timer, char *buf)
|
|
{
|
|
struct tm tmv;
|
|
|
|
if (localtime_r(timer, &tmv) == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
return asctime_write(&tmv, buf);
|
|
}
|
|
|
|
#endif /* VLIBC_LEVEL_GE(2) */
|