0

It's the first time I use 64-bit time_t structure to do operations with time. The compiler is the TI's C Compiler for CC3220SF.

Here my function that should return the seconds to the next event:

#define ACQ_INTERVAL    1 // in minutes
time_t _lastAcquisition;

time_t _timeToAcquire(void)
{
    time_t now = _getEpoch(); // from internal RTC
    if (_lastAcquisition == 0) _lastAcquisition = now;
    time_t diff = now - _lastAcquisition; // seconds since last acquisition
    time_t next = ACQ_INTERVAL * 60;

    UART_PRINT("Interval is %lld s\r\n", next);
    UART_PRINT("Current epoch is %lld, last acquisition was %lld, next one in %lld s\r\n", now, _lastAcquisition, next - diff);
    return next - diff; // seconds to next acquisition
}

UART_PRINT is just a wrapper for printf. Here the _getEpoch() function:

time_t _getEpoch(void)
{
    _i16 ret;
    _u8 pConfigOpt = SL_DEVICE_GENERAL_DATE_TIME;
    _u16 pConfigLen = sizeof(SlDateTime_t);

    SlDateTime_t dateTime = {0};
    ret = sl_DeviceGet(SL_DEVICE_GENERAL, &pConfigOpt, &pConfigLen, (unsigned char *) &dateTime);
    ASSERT_ON_ERROR(ret);

    struct tm t;
    time_t t_of_day;

    t.tm_year = dateTime.tm_year - 1900;
    t.tm_mon = dateTime.tm_mon - 1;
    t.tm_mday = dateTime.tm_day;
    t.tm_hour = dateTime.tm_hour;
    t.tm_min = dateTime.tm_min;
    t.tm_sec = dateTime.tm_sec;
    t.tm_isdst = -1;
    t_of_day = mktime(&t);

    return t_of_day;
}

Usually it works fine, but sometimes I get something weird like this output:

Interval is 60 s

Current epoch is 1511088032, last acquisition was 1511086500, next one in 18446744073709550144 s

Obviously there's something wrong. The difference should be 1532. Furthermore the huge number seems something like 2^64 - x. But x would be 1742... and I don't understand where it might come from.

I double checked the definition of time_t:

typedef long long __time64_t;

#if defined(_TARGET_DEFAULTS_TO_TIME64) || (__TI_TIME_USES_64) && __TI_TIME_USES_64)
    typedef __time64_t time_t;
#else
    typedef __time32_t time_t;
#endif

the __TI_TIME_USES_64 is defined and set to 1 (the IDE shows me the first section of #if is the one enabled).

Community
  • 1
  • 1
Mark
  • 4,338
  • 7
  • 58
  • 120
  • Can you grant that the function `mktime()` supports 64 bit? Sounds somehow like 32 bit wrap-arounds happen. (If somewhere 64 bit numbers are converted to 32 bit and later back to 64 bit you may get surprising results due to overflow/underflow in 32 bit and the sign extension.) Furthermore, if `time_t` is accidentally 32 bit and you `printf()` with `"%lld"` it considers 4 additional "random" bytes. To eliminate the doubts, I would include `assert(sizeof (time_t) == 8);` at the appropriate places (or print it if `assert` is not available). – Scheff's Cat Nov 19 '17 at 13:53
  • `mktime()` is defined as follow: `static __inline time_t mktime(struct tm *tptr) { return __mktime64(tptr); }` – Mark Nov 19 '17 at 13:57
  • Is your `lastAcquisition` variable or `timeToAcquire()` function called by several threads/tasks concurrently ? Are you certain there are no race conditions or thread safety issues with your code ? – nos Nov 19 '17 at 16:48
  • I'm using no RTOS, so I have only one thread. I don't call anything from an ISR. Furthermore both are referenced only one time, `lastAcquisition` is set a couple of line before the call to `timeToAcquire()` in the same function. – Mark Nov 19 '17 at 17:11
  • `time_t` is some arithmetic type. Rather than guess it matches `long long`, be explicit. `UART_PRINT("%lld\n", now, (long long) (next - diff));` if that does not work,then "UART_PRINT is just a wrapper for printf." is false or `printf()` is non-compliant. – chux - Reinstate Monica Nov 20 '17 at 02:23
  • don't use `time_t _lastAcquisition;`. Names beginning with `_` in global scope are reserved. In fact you should never use names begin `_` because they're reserved in various places. See [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/q/228783/995714) – phuclv Nov 28 '20 at 00:41

1 Answers1

1

You have

now = 1511088032
_lastAcquisition = 1511086500
diff = now - _lastAcquisition = 1532
next - diff = 60 - diff = -1472

It simply looks like the %lld specifier on your platform is buggy and works like %llu (unsigned long long). The huge number you see is

18,446,744,073,709,550,144 = 2^64 - 1472

which is exactly -1472 cast to an unsigned 64-bit value. If long long has 64 bits, the %lld specifier should never produce numbers larger than INT64_MAX which is 9,223,372,036,854,775,807.

nwellnhof
  • 32,319
  • 7
  • 89
  • 113
  • mmm, I've just tried: `time_t foo = -1000; UART_PRINT("%lld\r\n", foo);` and the output is -1000. Hence the function works... but if it's bugged sometimes doesn't... – Mark Nov 19 '17 at 14:04
  • 1
    @Mark: Since `foo` in that example is a compile-time constant, it's quite possible that the compiler may have replaced the `printf` call with a simple `puts` call with a constant string. I don't know about your compiler, but GCC is known to do such optimizations. In that case, it would simply mean that the compiler does the correct thing, while the runtime `printf` implementation may still be buggy. – Dolda2000 Nov 19 '17 at 14:08