Notes on 'timesub"

John Dlugosz JDlugosz at
Thu Jan 15 17:39:43 UTC 2009

The implementation of 'timesub' uses quite a bit of complex logic,
approximations, and looping to do what can be done with a single
expression.  The part of the function that digests the number of days
into y/m/d fields has been known since before computers as "Julian Day
Number" and that can be harnessed directly simply by subtracting a
constant for the Epoch base.


Here is my version, which is not so digested into my own library that
you can't follow the logic:


void timezone_t::state::timesub (

   const __time64_t t, // input time number

   const long offset, // added to time, but figures date from original
(e.g. like a denormal value)

   ymd_hms& tmp  // output

   ) const


 // more complex than it needs to be!

 static const int JDayEpoch= Julian_day_number (ymd(EPOCH_YEAR, 1, 1));

 int days_in_epoch = t / SECSPERDAY;

 int rem = t - days_in_epoch * SECSPERDAY;

 int corr= count_leap_seconds (JDayEpoch, JDayEpoch+days_in_epoch);

 tmp= Julian_day_number (JDayEpoch+days_in_epoch);

 tmp.set_normalized (hms(0,0,rem+offset - corr));



In your code, the part I'm referring to is the middle.  First it finds
'corr' for leap seconds, and afterwards it adds the seconds into the
h/m/s possibly overflowing into the d/m/y.  I have those in callable
functions, but the approach is the same.  It's just that the middle
part, converting a number of seconds into y/m/d, is not as hard as you
make it out to be.  


This is a direct implementation of the published formula, which involves
no looping or successive approximations or peeling off each month


ymd Julian_day_number (int J)


 const int j= J+32044;

 const int g= j / 146097;

 const int dg= j % 146097;

 const int c= (dg / 36524 + 1) * 3 / 4;

 const int dc= dg - c * 36524;

 const int b= dc / 1461;

 const int db= dc % 1461;

 const int a= (db/365+1) * 3 / 4;

 const int da= db - a * 365;

 const int y= g*400 + c*100 + b*4 + a;

 const int m= (da*5+308) / 153 - 2;

 const int d= da - (m+4) *153 / 5 + 122;

 return ymd (y-4800+(m+2)/12,  (m+2)%12+1, d+1);



(The comment that it is (still) more complex than it needs to be is
because the normalization code in my library can handle that directly,
so I can just call existing code.)




-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the tz mailing list