[LEAPSECS] DNS examples

Steffen Nurpmeso sdaoden at yandex.com
Sat Jan 24 08:47:06 EST 2015


Brooks Harris <brooks at edlmax.com> wrote:
 |On 2015-01-23 10:33 AM, Clive D.W. Feather wrote:
 |> Steffen Nurpmeso said:
 |>>|> Well.  PHK follows the IERS format which uses the 1st of the month
 |>>|> after the leap second, i.e., the second after the leap occurred.
 |>>|
 |>>|This is an implementation detail.  PHK???s choice is as \
 |>>|good as the other.
 |>>
 |>> And i disagree with that.  The ISO C(99) standard doesn't offer
 |>> a JDN-TO-Gregorian and vice versa calculation.  There is the
 |>> well-known algorithm from Communications of the ACM, Vol 6, No 8,
 |>> but it is not in the standard.
 |> Irrelevant. The C Standard, in general, holds only those facilities which
 |>
 |> Converting JDN to Gregorian fits into neither of these categories, so it
 |> does not belong in the C Standard.
 |>
 |>> So in order to calculate the
 |>> actual date where the drift adjustment occurs you have to face
 |>> a very elaborate conversion.
 |> No, you need to use a library that's already been written to do the job.
 |> Takes 10 seconds or so.
 |>
 |What "library that's already been written to do the job" are you 
 |referring to, specifically?

To an internal one which uses the conversion functions as above.
Some "manual optimization" has been done back then, i guess the
compiled result wasn't satisfactory.  Since i haven't seen those
well-known functions in that very form, maybe someone finds them
useful.  There are better ones, but these are integer only and
where sufficient for our purpose, their restrictions were
documented.
Compile via "cc -o zt FILE.c", use via "./zt JDN" or "./zt YEAR
MONTH DAY".
Ciao!

--steffen

  #include <stdio.h>
  #include <stdlib.h>
  //
  #define sz size_t
  #define ui32 unsigned int
  #define ui16 unsigned short
  #define ui8 unsigned char
  //
  #  define NIL                           0x0
  #ifdef __cplusplus
  #  define s(TYPE,VAR)                   static_cast<TYPE>(VAR)
  #else
  #  define s(TYPE,VAR)                   ((TYPE)(VAR))
  #endif
  //
  #define _pub
  #define _sta
  #define _Nydin
  #define _Nydout
  #ifndef NDEBUG
  #define _Inj(X) X
  #else
  #define _Inj(X)
  #endif
  #define _AssertRet(X) if ((X) == 0) return
  //
  //---
  #if 0
  Please note that the documentation states clearly:
  * Date uses both, the julian-day-number (JDN),
  * defined as the number of days since 4713-01-01 BC,
  * and gregorian dates (year-month-day stuff).
  * The algorithms used internally (are mostly based on JDN and)
  * only work correct for the range #jdn_min ("gregorian" year #year_min)
  * and #jdn_max ("gregorian" year #year_max,
  * which is the period in between, and including, 01-01-01 and 65535-12-31.
  * "Correct" is not really correct though,
  * since holes (non-existing dates) are unknown to the algorithms,
  * and leap year calculations do not work correct until the final introduction
  * of the gregorian date, 1582-10-15.
  *
  * \note
  * Thus dates before 1582-10-15 \e cannot be correct.
  * (But julian-day-numbers as such are.)
  
  pub static const ui4    year_min = 1;
  pub static const ui4    year_max = 65535;
  * JDN of 01-01-01.
  pub static const ui4    jdn_min = 1721426;
  
  * JDN of 65535-12-31.
  */
  pub static const ui32   jdn_max = 25657591;
  
  * JDN of the \UNIX epoch (1970-01-01T00:00:00 (UTC)).
  pub static const ui32   jdn_epoch = 2440588;
  
  * (UTC) JDN for 32 bit \UNIX epoch signedness flip.
  pub static const ui32   jdn_unix32_flip = 2465443;
  
  * Midnight seconds for 32 bit \UNIX epoch signedness flip.
  pub static const ui32   midsec_unix32_flip = 11647;
  #endif
  #define _YEAR_MIN               1
  #define _YEAR_MAX               65535
  #define _JDN_MIN                1721426
  #define _JDN_MAX                25657591
  //---
  _pub _sta void
  /*DateTime::*/jdnToGregorian(ui32 _jdn, ui32 *_y, ui32 *_m, ui32 *_d)
  {
          // Algorithm is taken from Communications of the ACM, Vol 6, No 8.
          // (via third hand, plus adjustments)
          sz jdn, y, x;
          _Inj( if(_y) *_y = _YEAR_MIN; )
          _Inj( if(_m) *_m = 1; )
          _Inj( if(_d) *_d = 1; )
          _AssertRet(_y != NIL);
          _AssertRet(_m != NIL);
          _AssertRet(_d != NIL);
          _Nydin;
  
          jdn = _jdn;
          jdn -= 1721119;
          jdn <<= 2;
          --jdn;
          y =     jdn / 146097;
                  jdn %= 146097;
          jdn |= 3;
          y *= 100;
          y +=    jdn / 1461;
                  jdn %= 1461;
          jdn += 4;
          jdn >>= 2;
          x = jdn;
          jdn <<= 2;
          jdn += x;
          jdn -= 3;
          x =     jdn / 153;      // x -> month
                  jdn %= 153;
          jdn += 5;
          jdn /= 5;       // _jdn -> day
          if(x < 10)
                  x += 3;
          else {
                  x -= 9;
                  ++y;
          }
  
          *_y = s(ui32,y & 0xFFFF);
          *_m = s(ui32,x & 0xFF);
          *_d = s(ui32,jdn & 0xFF);
  
          _Nydout;
          return;
  }
  _pub _sta ui32
  /*DateTime::*/gregorianToJDN(ui32 _y, ui32 _m, ui32 _d)
  {
          // Algorithm is taken from Communications of the ACM, Vol 6, No 8.
          // (via third hand, plus adjustments)
          ui32 y = (_y ? _y : 1), m = (_m ? _m : 1), d = (_d ? _d : 1);
          sz jdn;
          _Nydin;
  
          if(m > 2)
                  m -= 3;
          else {
                  m += 9;
                  --y;
          }
          jdn = y;
          jdn /= 100;
          y -= 100 * jdn;
          y *= 1461;
          y >>= 2;
          jdn *= 146097;
          jdn >>= 2;
          jdn += y;
          jdn += d;
          jdn += 1721119;
          m *= 153;
          m += 2;
          m /= 5;
          jdn += m;
  
          _Nydout;
          return(s(ui32,jdn));
  }
  //---
  //
  int main(int argc, char **argv) {
    ui32 jdn, y, m, d;
    jdn = y = m = d = 0;
    if (argc == 2) {
      jdn = (ui32)strtoul(argv[1], NULL, 0);
      if (jdn < _JDN_MIN || jdn > _JDN_MAX)
        printf("BAD (%d - %d)\n",_JDN_MIN,_JDN_MAX);
      jdnToGregorian(jdn, &y, &m, &d);
    } else if (argc == 4) {
      y = (ui32)strtoul(argv[1], NULL, 0);
      if (y < _YEAR_MIN || y > _YEAR_MAX)
        printf("BAD (%d - %d)\n",_YEAR_MIN,_YEAR_MAX);
      m = (ui32)strtoul(argv[2], NULL, 0);
      d = (ui32)strtoul(argv[3], NULL, 0);
      jdn = gregorianToJDN(y, m, d);
    }
    printf("JDN=%u Gregorian=%04u-%02u-%02u\n", jdn, y, m, d);
    return 0;
  }


More information about the LEAPSECS mailing list