Skip to content

[flang] Update the date_and_time intrinsic for AIX #104849

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 28, 2024

Conversation

kkwli
Copy link
Collaborator

@kkwli kkwli commented Aug 19, 2024

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.

@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category labels Aug 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 19, 2024

@llvm/pr-subscribers-flang-runtime

Author: Kelvin Li (kkwli)

Changes

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.


Full diff: https://github.com/llvm/llvm-project/pull/104849.diff

1 Files Affected:

  • (modified) flang/runtime/time-intrinsic.cpp (+60-3)
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) {

Copy link

github-actions bot commented Aug 19, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@klausler klausler removed their request for review August 19, 2024 20:34
@kkwli
Copy link
Collaborator Author

kkwli commented Aug 26, 2024

Ping

Copy link
Contributor

@jeanPerier jeanPerier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small style nits. I am not an expert of time intrinsics and cannot test the patch on AIX though.

@kkwli kkwli self-assigned this Aug 26, 2024
Copy link
Contributor

@DanielCChen DanielCChen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@kkwli
Copy link
Collaborator Author

kkwli commented Aug 28, 2024

Thanks for the review.

@kkwli kkwli merged commit 8b198ee into llvm:main Aug 28, 2024
8 checks passed
@kkwli kkwli deleted the date_and_time-aix branch August 28, 2024 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants