Notes on 'timesub"
John Dlugosz
JDlugosz at TradeStation.com
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
individually:
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.)
--John
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mm.icann.org/pipermail/tz/attachments/20090115/7091b3d0/attachment.htm>
More information about the tz
mailing list