[flang-commits] [flang] [flang] Update the date_and_time intrinsic for AIX (PR #104849)

Kelvin Li via flang-commits flang-commits at lists.llvm.org
Mon Aug 19 13:27:22 PDT 2024


https://github.com/kkwli created https://github.com/llvm/llvm-project/pull/104849

Currently, the `strftime` routine is called to get the timezone for the `ZONE` argument. On AIX, this routine requires an environment variable (i.e. `XPG_SUS_ENV=ON`) set in order to return _+HHMM_/_-HHMM_ with the `%z` format. This patch is to add computation of the time difference from UTC for AIX platform.

>From 8c61a66a3a5d92a5d1a8efb2104ebb5a34b9d97a Mon Sep 17 00:00:00 2001
From: Kelvin Li <kli at ca.ibm.com>
Date: Mon, 19 Aug 2024 11:43:41 -0400
Subject: [PATCH] [flang] Update the date_and_time intrinsic for AIX

---
 flang/runtime/time-intrinsic.cpp | 63 ++++++++++++++++++++++++++++++--
 1 file changed, 60 insertions(+), 3 deletions(-)

diff --git a/flang/runtime/time-intrinsic.cpp b/flang/runtime/time-intrinsic.cpp
index 92b937bc6f6267..e6c252c85d1668 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -247,6 +247,58 @@ static void DateAndTimeUnavailable(Fortran::runtime::Terminator &terminator,
 }
 
 #ifndef _WIN32
+#ifdef _AIX
+// Compute the time difference from GMT/UTC to get around the behavior of
+// strfname on AIX that requires setting an environment variable for numeric
+// value for ZONE.
+// The ZONE and the VALUES(4) arguments of the DATE_AND_TIME intrinsic has
+// the resolution to the minute.
+static int computeUTCDiff(const tm &localTime, bool *err) {
+  tm utcTime;
+  const time_t timer{mktime(const_cast<tm *>(&localTime))};
+  if (timer < 0) {
+    *err = true;
+    return 0;
+  }
+
+  // Get the GMT/UTC time
+  if (gmtime_r(&timer, &utcTime) == nullptr) {
+    *err = true;
+    return 0;
+  }
+
+  // Adjust for day difference
+  auto dayDiff{localTime.tm_mday - utcTime.tm_mday};
+  auto localHr{localTime.tm_hour};
+  if (dayDiff > 0) {
+    if (dayDiff == 1)
+      localHr += 24;
+    else
+      utcTime.tm_hour += 24;
+  } else if (dayDiff < 0) {
+    if (dayDiff == -1)
+      utcTime.tm_hour += 24;
+    else
+      localHr += 24;
+  }
+  return (localHr*60 + localTime.tm_min) - (utcTime.tm_hour*60 + utcTime.tm_min);
+}
+#endif
+
+static std::size_t getUTCOffsetToBuffer(char *buffer, const std::size_t &buffSize,
+    tm *localTime) {
+#ifdef _AIX
+  // format: +HHMM or -HHMM
+  bool err{false};
+  auto utcOffset{computeUTCDiff(*localTime, &err)};
+  auto hour{utcOffset/60};
+  auto hrMin{hour*100 + (utcOffset - hour*60)};
+  auto n{sprintf(buffer, "%+05d", hrMin)};
+  return err ? 0 : n + 1;
+#else
+  return std::strftime(buffer, buffSize, "%z", localTime);
+#endif
+}
 
 // SFINAE helper to return the struct tm.tm_gmtoff which is not a POSIX standard
 // field.
@@ -263,8 +315,13 @@ GetGmtOffset(const TM &tm, fallback_implementation) {
   // tm.tm_gmtoff is not available, there may be platform dependent alternatives
   // (such as using timezone from <time.h> when available), but so far just
   // return -HUGE to report that this information is not available.
-  return -std::numeric_limits<Fortran::runtime::CppTypeFor<
-      Fortran::common::TypeCategory::Integer, KIND>>::max();
+  bool err{false};
+  auto diff{computeUTCDiff(tm, &err)};
+  if (err)
+    return -std::numeric_limits<Fortran::runtime::CppTypeFor<
+        Fortran::common::TypeCategory::Integer, KIND>>::max();
+
+  return diff;
 }
 template <typename TM = struct tm> struct GmtOffsetHelper {
   template <int KIND> struct StoreGmtOffset {
@@ -317,7 +374,7 @@ static void GetDateAndTime(Fortran::runtime::Terminator &terminator, char *date,
     // Note: this may leave the buffer empty on many platforms. Classic flang
     // has a much more complex way of doing this (see __io_timezone in classic
     // flang).
-    auto len{std::strftime(buffer, buffSize, "%z", &localTime)};
+    auto len{getUTCOffsetToBuffer(buffer, buffSize, &localTime)};
     copyBufferAndPad(zone, zoneChars, len);
   }
   if (values) {



More information about the flang-commits mailing list