Thread: time.h

  1. #1
    Registered User
    Join Date
    Apr 2013
    Posts
    38

    time.h

    Hey guys, I am just having trouble with using time, I have a basic program that basicly works out shift timings for each pers, I am having an issue getting it to display the time in general, for example:


    if one person was to start 1100h and work for say 2hours or 120mins, I obviously I can't just add the two together without a little math and get 1300h. (Due to changing values a math formular wouldn't work)


    I have integers representing the time and time each person needs to work that do change depending on input from user. So basicly if someone could help me out with some code that will represent time depending on input and the required code that will add another input (required time to work(say 120mins)) giving a final result of a start time and finish time.


    Sorry if this is as clear as mud, I would post my code so u have a better idea but I am on phone waiting for an X-ray :/


    Thanks heaps

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Any time period that goes over 0000 hrs or 2400 hrs, will have two parts to it.

    1) the time before Midnight, and 2) the time after Midnight. You could calculate each one, and then add them together, but if you use "imaginary" hours above 2400, then it's even easier, and one calculation should be all you need.

    Work it through by hand a few times, and you'll get it.

    Good luck with the X-rays.

  3. #3
    Registered User
    Join Date
    Apr 2013
    Posts
    38
    Yeah I was thinking about this method, however the issue I was faced with was creating 'if statements' for every hour of the day (for minutes)
    Code:
    if (time >= 60) {
         time = time + 100;
    }
    I came up with a formular to change from pm to am easy enough. I was just hoping for a cleaner line of code instead of 24 if statements :P

    actually thinking about that if statement wouldn't work anyway :/ or would it? I need my computer in front of me haha I am hopeless at doing this in my head..
    Last edited by Ryan Huddo; 04-29-2013 at 07:32 PM.

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    If you start coding up 24 if statements, I'll have to pin a goofy hat on your head! It's just a little addition and subtraction is all it is.

    You don't need a computer in front of you, just paper and pen will do fine.

    "24 if statements, one for every hour" ----> dear gawd! :rofl:

  5. #5
    Registered User
    Join Date
    Apr 2013
    Posts
    38
    Quote Originally Posted by Adak View Post
    If you start coding up 24 if statements, I'll have to pin a goofy hat on your head! It's just a little addition and subtraction is all it is.

    You don't need a computer in front of you, just paper and pen will do fine.

    "24 if statements, one for every hour" ----> dear gawd! :rofl:
    Quote Originally Posted by Adak View Post
    If you start coding up 24 if statements, I'll have to pin a goofy hat on your head! It's just a little addition and subtraction is all it is.

    You don't need a computer in front of you, just paper and pen will do fine.

    "24 if statements, one for every hour" ----> dear gawd! :rofl:
    Yeah I am still learning, unfortunately.

    Ok well could I have a hand please, its also a programming restraint not just math.
    If I use say (int pre set for ease of explanation);
    Code:
    int x = 120;   // x represents minutes between shifts
    int startTime = 1400   // 2pm
    int finishTime  //Doesn't have a value yet.
    
    finishTime = startTime + (x / .6);   // (1400 + 200 = 1600) Awesome.
    However if I had a int x of a number that doesn't equate to an even hour, the math wont work out.

    Maybe if I approached a different way? Can you make rules for integers? for example; the tenths column cannot be >=6 without carrying the 1 to the hundredth column and resetting the tenth column to 0..

    ANY insight would be fantastic. Like I stated I am learning (self learning) and this is a project idea I thought up and it is proving to be a chalenge.

    Thanks

  6. #6
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    What if "time" wasn't a single integer, but composed of TWO integers: hours and minutes?

    You could also represent time with a float or double data type, where every 1/10th of an hour equals 6 minutes, but I don't prefer this way of handling it. Using two int's (or three if seconds must be handled, seems intuitively correct.

  7. #7
    Registered User
    Join Date
    Apr 2013
    Posts
    38
    Quote Originally Posted by Adak View Post
    What if "time" wasn't a single integer, but composed of TWO integers: hours and minutes?

    You could also represent time with a float or double data type, where every 1/10th of an hour equals 6 minutes, but I don't prefer this way of handling it. Using two int's (or three if seconds must be handled, seems intuitively correct.
    Ah, this looks promising well how would I split one result into two integers? For example time integer comes back as 65? How would I split that into two intigers of say "hours = 1" and mins = 5" also would if be different with 3 figure digits(125mins for example)?

    ta

  8. #8
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    When working with times it helps to understand modular arithmetic. The operators / (division) and % (remainder/modulo) are your friends.

    Bye, Andreas

  9. #9
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    You do realize that variables of time_t type represent seconds since Epoch (in UTC)? That you can call difftime(later,earlier) to get the difference in seconds? That you can use localtime() to convert a time_t into broken-down local time (year, month, day, hour, minute, second); and mktime() to do the conversion the other way?

    When you start writing your own date-time conversion routines, or your own datetime types, you're almost always going about it the wrong way.

    For example, what happens if a shift extends past a daylight savings time change? (Oh, that'll never happen, right?) The above functions handle it perfectly, without you having to worry about it at all. You can even use setenv("TZ", ":Wherever/youwant", 1); tzset(); to set a new timezone (process-wide, affects all threads in this process), if the system default timezone is unsuitable for your calculations.

    Since mktime() normalizes your input fields, you can use plain seconds (from midnight) to specify daily values. To get an actual time stamp (time_t or a broken down struct tm), you fill in the year, month, and day; zero out hours and minutes; and set the seconds. After calling mktime(), the fields are normalized -- even the date may change.

    Thus, I recommend you store any repeating values as seconds since midnight, and durations as seconds. To store days, you could use the midday timestamp (that avoids any ambiguities wrt. daylight savings time or leap seconds). To store actual shift timestamps (start and end), use a pair of time_t's.

    Questions? Need a practical example?

  10. #10
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    As a practical programming matter, you should learn to work with the many functions in time.h, as Nominal Animal has mentioned. BIG help there.

    If you want to figure out how it can be done, on your own, (which is what I thought you wanted), then ignore time.h and it's functions.

    Let's say a worker started at 2230 hrs and stopped at 0210 hrs. Generally, it's easiest to use the smallest data type you have as your standard - that could be minutes or seconds. I'll pick minutes.

    Work before Midnight:
    ..24hrs: 00min equals 24 * 60 = 1,440 is Midnight, in minutes.
    -22hrs: 30min equals 22 * 60 + 30 = 1,350 Starting time in minutes
    =============================================
    90 minutes = 1440 - 1350

    + time after midnight: 2 hrs.*60 + 10 minutes = 120 + 10 = 130

    220 = 90 + 130

    3 = 220/60 //integer division in C, has no fractional part
    40 = 220 % 60 //where % equals MOD operator in C

    Total time: 3 hrs. 40 minutes

    This isn't the only way to do it, but it's probably the simplest way to "roll your own", with time.

  11. #11
    Registered User
    Join Date
    Apr 2013
    Posts
    38
    Ah thanks guys, this is all helping me a great deal, as previously stated I am new to programming; however as I am still in that frustrating learning curve that I would imagine most people would give up at I am really enjoying this and could see myself developing (skills) over time due to my interest. So in saying that yes Adak; I am looking to do it on my own, one of the things I am trying to learn at the moment is different ways to approach an objective (or cross roads) in programming. So all this is great help.

    However learning time functions would also be great to know; I would probably use both methods in two different projects just for practice.. So I will take you up on your offer Normal Animal (providing your not being sarcastic :P); I would love a practical example.

    Thanks guys!

  12. #12
    Ticked and off
    Join Date
    Oct 2011
    Location
    La-la land
    Posts
    1,728
    Quote Originally Posted by Ryan Huddo View Post
    I am looking to do it on my own
    Adak is absolutely right; it is useful to learn how to do it on your own. However, the details -- like localization and daylight savings -- are quite complicated to get right. I for one expect my devices to switch properly (but the non-Linux ones do not).

    Quote Originally Posted by Ryan Huddo View Post
    However learning time functions would also be great to know; I would probably use both methods in two different projects just for practice.. So I will take you up on your offer Normal Animal (providing your not being sarcastic :P); I would love a practical example.
    Absolutely. (I'm always serious when I offer an example.) Comparing the two methods, and especially their results (especially if you test also those bothersome points like date changes, leap seconds, daylight savings changes), is very, very useful.

    I didn't know what you wanted to see, so I created the following complete program as a crash course:
    Code:
    #define  _XOPEN_SOURCE 600
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <time.h>
    #include <ctype.h>
    #include <errno.h>
    #include <locale.h>
    #include <langinfo.h>
    #include <math.h>
    
    static const char *datetime_format[] = {
        "%c",               /* Local date and time */
        "%Ec",              /* Alternate local date and time */
        "%X",               /* Local time */
        "%EX",              /* Alternate local time */
        "%Y-%m-%d %T",      /* ISO date-time with seconds */
        "%Y-%m-%d %R",      /* ISO date-time without seconds */
        "%Y-%m-%d T %T",    /* ISO date-time using T, with seconds */
        "%Y-%m-%d T %R",    /* ISO date-time using T, without seconds */
        "%r",               /* Local 12-hour time */
        "%H:%M:%S",         /* 24-hour time */
        "%I:%M:%S %p",      /* 12-hour time */
        "%H:%M",            /* Just hours and minutes (24-hour clock) */
        "%I:%M %p",         /* Just hours and minutes (12-hour clock) */
        "%H",               /* Just hours (24-hour clock) */
        "%I %p",            /* Just hours (12-hour clock) */
        "%a %H:%M:%S",      /* Weekday hour:minutes:seconds (24-hour clock) */
        "%a %I:%M:%S %p",   /* Weekday hour:minutes:seconds (12-hour clock) */
        "%a %H:%M",         /* Weekday hour:minutes (24-hour clock) */
        "%a %I:%M %p",      /* Weekday hour:minutes (12-hour clock) */
        "%a %H",            /* Weekday hour (24-hour clock) */
        "%a %I %p",         /* Weekday hour (12-hour clock) */
        NULL /* End of list */
    };
    
    /* Parse specified date or time string.
     * Unset fields are set to -1.
    */
    int datetime(const char *const string, struct tm *const ptr)
    {
        char   *ends;
        size_t  i;
    
        /* Neither pointer can be NULL. */
        if (!string || !ptr)
            return errno = EINVAL;
    
        /* Check each datetime_format in order. */
        for (i = 0; datetime_format[i]; i++) {
    
            /* Make all date/time fields invalid. */
            ptr->tm_sec = -1;
            ptr->tm_min = -1;
            ptr->tm_hour = -1;
            ptr->tm_mday = -1;
            ptr->tm_mon = -1;
            ptr->tm_year = -1;
            ptr->tm_wday = -1;
            ptr->tm_yday = -1;
            ptr->tm_isdst = -1;
            ends = strptime(string, datetime_format[i], ptr);
    
            /* No match? */
            if (!ends)
                continue;
    
            /* Skip trailing garbage (ignore all but letters and digits) */
            while (*ends && !isalpha(*ends))
                ends++;
    
            /* If there is trailing garbage, no match. */
            if (*ends)
                continue;
    
            /* We had a match. */
            return 0;
        }
    
        /* No match. */
        return errno = EINVAL;
    }
    
    char *sdup(const char *const original, const char *const empty)
    {
        if (original && *original)
            return strdup(original);
        else
            return strdup(empty);
    }
    
    int main(int argc, char *argv[])
    {
        struct tm   now_tm, enter_tm, exit_tm;
        time_t      now_time, enter_time, exit_time;
        char        buffer[1024];
        const char *datetime_format;
        int         days, hours, minutes;
    
        /* Our time functions are locale-aware. */
        setlocale(LC_TIME, ""); /* Time defaults (from user environment) */
        setlocale(LC_MESSAGES, ""); /* Message defaults (from user environment) */
    
        /* Get strftime() formats based on current locale. */
        datetime_format = sdup(nl_langinfo(D_T_FMT), "%c");
    
        /* Get current time. */
        now_time = time(NULL);
        now_tm = *(struct tm *)localtime(&now_time);
    
        /* Check for correct number of arguments. */
        if (argc != 3) {
            fprintf(stderr, "\nUsage: %s when-entered when-exited\n\n", argv[0]);
            return 1;
        }
    
        /* Parse enter date/time. */
        if (datetime(argv[1], &enter_tm)) {
            fprintf(stderr, "%s: Sorry, cannot understand that date/time format.\n", argv[1]);
            return 1;
        }
        /* Weekday only? */
        if (enter_tm.tm_mday == -1 && enter_tm.tm_wday != -1) {
            enter_tm.tm_year = now_tm.tm_year;
            enter_tm.tm_mon = now_tm.tm_mon;
            enter_tm.tm_mday = now_tm.tm_mday;
            while (enter_tm.tm_wday != now_tm.tm_wday) {
                enter_tm.tm_mday--; /* mktime() will normalize this! */
                enter_tm.tm_wday = (enter_tm.tm_wday + 1) % 7;
            }
        } else {
            /* Missing year/month/day? */
            if (enter_tm.tm_year == -1)
                enter_tm.tm_year = now_tm.tm_year;
            if (enter_tm.tm_mon == -1)
                enter_tm.tm_mon = now_tm.tm_mon;
            if (enter_tm.tm_mday == -1)
                enter_tm.tm_mday = now_tm.tm_mday;
        }
        /* Hours? */
        if (enter_tm.tm_hour == -1) {
            fprintf(stderr, "%s: No entering time specified.\n", argv[1]);
            return 1;
        } else {
            if (enter_tm.tm_min == -1) {
                /* No minutes specified, only hour */
                enter_tm.tm_min = 0;
                enter_tm.tm_sec = 0;
            } else
            if (enter_tm.tm_sec == -1) {
                /* No seconds specified, only hour and minutes */
                enter_tm.tm_sec = 0;
            }
        }
    
        /* Normalize enter_tm, and also get it as seconds since epoch. */
        enter_time = mktime(&enter_tm);
        if (enter_time == (time_t)-1) {
            fprintf(stderr, "%s: Sorry, something is wonky about that date/time.\n", argv[1]);
            return 1;
        }
    
        /* Parse exit date/time. */
        if (datetime(argv[2], &exit_tm)) {
            fprintf(stderr, "%s: Sorry, cannot understand that date/time format.\n", argv[2]);
            return 1;
        }
    
        /* Weekday only? */
        if (exit_tm.tm_mday == -1 && exit_tm.tm_wday != -1) {
            exit_tm.tm_year = now_tm.tm_year;
            exit_tm.tm_mon = now_tm.tm_mon;
            exit_tm.tm_mday = now_tm.tm_mday;
            while (exit_tm.tm_wday != now_tm.tm_wday) {
                exit_tm.tm_mday--; /* mktime() will normalize this! */
                exit_tm.tm_wday = (exit_tm.tm_wday + 1) % 7;
            }
        } else {
            /* Missing year/month/day? Use enter date, if so. */
            if (exit_tm.tm_year == -1)
                exit_tm.tm_year = enter_tm.tm_year;
            if (exit_tm.tm_mon == -1)
                exit_tm.tm_mon = enter_tm.tm_mon;
            if (exit_tm.tm_mday == -1)
                exit_tm.tm_mday = enter_tm.tm_mday;
        }
    
        /* Hours? */
        if (exit_tm.tm_hour == -1) {
            fprintf(stderr, "%s: No entering time specified.\n", argv[2]);
            return 1;
        } else {
            if (exit_tm.tm_min == -1) {
                /* No minutes specified, only hour */
                exit_tm.tm_min = 0;
                exit_tm.tm_sec = 0;
            } else
            if (exit_tm.tm_sec == -1) {
                /* No seconds specified, only hour and minutes */
                exit_tm.tm_sec = 0;
            }
        }
    
        /* Normalize exit_tm, and also get it as seconds since epoch. */
        exit_time = mktime(&exit_tm);
        if (exit_time == (time_t)-1) {
            fprintf(stderr, "%s: Sorry, something is wonky about that date/time.\n", argv[2]);
            return 1;
        }
    
        /* Show enter date/time in current locale. */
        if (strftime(buffer, sizeof buffer, datetime_format, &enter_tm))
            printf("Entered: %s\n", buffer);
        else
            printf("Entered: %s\n", asctime(&enter_tm));
    
        /* Show enter date/time in current locale. */
        if (strftime(buffer, sizeof buffer, datetime_format, &exit_tm))
            printf("Exited:  %s\n", buffer);
        else
            printf("Exited:  %s\n", asctime(&exit_tm));
    
        printf("Difference: %.0f seconds", difftime(exit_time, enter_time));
    
        /* Round minutes. */
        minutes = (int)round(difftime(exit_time, enter_time) / 60.0);
        printf(" (or about %d minutes, or about %.0f hours)\n", minutes, minutes / 60.0);
        
        days = minutes / 1440;
        minutes = minutes % 1440; /* or minutes - 1440*days */
        hours = minutes / 60;
        minutes = minutes % 60; /* or minutes - 60*hours */
    
        if (days > 0)
            printf("Duration: %d days, %d hours, %d minutes\n", days, hours, minutes);
        else
        if (hours > 0)
            printf("Duration: %d hours, %d minutes\n", hours, minutes);
        else
        if (minutes > 0)
            printf("Duration: %d minutes\n", minutes);
        else
        if (minutes < 0)
            printf("Exited before entered.\n");
    
        free((void *)datetime_format);
        return 0;
    }
    Compile using for example
    Code:
        gcc -W -Wall -O3 example.c -o example
    Try running with using the following:
    Code:
        ./example
        ./example "monday 8 am" "7 pm"
        ./example 8:23 17:21
        ./example '2013-05-01 08:11' 17:19
    Note that your default locale will affect what formats it parses. You can run e.g. export LC_ALL=C to set the default POSIX locale, if your default locale is something else; I use a Finnish one, fi_FI.UTF-8.

    You supply the program two parameters on the command line: enter and exit timestamps. You need to put them in quotes if they contain spaces.

    While the program is long, it is also pretty powerful. By adding new formats (see man 3 strptime for the format specifications) into the datetime_format array you can support new formats. (I should have added it to try the default C/POSIX locale if the user one does not work, but I was too lazy! It would be just a few lines more, though.)

    The datetime() function simply tries each format in turn, and returns zero if one matches. Note that it sets unset fields to -1.

    In main(), you can see the locale initialization, and checking the command-line parameters.

    When the enter date/time is parsed, the case where only a weekday is specified is special: we simply decrement the day-of-month number and increment the weekday number, until it matches today. (Thus, we get a day within the past week, including today.) Otherwise year/month/day is taken from today's date, so you can get by with only specifying the day (and not month or year).

    For time, at least the hour has to be specified (in which case minutes and seconds are reset to zero). If seconds is not specified, it is set to zero; if minutes is not specified, both minutes and seconds are set to zero.

    For the exit date/time, the weekday logic is exactly the same. If the date is not specified, it is not today but the enter date. This way you can specify just the enter date, and the exit date defaults to the enter date.

    (It might be better logic to parse exit date first, and use exit date as the basis for the enter date. That way, if today was Tuesday, and you specify enter as Thursday and exit as Wednesday, it'd get the dates correct -- inside for almost a week almost a week ago. As it is now, the above program will get it wrong. Fixing it is very easy; I'm leaving it in as a enticement to explore how the code behaves if you edit it.)

    Finally, the program uses nl_langinfo(D_T_FMT) to obtain the locale-specific date-time format string. It may return NULL, and a non-NULL pointer may point to local storage (overwritten at next nl_langinfo() call, or garbled if setlocale() is called), so I wrote a small helper that creates a dynamically allocated copy. (If NULL, the second one is used instead; "%c" means the preferred date-time format for the locale.)

    So, the code also shows how to output timestamps in localized formats. (nl_langinfo(D_FMT) is for date part only, and nl_langinfo(T_FMT) is for time part only, if you happen to want those. You can also find out other locale-formatting details using that function; see man 3 nl_langinfo for details.)




    This post is not intended as sarcasm either. It is not a simple example, either. It is more of a example in the vein of "look how powerful the standard library stuff is", with a real-world executable for you to play with.

    For actual example code to date/time manipulation, perhaps you could ask for a specific task to handle in example code?

    It would be much more sane that way; I and others could show a couple of different examples to do that, and explain them in detail. You only need to specify what kind of a calendar or time operation you wish to see. There are way too many for me to pick one..

  13. #13
    Registered User
    Join Date
    Apr 2013
    Posts
    38
    Quote Originally Posted by Nominal Animal View Post
    ^
    Thanks so much for this, you really went out of your way. I do apologise for the late reply, I have been tied up with work and its kept me busy. I am sort of free in from monday on, so I will really sit down and go over this. Once again thanks mate, your a top bloke!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 04-17-2013, 11:32 PM
  2. Replies: 2
    Last Post: 04-17-2013, 12:25 AM
  3. [HELP] Code to Convert Army Time to Normal Time?
    By Kipper DeVera in forum C++ Programming
    Replies: 9
    Last Post: 08-21-2011, 11:50 PM
  4. Replies: 23
    Last Post: 05-22-2011, 11:20 PM
  5. Replies: 7
    Last Post: 11-21-2009, 01:02 AM