libs/libc/time: mktime normalize struct tm
Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
This commit is contained in:
parent
fd07e7b012
commit
fdff92fd19
8 changed files with 211 additions and 74 deletions
|
|
@ -39,16 +39,51 @@
|
|||
#ifndef CONFIG_GREGORIAN_TIME
|
||||
# undef CONFIG_JULIAN_TIME
|
||||
#else
|
||||
# define JD_OF_EPOCH 2440588 /* Julian Date of noon, J1970 */
|
||||
# define JD_OF_EPOCH 2440588 /* Julian Date of noon, J1970 */
|
||||
|
||||
# ifdef CONFIG_JULIAN_TIME
|
||||
# define GREG_DUTC -141427 /* Default is October 15, 1582 */
|
||||
# define GREG_YEAR 1582
|
||||
# define GREG_MONTH 10
|
||||
# define GREG_DAY 15
|
||||
# define GREG_DUTC -141427 /* Default is October 15, 1582 */
|
||||
# define GREG_YEAR 1582
|
||||
# define GREG_MONTH 10
|
||||
# define GREG_DAY 15
|
||||
# endif /* CONFIG_JULIAN_TIME */
|
||||
#endif /* !CONFIG_GREGORIAN_TIME */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define TM_WDAY_BASE TM_MONDAY
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <nuttx/time.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
|
|
@ -75,7 +76,7 @@ FAR char *asctime_r(FAR const struct tm *tp, FAR char *buf)
|
|||
snprintf(tmp, sizeof(tmp), "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
|
||||
g_wday_name[tp->tm_wday], g_mon_name[tp->tm_mon],
|
||||
tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec,
|
||||
1900 + tp->tm_year);
|
||||
TM_YEAR_BASE + tp->tm_year);
|
||||
strlcpy(buf, tmp, 26);
|
||||
|
||||
return buf;
|
||||
|
|
|
|||
|
|
@ -95,13 +95,13 @@ time_t clock_calendar2utc(int year, int month, int day)
|
|||
|
||||
/* Correct year & month ranges. Shift month into range 1-12 */
|
||||
|
||||
dyear = (month - 1) / 12;
|
||||
month -= 12 * dyear;
|
||||
dyear = (month - 1) / MONSPERYEAR;
|
||||
month -= MONSPERYEAR * dyear;
|
||||
year += dyear;
|
||||
|
||||
if (month < 1)
|
||||
{
|
||||
month += 12;
|
||||
month += MONSPERYEAR;
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
|
|
@ -158,11 +158,11 @@ time_t clock_calendar2utc(int year, int month, int day)
|
|||
|
||||
/* Years since epoch in units of days (ignoring leap years). */
|
||||
|
||||
days = (year - 1970) * 365;
|
||||
days = (year - EPOCH_YEAR) * DAYSPERNYEAR;
|
||||
|
||||
/* Add in the extra days for the leap years prior to the current year. */
|
||||
|
||||
days += (year - 1969) >> 2;
|
||||
days += (year - EPOCH_YEAR - 1) >> 2;
|
||||
|
||||
/* Add in the days up to the beginning of this month. */
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@
|
|||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
|
|
@ -161,20 +160,20 @@ static void clock_utc2calendar(time_t days, FAR int *year, FAR int *month,
|
|||
* 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 */
|
||||
value = days / (4 * DAYSPERNYEAR + 1); /* Number of 4-years periods since the epoch */
|
||||
days -= value * (4 * DAYSPERNYEAR + 1); /* Remaining days */
|
||||
value <<= 2; /* Years since the epoch */
|
||||
|
||||
/* Then we will brute force the next 0-3 years
|
||||
*
|
||||
* Is this year a leap year? (we'll need this later too)
|
||||
*/
|
||||
|
||||
leapyear = clock_isleapyear(value + 1970);
|
||||
leapyear = clock_isleapyear(value + EPOCH_YEAR);
|
||||
|
||||
/* Get the number of days in the year */
|
||||
|
||||
tmp = (leapyear ? 366 : 365);
|
||||
tmp = (leapyear ? DAYSPERLYEAR : DAYSPERNYEAR);
|
||||
|
||||
/* Do we have that many days left to account for? */
|
||||
|
||||
|
|
@ -187,11 +186,11 @@ static void clock_utc2calendar(time_t days, FAR int *year, FAR int *month,
|
|||
|
||||
/* Is the next year a leap year? */
|
||||
|
||||
leapyear = clock_isleapyear(value + 1970);
|
||||
leapyear = clock_isleapyear(value + EPOCH_YEAR);
|
||||
|
||||
/* Get the number of days in the next year */
|
||||
|
||||
tmp = (leapyear ? 366 : 365);
|
||||
tmp = (leapyear ? DAYSPERLYEAR : DAYSPERNYEAR);
|
||||
}
|
||||
|
||||
/* At this point, 'value' has the years since 1970 and 'days' has number
|
||||
|
|
@ -199,7 +198,7 @@ static void clock_utc2calendar(time_t days, FAR int *year, FAR int *month,
|
|||
* a leap year.
|
||||
*/
|
||||
|
||||
*year = 1970 + value;
|
||||
*year = EPOCH_YEAR + value;
|
||||
|
||||
/* Handle the month (zero based) */
|
||||
|
||||
|
|
@ -314,24 +313,22 @@ FAR struct tm *gmtime_r(FAR const time_t *timep, FAR struct tm *result)
|
|||
|
||||
sec = epoch;
|
||||
|
||||
linfo("hour=%d min=%d sec=%d\n",
|
||||
(int)hour, (int)min, (int)sec);
|
||||
linfo("hour=%d min=%d sec=%d\n", hour, min, sec);
|
||||
|
||||
/* Convert the days since the EPOCH to calendar day */
|
||||
|
||||
clock_utc2calendar(jdn, &year, &month, &day);
|
||||
|
||||
linfo("jdn=%d year=%d month=%d day=%d\n",
|
||||
(int)jdn, (int)year, (int)month, (int)day);
|
||||
linfo("jdn=%d year=%d month=%d day=%d\n", (int)jdn, year, month, 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;
|
||||
result->tm_year = year - TM_YEAR_BASE; /* Relative to 1900 */
|
||||
result->tm_mon = month - 1; /* zero-based */
|
||||
result->tm_mday = day; /* one-based */
|
||||
result->tm_hour = hour;
|
||||
result->tm_min = min;
|
||||
result->tm_sec = sec;
|
||||
|
||||
result->tm_wday = clock_dayoftheweek(day, month, year);
|
||||
result->tm_yday = day - 1 +
|
||||
|
|
|
|||
|
|
@ -52,13 +52,13 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <nuttx/time.h>
|
||||
#include <nuttx/init.h>
|
||||
#include <nuttx/fs/fs.h>
|
||||
#include <nuttx/mutex.h>
|
||||
|
|
@ -94,42 +94,8 @@
|
|||
#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
|
||||
#define SECSPERMIN 60
|
||||
#define MINSPERHOUR 60
|
||||
#define HOURSPERDAY 24
|
||||
#define DAYSPERWEEK 7
|
||||
#define DAYSPERNYEAR 365
|
||||
#define DAYSPERLYEAR 366
|
||||
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
|
||||
#define SECSPERDAY ((int_fast32_t)SECSPERHOUR * HOURSPERDAY)
|
||||
#define MONSPERYEAR 12
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define TM_WDAY_BASE TM_MONDAY
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
#define EPOCH_WDAY TM_THURSDAY
|
||||
|
||||
#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
|
||||
|
||||
|
|
@ -2488,7 +2454,7 @@ static time_t time2sub(FAR struct tm *tmp,
|
|||
t = hi;
|
||||
}
|
||||
|
||||
if ((*funcp) (&t, offset, &mytm) == NULL)
|
||||
if ((*funcp)(&t, offset, &mytm) == NULL)
|
||||
{
|
||||
/* Assume that t is too extreme to be represented in
|
||||
* a struct tm; arrange things so that it is less
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/time.h>
|
||||
|
|
@ -384,8 +383,8 @@ size_t strftime(FAR char *s, size_t max, FAR const char *format,
|
|||
|
||||
case 's':
|
||||
{
|
||||
len = snprintf(dest, chleft, "%ju",
|
||||
(uintmax_t)mktime((FAR struct tm *)tm));
|
||||
struct tm tmp = *tm;
|
||||
len = snprintf(dest, chleft, "%ju", (uintmax_t)mktime(&tmp));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -439,7 +438,8 @@ size_t strftime(FAR char *s, size_t max, FAR const char *format,
|
|||
|
||||
case 'Y':
|
||||
{
|
||||
len = snprintf(dest, chleft, "%04d", tm->tm_year + 1900);
|
||||
len = snprintf(dest, chleft, "%04d",
|
||||
tm->tm_year + TM_YEAR_BASE);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@
|
|||
#include <ctype.h>
|
||||
#include <locale.h>
|
||||
#include <strings.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <nuttx/time.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define _ctloc(x) (g_defaulttimelocale.x)
|
||||
|
||||
/* We do not implement alternate representations. However, we always
|
||||
|
|
|
|||
|
|
@ -53,10 +53,143 @@
|
|||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const int g_mon_lengths[2][MONSPERYEAR] =
|
||||
{
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static void adjust(FAR int *tenx, FAR int *x, int base)
|
||||
{
|
||||
while (*x < 0)
|
||||
{
|
||||
*x += base;
|
||||
(*tenx)--;
|
||||
}
|
||||
|
||||
while (*x > (base - 1))
|
||||
{
|
||||
*x -= base;
|
||||
(*tenx)++;
|
||||
}
|
||||
}
|
||||
|
||||
static void normalize(FAR struct tm *tm)
|
||||
{
|
||||
bool leapyear = false;
|
||||
int year;
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
/* Adjust mon field */
|
||||
|
||||
adjust(&tm->tm_year, &tm->tm_mon, MONSPERYEAR);
|
||||
|
||||
/* Get an absolute year */
|
||||
|
||||
year = tm->tm_year + TM_YEAR_BASE;
|
||||
|
||||
/* Is this a leap year? */
|
||||
|
||||
leapyear = clock_isleapyear(year);
|
||||
|
||||
/* Adjust mday field */
|
||||
|
||||
while (tm->tm_mday < 1)
|
||||
{
|
||||
tm->tm_mon--;
|
||||
if (tm->tm_mon < 0)
|
||||
{
|
||||
tm->tm_mday += g_mon_lengths[leapyear][TM_DECEMBER];
|
||||
break;
|
||||
}
|
||||
|
||||
tm->tm_mday += g_mon_lengths[leapyear][tm->tm_mon];
|
||||
}
|
||||
|
||||
if (tm->tm_mon < 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while (tm->tm_mday > g_mon_lengths[leapyear][tm->tm_mon])
|
||||
{
|
||||
tm->tm_mday -= g_mon_lengths[leapyear][tm->tm_mon];
|
||||
tm->tm_mon++;
|
||||
if (tm->tm_mon > (MONSPERYEAR - 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tm->tm_mon > (MONSPERYEAR - 1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Adjust seconds field */
|
||||
|
||||
adjust(&tm->tm_min, &tm->tm_sec, SECSPERMIN);
|
||||
|
||||
/* Adjust minutes field */
|
||||
|
||||
adjust(&tm->tm_hour, &tm->tm_min, MINSPERHOUR);
|
||||
|
||||
/* Adjust hours field */
|
||||
|
||||
while (tm->tm_hour < 0)
|
||||
{
|
||||
tm->tm_hour += HOURSPERDAY;
|
||||
tm->tm_mday--;
|
||||
|
||||
if (tm->tm_mday < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tm->tm_mday < 1)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
while (tm->tm_hour > (HOURSPERDAY - 1))
|
||||
{
|
||||
tm->tm_hour -= HOURSPERDAY;
|
||||
tm->tm_mday++;
|
||||
|
||||
if (tm->tm_mday > g_mon_lengths[leapyear][tm->tm_mon])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tm->tm_mday > g_mon_lengths[leapyear][tm->tm_mon])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update the years field */
|
||||
|
||||
tm->tm_year = year - TM_YEAR_BASE;
|
||||
|
||||
/* Determine the day of the year; -1 because the mday is 1-indexed */
|
||||
|
||||
tm->tm_yday = tm->tm_mday - 1 + clock_daysbeforemonth(tm->tm_mon,
|
||||
leapyear);
|
||||
|
||||
/* Finally calculate the weekday */
|
||||
|
||||
tm->tm_wday = clock_dayoftheweek(tm->tm_mday, tm->tm_mon + 1, year);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
|
@ -74,11 +207,16 @@ time_t timegm(FAR struct tm *tp)
|
|||
time_t ret;
|
||||
time_t jdn;
|
||||
|
||||
/* Normalize struct tm */
|
||||
|
||||
normalize(tp);
|
||||
|
||||
/* Get the EPOCH-relative julian date from the calendar year,
|
||||
* month, and date
|
||||
*/
|
||||
|
||||
jdn = clock_calendar2utc(tp->tm_year + 1900, tp->tm_mon, tp->tm_mday);
|
||||
jdn = clock_calendar2utc(tp->tm_year + TM_YEAR_BASE, tp->tm_mon,
|
||||
tp->tm_mday);
|
||||
linfo("jdn=%d tm_year=%d tm_mon=%d tm_mday=%d\n",
|
||||
(int)jdn, tp->tm_year, tp->tm_mon, tp->tm_mday);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue