NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: number of seconds since the epoch



    Date:        Thu, 9 Dec 2010 02:26:35 +0000
    From:        Taylor R Campbell <campbell+netbsd%mumble.net@localhost>
    Message-ID:  <20101209022635.033DD98296%pluto.mumble.net@localhost>

  | I'd like to do this without customizing my installation of
  | the operating system from source,

Of course.

  | as you (Robert Elz) suggested, much
  | as such a custom installation may be the right thing.

Whether custom installations are a good thing, let alone "the right thing"
is a whole other question, but that is certainly not what I suggested, and
worse than that, wouldn't even work with the method I suggested, the
standard timezone files need to remain in place (or you would need to
use non-standard interfaces into the timezone code).

What I suggested was using the zic tool (its on every NetBSD system)
to build your own private copy of your particular timezone file.
I didn't say you should install it anywhere special, just anywhere you
know where it is (definitely not /usr/share/zoneinfo).

For now, let's say you put it in /tmp/leap-zone (but of course, /tmp
would not normally be a good choice for anything more than debugging).

Then you do (this is very rough pseudo code only), and assuming
you're in California (or Oregon, etc)

        zic -d . -L /usr/src/share/zoneinfo/leapseconds \
                 /usr/src/share/zoneinfo/northamerica
        cp US/Pacific /tmp/leap-zone

        TZ=US/Pacific (or whatever is correct for you - this needs to be
                        from the same source data as /tmp/leap-zone, except
                        leap-zone needs to be built with zic -L, whereas
                        US/Pacific isn't - aside from leap seconds the two
                        need to represent the same timezone).

        a = time(0);
        tm = localtime(&a);
        
        TZ=/tmp/leap-zone
        tzset();

        b = mktime(tm);

        if (b - a == 24)
                printf("success");


Ideally you should use the same source zone files as your system was built
with (hence the references to /usr/src) but you can download an updated
set from the net - the most up to date version currently is
        ftp://elsie.nci.nih.gov/pub/tzdata2010o.tar.gz
(also available from other sources, including munnari.oz.au).  If you use
that, to be sure of correctness, you should use it to update your system
zone files (without using -L on zic) and then build the zone file you
need (but do not install) with -L - just in case there's been a change in
summer time rules in your zone between the set installed with the system,
and the current data.

Once again (to repeat myself from last time) - I am assuming this should
work, I am not promising, and haven't even tested it, as I have no need
to know this peculiar value.

Another way would be

        n=$( grep '^Leap' /usr/src/share/zoneinfo/leapseconds | wc -l )
        t=$( date '+%s' )
        z=$(( $t + $n ))
        echo $z

Doing it this simply requires making the assumption that all leap seconds
are added, never subtracted, which has been historically true, but isn't
strictly correct.  To correct that an easy way would be two grep|wc -l
commands with more complex patterns (to match added, and removed leap
seconds respectively) then subtract the removed seconds in the final
calculation of z.   This one I did test...

Of course, both of these methods rely upon having an up to date version of
the leapseconds file.

And of course, once you know you have that, you can count the leap seconds
from it yourself, and then you can just do

        t = time(0) + 24;

and be done with it!

  | Also, it looks
  | like even if I do replace the zoneinfo files, time, gettimeofday, and
  | clock_gettime will still behave badly on a leap second, and rewind.

Ah, no, leap seconds don't work like that.   The system as a whole has
never heard of leap seconds, and will just ignore them.   That means, the
leap second is treated exactly the same as any other second (not that we
pretend it never happened and time stood still).

What happens after that depends upon what time synchronisation your
system is using.  If it is using nothing, your systems clock will now
be one second fast (or slow for a deleted leap second), that is compared
with "correct" time, and it will remain that way.   Without time
synchronisation, an error of a second is well within normal bounds, and
obviously (as there is no sync) no-one cares.

If you're using ntp (or something) to sync the time, then as soon as the
server notices that your system has "drifted away" from the true time,
it will begin to bring it back in line.  That is, future seconds will all
be a little longer than real seconds (or shorter, if it was a deleted
leap second), until your system is back in sync with real time (which may
take a few hours to accomplish).   True elastic seconds...

But unless someone goes explicitly setting the clock (causing time to jump)
you'll get a relatively smooth progression of exactly 86400 ticks every day.
(This is why posix seconds, and time_t values, are defined the way they are,
as truly processing leap seconds correctly is a real shock to most 
applications).

I'd be kind of interested to learn what kind of application you're needing
this for - only stuff doing astronomical studies is likely to care, I would
have thought, for everything else (that cares more than trivially about time)
you either want precise interval measurements (so you disable sync, and just
care about how much time elapsed between start and finish, and what the
clock actually said those times represent is irrelevant), or they want times
that match the human expectation of the clock, for which 86400 seconds a day
does a pretty good job, even if the seconds aren't all precisely the same
length.

kre



Home | Main Index | Thread Index | Old Index