Getting a string date from a number of seconds from01/01/1904

D

David Requena

Hi All,

I'm trying to parse a file which has some timestamps embedded. These're
expressed as a number of seconds elapsed since 01/01/1904 (macintosh
time).

I know OS X provides some APIs to handle these but fact is I'm not
coding on a mac. Standard C functions that I've been looking at ( for
example char *ctime(const time_t *time); ) take a time_t based on
01/01/1970.

What would be the best aproach for this problem?

As a side question, how could I represent a date previous to 01/01/1970
in standard C?

TIA,
David
 
K

Keith Thompson

David Requena said:
I'm trying to parse a file which has some timestamps embedded. These're
expressed as a number of seconds elapsed since 01/01/1904 (macintosh
time).

I know OS X provides some APIs to handle these but fact is I'm not
coding on a mac. Standard C functions that I've been looking at ( for
example char *ctime(const time_t *time); ) take a time_t based on
01/01/1970.

What would be the best aproach for this problem?

The C standard says only that time_t is an arithmetic type capable of
representing times. It could be integer or floating-point, its
resolution isn't necessarily 1 second, and the numeric value needn't
even be linearly related to time. The number of seconds since
1970-01-01 is probably the most common representation, but it's not
guaranteed by the C standard (though it is by the POSIX standard).

If you have a timestamp representing the number of seconds since
1904-01-01, *and* you're willing to assume that time_t is an integer
representing seconds since 1970-01-01, you can probably just subtract
2082844800 from your 1904-based timestamp to get a 1970-based
timestamp.
As a side question, how could I represent a date previous to 01/01/1970
in standard C?

See the caveats above, but if time_t is a signed type you can just use
a negative value (other than -1, which is reserved as an error
indicator).
 
M

Michael Wojcik

I'm trying to parse a file which has some timestamps embedded. These're
expressed as a number of seconds elapsed since 01/01/1904 (macintosh
time).

I know OS X provides some APIs to handle these but fact is I'm not
coding on a mac. Standard C functions that I've been looking at ( for
example char *ctime(const time_t *time); ) take a time_t based on
01/01/1970.

Some of them do, yes. Others work with a (hint) struct tm.
What would be the best aproach for this problem?

I'd recommend creating a struct tm with your timestamp, then using
mktime to normalize it. That ought to work for any time in the
interval where time_t is defined in your implementation, if it
supports calendar time. (The standard doesn't require that it do so,
but I don't know of an implementation that doesn't.)

This method is somewhat complicated by the fact that struct tm's
tm_sec is an int, and so the Mac timestamp may overflow it; so we
can't just slap the Mac time in as tm_sec and set the rest of the
fields to 1904-01-01. I'll use Keith's suggestion of subtracting
2082844800 to create a time from 1970-01-01. On typical 32-bit
systems that still leaves us with a Y2038 problem; fixing that is
left as an exercise for someone else.

Here's some UNTESTED sample code. It assumes you and your timestamps
are in GMT (and that they're the time since 00:00 on 1904-01-01); if
not, that should be easy to correct for by setting tm_hour to the
offset from GMT.

{
/* Seconds between 00:00 1904-01-01 and 00:00 1970-01-01 */
static const unsigned long SecsUntil1970 = 2082844800;

struct tm MacTime = {0};
unsigned long MacTimestamp;
time_t CTime;

MacTimestamp = ...; /* get timestamp: secs since 00:00 1904-01-01 GMT */
if (MacTimestamp < SecsUntil1970)
/* handle separately... */;

/* Create unnormalized struct tm representing Macintosh timestamp */
MacTime.tm_sec = MacTimestamp - SecsUntil1970;
MacTime.tm_hour = 0; /* adjust this for your timezone */
MacTime.tm_year = 70;

/* Convert to time_t */
CTime = mktime(&MacTime);

/* Now convert to string with ctime or (better) strftime ... */
}
As a side question, how could I represent a date previous to 01/01/1970
in standard C?

With a struct tm, as above. Only the implementation can create
time_t values in a portable way, so in fully portable code you can't
manually create a time_t for any date. But the contents of struct tm
are standard and you can create those for arbitrary dates, within the
range the member types support.

(I *think* all of that is right, and I checked the relevant sections
of the standard. No doubt someone here will point out any errors.)

--
Michael Wojcik (e-mail address removed)

This is a "rubbering action game," a 2D platformer where you control a
girl equipped with an elastic rope with a fishing hook at the end.
-- review of _Umihara Kawase Shun_ for the Sony Playstation
 
C

Christian Bau

"David Requena said:
Hi All,

I'm trying to parse a file which has some timestamps embedded. These're
expressed as a number of seconds elapsed since 01/01/1904 (macintosh
time).

I know OS X provides some APIs to handle these but fact is I'm not
coding on a mac. Standard C functions that I've been looking at ( for
example char *ctime(const time_t *time); ) take a time_t based on
01/01/1970.

What would be the best aproach for this problem?

As a side question, how could I represent a date previous to 01/01/1970
in standard C?

Easy. Express it as the number of seconds from any fixed date that you
choose, and store it as a value of type double, or type long long. You
can of course choose the data 01/01/1970 as your starting date. In many
implementations, the type time_t won't do it. And storing values of type
time_t in a file is asking for trouble, because different
implementations will have different values.
 
D

David Requena

Thanks for your help, Michael.

I'm just curious as to how did you calculate SecsUntil1970 =
2082844800. I had been thinking about a similar solution but didn't
come up with a proper way to take leap years and such into account.

TIA,
David
 
K

Keith Thompson

David Requena said:
Thanks for your help, Michael.

I'm just curious as to how did you calculate SecsUntil1970 =
2082844800. I had been thinking about a similar solution but didn't
come up with a proper way to take leap years and such into account.

That was me. I didn't post the method because it's Unix-specific.

% date +%s -d '1904-01-01 00:00:00 UTC'
-2082844800
% date +%s -d '1970-01-01 00:00:00 UTC'
0

This depends on the GNU date command (and older versions of it may not
handle dates before 1970).

More portably, you can compute

(1970-1904)*365*86400 + 17*86400

where 17 is the number of leap days between 1904-01-01 and 1970-01-01
(1904, 1908, ..., 1968).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top