|
Home > Archive > Unix Programming > July 2007 > seconds past midnight?
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
seconds past midnight?
|
|
| Richard Eich 2007-07-20, 1:20 pm |
| SLES9 and RHES4. Stock GCC and CLIB
I need seconds past midnight for the local machine. I can do this by
a series of conversions, but since I have to do a lot of them I've
been looking for a single call (or minimal number of calls) that
produces this.
Google and man coming up empty so far. Anyone have a good reference
I can check?
| |
| Giorgos Keramidas 2007-07-20, 1:20 pm |
| On Fri, 20 Jul 2007 16:06:14 GMT, Richard Eich <richard.eich@domain.invalid> wrote:
> SLES9 and RHES4. Stock GCC and CLIB
>
> I need seconds past midnight for the local machine. I can do this by
> a series of conversions, but since I have to do a lot of them I've
> been looking for a single call (or minimal number of calls) that
> produces this.
>
> Google and man coming up empty so far. Anyone have a good reference
> I can check?
Try Googling for the manpages of strftime(), localtime(), gmtime(),
mktime(), and similar calls. A sample program using them is shown
below. It doesn't *print* the difference in seconds of the current time
and today's midnight, but it comes pretty close and should be _very_
easy to adapt:
------------------------------------------------------------------------
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void ptime(const char *, struct tm *);
int
main(void)
{
char errbuf[LINE_MAX + 1];
struct tm now, midnight;
time_t now_sec;
now_sec = time(NULL);
if (localtime_r(&now_sec, &now) == NULL) {
int save_errno = errno;
if (strerror_r(save_errno, errbuf, sizeof(errbuf)) != 0)
exit(EXIT_FAILURE);
fprintf(stderr, "localtime_r: error %d: %s\n",
save_errno, errbuf);
exit(EXIT_FAILURE);
}
/* Copy the current time to 'midnight' and tweak. */
midnight = now;
midnight.tm_sec = 0;
midnight.tm_min = 0;
midnight.tm_hour = 0;
ptime("now", &now);
ptime("midnight", &midnight);
return 0;
}
void
ptime(const char *txt, struct tm *tm)
{
char errbuf[LINE_MAX + 1];
char timebuf[LINE_MAX + 1];
time_t sec;
if (tm == NULL)
return;
if (txt == NULL)
txt = "??";
sec = mktime(tm);
if (strftime(timebuf, sizeof(timebuf) - 1,
"%Y-%m-%d %H:%M:%S", tm) >= sizeof(timebuf)) {
int save_errno = errno;
if (strerror_r(save_errno, errbuf, sizeof(errbuf)) != 0)
exit(EXIT_FAILURE);
fprintf(stderr, "strftime @ %p: error %d: %s\n", tm,
save_errno, errbuf);
exit(EXIT_FAILURE);
}
printf("%-10s | %12llu | %s\n", txt, (unsigned long long)sec,
timebuf);
}
------------------------------------------------------------------------
Compile this with your C compiler, run it and it should print something
similar to:
$ ./a.out
now | 1184950846 | 2007-07-20 20:00:46
midnight | 1184878800 | 2007-07-20 00:00:00
$
| |
| shakahshakah@gmail.com 2007-07-20, 1:20 pm |
| On Jul 20, 12:06 pm, Richard Eich <richard.e...@domain.invalid> wrote:
> SLES9 and RHES4. Stock GCC and CLIB
>
> I need seconds past midnight for the local machine. I can do this by
> a series of conversions, but since I have to do a lot of them I've
> been looking for a single call (or minimal number of calls) that
> produces this.
>
> Google and man coming up empty so far. Anyone have a good reference
> I can check
Isn't it just time(0) % 86400, for GMT at least?
| |
| Eric Sosman 2007-07-20, 1:20 pm |
| Richard Eich wrote On 07/20/07 12:06,:
> SLES9 and RHES4. Stock GCC and CLIB
>
> I need seconds past midnight for the local machine. I can do this by
> a series of conversions, but since I have to do a lot of them I've
> been looking for a single call (or minimal number of calls) that
> produces this.
>
> Google and man coming up empty so far. Anyone have a good reference
> I can check?
It ought to be pretty simple to cache the result of
the conversions so that you only need to do them once
per day (or per execution). Something like
int secondsSinceMidnight(void) {
static time_t midnight = 0;
time_t now = time(NULL);
if (now - midnight >= 24 * 60 * 60) {
struct tm *p = localtime(&now);
p->tm_hour = 0;
p->tm_min = 0;
p->tm_sec = 0;
midnight = mktime(p);
}
return now - midnight;
}
As it stands, this isn't quite good enough: it will get
confused by the start and end of daylight saving time.
The changes you'll need depend on just how you want to
define "seconds past midnight" in light of DST, and that
in turn depends on what use you're making of the result.
But the complications are largely beside the point: the
basic idea of caching the result allows you to amortize
the cost of those complications over a long period.
--
Eric.Sosman@sun.com
| |
| John W. Krahn 2007-07-20, 7:21 pm |
| Richard Eich wrote:
> SLES9 and RHES4. Stock GCC and CLIB
>
> I need seconds past midnight for the local machine. I can do this by
> a series of conversions, but since I have to do a lot of them I've
> been looking for a single call (or minimal number of calls) that
> produces this.
$ PERL -MTime::Local -le'print time - timelocal 0,0,0, (localtime)[3..8]'
49716
John
--
Perl isn't a toolbox, but a small machine shop where you
can special-order certain sorts of tools at low cost and
in short order. -- Larry Wall
| |
| Richard Eich 2007-07-21, 7:27 am |
| keramida@ceid.upatras.gr wrote...
> On Fri, 20 Jul 2007 16:06:14 GMT, Richard Eich <richard.eich@domain.invalid> wrote:
>
> Try Googling for the manpages of strftime(), localtime(), gmtime(),
> mktime(), and similar calls. A sample program using them is shown
> below. It doesn't *print* the difference in seconds of the current time
> and today's midnight, but it comes pretty close and should be _very_
> easy to adapt:
>
> ------------------------------------------------------------------------
> #include <errno.h>
> #include <limits.h>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
> #include <time.h>
>
> void ptime(const char *, struct tm *);
>
> int
> main(void)
> {
> char errbuf[LINE_MAX + 1];
> struct tm now, midnight;
> time_t now_sec;
>
> now_sec = time(NULL);
> if (localtime_r(&now_sec, &now) == NULL) {
> int save_errno = errno;
>
> if (strerror_r(save_errno, errbuf, sizeof(errbuf)) != 0)
> exit(EXIT_FAILURE);
> fprintf(stderr, "localtime_r: error %d: %s\n",
> save_errno, errbuf);
> exit(EXIT_FAILURE);
> }
>
> /* Copy the current time to 'midnight' and tweak. */
> midnight = now;
> midnight.tm_sec = 0;
> midnight.tm_min = 0;
> midnight.tm_hour = 0;
>
> ptime("now", &now);
> ptime("midnight", &midnight);
>
> return 0;
> }
>
> void
> ptime(const char *txt, struct tm *tm)
> {
> char errbuf[LINE_MAX + 1];
> char timebuf[LINE_MAX + 1];
> time_t sec;
>
> if (tm == NULL)
> return;
> if (txt == NULL)
> txt = "??";
>
> sec = mktime(tm);
> if (strftime(timebuf, sizeof(timebuf) - 1,
> "%Y-%m-%d %H:%M:%S", tm) >= sizeof(timebuf)) {
> int save_errno = errno;
>
> if (strerror_r(save_errno, errbuf, sizeof(errbuf)) != 0)
> exit(EXIT_FAILURE);
> fprintf(stderr, "strftime @ %p: error %d: %s\n", tm,
> save_errno, errbuf);
> exit(EXIT_FAILURE);
> }
> printf("%-10s | %12llu | %s\n", txt, (unsigned long long)sec,
> timebuf);
> }
> ------------------------------------------------------------------------
>
> Compile this with your C compiler, run it and it should print something
> similar to:
>
> $ ./a.out
> now | 1184950846 | 2007-07-20 20:00:46
> midnight | 1184878800 | 2007-07-20 00:00:00
> $
Thanks very much -- it's amazing how much reading the right resource
helps. ;)
| |
| Richard Eich 2007-07-21, 7:27 am |
| Eric.Sosman@sun.com wrote...
> Richard Eich wrote On 07/20/07 12:06,:
>
> It ought to be pretty simple to cache the result of
> the conversions so that you only need to do them once
> per day (or per execution). Something like
>
> int secondsSinceMidnight(void) {
> static time_t midnight = 0;
> time_t now = time(NULL);
> if (now - midnight >= 24 * 60 * 60) {
> struct tm *p = localtime(&now);
> p->tm_hour = 0;
> p->tm_min = 0;
> p->tm_sec = 0;
> midnight = mktime(p);
> }
> return now - midnight;
> }
>
> As it stands, this isn't quite good enough: it will get
> confused by the start and end of daylight saving time.
> The changes you'll need depend on just how you want to
> define "seconds past midnight" in light of DST, and that
> in turn depends on what use you're making of the result.
> But the complications are largely beside the point: the
> basic idea of caching the result allows you to amortize
> the cost of those complications over a long period.
This is pretty much how I'm doing it now, only without the caching
idea. This is workable -- thank you very much.
| |
| Richard Eich 2007-07-21, 7:27 am |
| shakahshakah@gmail.com wrote...
> On Jul 20, 12:06 pm, Richard Eich <richard.e...@domain.invalid> wrote:
>
> Isn't it just time(0) % 86400, for GMT at least?
LOL. Boy, is this answer ever humiliating...
| |
| shakahshakah@gmail.com 2007-07-23, 7:22 am |
| On Jul 21, 8:04 am, Richard Eich <richard.e...@domain.invalid> wrote:
> shakahsha...@gmail.com wrote...
>
>
>
>
> LOL. Boy, is this answer ever humiliating...
Granted I posted without thinking too much about it, but feel free to
enlighten me.
| |
| Henry Townsend 2007-07-23, 1:21 pm |
| shakahshakah@gmail.com wrote:
> On Jul 21, 8:04 am, Richard Eich <richard.e...@domain.invalid> wrote:
>
> Granted I posted without thinking too much about it, but feel free to
> enlighten me.
I think he meant humiliating for him because it's so simple and obvious.
| |
| Ralf Fassel 2007-07-23, 7:20 pm |
| * Henry Townsend <henry.townsend@not.here>
| >>> Isn't it just time(0) % 86400, for GMT at least?
| >> LOL. Boy, is this answer ever humiliating...
| > Granted I posted without thinking too much about it, but feel free
| > to enlighten me.
|
| I think he meant humiliating for him because it's so simple and
| obvious.
.... and wrong? time(0) gives the seconds since the epoch, but not all
days since then had 86400 seconds (leap seconds, DST switches).
Consider:
now time(0) -> 1185214831 // Mon Jul 23 20:20:31 CEST 2007
midnight -> 1185141600 // Mon Jul 23 00:00:00 CEST 2007
1185214831 - 1185141600 = 73231
but now % 86400 = 66031
R'
| |
| Logan Shaw 2007-07-24, 1:22 am |
| Ralf Fassel wrote:
> * Henry Townsend <henry.townsend@not.here>
> | >>> Isn't it just time(0) % 86400, for GMT at least?
> | >> LOL. Boy, is this answer ever humiliating...
> | > Granted I posted without thinking too much about it, but feel free
> | > to enlighten me.
> |
> | I think he meant humiliating for him because it's so simple and
> | obvious.
>
> ... and wrong? time(0) gives the seconds since the epoch, but not all
> days since then had 86400 seconds (leap seconds, DST switches).
He said GMT. Because of DST, it would not work for any timezone
other than GMT (UTC).
As was discussed here recently (I think), leap seconds should not
be an issue because according to Unix timekeeping (localtime() and
such) they don't exist. An ntp daemon or some other "external"
thing can correct for leap seconds, but it does it by changing the
rate at which time_t advances, rather than by changing the rules
that map time_t values onto local times.
So, I think it would work for GMT. However, that's not a very
general solution, and it seems shaky because it's hard to prove
that it even works for GMT. It may be *possible* to prove that,
but since there are other ways whose correctness is easier to
prove, I would go with one of them.
- Logan
| |
| Peter J. Holzer 2007-07-28, 1:24 am |
| On 2007-07-24 00:49, Logan Shaw <lshaw-usenet@austin.rr.com> wrote:
> Ralf Fassel wrote:
>
> He said GMT. Because of DST, it would not work for any timezone
> other than GMT (UTC).
Even without DST, it doesn't work for any timezone with an offset other
then 0.
> So, I think it would work for GMT. However, that's not a very
> general solution, and it seems shaky because it's hard to prove
> that it even works for GMT.
I don't see how that can be hard to prove. The standard says:
| If the year is >=1970 and the value is non-negative, the value is
| related to a Coordinated Universal Time name according to the C-language
| expression, where tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all
| integer types:
|
| tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
| (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
| ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
31536000 is a multiple of 86400, so at midnight UTC (when tm_sec, tm_min
and tm_hour are all 0), the whole expresssion always evaluates to a
multiple of 86400, so time(0) % 86400 is always the number of seconds
since midnight UTC.
hp
--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
|
|
|
|
|