@@ -247,6 +247,61 @@ static void DateAndTimeUnavailable(Fortran::runtime::Terminator &terminator,
247247}
248248
249249#ifndef _WIN32
250+ #ifdef _AIX
251+ // Compute the time difference from GMT/UTC to get around the behavior of
252+ // strfname on AIX that requires setting an environment variable for numeric
253+ // value for ZONE.
254+ // The ZONE and the VALUES(4) arguments of the DATE_AND_TIME intrinsic has
255+ // the resolution to the minute.
256+ static int computeUTCDiff (const tm &localTime, bool *err) {
257+ tm utcTime;
258+ const time_t timer{mktime (const_cast <tm *>(&localTime))};
259+ if (timer < 0 ) {
260+ *err = true ;
261+ return 0 ;
262+ }
263+
264+ // Get the GMT/UTC time
265+ if (gmtime_r (&timer, &utcTime) == nullptr ) {
266+ *err = true ;
267+ return 0 ;
268+ }
269+
270+ // Adjust for day difference
271+ auto dayDiff{localTime.tm_mday - utcTime.tm_mday };
272+ auto localHr{localTime.tm_hour };
273+ if (dayDiff > 0 ) {
274+ if (dayDiff == 1 ) {
275+ localHr += 24 ;
276+ } else {
277+ utcTime.tm_hour += 24 ;
278+ }
279+ } else if (dayDiff < 0 ) {
280+ if (dayDiff == -1 ) {
281+ utcTime.tm_hour += 24 ;
282+ } else {
283+ localHr += 24 ;
284+ }
285+ }
286+ return (localHr * 60 + localTime.tm_min ) -
287+ (utcTime.tm_hour * 60 + utcTime.tm_min );
288+ }
289+ #endif
290+
291+ static std::size_t getUTCOffsetToBuffer (
292+ char *buffer, const std::size_t &buffSize, tm *localTime) {
293+ #ifdef _AIX
294+ // format: +HHMM or -HHMM
295+ bool err{false };
296+ auto utcOffset{computeUTCDiff (*localTime, &err)};
297+ auto hour{utcOffset / 60 };
298+ auto hrMin{hour * 100 + (utcOffset - hour * 60 )};
299+ auto n{sprintf (buffer, " %+05d" , hrMin)};
300+ return err ? 0 : n + 1 ;
301+ #else
302+ return std::strftime (buffer, buffSize, " %z" , localTime);
303+ #endif
304+ }
250305
251306// SFINAE helper to return the struct tm.tm_gmtoff which is not a POSIX standard
252307// field.
@@ -263,8 +318,19 @@ GetGmtOffset(const TM &tm, fallback_implementation) {
263318 // tm.tm_gmtoff is not available, there may be platform dependent alternatives
264319 // (such as using timezone from <time.h> when available), but so far just
265320 // return -HUGE to report that this information is not available.
266- return -std::numeric_limits<Fortran::runtime::CppTypeFor<
267- Fortran::common::TypeCategory::Integer, KIND>>::max ();
321+ const auto negHuge{-std::numeric_limits<Fortran::runtime::CppTypeFor<
322+ Fortran::common::TypeCategory::Integer, KIND>>::max ()};
323+ #ifdef _AIX
324+ bool err{false };
325+ auto diff{computeUTCDiff (tm, &err)};
326+ if (err) {
327+ return negHuge;
328+ } else {
329+ return diff;
330+ }
331+ #else
332+ return negHuge;
333+ #endif
268334}
269335template <typename TM = struct tm > struct GmtOffsetHelper {
270336 template <int KIND> struct StoreGmtOffset {
@@ -317,7 +383,7 @@ static void GetDateAndTime(Fortran::runtime::Terminator &terminator, char *date,
317383 // Note: this may leave the buffer empty on many platforms. Classic flang
318384 // has a much more complex way of doing this (see __io_timezone in classic
319385 // flang).
320- auto len{std::strftime (buffer, buffSize, " %z " , &localTime)};
386+ auto len{getUTCOffsetToBuffer (buffer, buffSize, &localTime)};
321387 copyBufferAndPad (zone, zoneChars, len);
322388 }
323389 if (values) {
0 commit comments