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.
Anonymous
code fix and additional tests committed with revision [r13269]
Related
Commit: [r13269]