2

I am trying to make an easily accessible TimeDate variable, but am having problems with conversion. In time.h, how would I convert time_t (seconds since 1/1/1970), into the current local timezone (compensating for daylight savings time if applicable), so that:

time_t Seconds;

Becomes:

struct TimeDate
{
    short YYYY;
    unsigned char MM;
    unsigned char DD;

    unsigned char HH; //Non-DST, non-timezone, IE UTC (user has to add DST and TZO to get what they need)
    unsigned char MM;
    unsigned char S;

    char TZ[4]; //This can be optionally a larger array, null terminated preferably
    char TZO; //Timezone Offset from UTC        

    char DST; //Positive is DST (and amount of DST to apply), 0 is none, negative is unknown/error
};

Without using any string literals (bar for the timezone name) in the process (to keep it efficient)? This is also taking into account leap years. Bonus if TimeDate can be converted back into time_t.

SE Does Not Like Dissent
  • 1,767
  • 3
  • 16
  • 36

1 Answers1

9

The C standard library (accessible in C++ by using ctime) provides localtime for exactly that purpose (or gmtime for UTC). You could shoe-horn the resultant struct tm into your own structure after that if there's some reason why the standard one is not sufficient to your needs.

The one thing it doesn't provide is the timezone itself but you can get that (and the offset in ISO 8601 format) by using strftime with the %Z and %z format strings


By way of example, here's a program that demonstrates this in action:

#include <iostream>
#include <cstdlib>
#include <ctime>

int main(void) {
    time_t t;
    struct tm *tim;
    char tz[32];
    char ofs[32];

    std::system ("date");
    std::cout << std::endl;

    t = std::time (0);
    tim = std::localtime (&t);
    std::strftime (tz, sizeof (tz), "%Z", tim);
    std::strftime (ofs, sizeof (ofs), "%z", tim);

    std::cout << "Year:        " << (tim->tm_year + 1900) << std::endl;
    std::cout << "Month:       " << (tim->tm_mon + 1) << std::endl;
    std::cout << "Day:         " << tim->tm_mday << std::endl;
    std::cout << "Hour:        " << tim->tm_hour << std::endl;
    std::cout << "Minute:      " << tim->tm_min << std::endl;
    std::cout << "Second:      " << tim->tm_sec << std::endl;
    std::cout << "Day of week: " << tim->tm_wday << std::endl;
    std::cout << "Day of year: " << tim->tm_yday << std::endl;
    std::cout << "DST?:        " << tim->tm_isdst << std::endl;
    std::cout << "Timezone:    " << tz << std::endl;
    std::cout << "Offset:      " << ofs << std::endl;

    return 0;
}

When I run this on my box, I see:

Wed Sep 28 20:45:39 WST 2011

Year:        2011
Month:       9
Day:         28
Hour:        20
Minute:      45
Second:      39
Day of week: 3
Day of year: 270
DST?:        0
Timezone:    WST
Offset:      +0800
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Hi pax, looking at localtime, it puts into a tm structure, of which is days/hours/minutes ... since 1/1/1970. The problem with this is I don't want how many hours have elapsed since 1/1/1970, I want what the present time is (in UTC format with DST/Timezone separate). It also does not supply the timezone employed or the amount of hours the timezone is offset by. – SE Does Not Like Dissent Sep 28 '11 at 11:20
  • Hi nemo, he had modified the description since my comment, but it still does not address my question, which is how do I convert time_t into the TimeDate structure, IE how I convert into TimeDate is notoriously missing (paraphrase: how do I convert tm into TimeDate). Also note timezone/leap years issue. – SE Does Not Like Dissent Sep 28 '11 at 11:36
  • Or to put it more bluntly: tm is a stucture, not a conversion method. – SE Does Not Like Dissent Sep 28 '11 at 11:37
  • @SSight3, `tm` is a struct populated by `localtime` or `gmtime` to hold the current date and time (local or UTC). It does not store hours/minutes/seconds since 1970, it store the absolute time. That appears to be what you want. – paxdiablo Sep 28 '11 at 11:42
  • 1
    The fields in struct tm are exactly what you asked for. They have nothing to do with 1970. So I think you need to read the description for it again. – Nemo Sep 28 '11 at 11:44
  • @Pax: Your information appears to be false. Link backing up my point: http://www.cplusplus.com/reference/clibrary/ctime/tm/ . I quote "years since 1900", "days since", "months since" etc etc. I might add it is still not a conversion method. – SE Does Not Like Dissent Sep 28 '11 at 12:01
  • @SSight3, no, my information is correct other than a minor adjustment you need to make (add 1900 to the `tm_year` value) - everything else is absolute. 2011-09-28 at 4:15pm would be stored as year=111, mon=8 (0-based), day=28, hour=16, minute=15, seconds=0. You will be seriously wasting your time re-implementing something that the standard libraries already provide. All of that "since" stuff has nothing to do with 1970, it's hours since midnight, months sine Jan, days since Sunday and so on. – paxdiablo Sep 28 '11 at 12:08
  • @Pax: Still not a conversion method and still fails on the timezone front. I think you're looking for a quick-fix solution to a problem. If I wanted an obvious solution I wouldn't enquire with experienced programmers to tell me to use struct tm. I don't want struct tm, I don't want to touch it's bloated corpse with a 240ft clown barge pole, and I imagine there is probably an extremely clever mathematical formulae that can deduce the above properties based entirely on seconds (by way of stackable modulus), minus timezone name. – SE Does Not Like Dissent Sep 28 '11 at 12:42
  • 1
    @SSight3: you're free to make that decision if you think the standard C stuff doesn't suit your purpose but I've not seen _any_ requirement in your question that it can't meet. I personally think you're wasting your time and that you should rethink your obvious aversion to using the facilities _already provided to you,_ but that's your call, not mine. All I can do is offer advice - lead a horse to water and all that stuff :-) – paxdiablo Sep 28 '11 at 12:50
  • 2
    @SSight3: He just provided a complete program that does everything you are asking for using 100% standard C++ interfaces. If you do not accept his answer, you need to change your question, because it does everything you asked for in every detail. – Nemo Sep 28 '11 at 14:34