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