Skip to content

Commit 12c7543

Browse files
committed
libc: common: implement multiple time functions
Implemented the following: - `asctime_r()` - `asctime()` - `localtime()` - `localtime_r()` - `ctime()` - `ctime_r()` Specifically: - the implementation of `localtime()` & `localtime_r()` simply wraps around the gmtime() & gmtime_r() functions, the results are always expressed as UTC. - `ctime()` is equivalent to `asctime(localtime(clock))`, it inherits the limitation of `localtime()` as well, which only supports UTC results currently. Added tests for these newly implemented functions. Signed-off-by: Yong Cong Sin <ycsin@meta.com> Signed-off-by: Yong Cong Sin <yongcong.sin@gmail.com>
1 parent 7f7bba5 commit 12c7543

File tree

13 files changed

+256
-5
lines changed

13 files changed

+256
-5
lines changed

doc/services/portability/posix/option_groups/index.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,8 @@ Enable this option with :kconfig:option:`CONFIG_POSIX_THREAD_SAFE_FUNCTIONS`.
981981
:header: API, Supported
982982
:widths: 50,10
983983

984-
asctime_r(),
985-
ctime_r(),
984+
asctime_r(), yes
985+
ctime_r(), yes (UTC timezone only)
986986
flockfile(),
987987
ftrylockfile(),
988988
funlockfile(),
@@ -993,7 +993,7 @@ Enable this option with :kconfig:option:`CONFIG_POSIX_THREAD_SAFE_FUNCTIONS`.
993993
getpwnam_r(),yes :ref:`†<posix_undefined_behaviour>`
994994
getpwuid_r(),yes :ref:`†<posix_undefined_behaviour>`
995995
gmtime_r(), yes
996-
localtime_r(),
996+
localtime_r(), yes (UTC timezone only)
997997
putc_unlocked(),
998998
putchar_unlocked(),
999999
rand_r(), yes

lib/libc/common/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ zephyr_system_include_directories(include)
55
zephyr_library()
66
zephyr_library_property(ALLOW_EMPTY TRUE)
77
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ABORT source/stdlib/abort.c)
8+
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_ASCTIME source/time/asctime.c)
89
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_GMTIME_R source/time/gmtime_r.c)
10+
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_LOCALTIME_R_UTC source/time/localtime_r_utc.c)
11+
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_CTIME source/time/ctime.c)
912
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_TIME source/time/time.c)
1013
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_MALLOC source/stdlib/malloc.c)
1114
zephyr_library_sources_ifdef(CONFIG_COMMON_LIBC_STRNLEN source/string/strnlen.c)

lib/libc/common/Kconfig

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,44 @@ config COMMON_LIBC_ABORT
66
help
77
common implementation of abort().
88

9+
config COMMON_LIBC_ASCTIME
10+
bool
11+
help
12+
common implementation of asctime().
13+
14+
config COMMON_LIBC_ASCTIME_R
15+
bool "Thread-safe version of asctime()"
16+
default y if POSIX_THREAD_SAFE_FUNCTIONS
17+
select COMMON_LIBC_ASCTIME
18+
help
19+
common implementation of asctime_r().
20+
21+
config COMMON_LIBC_CTIME
22+
bool
23+
select COMMON_LIBC_LOCALTIME_R_UTC
24+
help
25+
common implementation of ctime().
26+
27+
config COMMON_LIBC_CTIME_R
28+
bool "Thread-safe version of ctime()"
29+
default y if POSIX_THREAD_SAFE_FUNCTIONS
30+
select COMMON_LIBC_CTIME
31+
help
32+
common implementation of ctime_r().
33+
934
config COMMON_LIBC_GMTIME_R
1035
bool
1136
help
1237
common implementation of gmtime_r().
1338

39+
config COMMON_LIBC_LOCALTIME_R_UTC
40+
bool
41+
select COMMON_LIBC_GMTIME_R
42+
help
43+
Simple implementation of localtime() & localtime_r().
44+
This option just wraps around the gmtime(), the result is always expressed as
45+
Coordinated Universal Time (UTC).
46+
1447
config COMMON_LIBC_TIME
1548
bool
1649
help

lib/libc/common/source/time/asctime.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright (c) 2024 Meta Platforms
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <time.h>
10+
11+
#include <zephyr/sys/util.h>
12+
13+
#define DATE_STRING_BUF_SZ 26U
14+
#define DATE_WDAY_STRING_SZ 7U
15+
#define DATE_MON_STRING_SZ 12U
16+
#define DATE_TM_YEAR_BASE 1900
17+
18+
static char *asctime_impl(const struct tm *tp, char *buf)
19+
{
20+
static const char wday_str[DATE_WDAY_STRING_SZ][3] = {
21+
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
22+
};
23+
static const char mon_str[DATE_MON_STRING_SZ][3] = {
24+
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
25+
};
26+
27+
if ((buf == NULL) || (tp == NULL) || ((unsigned int)tp->tm_wday >= DATE_WDAY_STRING_SZ) ||
28+
((unsigned int)tp->tm_mon >= DATE_MON_STRING_SZ)) {
29+
return NULL;
30+
}
31+
32+
unsigned int n = (unsigned int)snprintf(
33+
buf, DATE_STRING_BUF_SZ, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n", wday_str[tp->tm_wday],
34+
mon_str[tp->tm_mon], tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec,
35+
DATE_TM_YEAR_BASE + tp->tm_year);
36+
37+
if (n >= DATE_STRING_BUF_SZ) {
38+
return NULL;
39+
}
40+
41+
return buf;
42+
}
43+
44+
char *asctime(const struct tm *tp)
45+
{
46+
static char buf[DATE_STRING_BUF_SZ];
47+
48+
return asctime_impl(tp, buf);
49+
}
50+
51+
#if defined(CONFIG_COMMON_LIBC_ASCTIME_R)
52+
char *asctime_r(const struct tm *tp, char *buf)
53+
{
54+
return asctime_impl(tp, buf);
55+
}
56+
#endif /* CONFIG_COMMON_LIBC_ASCTIME_R */

lib/libc/common/source/time/ctime.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2024 Meta Platforms
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <time.h>
8+
9+
/**
10+
* `ctime()` is equivalent to `asctime(localtime(clock))`
11+
* See: https://pubs.opengroup.org/onlinepubs/009695399/functions/ctime.html
12+
*/
13+
14+
char *ctime(const time_t *clock)
15+
{
16+
return asctime(localtime(clock));
17+
}
18+
19+
#if defined(CONFIG_COMMON_LIBC_CTIME_R)
20+
char *ctime_r(const time_t *clock, char *buf)
21+
{
22+
struct tm tmp;
23+
24+
return asctime_r(localtime_r(clock, &tmp), buf);
25+
}
26+
#endif /* CONFIG_COMMON_LIBC_CTIME_R */
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) 2024 Meta Platforms
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <time.h>
8+
9+
struct tm *localtime_r(const time_t *timer, struct tm *result)
10+
{
11+
return gmtime_r(timer, result);
12+
}
13+
14+
struct tm *localtime(const time_t *timer)
15+
{
16+
return gmtime(timer);
17+
}

lib/libc/minimal/Kconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ config MINIMAL_LIBC_TIME
3939
bool "Time functions"
4040
select COMMON_LIBC_TIME if POSIX_TIMERS
4141
select COMMON_LIBC_GMTIME_R
42+
select COMMON_LIBC_ASCTIME
43+
select COMMON_LIBC_LOCALTIME_R_UTC
44+
select COMMON_LIBC_CTIME
4245
default y
4346
help
4447
Enable time() and gmtime_r() for the minimal libc.

lib/libc/minimal/include/time.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,22 @@ typedef _SUSECONDS_T_ suseconds_t;
4545

4646
/*
4747
* Conversion between civil time and UNIX time. The companion
48-
* localtime() and inverse mktime() are not provided here since they
48+
* mktime() is not provided here since it
4949
* require access to time zone information.
50+
*
51+
* The localtime() & localtime_r() simply
52+
* wraps around the gmtime() & gmtime_r() functions, the
53+
* results are always expressed as UTC.
5054
*/
5155
struct tm *gmtime(const time_t *timep);
5256
struct tm *gmtime_r(const time_t *ZRESTRICT timep,
5357
struct tm *ZRESTRICT result);
58+
char *asctime(const struct tm *timeptr);
59+
struct tm *localtime(const time_t *timer);
60+
char *ctime(const time_t *clock);
61+
char *asctime_r(const struct tm *ZRESTRICT tp, char *ZRESTRICT buf);
62+
char *ctime_r(const time_t *clock, char *buf);
63+
struct tm *localtime_r(const time_t *ZRESTRICT timer, struct tm *ZRESTRICT result);
5464

5565
time_t time(time_t *tloc);
5666

lib/posix/options/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ rsource "Kconfig.profile"
1010

1111
rsource "Kconfig.aio"
1212
rsource "Kconfig.barrier"
13+
rsource "Kconfig.c_lang_r"
1314
rsource "Kconfig.c_lib_ext"
1415
rsource "Kconfig.device_io"
1516
rsource "Kconfig.fd_mgmt"

lib/posix/options/Kconfig.c_lang_r

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Copyright (c) 2024 Tenstorrent AI ULC
2+
# Copyright (c) 2024 Meta Platforms
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config POSIX_C_LANG_SUPPORT_R
7+
bool "Thread-Safe General ISO C Library"
8+
select COMMON_LIBC_ASCTIME_R
9+
select COMMON_LIBC_CTIME_R
10+
select COMMON_LIBC_GMTIME_R
11+
select COMMON_LIBC_LOCALTIME_R_UTC
12+
help
13+
Select 'y' here and Zephyr will provide an implementation of the POSIX_C_LANG_SUPPORT_R
14+
Option Group, consisting of asctime_r(), ctime_r(), gmtime_r(), localtime_r(), rand_r(),
15+
strerror_r(), and strtok_r()
16+
17+
For more informnation, please see
18+
https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_subprofiles.html

0 commit comments

Comments
 (0)