[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