views:

2000

answers:

5

What I want to do is convert an epoch time (seconds since midnight 1/1/1970) to "real" time (m/d/y h:m:s)

So far, I have the following algorithm, which to me feels a bit ugly:

void DateTime::splitTicks(time_t time) {
    seconds = time % 60;
    time /= 60;
    minutes = time % 60;
    time /= 60;
    hours = time % 24;
    time /= 24;

    year = DateTime::reduceDaysToYear(time);
    month = DateTime::reduceDaysToMonths(time,year);
    day = int(time);
}

int DateTime::reduceDaysToYear(time_t &days) {
    int year;
    for (year=1970;days>daysInYear(year);year++) {
        days -= daysInYear(year);
    }
    return year;
}

int DateTime::reduceDaysToMonths(time_t &days,int year) {
    int month;
    for (month=0;days>daysInMonth(month,year);month++)
        days -= daysInMonth(month,year);
    return month;
}

you can assume that the members seconds, minutes, hours, month, day, and year all exist.

Using the for loops to modify the original time feels a little off, and I was wondering if there is a "better" solution to this.

+2  A: 

What's wrong with just calling to this functionality as exposed by time.h, e.g. by gmtime if GMT rather than some specific timezone is what you're after?

Alex Martelli
Nothing wrong with it, I did not even know it existed. Thanks! But, I am still interested to know how my implementation could be better.
Austin Hyde
@Austin, "thanks" and no upvote is not compliant with normal SO etiquette!-)
Alex Martelli
(Let me haste to indicate that this isn't self-serving, as I'm maxed out for the day anyway: it's about smooth and normal application of SO's basic etiquette -- you upvote answers you find helpful!!!).
Alex Martelli
@Alex, I just haven't gotten there yet. Don't worry :D
Austin Hyde
+2  A: 

Be careful about leap years in your daysInMonth function.

If you want very high performance, you can precompute the pair to get to month+year in one step, and then calculate the day/hour/min/sec.

A good solution is the one in the gmtime source code:

/*
 * gmtime - convert the calendar time into broken down time
 */
/* $Header: gmtime.c,v 1.4 91/04/22 13:20:27 ceriel Exp $ */

#include        <time.h>
#include        <limits.h>
#include        "loc_time.h"

struct tm *
gmtime(register const time_t *timer)
{
        static struct tm br_time;
        register struct tm *timep = &br_time;
        time_t time = *timer;
        register unsigned long dayclock, dayno;
        int year = EPOCH_YR;

        dayclock = (unsigned long)time % SECS_DAY;
        dayno = (unsigned long)time / SECS_DAY;

        timep->tm_sec = dayclock % 60;
        timep->tm_min = (dayclock % 3600) / 60;
        timep->tm_hour = dayclock / 3600;
        timep->tm_wday = (dayno + 4) % 7;       /* day 0 was a thursday */
        while (dayno >= YEARSIZE(year)) {
                dayno -= YEARSIZE(year);
                year++;
        }
        timep->tm_year = year - YEAR0;
        timep->tm_yday = dayno;
        timep->tm_mon = 0;
        while (dayno >= _ytab[LEAPYEAR(year)][timep->tm_mon]) {
                dayno -= _ytab[LEAPYEAR(year)][timep->tm_mon];
                timep->tm_mon++;
        }
        timep->tm_mday = dayno + 1;
        timep->tm_isdst = 0;

        return timep;
}
rxin
+2  A: 

The standard library provides functions for doing this. gmtime() or localtime() will convert a time_t (seconds since the epoch) into a struct tm. strftime() can then be used to convert a struct tm into a string based on the format you specify.

see: http://www.cplusplus.com/reference/clibrary/ctime/

Date/time calculations can get tricky. You are much better off using an existing solution rather than trying to roll your own, unless you have a really good reason.

sdtom
This started off as homework a while back, but now I am interested in making it better. Normally, I would go for the library solution, but 1) I didn't know the time functions were built in and 2) I want to perfect my implementation.
Austin Hyde
A: 

If your original time type is time_t, you have to use functions from time.h i.e. gmtime etc. to get portable code. The C/C++ standards do not specify internal format (or even exact type) for the time_t, so you cannot directly convert or manipulate time_t values.

All that is known is that time_t is "arithmetic type", but results of arithmetic operations are not specified - you cannot even add/subtract reliably. In practice, many systems use integer type for time_t with internal format of seconds since epoch, but this is not enforced by standards.

In short, use gmtime (and time.h functionality in general).

eidolon
A: 

OK, so I know you're looking for a procedural solution... but if you haven't seen it already, check out http://www.epochconverter.com. It is a very useful way to check your work :)

Tom