Thread: libmusl time: Help understanding how __year_to_secs works

  1. #1
    Registered User
    Join Date
    Jan 2022
    Posts
    1

    libmusl time: Help understanding how __year_to_secs works

    Hey guys!

    Looking to implement some functions that relate to time within a project I am working on and decided to look at what other devs have done to handle time within C. I decided to look into the C standard libraries, in particular muslc (I've read that this is a good standard library) in hopes to guide my work and to learn more about how it is implemented.

    I have encounted a function that is beyond my comprehension by just reading the source alone. There is no documentation I can find on it, however I am new to poking around large libraries like this, so I am not entirely sure where to look either. The function in question is as follows:

    Code:
    long long __year_to_secs(long long year, int *is_leap)
    {
        if (year-2ULL <= 136) {
            int y = year;
            int leaps = (y-68)>>2;
            if (!((y-68)&3)) {
                leaps--;
                if (is_leap) *is_leap = 1;
            } else if (is_leap) *is_leap = 0;
            return 31536000*(y-70) + 86400*leaps;
        }
    
        int cycles, centuries, leaps, rem;
    
        if (!is_leap) is_leap = &(int){0};
        cycles = (year-100) / 400;
        rem = (year-100) % 400;
        if (rem < 0) {
            cycles--;
            rem += 400;
        }
        if (!rem) {
            *is_leap = 1;
            centuries = 0;
            leaps = 0;
        } else {
            if (rem >= 200) {
                if (rem >= 300) centuries = 3, rem -= 300;
                else centuries = 2, rem -= 200;
            } else {
                if (rem >= 100) centuries = 1, rem -= 100;
                else centuries = 0;
            }
            if (!rem) {
                *is_leap = 0;
                leaps = 0;
            } else {
                leaps = rem / 4U;
                rem %= 4U;
                *is_leap = !rem;
            }
        }
    
        leaps += 97*cycles + 24*centuries - *is_leap;
    
        return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
    }
    I am posting this here to hopefully get some insight into understanding this code (concepts and algorithms used), and perhaps be pointed to some resources that might be available to me to aid in understanding it (documentation I may be missing?).

  2. #2
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,110
    First of all, wherever you got this "Library", it is NOT a "Standard Library".

    Standard libraries, are the libraries provided with the compiler. The Operating System may, and usually does contain other libraries as part of the O/S. They would be well documented if designed to be used by a programmer.

    Where did you obtain this "library"? What was the file you downloaded?

  3. #3
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    musl libc

    musl is a C standard library implementation for Linux.
    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  4. #4
    Registered User rstanley's Avatar
    Join Date
    Jun 2014
    Location
    New York, NY
    Posts
    1,110
    Quote Originally Posted by stahta01 View Post
    musl libc

    Tim S.
    I was not familiar with that library. Thanks!

    iamsoydev:

    The library is well documented at the link Tim provided.

  5. #5
    Registered User
    Join Date
    Feb 2019
    Posts
    1,078
    What an interesting thechnique:

    Code:
    if ( ! is_leap ) is_leap = &(int){0};

  6. #6
    Registered User
    Join Date
    Oct 2019
    Posts
    82
    Quote Originally Posted by flp1969 View Post
    What an interesting thechnique:

    Code:
    if ( ! is_leap ) is_leap = &(int){0};
    Yeah, interesting. That caught my eye, too.

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Start by wrapping a small test program around it.
    Code:
    int main ( ) {
        for ( int year = 0 ; year <= 2100 ; year++ ) {
            int leap = 42;
            long long seconds = __year_to_secs(year, &leap);
            printf("year=%d seconds=%lld, leap=%d\n", year, seconds, leap);
        }
    }
    
    $ gcc -Wall -Wextra -g foo.c
    $ ./a.out 
    year=65 seconds=-157766400, leap=0
    year=66 seconds=-126230400, leap=0
    year=67 seconds=-94694400, leap=0
    year=68 seconds=-63158400, leap=1
    year=69 seconds=-31536000, leap=0
    year=70 seconds=0, leap=0
    year=71 seconds=31536000, leap=0
    year=72 seconds=63072000, leap=1
    year=73 seconds=94694400, leap=0
    year=74 seconds=126230400, leap=0
    year=75 seconds=157766400, leap=0
    ...
    year=1900 seconds=57749241600, leap=0
    year=1901 seconds=57780777600, leap=0
    year=1902 seconds=57812313600, leap=0
    year=1903 seconds=57843849600, leap=0
    year=1904 seconds=57875385600, leap=1
    year=1905 seconds=57907008000, leap=0
    year=1906 seconds=57938544000, leap=0
    year=1907 seconds=57970080000, leap=0
    year=1908 seconds=58001616000, leap=1
    year=1909 seconds=58033238400, leap=0
    year=1910 seconds=58064774400, leap=0
    ...
    Year 70 seems an odd place to start counting from.

    > __year_to_secs
    Names beginning with double underscores are reserved identifiers.
    Quote Originally Posted by c99
    7.1.3 Reserved identifiers
    — All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
    — All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
    The simple calculation ignores all the calendar meddling through centuries past.
    Gregorian calendar - Wikipedia
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    Quote Originally Posted by Salem View Post
    Year 70 seems an odd place to start counting from.
    In the tm structure, the tm_year field is the year minus 1900, so a value of 70 is 1970, which is the Unix epoch. Not so odd after all (well, I guess you could say the Unix epoch of 1970 was an odd choice, but at least it explains why this function starts years at 70).

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Understanding how cache works
    By baxy in forum C++ Programming
    Replies: 6
    Last Post: 08-24-2015, 05:26 AM
  2. Getting a general understanding how this stuff works.
    By overclocking in forum C Programming
    Replies: 4
    Last Post: 03-01-2014, 12:11 PM
  3. c sendfile doesn't works the 2nd time
    By polslinux in forum C Programming
    Replies: 5
    Last Post: 08-08-2012, 04:59 AM
  4. Works only part of the time?
    By scr0llwheel in forum C++ Programming
    Replies: 1
    Last Post: 01-07-2003, 08:34 PM
  5. Function works one time, and not another...
    By Captain Penguin in forum C++ Programming
    Replies: 3
    Last Post: 10-05-2002, 10:14 PM

Tags for this Thread