[clang] [clang-tools-extra] [libc] [libc][c11] implement ctime (PR #107285)

Зишан Мирза via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 6 09:49:59 PDT 2024


https://github.com/zimirza updated https://github.com/llvm/llvm-project/pull/107285

>From b982621407a1ab1746a023809aae5c6a2b983679 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Tue, 3 Sep 2024 22:47:30 +0200
Subject: [PATCH 01/42] [libc][c11] implement ctime (#86567)

---
 libc/src/time/CMakeLists.txt      |  11 ++
 libc/src/time/ctime.cpp           |  23 ++++
 libc/src/time/ctime.h             |  21 +++
 libc/src/time/time_utils.h        |  46 +++++++
 libc/test/src/time/ctime_test.cpp | 215 ++++++++++++++++++++++++++++++
 5 files changed, 316 insertions(+)
 create mode 100644 libc/src/time/ctime.cpp
 create mode 100644 libc/src/time/ctime.h
 create mode 100644 libc/test/src/time/ctime_test.cpp

diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 5680718715974e..befe67677f3ec7 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -36,6 +36,17 @@ add_entrypoint_object(
     libc.include.time
 )
 
+add_entrypoint_object(
+  ctime
+  SRCS
+    ctime.cpp
+  HDRS
+    ctime.h
+  DEPENDS
+    .time_utils
+    libc.include.time
+)
+
 add_entrypoint_object(
   difftime
   SRCS
diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
new file mode 100644
index 00000000000000..f3181816ad9ab1
--- /dev/null
+++ b/libc/src/time/ctime.cpp
@@ -0,0 +1,23 @@
+//===-- Implementation of asctime function --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/time/ctime.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/time/time_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+LLVM_LIBC_FUNCTION(char *, ctime, (const struct tm *timeptr)) {
+  static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+  return time_utils::ctime(timeptr, buffer, TimeConstants::CTIME_MAX_BYTES);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
new file mode 100644
index 00000000000000..ec5530ffb5bc71
--- /dev/null
+++ b/libc/src/time/ctime.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of ctime ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_CTIME_H
+#define LLVM_LIBC_SRC_TIME_CTIME_H
+
+#include "src/__support/macros/config.h"
+#include <time.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *ctime(const struct tm *timeptr);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_CTIME_H
diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 47f55f7d389122..6fa590fefac8d0 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -62,6 +62,9 @@ struct TimeConstants {
   static constexpr int ASCTIME_BUFFER_SIZE = 256;
   static constexpr int ASCTIME_MAX_BYTES = 26;
 
+  static constexpr int CTIME_BUFFER_SIZE = 256;
+  static constexpr int CTIME_MAX_BYTES = 26;
+
   /* 2000-03-01 (mod 400 year, immediately after feb29 */
   static constexpr int64_t SECONDS_UNTIL2000_MARCH_FIRST =
       (946684800LL + SECONDS_PER_DAY * (31 + 29));
@@ -145,6 +148,49 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
   return buffer;
 }
 
+LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer,
+                        size_t bufferLength) {
+  if (timeptr == nullptr || buffer == nullptr) {
+    invalid_value();
+    return nullptr;
+  }
+  if (timeptr->tm_wday < 0 ||
+      timeptr->tm_wday > (TimeConstants::DAYS_PER_WEEK - 1)) {
+    invalid_value();
+    return nullptr;
+  }
+  if (timeptr->tm_mon < 0 ||
+      timeptr->tm_mon > (TimeConstants::MONTHS_PER_YEAR - 1)) {
+    invalid_value();
+    return nullptr;
+  }
+
+  // TODO(rtenneti): i18n the following strings.
+  static const char *week_days_name[TimeConstants::DAYS_PER_WEEK] = {
+      "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+  static const char *months_name[TimeConstants::MONTHS_PER_YEAR] = {
+      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+  // TODO(michaelr): look into removing this call to __builtin_snprintf that may
+  // be emitted as a call to snprintf. Alternatively, look into using our
+  // internal printf machinery.
+  int written_size = __builtin_snprintf(
+      buffer, bufferLength, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+      week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
+      timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
+      TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
+  if (written_size < 0)
+    return nullptr;
+  if (static_cast<size_t>(written_size) >= bufferLength) {
+    out_of_range();
+    return nullptr;
+  }
+  return buffer;
+}
+
+
 LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
   int64_t seconds = *timer;
   // Update the tm structure's year, month, day, etc. from seconds.
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
new file mode 100644
index 00000000000000..bbf915188eacee
--- /dev/null
+++ b/libc/test/src/time/ctime_test.cpp
@@ -0,0 +1,215 @@
+//===-- Unittests for ctime ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// make check-libc LIBC_TEST_TARGET=call_ctime VERBOSE=1
+#include "src/errno/libc_errno.h"
+#include "src/time/ctime.h"
+#include "test/UnitTest/Test.h"
+#include "test/src/time/TmHelper.h"
+
+static inline char *call_ctime(struct tm *tm_data, int year, int month,
+                               int mday, int hour, int min, int sec, int wday,
+                               int yday) {
+  LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
+      tm_data, year, month, mday, hour, min, sec, wday, yday);
+  return LIBC_NAMESPACE::ctime(tm_data);
+}
+
+TEST(LlvmLibcCtime, Nullptr) {
+  char *result;
+  result = LIBC_NAMESPACE::ctime(nullptr);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+}
+
+// Weekdays are in the range 0 to 6. Test passing invalid value in wday.
+TEST(LlvmLibcCtime, InvalidWday) {
+  struct tm tm_data;
+
+  // Test with wday = -1.
+  call_ctime(&tm_data,
+             1970, // year
+             1,    // month
+             1,    // day
+             0,    // hr
+             0,    // min
+             0,    // sec
+             -1,   // wday
+             0);   // yday
+  ASSERT_ERRNO_EQ(EINVAL);
+
+  // Test with wday = 7.
+  call_ctime(&tm_data,
+             1970, // year
+             1,    // month
+             1,    // day
+             0,    // hr
+             0,    // min
+             0,    // sec
+             7,    // wday
+             0);   // yday
+  ASSERT_ERRNO_EQ(EINVAL);
+}
+
+// Months are from January to December. Test passing invalid value in month.
+TEST(LlvmLibcCtime, InvalidMonth) {
+  struct tm tm_data;
+
+  // Test with month = 0.
+  call_ctime(&tm_data,
+             1970, // year
+             0,    // month
+             1,    // day
+             0,    // hr
+             0,    // min
+             0,    // sec
+             4,    // wday
+             0);   // yday
+  ASSERT_ERRNO_EQ(EINVAL);
+
+  // Test with month = 13.
+  call_ctime(&tm_data,
+             1970, // year
+             13,   // month
+             1,    // day
+             0,    // hr
+             0,    // min
+             0,    // sec
+             4,    // wday
+             0);   // yday
+  ASSERT_ERRNO_EQ(EINVAL);
+}
+
+TEST(LlvmLibcCtime, ValidWeekdays) {
+  struct tm tm_data;
+  char *result;
+  // 1970-01-01 00:00:00.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      1,    // month
+                      1,    // day
+                      0,    // hr
+                      0,    // min
+                      0,    // sec
+                      4,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
+
+  // 1970-01-03 00:00:00.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      1,    // month
+                      3,    // day
+                      0,    // hr
+                      0,    // min
+                      0,    // sec
+                      6,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Sat Jan  3 00:00:00 1970\n", result);
+
+  // 1970-01-04 00:00:00.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      1,    // month
+                      4,    // day
+                      0,    // hr
+                      0,    // min
+                      0,    // sec
+                      0,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Sun Jan  4 00:00:00 1970\n", result);
+}
+
+TEST(LlvmLibcCtime, ValidMonths) {
+  struct tm tm_data;
+  char *result;
+  // 1970-01-01 00:00:00.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      1,    // month
+                      1,    // day
+                      0,    // hr
+                      0,    // min
+                      0,    // sec
+                      4,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
+
+  // 1970-02-01 00:00:00.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      2,    // month
+                      1,    // day
+                      0,    // hr
+                      0,    // min
+                      0,    // sec
+                      0,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Sun Feb  1 00:00:00 1970\n", result);
+
+  // 1970-12-31 23:59:59.
+  result = call_ctime(&tm_data,
+                      1970, // year
+                      12,   // month
+                      31,   // day
+                      23,   // hr
+                      59,   // min
+                      59,   // sec
+                      4,    // wday
+                      0);   // yday
+  ASSERT_STREQ("Thu Dec 31 23:59:59 1970\n", result);
+}
+
+TEST(LlvmLibcCtime, EndOf32BitEpochYear) {
+  struct tm tm_data;
+  char *result;
+  // Test for maximum value of a signed 32-bit integer.
+  // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
+  result = call_ctime(&tm_data,
+                      2038, // year
+                      1,    // month
+                      19,   // day
+                      3,    // hr
+                      14,   // min
+                      7,    // sec
+                      2,    // wday
+                      7);   // yday
+  ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
+}
+
+TEST(LlvmLibcCtime, Max64BitYear) {
+  if (sizeof(time_t) == 4)
+    return;
+  // Mon Jan 1 12:50:50 2170 (200 years from 1970),
+  struct tm tm_data;
+  char *result;
+  result = call_ctime(&tm_data,
+                      2170, // year
+                      1,    // month
+                      1,    // day
+                      12,   // hr
+                      50,   // min
+                      50,   // sec
+                      1,    // wday
+                      50);  // yday
+  ASSERT_STREQ("Mon Jan  1 12:50:50 2170\n", result);
+
+  // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
+  // This test would cause buffer overflow and thus asctime returns nullptr.
+  result = call_ctime(&tm_data,
+                      2147483647, // year
+                      1,          // month
+                      1,          // day
+                      12,         // hr
+                      50,         // min
+                      50,         // sec
+                      2,          // wday
+                      50);        // yday
+  ASSERT_ERRNO_EQ(EOVERFLOW);
+  ASSERT_STREQ(nullptr, result);
+}

>From bbbd2a9ca60d1e492b5f0c7cb909770e6d504703 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 18:51:34 +0200
Subject: [PATCH 02/42] [libc][c11] implement ctime

remove buffer length
---
 libc/src/time/time_utils.h | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 6fa590fefac8d0..6b2480bc1c0fb0 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -148,8 +148,7 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
   return buffer;
 }
 
-LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer,
-                        size_t bufferLength) {
+LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer) {
   if (timeptr == nullptr || buffer == nullptr) {
     invalid_value();
     return nullptr;
@@ -177,13 +176,13 @@ LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer,
   // be emitted as a call to snprintf. Alternatively, look into using our
   // internal printf machinery.
   int written_size = __builtin_snprintf(
-      buffer, bufferLength, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+      buffer, strlen(buffer), "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
       week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
       timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
       TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
   if (written_size < 0)
     return nullptr;
-  if (static_cast<size_t>(written_size) >= bufferLength) {
+  if (static_cast<size_t>(written_size) >= strlen(buffer)) {
     out_of_range();
     return nullptr;
   }

>From e146ac1516944cad0c2e419dd7868b854fb93778 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 19:11:37 +0200
Subject: [PATCH 03/42] [libc][c11] implement ctime

fix: buffer length
---
 libc/src/time/time_utils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 6b2480bc1c0fb0..2386d149072475 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -176,7 +176,7 @@ LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer) {
   // be emitted as a call to snprintf. Alternatively, look into using our
   // internal printf machinery.
   int written_size = __builtin_snprintf(
-      buffer, strlen(buffer), "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+      buffer, strlen(buffer)+32, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
       week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
       timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
       TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);

>From eb02ef75d5fcec26900d40701c96d0a27abd041c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 19:27:58 +0200
Subject: [PATCH 04/42] [libc][c11] implement ctime

add buffer length
---
 libc/src/time/time_utils.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 2386d149072475..c4c8b771f865fc 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -148,7 +148,7 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
   return buffer;
 }
 
-LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer) {
+LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer, size_t buffer_length) {
   if (timeptr == nullptr || buffer == nullptr) {
     invalid_value();
     return nullptr;
@@ -176,13 +176,13 @@ LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer) {
   // be emitted as a call to snprintf. Alternatively, look into using our
   // internal printf machinery.
   int written_size = __builtin_snprintf(
-      buffer, strlen(buffer)+32, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
+      buffer, buffer_length, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
       week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
       timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
       TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
   if (written_size < 0)
     return nullptr;
-  if (static_cast<size_t>(written_size) >= strlen(buffer)) {
+  if (static_cast<size_t>(written_size) >= buffer_length) {
     out_of_range();
     return nullptr;
   }

>From 12adb50dc09d9d500ffad40dc58e2a6d94e7073c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 19:43:41 +0200
Subject: [PATCH 05/42] [libc][c11] implement ctime

fix: ctime implementation
---
 libc/src/time/time_utils.h | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index c4c8b771f865fc..4cf32ee64cec11 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -148,11 +148,14 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
   return buffer;
 }
 
-LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer, size_t buffer_length) {
-  if (timeptr == nullptr || buffer == nullptr) {
+LIBC_INLINE char *ctime(const time_t *t_ptr, char *buffer,
+                        size_t buffer_length) {
+  if (t_ptr == nullptr || buffer == nullptr) {
     invalid_value();
     return nullptr;
   }
+  const struct tm *timeptr;
+  timeptr = localtime(t_ptr);
   if (timeptr->tm_wday < 0 ||
       timeptr->tm_wday > (TimeConstants::DAYS_PER_WEEK - 1)) {
     invalid_value();
@@ -189,7 +192,6 @@ LIBC_INLINE char *ctime(const struct tm *timeptr, char *buffer, size_t buffer_le
   return buffer;
 }
 
-
 LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
   int64_t seconds = *timer;
   // Update the tm structure's year, month, day, etc. from seconds.

>From b10a47054c26a047e524a424badde2aeb894483b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 19:55:59 +0200
Subject: [PATCH 06/42] [libc][c11] implement ctime

fix: tests
---
 libc/test/src/time/ctime_test.cpp | 46 +++++++++++++++----------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index bbf915188eacee..bcc4fe16f795b2 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -12,12 +12,12 @@
 #include "test/UnitTest/Test.h"
 #include "test/src/time/TmHelper.h"
 
-static inline char *call_ctime(struct tm *tm_data, int year, int month,
+static inline char *call_ctime(struct time_t *t, int year, int month,
                                int mday, int hour, int min, int sec, int wday,
                                int yday) {
   LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
-      tm_data, year, month, mday, hour, min, sec, wday, yday);
-  return LIBC_NAMESPACE::ctime(tm_data);
+      localtime(t), year, month, mday, hour, min, sec, wday, yday);
+  return LIBC_NAMESPACE::ctime(t);
 }
 
 TEST(LlvmLibcCtime, Nullptr) {
@@ -29,10 +29,10 @@ TEST(LlvmLibcCtime, Nullptr) {
 
 // Weekdays are in the range 0 to 6. Test passing invalid value in wday.
 TEST(LlvmLibcCtime, InvalidWday) {
-  struct tm tm_data;
+  struct time_t t;
 
   // Test with wday = -1.
-  call_ctime(&tm_data,
+  call_ctime(&t,
              1970, // year
              1,    // month
              1,    // day
@@ -44,7 +44,7 @@ TEST(LlvmLibcCtime, InvalidWday) {
   ASSERT_ERRNO_EQ(EINVAL);
 
   // Test with wday = 7.
-  call_ctime(&tm_data,
+  call_ctime(&t,
              1970, // year
              1,    // month
              1,    // day
@@ -58,10 +58,10 @@ TEST(LlvmLibcCtime, InvalidWday) {
 
 // Months are from January to December. Test passing invalid value in month.
 TEST(LlvmLibcCtime, InvalidMonth) {
-  struct tm tm_data;
+  struct time_t t;
 
   // Test with month = 0.
-  call_ctime(&tm_data,
+  call_ctime(&t,
              1970, // year
              0,    // month
              1,    // day
@@ -73,7 +73,7 @@ TEST(LlvmLibcCtime, InvalidMonth) {
   ASSERT_ERRNO_EQ(EINVAL);
 
   // Test with month = 13.
-  call_ctime(&tm_data,
+  call_ctime(&t,
              1970, // year
              13,   // month
              1,    // day
@@ -86,10 +86,10 @@ TEST(LlvmLibcCtime, InvalidMonth) {
 }
 
 TEST(LlvmLibcCtime, ValidWeekdays) {
-  struct tm tm_data;
+  struct time_t t;
   char *result;
   // 1970-01-01 00:00:00.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       1,    // month
                       1,    // day
@@ -101,7 +101,7 @@ TEST(LlvmLibcCtime, ValidWeekdays) {
   ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
 
   // 1970-01-03 00:00:00.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       1,    // month
                       3,    // day
@@ -113,7 +113,7 @@ TEST(LlvmLibcCtime, ValidWeekdays) {
   ASSERT_STREQ("Sat Jan  3 00:00:00 1970\n", result);
 
   // 1970-01-04 00:00:00.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       1,    // month
                       4,    // day
@@ -126,10 +126,10 @@ TEST(LlvmLibcCtime, ValidWeekdays) {
 }
 
 TEST(LlvmLibcCtime, ValidMonths) {
-  struct tm tm_data;
+  struct time_t t;
   char *result;
   // 1970-01-01 00:00:00.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       1,    // month
                       1,    // day
@@ -141,7 +141,7 @@ TEST(LlvmLibcCtime, ValidMonths) {
   ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
 
   // 1970-02-01 00:00:00.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       2,    // month
                       1,    // day
@@ -153,7 +153,7 @@ TEST(LlvmLibcCtime, ValidMonths) {
   ASSERT_STREQ("Sun Feb  1 00:00:00 1970\n", result);
 
   // 1970-12-31 23:59:59.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       1970, // year
                       12,   // month
                       31,   // day
@@ -166,11 +166,11 @@ TEST(LlvmLibcCtime, ValidMonths) {
 }
 
 TEST(LlvmLibcCtime, EndOf32BitEpochYear) {
-  struct tm tm_data;
+  struct time_t t;
   char *result;
   // Test for maximum value of a signed 32-bit integer.
   // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       2038, // year
                       1,    // month
                       19,   // day
@@ -186,9 +186,9 @@ TEST(LlvmLibcCtime, Max64BitYear) {
   if (sizeof(time_t) == 4)
     return;
   // Mon Jan 1 12:50:50 2170 (200 years from 1970),
-  struct tm tm_data;
+  struct time_t t;
   char *result;
-  result = call_ctime(&tm_data,
+  result = call_ctime(&t,
                       2170, // year
                       1,    // month
                       1,    // day
@@ -200,8 +200,8 @@ TEST(LlvmLibcCtime, Max64BitYear) {
   ASSERT_STREQ("Mon Jan  1 12:50:50 2170\n", result);
 
   // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
-  // This test would cause buffer overflow and thus asctime returns nullptr.
-  result = call_ctime(&tm_data,
+  // This test would cause buffer overflow and thus ctime returns nullptr.
+  result = call_ctime(&t,
                       2147483647, // year
                       1,          // month
                       1,          // day

>From bd482baa9922c0aeb34c617fcbc943fb6c811bb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 20:01:34 +0200
Subject: [PATCH 07/42] [libc][ctime] ctime implementation

fix: function declaration
---
 libc/src/time/ctime.cpp | 6 +++---
 libc/src/time/ctime.h   | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index f3181816ad9ab1..5997018689c802 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of asctime function --------------------------------===//
+//===-- Implementation of ctime function --------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -15,9 +15,9 @@ namespace LIBC_NAMESPACE_DECL {
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
-LLVM_LIBC_FUNCTION(char *, ctime, (const struct tm *timeptr)) {
+LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t)) {
   static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
-  return time_utils::ctime(timeptr, buffer, TimeConstants::CTIME_MAX_BYTES);
+  return time_utils::ctime(&t, buffer, TimeConstants::CTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index ec5530ffb5bc71..b4e31ae852fe76 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -14,7 +14,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-char *ctime(const struct tm *timeptr);
+char *ctime(const time_t *t);
 
 } // namespace LIBC_NAMESPACE_DECL
 

>From a1d86d2430dc46bd8154307a6a63bcc9a632de07 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 20:09:03 +0200
Subject: [PATCH 08/42] [libc][c11] ctime implementation

format code with `clang-format`
---
 libc/test/src/time/ctime_test.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index bcc4fe16f795b2..19daa88ddeb4d6 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -12,9 +12,8 @@
 #include "test/UnitTest/Test.h"
 #include "test/src/time/TmHelper.h"
 
-static inline char *call_ctime(struct time_t *t, int year, int month,
-                               int mday, int hour, int min, int sec, int wday,
-                               int yday) {
+static inline char *call_ctime(struct time_t *t, int year, int month, int mday,
+                               int hour, int min, int sec, int wday, int yday) {
   LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
       localtime(t), year, month, mday, hour, min, sec, wday, yday);
   return LIBC_NAMESPACE::ctime(t);

>From de83e31dc35dde34ed920444d63facb4d1bdc7dd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 20:23:15 +0200
Subject: [PATCH 09/42] [libc][c11] implement ctime

implement `ctime_r`
---
 libc/src/time/ctime.cpp             |  2 +-
 libc/src/time/ctime.h               |  2 +-
 libc/src/time/ctime_r.cpp           | 22 +++++++++++
 libc/src/time/ctime_r.h             | 21 ++++++++++
 libc/test/src/time/ctime_r_test.cpp | 60 +++++++++++++++++++++++++++++
 libc/test/src/time/ctime_test.cpp   |  2 +-
 6 files changed, 106 insertions(+), 3 deletions(-)
 create mode 100644 libc/src/time/ctime_r.cpp
 create mode 100644 libc/src/time/ctime_r.h
 create mode 100644 libc/test/src/time/ctime_r_test.cpp

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index 5997018689c802..7089d5f7ff0c38 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -1,4 +1,4 @@
-//===-- Implementation of ctime function --------------------------------===//
+//===-- Implementation of ctime function ----------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index b4e31ae852fe76..4afc8fddc8c44a 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -1,4 +1,4 @@
-//===-- Implementation header of ctime ------------------------*- C++ -*-===//
+//===-- Implementation header of ctime --------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
new file mode 100644
index 00000000000000..c25217d8d22cfc
--- /dev/null
+++ b/libc/src/time/ctime_r.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of ctime_r function --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/time/ctime_r.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/time/time_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t, char *buffer)) {
+  return time_utils::ctime(t, buffer, TimeConstants::CTIME_MAX_BYTES);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
new file mode 100644
index 00000000000000..688646c8d12674
--- /dev/null
+++ b/libc/src/time/ctime_r.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of ctime_r ------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_TIME_ASCTIME_R_H
+#define LLVM_LIBC_SRC_TIME_ASCTIME_R_H
+
+#include "src/__support/macros/config.h"
+#include <time.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+char *ctime_r(const time_t *t, char *buffer);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H
diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
new file mode 100644
index 00000000000000..ab742368f02cc3
--- /dev/null
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -0,0 +1,60 @@
+//===-- Unittests for ctime_r ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/errno/libc_errno.h"
+#include "src/time/ctime_r.h"
+#include "src/time/time_utils.h"
+#include "test/UnitTest/Test.h"
+#include "test/src/time/TmHelper.h"
+
+using LIBC_NAMESPACE::time_utils::TimeConstants;
+
+static inline char *call_ctime_r(time_t *t, int year, int month, int mday,
+                                 int hour, int min, int sec, int wday, int yday,
+                                 char *buffer) {
+  LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
+      localtime(t), year, month, mday, hour, min, sec, wday, yday);
+  return LIBC_NAMESPACE::ctime_r(t, buffer);
+}
+
+// ctime and ctime_r share the same code and thus didn't repeat all the
+// tests from ctime. Added couple of validation tests.
+TEST(LlvmLibcCtimeR, Nullptr) {
+  char *result;
+  result = LIBC_NAMESPACE::ctime_r(nullptr, nullptr);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+
+  char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+  result = LIBC_NAMESPACE::ctime_r(nullptr, buffer);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+
+  time_t t;
+  result = LIBC_NAMESPACE::ctime_r(&tm_data, nullptr);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+}
+
+TEST(LlvmLibcCtimeR, ValidDate) {
+  char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+  struct time_t t;
+  char *result;
+  // 1970-01-01 00:00:00. Test with a valid buffer size.
+  result = call_ctime_r(&t,
+                        1970, // year
+                        1,    // month
+                        1,    // day
+                        0,    // hr
+                        0,    // min
+                        0,    // sec
+                        4,    // wday
+                        0,    // yday
+                        buffer);
+  ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
+}
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index 19daa88ddeb4d6..6d1282e181baba 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -1,4 +1,4 @@
-//===-- Unittests for ctime ---------------------------------------------===//
+//===-- Unittests for ctime -----------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From b7d6c7398ee6dd7f9de72819577a14d224c803d9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 20:25:49 +0200
Subject: [PATCH 10/42] [libc][c11] implement ctime

fix: `ctime_r` header file
---
 libc/src/time/ctime_r.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
index 688646c8d12674..93acad13c28e44 100644
--- a/libc/src/time/ctime_r.h
+++ b/libc/src/time/ctime_r.h
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_SRC_TIME_ASCTIME_R_H
-#define LLVM_LIBC_SRC_TIME_ASCTIME_R_H
+#ifndef LLVM_LIBC_SRC_TIME_CTIME_R_H
+#define LLVM_LIBC_SRC_TIME_CTIME_R_H
 
 #include "src/__support/macros/config.h"
 #include <time.h>

>From 948786a3f51c5619c58a4c307ac17411a1ef82a4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Wed, 4 Sep 2024 20:27:31 +0200
Subject: [PATCH 11/42] [libc][c11] implement ctime

add `ctime_r` to `cmake`
---
 libc/src/time/CMakeLists.txt | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index befe67677f3ec7..1605a6b897c14b 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -47,6 +47,17 @@ add_entrypoint_object(
     libc.include.time
 )
 
+add_entrypoint_object(
+  ctime_r
+  SRCS
+    ctime_r.cpp
+  HDRS
+    ctime_r.h
+  DEPENDS
+    .time_utils
+    libc.include.time
+)
+
 add_entrypoint_object(
   difftime
   SRCS

>From 574583a7f8db33516bbee82414e71943d7588e59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 13:02:46 +0200
Subject: [PATCH 12/42] [libc][c11] implement ctime

add `ctime` and `ctime_r` to build system
---
 libc/config/linux/x86_64/entrypoints.txt |  2 ++
 libc/newhdrgen/yaml/time.yaml            | 13 +++++++++++++
 libc/spec/stdc.td                        | 13 +++++++++++++
 3 files changed, 28 insertions(+)

diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 3fd88fc0020e55..2a38db5bcdad8c 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1003,6 +1003,8 @@ if(LLVM_LIBC_FULL_BUILD)
     # time.h entrypoints
     libc.src.time.asctime
     libc.src.time.asctime_r
+    libc.src.time.ctime
+    libc.src.time.ctime_r
     libc.src.time.clock
     libc.src.time.clock_gettime
     libc.src.time.difftime
diff --git a/libc/newhdrgen/yaml/time.yaml b/libc/newhdrgen/yaml/time.yaml
index d2344671831c7a..69b40bef3160dd 100644
--- a/libc/newhdrgen/yaml/time.yaml
+++ b/libc/newhdrgen/yaml/time.yaml
@@ -24,6 +24,19 @@ functions:
     arguments:
       - type: struct tm *
       - type: char *
+  - name: ctime
+    standard:
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const time_t *
+  - name: ctime_r
+    standard:
+      - stdc
+    return_type: char *
+    arguments:
+      - type: const time_t *
+      - type: char *
   - name: clock
     standard:
       - stdc
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a4ae3e1ff7d9c6..f5ae14ab12d705 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -1600,6 +1600,19 @@ def StdC : StandardSpec<"stdc"> {
                   ArgSpec<CharPtr>,
               ]
           >,
+          FunctionSpec<
+              "ctime",
+              RetValSpec<CharPtr>,
+              [ArgSpec<StructTmPtr>]
+          >,
+          FunctionSpec<
+              "ctime_r",
+              RetValSpec<CharPtr>,
+              [
+                  ArgSpec<StructTmPtr>,
+                  ArgSpec<CharPtr>,
+              ]
+          >,
           FunctionSpec<
               "clock",
               RetValSpec<ClockT>,

>From 7743993d6017e94a4c138008d3f13ff0048bad24 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 13:04:07 +0200
Subject: [PATCH 13/42] [libc][c11] implement ctime

refactor `ctime` and `ctime_r` to use `asctime`
---
 libc/src/time/ctime.cpp    |  4 ++--
 libc/src/time/ctime.h      |  2 +-
 libc/src/time/time_utils.h | 44 --------------------------------------
 3 files changed, 3 insertions(+), 47 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index 7089d5f7ff0c38..ceea1e01bec0f8 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -15,9 +15,9 @@ namespace LIBC_NAMESPACE_DECL {
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
-LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t)) {
+LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
-  return time_utils::ctime(&t, buffer, TimeConstants::CTIME_MAX_BYTES);
+  return time_utils::asctime(localtime(&t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index 4afc8fddc8c44a..d5be450d03f231 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -14,7 +14,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-char *ctime(const time_t *t);
+char *ctime(const time_t *t_ptr);
 
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 4cf32ee64cec11..688fac28fd2293 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -148,50 +148,6 @@ LIBC_INLINE char *asctime(const struct tm *timeptr, char *buffer,
   return buffer;
 }
 
-LIBC_INLINE char *ctime(const time_t *t_ptr, char *buffer,
-                        size_t buffer_length) {
-  if (t_ptr == nullptr || buffer == nullptr) {
-    invalid_value();
-    return nullptr;
-  }
-  const struct tm *timeptr;
-  timeptr = localtime(t_ptr);
-  if (timeptr->tm_wday < 0 ||
-      timeptr->tm_wday > (TimeConstants::DAYS_PER_WEEK - 1)) {
-    invalid_value();
-    return nullptr;
-  }
-  if (timeptr->tm_mon < 0 ||
-      timeptr->tm_mon > (TimeConstants::MONTHS_PER_YEAR - 1)) {
-    invalid_value();
-    return nullptr;
-  }
-
-  // TODO(rtenneti): i18n the following strings.
-  static const char *week_days_name[TimeConstants::DAYS_PER_WEEK] = {
-      "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
-
-  static const char *months_name[TimeConstants::MONTHS_PER_YEAR] = {
-      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-
-  // TODO(michaelr): look into removing this call to __builtin_snprintf that may
-  // be emitted as a call to snprintf. Alternatively, look into using our
-  // internal printf machinery.
-  int written_size = __builtin_snprintf(
-      buffer, buffer_length, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
-      week_days_name[timeptr->tm_wday], months_name[timeptr->tm_mon],
-      timeptr->tm_mday, timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec,
-      TimeConstants::TIME_YEAR_BASE + timeptr->tm_year);
-  if (written_size < 0)
-    return nullptr;
-  if (static_cast<size_t>(written_size) >= buffer_length) {
-    out_of_range();
-    return nullptr;
-  }
-  return buffer;
-}
-
 LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
   int64_t seconds = *timer;
   // Update the tm structure's year, month, day, etc. from seconds.

>From 2db41fce94abf0c600a274cd7f66161656f92539 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 13:10:02 +0200
Subject: [PATCH 14/42] [libc][c11] implement ctime

fix: `ctime_r`
---
 libc/src/time/ctime.cpp   | 2 +-
 libc/src/time/ctime_r.cpp | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index ceea1e01bec0f8..d4bcc6a5bc014e 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -17,7 +17,7 @@ using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
-  return time_utils::asctime(localtime(&t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
+  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index c25217d8d22cfc..b046b04a2e333b 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -15,8 +15,8 @@ namespace LIBC_NAMESPACE_DECL {
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
-LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t, char *buffer)) {
-  return time_utils::ctime(t, buffer, TimeConstants::CTIME_MAX_BYTES);
+LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
+  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL

>From 1fd0113bc57e004de03e7a637d5d5a14871b7ef8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 13:14:14 +0200
Subject: [PATCH 15/42] [libc][c11] implement ctime

add `ctime` and `ctime_r` to `aarch64` and `riscv` architecture
---
 libc/config/linux/aarch64/entrypoints.txt | 2 ++
 libc/config/linux/riscv/entrypoints.txt   | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 60aa7f5ccb319a..64fbe1a250c0ba 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -948,6 +948,8 @@ if(LLVM_LIBC_FULL_BUILD)
     # time.h entrypoints
     libc.src.time.asctime
     libc.src.time.asctime_r
+    libc.src.time.ctime
+    libc.src.time.ctime_r
     libc.src.time.clock
     libc.src.time.clock_gettime
     libc.src.time.difftime
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 9a2746dcb86f87..ff3d821c664c5b 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -883,6 +883,8 @@ if(LLVM_LIBC_FULL_BUILD)
     # time.h entrypoints
     libc.src.time.asctime
     libc.src.time.asctime_r
+    libc.src.time.ctime
+    libc.src.time.ctime_r
     libc.src.time.clock
     libc.src.time.clock_gettime
     libc.src.time.difftime

>From 2f1a873fe1edfdb169839b7cf78d1d04365d8d83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 14:04:59 +0200
Subject: [PATCH 16/42] [libc][c11] implement ctime

add `ctime` and `ctime_r` to more architectures
---
 libc/config/baremetal/arm/entrypoints.txt   | 2 ++
 libc/config/baremetal/riscv/entrypoints.txt | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index af9a8bc9925441..68030f7f1775b5 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -203,6 +203,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     # time.h entrypoints
     libc.src.time.asctime
     libc.src.time.asctime_r
+    libc.src.time.ctime
+    libc.src.time.ctime_r
     libc.src.time.difftime
     libc.src.time.gmtime
     libc.src.time.gmtime_r
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 6ebe2e4a29025f..5894b591072ef0 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -199,6 +199,8 @@ set(TARGET_LIBC_ENTRYPOINTS
     # time.h entrypoints
     libc.src.time.asctime
     libc.src.time.asctime_r
+    libc.src.time.ctime
+    libc.src.time.ctime_r
     libc.src.time.difftime
     libc.src.time.gmtime
     libc.src.time.gmtime_r

>From cd65c212e4d109b8670f14c9340f4dc63994e15f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 14:06:10 +0200
Subject: [PATCH 17/42] [libc][c11] implement ctime

- add symbols for `ctime` and `ctime_r`
- add `ctime` and `ctime_r` to clang formatted files list
- add `ctime` to env32-c test
---
 clang/docs/tools/clang-formatted-files.txt           | 4 ++++
 clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc   | 2 ++
 clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc | 3 +++
 clang/test/Analysis/cert/env34-c.c                   | 1 +
 4 files changed, 10 insertions(+)

diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index fc07357986d989..2261a726235c1b 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -3062,6 +3062,10 @@ libc/src/time/asctime.cpp
 libc/src/time/asctime.h
 libc/src/time/asctime_r.cpp
 libc/src/time/asctime_r.h
+libc/src/time/ctime.cpp
+libc/src/time/ctime.h
+libc/src/time/ctime_r.cpp
+libc/src/time/ctime_r.h
 libc/src/time/gmtime.cpp
 libc/src/time/gmtime.h
 libc/src/time/gmtime_r.cpp
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 463ce921f0672f..849aad0b227da6 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -220,6 +220,8 @@ SYMBOL(and, None, <iso646.h>)
 SYMBOL(and_eq, None, <iso646.h>)
 SYMBOL(asctime, None, <time.h>)
 SYMBOL(asctime_s, None, <time.h>)
+SYMBOL(ctime, None, <time.h>)
+SYMBOL(ctime_s, None, <time.h>)
 SYMBOL(asin, None, <math.h>)
 SYMBOL(asinf, None, <math.h>)
 SYMBOL(asinh, None, <math.h>)
diff --git a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
index b46bd2e4d7a4b5..7f0e32b6233e9c 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/StdSymbolMap.inc
@@ -617,6 +617,9 @@ SYMBOL(as_writable_bytes, std::, <span>)
 SYMBOL(asctime, std::, <ctime>)
 SYMBOL(asctime, None, <ctime>)
 SYMBOL(asctime, None, <time.h>)
+SYMBOL(ctime, std::, <ctime>)
+SYMBOL(ctime, None, <ctime>)
+SYMBOL(ctime, None, <time.h>)
 SYMBOL(asin, std::, <cmath>)
 SYMBOL(asin, None, <cmath>)
 SYMBOL(asin, None, <math.h>)
diff --git a/clang/test/Analysis/cert/env34-c.c b/clang/test/Analysis/cert/env34-c.c
index d307f0d8f4bb01..79facfe547fa12 100644
--- a/clang/test/Analysis/cert/env34-c.c
+++ b/clang/test/Analysis/cert/env34-c.c
@@ -16,6 +16,7 @@ lconv *localeconv(void);
 typedef struct {
 } tm;
 char *asctime(const tm *timeptr);
+char *ctime(const time_t *timeptr);
 
 int strcmp(const char*, const char*);
 extern void foo(char *e);

>From 207e1e0d49c54ecef2a80d8d95659cdd7ef68ca4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 14:34:17 +0200
Subject: [PATCH 18/42] [libc][c11] implement ctime

add header for `time_t`
---
 clang/test/Analysis/cert/env34-c.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/test/Analysis/cert/env34-c.c b/clang/test/Analysis/cert/env34-c.c
index 79facfe547fa12..618c089624675e 100644
--- a/clang/test/Analysis/cert/env34-c.c
+++ b/clang/test/Analysis/cert/env34-c.c
@@ -3,6 +3,7 @@
 // RUN:  -analyzer-config security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
 
+#include <time.h>
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
 char *setlocale(int category, const char *locale);

>From 925a6a6be58bc75493ecfd8da2e94e1423cf7c6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 14:58:51 +0200
Subject: [PATCH 19/42] [libc][c11] implement ctime

removed `ctime` from analysis test
---
 clang/test/Analysis/cert/env34-c.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/clang/test/Analysis/cert/env34-c.c b/clang/test/Analysis/cert/env34-c.c
index 618c089624675e..d307f0d8f4bb01 100644
--- a/clang/test/Analysis/cert/env34-c.c
+++ b/clang/test/Analysis/cert/env34-c.c
@@ -3,7 +3,6 @@
 // RUN:  -analyzer-config security.cert.env.InvalidPtr:InvalidatingGetEnv=true \
 // RUN:  -analyzer-output=text -verify -Wno-unused %s
 
-#include <time.h>
 #include "../Inputs/system-header-simulator.h"
 char *getenv(const char *name);
 char *setlocale(int category, const char *locale);
@@ -17,7 +16,6 @@ lconv *localeconv(void);
 typedef struct {
 } tm;
 char *asctime(const tm *timeptr);
-char *ctime(const time_t *timeptr);
 
 int strcmp(const char*, const char*);
 extern void foo(char *e);

>From 82ab5543f3895c15085605f8b6c877c87c058b40 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 16:13:43 +0200
Subject: [PATCH 20/42] [libc][c11] implement ctime

fix: `time_t` definition in `stdc.td`
---
 libc/spec/stdc.td | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index f5ae14ab12d705..a8d319d6f8380a 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -3,6 +3,8 @@ def StdC : StandardSpec<"stdc"> {
   NamedType StructTmType = NamedType<"struct tm">;
   PtrType StructTmPtr = PtrType<StructTmType>;
   PtrType TimeTTypePtr = PtrType<TimeTType>;
+  NamedType StructTimeTType = NamedType<"time_t">;
+  PtrType StructTimeTPtr = PtrType<StructTimeTType>;
   NamedType ClockT = NamedType<"clock_t">;
   NamedType LocaleT = NamedType<"locale_t">;
 
@@ -1603,13 +1605,13 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<
               "ctime",
               RetValSpec<CharPtr>,
-              [ArgSpec<StructTmPtr>]
+              [ArgSpec<StructTimeTPtr>]
           >,
           FunctionSpec<
               "ctime_r",
               RetValSpec<CharPtr>,
               [
-                  ArgSpec<StructTmPtr>,
+                  ArgSpec<StructTimeTPtr>,
                   ArgSpec<CharPtr>,
               ]
           >,

>From 6fa3bc0bf292486b38c4365445e136a3afad26ff Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 16:49:58 +0200
Subject: [PATCH 21/42] [libc][c11] implement ctime

fix: removed `ctime_s`
---
 clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
index 849aad0b227da6..b1f7dc286429cd 100644
--- a/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
+++ b/clang/lib/Tooling/Inclusions/Stdlib/CSymbolMap.inc
@@ -221,7 +221,6 @@ SYMBOL(and_eq, None, <iso646.h>)
 SYMBOL(asctime, None, <time.h>)
 SYMBOL(asctime_s, None, <time.h>)
 SYMBOL(ctime, None, <time.h>)
-SYMBOL(ctime_s, None, <time.h>)
 SYMBOL(asin, None, <math.h>)
 SYMBOL(asinf, None, <math.h>)
 SYMBOL(asinh, None, <math.h>)

>From a16d1a965ea0a9642b135a2bd09252955402b3ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 16:51:08 +0200
Subject: [PATCH 22/42] [libc][c11] implement ctime

add `ctime` and `ctime_r` to unsafe functions check
---
 clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index ea7eaa0b0ff811..a23f7ea87abe10 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -42,7 +42,7 @@ static StringRef getReplacementFor(StringRef FunctionName,
     // Try to find a better replacement from Annex K first.
     StringRef AnnexKReplacementFunction =
         StringSwitch<StringRef>(FunctionName)
-            .Cases("asctime", "asctime_r", "asctime_s")
+	    .Cases("asctime", "asctime_r", "asctime_s", "ctime", "ctime_r")
             .Case("gets", "gets_s")
             .Default({});
     if (!AnnexKReplacementFunction.empty())

>From f41a8ed581ac5a56fdb5e5360d99498850c77de6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 20:19:06 +0200
Subject: [PATCH 23/42] [libc][c11] implement ctime

fix: tests
---
 libc/test/src/time/ctime_test.cpp | 194 ++----------------------------
 1 file changed, 8 insertions(+), 186 deletions(-)

diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index 6d1282e181baba..c55fdb1b614aeb 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -12,10 +12,7 @@
 #include "test/UnitTest/Test.h"
 #include "test/src/time/TmHelper.h"
 
-static inline char *call_ctime(struct time_t *t, int year, int month, int mday,
-                               int hour, int min, int sec, int wday, int yday) {
-  LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
-      localtime(t), year, month, mday, hour, min, sec, wday, yday);
+static inline char *call_ctime(struct time_t *t) {
   return LIBC_NAMESPACE::ctime(t);
 }
 
@@ -26,189 +23,14 @@ TEST(LlvmLibcCtime, Nullptr) {
   ASSERT_STREQ(nullptr, result);
 }
 
-// Weekdays are in the range 0 to 6. Test passing invalid value in wday.
-TEST(LlvmLibcCtime, InvalidWday) {
-  struct time_t t;
-
-  // Test with wday = -1.
-  call_ctime(&t,
-             1970, // year
-             1,    // month
-             1,    // day
-             0,    // hr
-             0,    // min
-             0,    // sec
-             -1,   // wday
-             0);   // yday
-  ASSERT_ERRNO_EQ(EINVAL);
-
-  // Test with wday = 7.
-  call_ctime(&t,
-             1970, // year
-             1,    // month
-             1,    // day
-             0,    // hr
-             0,    // min
-             0,    // sec
-             7,    // wday
-             0);   // yday
-  ASSERT_ERRNO_EQ(EINVAL);
-}
-
-// Months are from January to December. Test passing invalid value in month.
-TEST(LlvmLibcCtime, InvalidMonth) {
-  struct time_t t;
-
-  // Test with month = 0.
-  call_ctime(&t,
-             1970, // year
-             0,    // month
-             1,    // day
-             0,    // hr
-             0,    // min
-             0,    // sec
-             4,    // wday
-             0);   // yday
-  ASSERT_ERRNO_EQ(EINVAL);
-
-  // Test with month = 13.
-  call_ctime(&t,
-             1970, // year
-             13,   // month
-             1,    // day
-             0,    // hr
-             0,    // min
-             0,    // sec
-             4,    // wday
-             0);   // yday
-  ASSERT_ERRNO_EQ(EINVAL);
-}
-
-TEST(LlvmLibcCtime, ValidWeekdays) {
-  struct time_t t;
-  char *result;
-  // 1970-01-01 00:00:00.
-  result = call_ctime(&t,
-                      1970, // year
-                      1,    // month
-                      1,    // day
-                      0,    // hr
-                      0,    // min
-                      0,    // sec
-                      4,    // wday
-                      0);   // yday
+TEST(LlvmLibcCtime, ValidUnixTimestamp0) {
+  struct time_t t = 0;
+  char* result = call_ctime(&t);
   ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
-
-  // 1970-01-03 00:00:00.
-  result = call_ctime(&t,
-                      1970, // year
-                      1,    // month
-                      3,    // day
-                      0,    // hr
-                      0,    // min
-                      0,    // sec
-                      6,    // wday
-                      0);   // yday
-  ASSERT_STREQ("Sat Jan  3 00:00:00 1970\n", result);
-
-  // 1970-01-04 00:00:00.
-  result = call_ctime(&t,
-                      1970, // year
-                      1,    // month
-                      4,    // day
-                      0,    // hr
-                      0,    // min
-                      0,    // sec
-                      0,    // wday
-                      0);   // yday
-  ASSERT_STREQ("Sun Jan  4 00:00:00 1970\n", result);
-}
-
-TEST(LlvmLibcCtime, ValidMonths) {
-  struct time_t t;
-  char *result;
-  // 1970-01-01 00:00:00.
-  result = call_ctime(&t,
-                      1970, // year
-                      1,    // month
-                      1,    // day
-                      0,    // hr
-                      0,    // min
-                      0,    // sec
-                      4,    // wday
-                      0);   // yday
-  ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
-
-  // 1970-02-01 00:00:00.
-  result = call_ctime(&t,
-                      1970, // year
-                      2,    // month
-                      1,    // day
-                      0,    // hr
-                      0,    // min
-                      0,    // sec
-                      0,    // wday
-                      0);   // yday
-  ASSERT_STREQ("Sun Feb  1 00:00:00 1970\n", result);
-
-  // 1970-12-31 23:59:59.
-  result = call_ctime(&t,
-                      1970, // year
-                      12,   // month
-                      31,   // day
-                      23,   // hr
-                      59,   // min
-                      59,   // sec
-                      4,    // wday
-                      0);   // yday
-  ASSERT_STREQ("Thu Dec 31 23:59:59 1970\n", result);
 }
 
-TEST(LlvmLibcCtime, EndOf32BitEpochYear) {
-  struct time_t t;
-  char *result;
-  // Test for maximum value of a signed 32-bit integer.
-  // Test implementation can encode time for Tue 19 January 2038 03:14:07 UTC.
-  result = call_ctime(&t,
-                      2038, // year
-                      1,    // month
-                      19,   // day
-                      3,    // hr
-                      14,   // min
-                      7,    // sec
-                      2,    // wday
-                      7);   // yday
-  ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", result);
-}
-
-TEST(LlvmLibcCtime, Max64BitYear) {
-  if (sizeof(time_t) == 4)
-    return;
-  // Mon Jan 1 12:50:50 2170 (200 years from 1970),
-  struct time_t t;
-  char *result;
-  result = call_ctime(&t,
-                      2170, // year
-                      1,    // month
-                      1,    // day
-                      12,   // hr
-                      50,   // min
-                      50,   // sec
-                      1,    // wday
-                      50);  // yday
-  ASSERT_STREQ("Mon Jan  1 12:50:50 2170\n", result);
-
-  // Test for Tue Jan 1 12:50:50 in 2,147,483,647th year.
-  // This test would cause buffer overflow and thus ctime returns nullptr.
-  result = call_ctime(&t,
-                      2147483647, // year
-                      1,          // month
-                      1,          // day
-                      12,         // hr
-                      50,         // min
-                      50,         // sec
-                      2,          // wday
-                      50);        // yday
-  ASSERT_ERRNO_EQ(EOVERFLOW);
-  ASSERT_STREQ(nullptr, result);
+TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
+  struct time_t t = 2147483647;
+  char* result = call_ctime(&t);
+  ASSERT_STREQ("Tue Jan  19 03:14:07 2038\n", result);
 }

>From cf3afc2770496d8e76a617add8b86c39195763d3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 20:19:43 +0200
Subject: [PATCH 24/42] [libc][c11] implement ctime

use asctime constants and remove ctime constants
---
 libc/src/time/ctime.cpp    | 10 +++++-----
 libc/src/time/ctime.h      |  1 -
 libc/src/time/ctime_r.cpp  |  2 +-
 libc/src/time/time_utils.h |  3 ---
 4 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index d4bcc6a5bc014e..dffebc20f47a58 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -6,10 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "src/time/ctime.h"
-#include "src/__support/common.h"
-#include "src/__support/macros/config.h"
-#include "src/time/time_utils.h"
+#include "ctime.h"
+#include "../__support/common.h"
+#include "../__support/macros/config.h"
+#include "time_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
@@ -17,7 +17,7 @@ using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
-  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
+  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index d5be450d03f231..6e9f5fa5d1382a 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -10,7 +10,6 @@
 #define LLVM_LIBC_SRC_TIME_CTIME_H
 
 #include "src/__support/macros/config.h"
-#include <time.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index b046b04a2e333b..2fb7c814a822cc 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
-  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::CTIME_MAX_BYTES);
+  return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 688fac28fd2293..47f55f7d389122 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -62,9 +62,6 @@ struct TimeConstants {
   static constexpr int ASCTIME_BUFFER_SIZE = 256;
   static constexpr int ASCTIME_MAX_BYTES = 26;
 
-  static constexpr int CTIME_BUFFER_SIZE = 256;
-  static constexpr int CTIME_MAX_BYTES = 26;
-
   /* 2000-03-01 (mod 400 year, immediately after feb29 */
   static constexpr int64_t SECONDS_UNTIL2000_MARCH_FIRST =
       (946684800LL + SECONDS_PER_DAY * (31 + 29));

>From 2ff2fa15e8ce647a5f2c5089e52184943ffd6c0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 20:23:33 +0200
Subject: [PATCH 25/42] [libc][c11] implement ctime

use `TimeTTypePtr` and remove `StructTimeTPtr`
---
 libc/spec/stdc.td | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index a8d319d6f8380a..c7b697d438a89e 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -3,8 +3,6 @@ def StdC : StandardSpec<"stdc"> {
   NamedType StructTmType = NamedType<"struct tm">;
   PtrType StructTmPtr = PtrType<StructTmType>;
   PtrType TimeTTypePtr = PtrType<TimeTType>;
-  NamedType StructTimeTType = NamedType<"time_t">;
-  PtrType StructTimeTPtr = PtrType<StructTimeTType>;
   NamedType ClockT = NamedType<"clock_t">;
   NamedType LocaleT = NamedType<"locale_t">;
 
@@ -1605,13 +1603,13 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<
               "ctime",
               RetValSpec<CharPtr>,
-              [ArgSpec<StructTimeTPtr>]
+              [ArgSpec<TimeTTypePtr>]
           >,
           FunctionSpec<
               "ctime_r",
               RetValSpec<CharPtr>,
               [
-                  ArgSpec<StructTimeTPtr>,
+                  ArgSpec<TimeTTypePtr>,
                   ArgSpec<CharPtr>,
               ]
           >,

>From 677775d55044af0c67d766d6e6348b71ef33efcd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 20:31:35 +0200
Subject: [PATCH 26/42] [libc][c11] implement ctime

remove `ctime` and `ctime_r` from `clang-tidy`

this will be done in https://github.com/llvm/llvm-project/issues/107445
---
 clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index a23f7ea87abe10..3d326c5a3b5743 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -42,7 +42,7 @@ static StringRef getReplacementFor(StringRef FunctionName,
     // Try to find a better replacement from Annex K first.
     StringRef AnnexKReplacementFunction =
         StringSwitch<StringRef>(FunctionName)
-	    .Cases("asctime", "asctime_r", "asctime_s", "ctime", "ctime_r")
+	    .Cases("asctime", "asctime_r", "asctime_s")
             .Case("gets", "gets_s")
             .Default({});
     if (!AnnexKReplacementFunction.empty())

>From f6b3037227a5ffca301cc53760b42679e534b54d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 20:40:24 +0200
Subject: [PATCH 27/42] [libc][c11] implement ctime

fix: tests
---
 libc/test/src/time/ctime_r_test.cpp | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
index ab742368f02cc3..fe5426fc5e553d 100644
--- a/libc/test/src/time/ctime_r_test.cpp
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -14,11 +14,7 @@
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
-static inline char *call_ctime_r(time_t *t, int year, int month, int mday,
-                                 int hour, int min, int sec, int wday, int yday,
-                                 char *buffer) {
-  LIBC_NAMESPACE::tmhelper::testing::initialize_tm_data(
-      localtime(t), year, month, mday, hour, min, sec, wday, yday);
+static inline char *call_ctime_r(time_t *t, char *buffer) {
   return LIBC_NAMESPACE::ctime_r(t, buffer);
 }
 
@@ -41,20 +37,11 @@ TEST(LlvmLibcCtimeR, Nullptr) {
   ASSERT_STREQ(nullptr, result);
 }
 
-TEST(LlvmLibcCtimeR, ValidDate) {
+TEST(LlvmLibcCtimeR, ValidUnixTimestamp) {
   char buffer[TimeConstants::CTIME_BUFFER_SIZE];
-  struct time_t t;
+  struct time_t t = 0;
   char *result;
   // 1970-01-01 00:00:00. Test with a valid buffer size.
-  result = call_ctime_r(&t,
-                        1970, // year
-                        1,    // month
-                        1,    // day
-                        0,    // hr
-                        0,    // min
-                        0,    // sec
-                        4,    // wday
-                        0,    // yday
-                        buffer);
+  result = call_ctime_r(&t, buffer);
   ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
 }

>From 50b8710ee1e0b2f8df82e7d938fc9dd713f374ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 21:00:23 +0200
Subject: [PATCH 28/42] [libc][c11] implement ctime

add error if argument is greater than 32bit int and fixed tests
---
 libc/src/time/ctime.cpp             |  5 ++++-
 libc/src/time/ctime_r.cpp           |  3 +++
 libc/test/src/time/ctime_r_test.cpp | 22 +++++++++++++++++++---
 libc/test/src/time/ctime_test.cpp   |  7 +++++++
 4 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index dffebc20f47a58..cd6c893bdc8321 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -16,7 +16,10 @@ namespace LIBC_NAMESPACE_DECL {
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
-  static char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+  if (t_ptr > 2147483647) {
+    return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+  }
+  static char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index 2fb7c814a822cc..73c0f2fb3f47aa 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -16,6 +16,9 @@ namespace LIBC_NAMESPACE_DECL {
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
+  if (t_ptr > 2147483647) {
+    return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+  }
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
index fe5426fc5e553d..34a385dc86c6ed 100644
--- a/libc/test/src/time/ctime_r_test.cpp
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -26,7 +26,7 @@ TEST(LlvmLibcCtimeR, Nullptr) {
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
 
-  char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+  char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
   result = LIBC_NAMESPACE::ctime_r(nullptr, buffer);
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
@@ -37,11 +37,27 @@ TEST(LlvmLibcCtimeR, Nullptr) {
   ASSERT_STREQ(nullptr, result);
 }
 
-TEST(LlvmLibcCtimeR, ValidUnixTimestamp) {
-  char buffer[TimeConstants::CTIME_BUFFER_SIZE];
+TEST(LlvmLibcCtimeR, ValidUnixTimestamp0) {
+  char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
   struct time_t t = 0;
   char *result;
   // 1970-01-01 00:00:00. Test with a valid buffer size.
   result = call_ctime_r(&t, buffer);
   ASSERT_STREQ("Thu Jan  1 00:00:00 1970\n", result);
 }
+
+TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
+  char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
+  struct time_t t = 2147483647;
+  char *result;
+  // 2038-01-19 03:14:07. Test with a valid buffer size.
+  char* result = call_ctime_r(&t, buffer);
+  ASSERT_STREQ("Tue Jan  19 03:14:07 2038\n", result);
+}
+
+TEST(LlvmLibcCtimeR, InvalidArgument) {
+  struct time_t t = 2147483648;
+  char* result = call_ctime(&t);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+}
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index c55fdb1b614aeb..e6494542ca5e39 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -34,3 +34,10 @@ TEST(LlvmLibcCtime, ValidUnixTimestamp32Int) {
   char* result = call_ctime(&t);
   ASSERT_STREQ("Tue Jan  19 03:14:07 2038\n", result);
 }
+
+TEST(LlvmLibcCtime, InvalidArgument) {
+  struct time_t t = 2147483648;
+  char* result = call_ctime(&t);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_STREQ(nullptr, result);
+}

>From 622579065d5ccc67910076002eee12ce4c24054c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 21:03:00 +0200
Subject: [PATCH 29/42] undo clang-tidy

---
 clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
index 3d326c5a3b5743..ea7eaa0b0ff811 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFunctionsCheck.cpp
@@ -42,7 +42,7 @@ static StringRef getReplacementFor(StringRef FunctionName,
     // Try to find a better replacement from Annex K first.
     StringRef AnnexKReplacementFunction =
         StringSwitch<StringRef>(FunctionName)
-	    .Cases("asctime", "asctime_r", "asctime_s")
+            .Cases("asctime", "asctime_r", "asctime_s")
             .Case("gets", "gets_s")
             .Default({});
     if (!AnnexKReplacementFunction.empty())

>From cf870c0b9ec421f137c48c04483efc7c8dcc829a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Thu, 5 Sep 2024 21:30:33 +0200
Subject: [PATCH 30/42] add header file for `time.h`

---
 libc/src/time/ctime.cpp             | 2 +-
 libc/src/time/ctime.h               | 2 +-
 libc/src/time/ctime_r.cpp           | 4 +++-
 libc/src/time/ctime_r.h             | 2 +-
 libc/test/src/time/ctime_r_test.cpp | 2 +-
 libc/test/src/time/ctime_test.cpp   | 2 +-
 6 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index cd6c893bdc8321..b14ff2607aae2d 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -23,4 +23,4 @@ LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
-} // namespace LIBC_NAMESPACE_DECL
+} // namespace LIBC_NAMESPACE_DECL
\ No newline at end of file
diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index 6e9f5fa5d1382a..73c21ba3526376 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -17,4 +17,4 @@ char *ctime(const time_t *t_ptr);
 
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC_TIME_CTIME_H
+#endif // LLVM_LIBC_SRC_TIME_CTIME_H
\ No newline at end of file
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index 73c0f2fb3f47aa..92dc8a05dad7c4 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include <time.h>
+
 #include "src/time/ctime_r.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"
@@ -22,4 +24,4 @@ LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
-} // namespace LIBC_NAMESPACE_DECL
+} // namespace LIBC_NAMESPACE_DECL
\ No newline at end of file
diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
index 93acad13c28e44..8823ef1686ddac 100644
--- a/libc/src/time/ctime_r.h
+++ b/libc/src/time/ctime_r.h
@@ -18,4 +18,4 @@ char *ctime_r(const time_t *t, char *buffer);
 
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H
+#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H
\ No newline at end of file
diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
index 34a385dc86c6ed..3608e1b604ec16 100644
--- a/libc/test/src/time/ctime_r_test.cpp
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -60,4 +60,4 @@ TEST(LlvmLibcCtimeR, InvalidArgument) {
   char* result = call_ctime(&t);
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
-}
+}
\ No newline at end of file
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index e6494542ca5e39..f41c3c2abe9153 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -40,4 +40,4 @@ TEST(LlvmLibcCtime, InvalidArgument) {
   char* result = call_ctime(&t);
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
-}
+}
\ No newline at end of file

>From eac511ec19213d95b19c30d0984d1ddd3ac83990 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 16:59:21 +0200
Subject: [PATCH 31/42] remove `time.h`

---
 libc/src/time/ctime_r.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index 92dc8a05dad7c4..0b128a01bb4f15 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -6,8 +6,6 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include <time.h>
-
 #include "src/time/ctime_r.h"
 #include "src/__support/common.h"
 #include "src/__support/macros/config.h"

>From 2f2a9a089c4789aee9e93c969ceaf3d1d908295e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 17:01:15 +0200
Subject: [PATCH 32/42] add function for `localtime` that temporarily use
 `gmtime`, since `localtime` is not yet implemented

---
 libc/src/time/time_utils.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 47f55f7d389122..bbc809efc842a3 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -156,6 +156,13 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
   return result;
 }
 
+// TODO: localtime is not yet implemented and a temporary solution is to
+//       use gmtime
+LIBC_INLINE struct tm *localtime(const time_t *timer, struct tm *result) {
+  struct tm *result = {0};
+  return time_utils::gmtime_internal(t_ptr, result);
+}
+
 } // namespace time_utils
 } // namespace LIBC_NAMESPACE_DECL
 

>From 602486b4d4f3747175debc44545fe90697acd01d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 17:26:18 +0200
Subject: [PATCH 33/42] added github issue for implementing `localtime`

---
 libc/src/time/time_utils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index bbc809efc842a3..4e1d727982a6b9 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -157,7 +157,7 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
 }
 
 // TODO: localtime is not yet implemented and a temporary solution is to
-//       use gmtime
+//       use gmtime, https://github.com/llvm/llvm-project/issues/107597
 LIBC_INLINE struct tm *localtime(const time_t *timer, struct tm *result) {
   struct tm *result = {0};
   return time_utils::gmtime_internal(t_ptr, result);

>From eadea599de626533bf6733692ad53df41185e4c1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:00:14 +0200
Subject: [PATCH 34/42] remove `struct tm` from `localtime`

---
 libc/src/time/time_utils.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 4e1d727982a6b9..948602c32c584e 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -158,7 +158,7 @@ LIBC_INLINE struct tm *gmtime_internal(const time_t *timer, struct tm *result) {
 
 // TODO: localtime is not yet implemented and a temporary solution is to
 //       use gmtime, https://github.com/llvm/llvm-project/issues/107597
-LIBC_INLINE struct tm *localtime(const time_t *timer, struct tm *result) {
+LIBC_INLINE struct tm *localtime(const time_t *timer) {
   struct tm *result = {0};
   return time_utils::gmtime_internal(t_ptr, result);
 }

>From 325de682ad4273c93d93081398c9a2e45cf8b641 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:04:42 +0200
Subject: [PATCH 35/42] use relative path

---
 libc/src/time/ctime.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index b14ff2607aae2d..49e766c0950472 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -7,8 +7,8 @@
 //===----------------------------------------------------------------------===//
 
 #include "ctime.h"
-#include "../__support/common.h"
-#include "../__support/macros/config.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
 #include "time_utils.h"
 
 namespace LIBC_NAMESPACE_DECL {

>From 42c0508841efabcd35ff58025a97978276d22063 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:06:40 +0200
Subject: [PATCH 36/42] add newline at end of files

---
 libc/src/time/ctime.cpp             | 2 +-
 libc/src/time/ctime_r.cpp           | 2 +-
 libc/test/src/time/ctime_r_test.cpp | 2 +-
 libc/test/src/time/ctime_test.cpp   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index 49e766c0950472..29b4ee2afcbac7 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -23,4 +23,4 @@ LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
-} // namespace LIBC_NAMESPACE_DECL
\ No newline at end of file
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index 0b128a01bb4f15..73c0f2fb3f47aa 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -22,4 +22,4 @@ LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }
 
-} // namespace LIBC_NAMESPACE_DECL
\ No newline at end of file
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
index 3608e1b604ec16..34a385dc86c6ed 100644
--- a/libc/test/src/time/ctime_r_test.cpp
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -60,4 +60,4 @@ TEST(LlvmLibcCtimeR, InvalidArgument) {
   char* result = call_ctime(&t);
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
-}
\ No newline at end of file
+}
diff --git a/libc/test/src/time/ctime_test.cpp b/libc/test/src/time/ctime_test.cpp
index f41c3c2abe9153..e6494542ca5e39 100644
--- a/libc/test/src/time/ctime_test.cpp
+++ b/libc/test/src/time/ctime_test.cpp
@@ -40,4 +40,4 @@ TEST(LlvmLibcCtime, InvalidArgument) {
   char* result = call_ctime(&t);
   ASSERT_ERRNO_EQ(EINVAL);
   ASSERT_STREQ(nullptr, result);
-}
\ No newline at end of file
+}

>From 2e51762d175f1005206dd53b237d419e13332753 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:07:55 +0200
Subject: [PATCH 37/42] add comment for tests

---
 libc/test/src/time/ctime_r_test.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libc/test/src/time/ctime_r_test.cpp b/libc/test/src/time/ctime_r_test.cpp
index 34a385dc86c6ed..52ed2dde73bddc 100644
--- a/libc/test/src/time/ctime_r_test.cpp
+++ b/libc/test/src/time/ctime_r_test.cpp
@@ -14,6 +14,7 @@
 
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
+// make check-libc LIBC_TEST_TARGET=call_ctime_r VERBOSE=1
 static inline char *call_ctime_r(time_t *t, char *buffer) {
   return LIBC_NAMESPACE::ctime_r(t, buffer);
 }

>From 9137851d1d899d3475798d0f2866de92a1baff5b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:11:10 +0200
Subject: [PATCH 38/42] add newline to end of files

---
 libc/src/time/ctime.h   | 2 +-
 libc/src/time/ctime_r.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/time/ctime.h b/libc/src/time/ctime.h
index 73c21ba3526376..6e9f5fa5d1382a 100644
--- a/libc/src/time/ctime.h
+++ b/libc/src/time/ctime.h
@@ -17,4 +17,4 @@ char *ctime(const time_t *t_ptr);
 
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC_TIME_CTIME_H
\ No newline at end of file
+#endif // LLVM_LIBC_SRC_TIME_CTIME_H
diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
index 8823ef1686ddac..93acad13c28e44 100644
--- a/libc/src/time/ctime_r.h
+++ b/libc/src/time/ctime_r.h
@@ -18,4 +18,4 @@ char *ctime_r(const time_t *t, char *buffer);
 
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H
\ No newline at end of file
+#endif // LLVM_LIBC_SRC_TIME_CTIME_R_H

>From 485e7fbdd6ff47d48fd32ccdc1d399b7f3afec0b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:18:00 +0200
Subject: [PATCH 39/42] return `nullptr` if `time_t` is greater than 32bit
 value

---
 libc/src/time/ctime.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index 29b4ee2afcbac7..4aa1e7e5e220e1 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -17,7 +17,7 @@ using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
   if (t_ptr > 2147483647) {
-    return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+    return nullptr;
   }
   static char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);

>From 3a44b7aa2c1ad8054f9f4dd8fc3235540b6fd5f7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:24:22 +0200
Subject: [PATCH 40/42] return `nullptr` if `time_t` is greater than 32bit
 value

---
 libc/src/time/ctime_r.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index 73c0f2fb3f47aa..b781613e91babb 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -17,7 +17,7 @@ using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
   if (t_ptr > 2147483647) {
-    return llvm::createStringError(llvm::errc::invalid_argument, "ERROR");
+    return nullptr;
   }
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
 }

>From cd47d24a22c2f4c85d53621392f2cd4d504f0913 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:34:42 +0200
Subject: [PATCH 41/42] add 32bit maximum value to `TimeConstants` struct

---
 libc/src/time/ctime.cpp    | 2 +-
 libc/src/time/ctime_r.cpp  | 2 +-
 libc/src/time/time_utils.h | 1 +
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/libc/src/time/ctime.cpp b/libc/src/time/ctime.cpp
index 4aa1e7e5e220e1..13432e88e08fa7 100644
--- a/libc/src/time/ctime.cpp
+++ b/libc/src/time/ctime.cpp
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime, (const time_t *t_ptr)) {
-  if (t_ptr > 2147483647) {
+  if (t_ptr > TimeConstants::MAXIMUM_32_BIT_VALUE) {
     return nullptr;
   }
   static char buffer[TimeConstants::ASCTIME_BUFFER_SIZE];
diff --git a/libc/src/time/ctime_r.cpp b/libc/src/time/ctime_r.cpp
index b781613e91babb..a8df3bfec36230 100644
--- a/libc/src/time/ctime_r.cpp
+++ b/libc/src/time/ctime_r.cpp
@@ -16,7 +16,7 @@ namespace LIBC_NAMESPACE_DECL {
 using LIBC_NAMESPACE::time_utils::TimeConstants;
 
 LLVM_LIBC_FUNCTION(char *, ctime_r, (const time_t *t_ptr, char *buffer)) {
-  if (t_ptr > 2147483647) {
+  if (t_ptr > TimeConstants::MAXIMUM_32_BIT_VALUE) {
     return nullptr;
   }
   return time_utils::asctime(localtime(t_ptr), buffer, TimeConstants::ASCTIME_MAX_BYTES);
diff --git a/libc/src/time/time_utils.h b/libc/src/time/time_utils.h
index 948602c32c584e..cc4d4b477b76d2 100644
--- a/libc/src/time/time_utils.h
+++ b/libc/src/time/time_utils.h
@@ -37,6 +37,7 @@ enum Month : int {
 };
 
 struct TimeConstants {
+  static constexpr int MAXIMUM_32_BIT_VALUE = 2147483647;
   static constexpr int SECONDS_PER_MIN = 60;
   static constexpr int MINUTES_PER_HOUR = 60;
   static constexpr int HOURS_PER_DAY = 24;

>From a28d5cb8e18f1aa5992097e42f30cdf1af3ce4bd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=97=D0=B8=D1=88=D0=B0=D0=BD=20=D0=9C=D0=B8=D1=80=D0=B7?=
 =?UTF-8?q?=D0=B0?= <149377404+zimirza at users.noreply.github.com>
Date: Fri, 6 Sep 2024 18:48:14 +0200
Subject: [PATCH 42/42] use `time_t.h` and include it in dependencies for
 `ctime` and `ctime_t`

---
 libc/src/time/CMakeLists.txt | 2 ++
 libc/src/time/ctime_r.h      | 2 +-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/libc/src/time/CMakeLists.txt b/libc/src/time/CMakeLists.txt
index 1605a6b897c14b..b3318e7ca87fa5 100644
--- a/libc/src/time/CMakeLists.txt
+++ b/libc/src/time/CMakeLists.txt
@@ -44,6 +44,7 @@ add_entrypoint_object(
     ctime.h
   DEPENDS
     .time_utils
+    libc.hdr.types.time_t
     libc.include.time
 )
 
@@ -55,6 +56,7 @@ add_entrypoint_object(
     ctime_r.h
   DEPENDS
     .time_utils
+    libc.hdr.types.time_t
     libc.include.time
 )
 
diff --git a/libc/src/time/ctime_r.h b/libc/src/time/ctime_r.h
index 93acad13c28e44..2ab4f7c3b62379 100644
--- a/libc/src/time/ctime_r.h
+++ b/libc/src/time/ctime_r.h
@@ -9,8 +9,8 @@
 #ifndef LLVM_LIBC_SRC_TIME_CTIME_R_H
 #define LLVM_LIBC_SRC_TIME_CTIME_R_H
 
+#include "hdr/types/time_t.h"
 #include "src/__support/macros/config.h"
-#include <time.h>
 
 namespace LIBC_NAMESPACE_DECL {
 



More information about the cfe-commits mailing list