Help with #5143 (Get TOD past 2100)

hello,

I"m trying to finish up this Open issue

and i’m struggling with this ticket right now.

this ticket is to change the current implementation of rtems_clock_get_tod: to use Gmtime as opposed to the current one that uses it’s own math and to allow years beyond 2100. I think I was able to get the implementation down but i am not sure if my testing verifies it correctly. that being said i also doubt what what i’ve written for rtems_clock_get_tod

 _TOD_Get_timeval( &now );

  current_time_tm = gmtime_r( &now.tv_sec, &buf );
  _Assert( current_time_tm != NULL );

  time_of_day->year   = 1900 + current_time_tm->tm_year;
  time_of_day->month  = 1 + current_time_tm->tm_mon;  
  time_of_day->day    = current_time_tm->tm_mday;
  time_of_day->hour   = current_time_tm->tm_hour;
  time_of_day->minute = current_time_tm->tm_min;
  time_of_day->second = current_time_tm->tm_sec;
  time_of_day->ticks  = now.tv_usec /
    rtems_configuration_get_microseconds_per_tick( );

this is my current implimentation rtems get clock_tod which calls gmtime_r and returns and populates the struct.

my current way i’m testing is to do this


  rtems_status_code status;
  rtems_time_of_day new_tod;
  status = rtems_clock_set( the_tod );
  rtems_test_assert( !status );

  status = rtems_clock_get_tod( &new_tod );
  rtems_test_assert( !status );
  
  rtems_test_assert( new_tod.year == the_tod->year );
  rtems_test_assert( new_tod.month == the_tod->month);
  rtems_test_assert( new_tod.day == the_tod->day );
  rtems_test_assert( new_tod.hour == the_tod->hour);
  rtems_test_assert( new_tod.minute == the_tod->minute );
  rtems_test_assert( new_tod.second == the_tod->second);
  rtems_test_assert( new_tod.ticks == the_tod->ticks ); 

currently i use the_tod as a passed in argument and it use rtems_clock_set to set that to the time. And then i use clock_get_tod to get the tod and compare the fields it seems to fail when i choose times above 2100 and i’ve tested with with years <2100.

I"m right now trying to write a test in linux first .

time_t now= 1745701522;
  struct tm     buf;
  struct tm     *current_time_tm;

 current_time_tm = gmtime_r( &now, &buf );
 time_t myTime_t = mktime(current_time_tm);
printf("The current local time is: %ld", myTime_t -now);

using time_t to set time (i use a epoch converter) then i pass it into gmtime_r then i use mktime to convert it and compare it with now

Am i on the right track what suggestion do you have?

thanks!

The current implementation is known to only support through 2100. If you have cases that fail on the current implementation and work on the new one that’s a good thing.

ok do you have any suggestions? should i add anything to my test?

Do you have a variety of dates/times being used as was suggested?

As I posted earlier, having cases that failed with the current implementation and work when switching to gmtime_r() is good.

Is the current code pushed to the MR? Post the MR URL for everyone to look at.

yes the MR is here Cannot obtain dates later than 2100 (!339) · Merge requests · RTEMS / RTOS / RTEMS · GitLab


rtems_time_of_day Dates[ NUMBER_OF_DATES ] = {
  /* YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, TICKS */
  {  1988,   1,    1,   12,    45,     00,     0 },
  {  1988,  12,   31,    9,    00,     00,     0 },
  {  1999,  12,   31,   23,    55,     59,     0 },
  {  1999,  06,   30,   00,    01,     30,     0 },
  {  2000,   1,    1,    0,    15,     59,     0 },
  {  2005,   2,    2,    5,    10,     59,     0 },
  {  2010,   3,    3,   10,     5,     59,     0 },
  {  2020,   4,    4,   15,     0,     59,     0 }
};

dates are here, any suggestions are welcome. i didn’t include the one with >2100

I suggest you have a look at sp2038. Changing the days tested out to year 3000 results in a failure:

*** BEGIN OF TEST SP 2038 ***
*** TEST VERSION: 7.0.0.34c362fee100659e36a6945204f77e71cb1c2f7e-modified
*** TEST STATE: EXPECTED_PASS
*** TEST BUILD: RTEMS_DEBUG RTEMS_POSIX_API
*** TEST TOOLS: 13.3.0 20240521 (RTEMS 7, RSB 170160cb918e7c68b4b35d8f0a42db6df81168e7, Newlib 1b3dcfd)
../../../testsuites/sptests/sp2038/init.c: 298 (sc) == RTEMS_SUCCESSFUL

The date and error is:

date is 2100/1/1 0:1:2, sc=RTEMS_INVALID_CLOCK

I lost the trail on setting at the TOD_Hook_Run() call.

The limit is set in the macro TOD_LATEST_YEAR.

And the TOD hook is not set. I suspect it is a way to set the time in hardware.

I think there is more to this change than the get clock call. The comment in the header says:

/*
 *  The following constant defines the latest year to which an
 *  RTEMS time of day can be set using rtems_clock_set().
 *
 *  32 bits can accept as latest point in time 2106-Feb-7 6:28:15
 *  but to simplify the implementation, is was decided to only
 *  check that the year is not greater than the year of this constant.
 *  The year 2099 was chosen because all years evenly divisible by 4 from 1988
 *  to 2099 are leap years.  In this time frame, years evenly divisible by 100
 *  are no leap years unless they are evenly divisible by 400.  Thus the year
 *  2000 is a leap year.
*/

@kiwichris A few things:

(1) That comment was written by Frank Kühndel in 2021. It does not state which type is 32-bits and fails. I cannot figure out what is magical about that date/time the comment cites. Even if it is correct, the comment needs more detail. We need to ask @frank_k for clarification.

7bbbe4225c9 cpukit/include/rtems/score/todimpl.h (Frank Kühndel 2021-04-08 15:41:15 +0200 161) * 32 bits can accept as latest point in time 2106-Feb-7 6:28:15

(2) To get this completely right, the function _TOD_Get_leap_year_index() appears to be incorrect for anything past 2100. Uses of this function need to be checked I think.

(3) There are no TOD hooks except in the tests. This only makes sense to use if the application wants to set another clock like an RTC when the RTEMS TOD is set. I added it for the use case of being virtualized and the integrator wanting setting the TOD to propagate to the host environment. So there should be no hooks to run.

Hmm i might truly be missing something what i tired to do today was i tried to run the tod2038 test and it says it fails at


../../../testsuites/sptests/sptod/init.c: 86 !status

I think i could use this test to verify if my method works. but i says it fails at where a Unisgned long is.

i used a similar method to testing in my test i moved the code testing the problematic year into my test

 sc = rtems_clock_set(the_tod);
   ASSERT_SC(sc);
    sc = rtems_clock_get_tod(&now);
    ASSERT_SC(sc);
    rtems_test_assert(memcmp(&now, the_tod, sizeof(now)) == 0);

it fails at the assert after rtems clock set
and if i comment it out it fails at the memcmp line

I do not remember the details but I can tell the history. Four years ago, I was writing tests for the RTEMS qualification project testing the rtems_clock_set() function. Back then its documentation said the latest possible date is 2514-05-31. When I tested that, I got an RTEMS_INVALID_NUMBER error as result – a result the function should not even be able to return according to the documentation.

I opened bug #4338 and investigate the issue.

To answer your 32-bit question, you can read in the bug report: * _TOD_To_seconds() converts the time_of_day structure into seconds using a variable time of type uint32_t*.

It was agreed not to change to 64-bit numbers, esp. because other RTEMS functions would need to be changed to cover this range of values. Moreover, possible issues with 32 bit architectures must be considered as well.

Thus, the maximum date would have been 2106-Feb-07 06:28:15. The first solution then limited the date to TOD_LATEST_YEAR = 2105 because that avoids an if-clause going down to Feb-7 6:28:15 (Git commit 7bbbe4225c9).

Sebastian then optimized the function further by reducing the maximum date to 2099 in Git commit ad41c17933e40f27.

so what does that have to do with my problem?

My post was a reply to Joel’s responds at Chris . He mentioned to ask me for clarification in point (1). It was not a response to your problem. Sorry for the confusion I may have caused.

FYI if you look at the upper right of @frank_k post you can see which post he is responding to. Discourse kind of makes it confusing but if someone uses the ‘reply’ button it does provide a link. Just mentioning this here for the benefit of everyone. :slight_smile:

You can click the button to expand the post or jump to it directly.

yes i know but i’m asking how the discussion of that issue applies to what i’m working on now?