Shortcomings in time calculations (time zones, timegm, leap years)
claudio velati
cl.velati@tiscali.it
Tue Feb 27 14:55:00 GMT 2018
Biblioteca come culla del nuovo Rinascimento ... il resto è silenzio
Sent from Mediacom PhonePadIl 27/feb/2018 01:10 PM "R. Diez via newlib" <newlib@sourceware.org> ha scritto:
>
> Hi all:
>
> First of all, many thanks for Newlib.
>
> I am writing firmware for a family of small embedded devices that live
> in different time zones and have to do extensive time calculations,
> including leap years. This is painful with Newlib.
>
> I am grateful that you have implemented 64-bit time_t recently (see
> USE_LONG_TIME_T). I can now stop using the following "y2038" library,
> which wasn't a smooth ride either:
>
> https://github.com/evalEmpire/y2038
>
> I had to jump through many hoops to get some error information out of
> Newlib's tzset(), and avoid leaks on invalid input. That is actually the
> only place in my entire firmware that needs environment variables at
> all. The gory details are here:
>
> Difficulties with tzset() and setenv()
> https://sourceware.org/ml/newlib/2017/msg00700.html
>
> The one thing I miss dearly is timegm(), which does the inverse of
> gmtime(), and is not standard, but widely available. More information
> about this is here:
>
> https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc
>
> The Boost implementation is small and could serve as a basis, look for
> internal_timegm() here:
>
> https://github.com/boostorg/chrono/blob/develop/include/boost/chrono/io/time_point_io.hpp
>
> But I suspect that such a routine could share source code with the
> existing mktime() implementation. For example, both routines share the
> same code in this project:
>
> https://github.com/freebsd/freebsd/blob/master/contrib/tzcode/stdtime/localtime.c
>
> In the process, I would make these macros in mktime.c public (or even
> better, as inline functions), as it would be very convenient to have
> such code readily available and well tested:
>
> #define _ISLEAP(y) (((y) % 4) == 0 && (((y) % 100) != 0 || (((y)+1900) %
> 400) == 0))
> ---> but beware of the "+1900" inside _ISLEAP!
> I would add a comment like "returns exactly 0 or 1, as it can be
> directly used as an array index"
>
> #define _DAYS_IN_YEAR(year) (_ISLEAP(year) ? 366 : 365)
>
> I know it's not much, but it saves searching around for something
> suitable, which actually took me longer than I expected.
>
> In fact, the logic is duplicated in Newlib already, see also
> is_leap_year() in strptime.c and isleap() in local.h (which does not
> seem to be a public header).
>
> Array __month_lengths[] inside local.h would also be a good candidate to
> be made public. Furthermore, 72 bytes of program memory could be saved
> if it were an array of uint8_t instead of 32-bit integers.
>
> Furthermore, it would save memory and performance if there were
> alternative entry points for routines like mktime() that just took the
> time zone as a parameter. This way, there would be no need to do a
> TZ_LOCK, and ultimately no need to have an environment at all for
> embedded targets.
>
> I cannot directly contribute source code at the moment. But I hope that
> this mailing list message may at least help others identify these
> shortcomings.
>
> Regards,
> rdiez
More information about the Newlib
mailing list