How many days since jan 1 1985... the hard way



  • Just found this gem in the source code for "pom" (phase of moon) in the FreeBSD distro, but I presume it actually dates back to the Berkeley days:

    ...
    #define EPOCH     85
    ...
    #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
    ...
            (void) time(&tt);
            GMT = gmtime(&tt);
            days = (GMT->tm_yday + 1) + ((GMT->tm_hour +
                (GMT->tm_min / 60.0) + (GMT->tm_sec / 3600.0)) / 24.0);
            for (cnt = EPOCH; cnt < GMT->tm_year; ++cnt)
                    days += isleap(1900 + cnt) ? 366 : 365;
    
    

    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.



  • @realmerlyn said:

    Just found this gem in the source code for "pom"

    You really could have just stopped ther-

    @realmerlyn said:

    (phase of moon)

    Oh :(

    @realmerlyn said:

    in the FreeBSD distro, but I presume it actually dates back to the Berkeley days:

    ...
    #define EPOCH     85
    ...
    #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
    ...
            (void) time(&tt);
            GMT = gmtime(&tt);
            days = (GMT->tm_yday + 1) + ((GMT->tm_hour +
                (GMT->tm_min / 60.0) + (GMT->tm_sec / 3600.0)) / 24.0);
            for (cnt = EPOCH; cnt < GMT->tm_year; ++cnt)
                    days += isleap(1900 + cnt) ? 366 : 365;
    


    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.

     

     So, in your proposed method, how do you deal with... oh, I dunno, leap years?



  • @pkmnfrk said:

    @realmerlyn said:
    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.
     

     So, in your proposed method, how do you deal with... oh, I dunno, leap years?

     

    Boy, are you going to feel silly when you figure it out.



  • @Ren said:

    @pkmnfrk said:

    @realmerlyn said:
    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.
     

     So, in your proposed method, how do you deal with... oh, I dunno, leap years?

     

    Boy, are you going to feel silly when you figure it out.

     

    Am I? Or, am I going to go "see, this is why date-time processing is best left to those who know what they're doing."?



  • @pkmnfrk said:

    @Ren said:
    @pkmnfrk said:
    @realmerlyn said:
    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.
     

     So, in your proposed method, how do you deal with... oh, I dunno, leap years?

     

    Boy, are you going to feel silly when you figure it out.

     

    Am I? Or, am I going to go "see, this is why date-time processing is best left to those who know what they're doing."?

     

    Yes, you probably are. Sadly, not in the way you think ;) 



  • @realmerlyn said:

    Yes, instead of just subtracting current epoch time (which they have in tt at the first step) from the base date's epoch time, and divide by 86400, they count up, year by year, adding in the number of days. Talk about doing it the hard way! At least they didn't count a month at a time... that would have been funny.
     

    The problem is in that the C standard does not guarantee that the time() result is epoch time in seconds. Not sure about POSIX.



  • @pkmnfrk said:

     So, in your proposed method, how do you deal with... oh, I dunno, leap years?

    How about just subtracting day numbers? And even that is overly complex, as the phase of the moon can be computed from time difference in any time unit.



  • @mol1111 said:

    The problem is in that the C standard does not guarantee that the time() result is epoch time in seconds. Not sure about POSIX.


    POSIX time defines:

    The time() function shall return the value of time in seconds since the Epoch.
    And this value of the epoch is riddled through thousands of programs. It'd be insane to not be able to presume it means the official Unix epoch, which is probably defined in some place I couldn't find in two clicks.


  • @realmerlyn said:

    ... source code... in the FreeBSD distro...

    Why would you even DO that to yourself? Are you that bored/suicidal?

    Yeah, the code is a WTF, but you never know... maybe when it was written way back when, this was the fastest way of doing it.



  • @realmerlyn said:

    POSIX time defines:

    The time() function shall return the value of time in seconds since the Epoch.

    And this value of the epoch is riddled through thousands of programs. It'd be insane to not be able to presume it means the official Unix epoch, which is probably defined in some place I couldn't find in two clicks.

    I've always thought that the epoch was unspecified to avoid constraining implementations, but here it is: [url]http://www.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_150[/url].

    Addendum: Why would you need the value of the epoch, anyway? You could always calculate the Unix time for the base date with mktime.



  • 86400 seconds is not equal to one day. Once in a while, you need to add or remove a leap second. That's why if you want to be accurate -and I presume an astronomical application needs to be- you can't just divide by 86400.



  • @vic said:

    86400 seconds is not equal to one day. Once in a while, you need to add or remove a leap second. That's why if you want to be accurate -and I presume an astronomical application needs to be- you can't just divide by 86400.

    I'd expect a moon phase app can easily afford to be inaccurate by a few minutes over a 40-year period.



  • @vic said:

    86400 seconds is not equal to one day. Once in a while, you need to add or remove a leap second. That's why if you want to be accurate -and I presume an astronomical application needs to be- you can't just divide by 86400.

    Why not just correct for the initial offset and take the modulus of the average length of a Lunaiton (approximately 255143 seconds)? After all, the math gymnastics are just to get a moon phase right? You might be off by a few hours here and there, but if all you care about is what day it happens this should be off less frequently than the code the OP posted. 





  • Ignoring all 24 leap seconds since epoch results in an error of less than 0.000002%. Who cares?



  • @vic said:

    86400 seconds is not equal to one day. Once in a while, you need to add or remove a leap second. That's why if you want to be accurate -and I presume an astronomical application needs to be- you can't just divide by 86400.


    You will be surprised to learn it is. The UNIX time is defined as the number of non-leap seconds since 1970-01-01T00:00:00Z (Epoch).

    Phase of the moon would better be calculated with leap seconds, but the 16 or so second difference is not significant for this.



  • @Bulb said:

    Phase of the moon would better be calculated with leap seconds, but the 16 or so second difference is not significant for this.

    Is that true? In other words, is the lunar month getting longer, and doing so at least half as quickly as the day? This crucial matter doesn't seem to be covered adequately in articles on the subject. I can't even find out whether or not the Islamic calendar is altered at the whim of infidels.



  • @fennec @fatbull : I know this app is probably a game more than a serious scientific software, but I don't understand the logic that makes you say it's OK to replace correct code with incorrect code just to save 2 lines of code and a few nanoseconds of CPU time.

    @rad131304 said:

    Why not just correct for the initial offset and take the modulus of the average length of a Lunaiton (approximately 255143 seconds)?

    You'd have the same problem. Just like the day the lunation is slowing down due to tidal effects, and is slightly cahotic. Whether half a minute of error is acceptable or not is debatable.

    @Bulb said:

    You will be surprised to learn it is. The UNIX time is defined as the number of non-leap seconds since 1970-01-01T00:00:00Z (Epoch).
     

    Correct, that's why you can't divide the UNIX time by 86400 to get the number of days, since actual days have leap seconds.


  • @vic said:

    @rad131304 said:

    Why not just correct for the initial offset and take the modulus of the average length of a Lunaiton (approximately 255143 seconds)?

    You'd have the same problem. Just like the day the lunation is slowing down due to tidal effects, and is slightly cahotic. Whether half a minute of error is acceptable or not is debatable.

    Not nearly as bad; you aren't propogating the leap second error compounding it's effect, just introducing it at the end when you try and determine the current date. Even then, the 16 or so leap seconds that another poster pointed out really don't have much statistical effect on 35 years; they add up over, say, a couple thousand, but you should fix that in your seconds to date converter not in the lunation calculator.

    I also agree that this method will have problems with the wandering of Lunation every once in a while, but, as I previously stated, if all you care about is the day this should be pretty darn accurate. You can be about 1/4 of a day off on your guess and still have a high probability of getting the date right. (I'm assuming that the wander of the moon's Lunation here is either a gaussian distribution or a normal distribution - e.g. a approximatable by a random walk or cyclic behavior). IIRC, the moon's max and min Lunations have a differential of about 43200 seconds, so I feel pretty confident that my spherical chicken will be close enough for government work.



  • @vic said:

    I don't understand the logic that makes you say it's OK to replace correct code with incorrect code

     

    Because I don't. Both alternatives (OP and division by 86400) handle leap seconds the same. The only significant difference is source code size.

    @vic said:

    @Bulb said:

    You will be surprised to learn it is. The UNIX time is defined as the number of non-leap seconds since 1970-01-01T00:00:00Z (Epoch).
     Correct, that's why you can't divide the UNIX time by 86400 to get the number of days, since actual days have leap seconds.

    No. That's exactly why you can divide the timestamp by 86400 to get the number of days. Posix timestamps are an approximation of UTC where each and every day shall be accounted for by exactly 86400 seconds.



  • @fatbull said:

    No. That's exactly why you can divide the timestamp by 86400 to get the number of days. Posix timestamps are an approximation of UTC where each and every day shall be accounted for by exactly 86400 seconds.

     

    OK, you managed to half-convince me. I guess the idea that timestamps represent the time in seconds elapsed since the epoch is implanted too deeply in my brain :-) So what happens to the unix time when there is a leap second, does it just skip a beat?



  • @vic said:

    So what happens to the unix time when there is a leap second, does it just skip a beat?

    It relies on computer clocks being so inaccurate that it's a non-issue.



  • @Bulb said:

    @vic said:

    86400 seconds is not equal to one day. Once in a while, you need to add or remove a leap second. That's why if you want to be accurate -and I presume an astronomical application needs to be- you can't just divide by 86400.


    You will be surprised to learn it is. The UNIX time is defined as the number of non-leap seconds since 1970-01-01T00:00:00Z (Epoch).

    Phase of the moon would better be calculated with leap seconds, but the 16 or so second difference is not significant for this.

    If your unix system is auto-syncing with an internet time server, doesn't it actually have the real time, not the Unix epoch time? So it would give you the right answer anyway, even if it would be wrong in Unix terms?


  • From what I've gathered over the past few days, when there's a leap second, the Unix Time actually "skips a beat". So yes, you can divide by 86400 to get precise real days, but this is done by being slightly ambiguous in enumerating seconds.



  • @pkmnfrk said:

    "see, this is why date-time processing is best left to those who know what they're doing."
     



  • @Faxmachinen said:

    "See, this is why I'm awesome."

    Damn straight I know what I'm doing.



  • @vic said:

    OK, you managed to half-convince me. I guess the idea that timestamps represent the time in seconds elapsed since the epoch is implanted too deeply in my brain :-) So what happens to the unix time when there is a leap second, does it just skip a beat?

    When there is a leap second, unix time repeats.  That is, the leap second itself and the normal second immediately following the leap second will have the same Unix timestamp.  If you actually need sub-second accuracy in timestamps including over leap seconds, Unix time is not an option, because a timestamp generated in that two-second window from the start of the leap second to the end of the following second is not unique; it could represent either of two points in time.

     Also, were there ever to be a negative leap second -- that is, a second removed from the day -- Unix time would skip over that second, and thus there would be values of the timestamp that didn't correspond to any actual time.


Log in to reply