libc: minimal: provide gmtime implementation
Implement the conversion from UNIX time to broken-down civil time per the gmtime() and gmtime_r() functions. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
This commit is contained in:
parent
acc1703241
commit
3e8df8b369
3 changed files with 113 additions and 0 deletions
|
@ -17,4 +17,5 @@ zephyr_library_sources(
|
||||||
source/stdout/stdout_console.c
|
source/stdout/stdout_console.c
|
||||||
source/stdout/sprintf.c
|
source/stdout/sprintf.c
|
||||||
source/stdout/fprintf.c
|
source/stdout/fprintf.c
|
||||||
|
source/time/gmtime.c
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_TIME_H_
|
#define ZEPHYR_LIB_LIBC_MINIMAL_INCLUDE_TIME_H_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <bits/restrict.h>
|
||||||
|
|
||||||
/* Minimal time.h to fulfill the requirements of certain libraries
|
/* Minimal time.h to fulfill the requirements of certain libraries
|
||||||
* like mbedTLS and to support time APIs.
|
* like mbedTLS and to support time APIs.
|
||||||
|
@ -38,6 +39,15 @@ struct timespec {
|
||||||
long tv_nsec;
|
long tv_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Conversion between civil time and UNIX time. The companion
|
||||||
|
* localtime() and inverse mktime() are not provided here since they
|
||||||
|
* require access to time zone information.
|
||||||
|
*/
|
||||||
|
struct tm *gmtime(const time_t *timep);
|
||||||
|
struct tm *gmtime_r(const time_t *_MLIBC_RESTRICT timep,
|
||||||
|
struct tm *_MLIBC_RESTRICT result);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
102
lib/libc/minimal/source/time/gmtime.c
Normal file
102
lib/libc/minimal/source/time/gmtime.c
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Peter Bigot Consulting, LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The time_civil_from_days function is derived directly from public
|
||||||
|
* domain content written by Howard Hinnant and available at:
|
||||||
|
* http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* A signed type with the representation of time_t without its
|
||||||
|
* impliciations.
|
||||||
|
*/
|
||||||
|
typedef time_t bigint_type;
|
||||||
|
|
||||||
|
/** Convert a UNIX time to civil time.
|
||||||
|
*
|
||||||
|
* This converts integral seconds since (before) 1970-01-01T00:00:00
|
||||||
|
* to the POSIX standard civil time representation. Any adjustments
|
||||||
|
* due to time zone, leap seconds, or a different epoch must be
|
||||||
|
* applied to @p time before invoking this function.
|
||||||
|
*
|
||||||
|
* @param time the time represented as seconds.
|
||||||
|
*
|
||||||
|
* @return the time information for corresponding to the provided
|
||||||
|
* instant.
|
||||||
|
*
|
||||||
|
* @see http://howardhinnant.github.io/date_algorithms.html#civil_from_days
|
||||||
|
*/
|
||||||
|
static void time_civil_from_days(bigint_type z,
|
||||||
|
struct tm *_MLIBC_RESTRICT tp)
|
||||||
|
{
|
||||||
|
tp->tm_wday = (z >= -4) ? ((z + 4) % 7) : ((z + 5) % 7 + 6);
|
||||||
|
z += 719468;
|
||||||
|
|
||||||
|
bigint_type era = ((z >= 0) ? z : (z - 146096)) / 146097;
|
||||||
|
unsigned int doe = (z - era * (bigint_type)146097);
|
||||||
|
unsigned int yoe = (doe - doe / 1460U + doe / 36524U - doe / 146096U)
|
||||||
|
/ 365U;
|
||||||
|
bigint_type y = (time_t)yoe + era * 400;
|
||||||
|
unsigned int doy = doe - (365U * yoe + yoe / 4U - yoe / 100U);
|
||||||
|
unsigned int mp = (5U * doy + 2U) / 153U;
|
||||||
|
unsigned int d = doy - (153U * mp + 2U) / 5U + 1U;
|
||||||
|
unsigned int m = mp + ((mp < 10) ? 3 : -9);
|
||||||
|
|
||||||
|
tp->tm_year = y + (m <= 2) - 1900;
|
||||||
|
tp->tm_mon = m - 1;
|
||||||
|
tp->tm_mday = d;
|
||||||
|
|
||||||
|
/* Everything above is explained on the referenced page, but
|
||||||
|
* doy is relative to --03-01 and we need it relative to
|
||||||
|
* --01-01.
|
||||||
|
*
|
||||||
|
* doy=306 corresponds to --01-01, doy=364 to --02-28, and
|
||||||
|
* doy=365 to --02-29. So we can just subtract 306 to handle
|
||||||
|
* January and February.
|
||||||
|
*
|
||||||
|
* For doy<306 we have to add the number of days before
|
||||||
|
* --03-01, which is 59 in a common year and 60 in a leap
|
||||||
|
* year. Note that the first year in the era is a leap year.
|
||||||
|
*/
|
||||||
|
if (doy >= 306U) {
|
||||||
|
tp->tm_yday = doy - 306U;
|
||||||
|
} else {
|
||||||
|
tp->tm_yday = doy + 59U + (((yoe % 4U == 0U) && (yoe % 100U != 0U)) || (yoe == 0U));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a UNIX time to civil time.
|
||||||
|
*
|
||||||
|
* This converts integral seconds since (before) 1970-01-01T00:00:00
|
||||||
|
* to the POSIX standard civil time representation. Any adjustments
|
||||||
|
* due to time zone, leap seconds, or a different epoch must be
|
||||||
|
* applied to @p time before invoking this function.
|
||||||
|
*/
|
||||||
|
struct tm *gmtime_r(const time_t *_MLIBC_RESTRICT timep,
|
||||||
|
struct tm *_MLIBC_RESTRICT tp)
|
||||||
|
{
|
||||||
|
time_t z = *timep;
|
||||||
|
bigint_type days = (z >= 0 ? z : z - 86399) / 86400;
|
||||||
|
unsigned int rem = z - days * 86400;
|
||||||
|
|
||||||
|
time_civil_from_days(days, tp);
|
||||||
|
|
||||||
|
tp->tm_hour = rem / 60U / 60U;
|
||||||
|
rem -= tp->tm_hour * 60 * 60;
|
||||||
|
tp->tm_min = rem / 60;
|
||||||
|
tp->tm_sec = rem - tp->tm_min * 60;
|
||||||
|
|
||||||
|
return tp;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tm *gmtime(const time_t *timep)
|
||||||
|
{
|
||||||
|
static struct tm shared;
|
||||||
|
|
||||||
|
return gmtime_r(timep, &shared);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue