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
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 61 additions & 3 deletions flang/runtime/time-intrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,59 @@ 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.
Expand All @@ -263,8 +316,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 {
Expand Down Expand Up @@ -317,7 +375,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) {
Expand Down
Loading