Menu ▾ ▴

#2110 32-bit: DATE('F'|'T') and TIME('F'|'T'|'O') never return a RexxInteger; RexxInteger.testGroup fails with UTC

5.3.0
pending
Erich
None
none
7
2026-10-10
2026-10-10
No

Summary: 32-bit: DATE('F'/'T') and TIME('F'/'T'/'O') always return a String; RexxInteger.testGroup TEST_INTEGER_TIME fails when the UTC offset is 0

In BuiltinFunctions.cpp, DATE('F'), DATE('T'), TIME('F'), TIME('T') and
TIME('O') are documented in the code as "if possible, return RexxInteger
instead of String", but the 32-bit branch (#ifndef __REXX64__) always
formats a String, even when the value fits in a 32-bit RexxInteger
(9 digits):

        case 'O':                          // 'O'ffset.  microseconds offset from UTC
            // if possible, return RexxInteger instead of String
#ifdef __REXX64__
            return new_integer(timestamp.timeZoneOffset);
#else
            timestamp.formatTimeZone(work);
            break;
#endif

ooRexx/base/class/RexxInteger.testGroup, TEST_INTEGER_TIME, expects a
RexxInteger whenever the result has no more digits than
.RexxInfo~internalDigits. On a 32-bit build TIME('F') and TIME('T') are
always longer than 9 digits, and TIME('O') is too for any non-zero offset
(it is in microseconds), so the test only fails when the offset is 0: with
TZ=UTC, or in a zone at UTC+0 (the UK, Ireland or Portugal in winter,
Iceland all year):

[failure]
  Test:   TEST_INTEGER_TIME
  Class:  RexxInteger.testGroup
  Line:   391
  Failed: assertTrue
    Expected: 1
    Actual:   0
    Message:  time('O') should return a RexxInteger

DATE('T') has the same inconsistency for dates before September 2001 (fewer
than 10 digits): date('T', '20000101', 'S') is 946684800, a String on
32-bit and a RexxInteger on 64-bit. No test catches that one, because
TEST_INTEGER_DATE only uses the current date.

Reproduce with any 32-bit build (the isInteger routine is the test group's
own):

say time('O') isInteger(time('O')) date('T','20000101','S') isInteger(date('T','20000101','S'))
::routine isInteger
  use strict arg number
  numeric digits 18
  if \number~dataType("W") then return 0
  if number~abs < 10 then number = number + 20
  numeric digits 1
  return \number~min~contains("E")
$ TZ=UTC rexx t.rex
0 0 946684800 0          <- 32-bit; 64-bit prints 0 1 946684800 1

Fix (attached diff): use Numerics::int64ToObject(), which returns a
RexxInteger when the value is within the whole-number range of the platform
and a NumberString otherwise, so the five cases need no #ifdef at all. On
64-bit nothing changes (the values always fit).

Tested on trunk r13263: native 64-bit Linux, the groups RexxInteger,
DATE, TIME, DateTime and TimeSpan pass as before (TZ=UTC); 32-bit
(a wasm32 build), the same groups went from 1 failure to 0 with TZ=UTC,
and still pass with TZ=Europe/Madrid, where TIME('O') (7200000000) is
correctly still not a RexxInteger. The format...() helpers of
RexxDateTime that the 32-bit branch used become unused by these BIFs.

Found running the official test suite on GitHub Actions runners, which
use UTC.

1 Attachments

Discussion

  • Erich

    Erich - 2026-10-10
    • status: open --> pending
    • assigned_to: Erich
     
  • Erich

    Erich - 2026-10-10

    code fix and additional tests committed with revision [r13269]

     

    Related

    Commit: [r13269]

Anonymous
Anonymous

Add attachments
Cancel