Ctime, mktime in C

72 views Asked by At

I can't have the time_in printed out right, can you please show where my code went wrong? Thank you and hope you have a great day!

Input: 55 17:30 11-06-2023 07:15 15-07-2023, the first number is the price for renting a bike (not very neccessary), and numbers after that are the rent time and the return time in the form: HH:MM DD-MM-YY, print out the rent time and the return time in the form long int using mktime and in the standard form (e.g Sat Jul 15 07:15:01 2023 ) using ctime

Here's my code:



#include <stdio.h>
#include <time.h>

int main(){
    int price;
    scanf("%d", &price);

    struct tm input_time;
    struct tm output_time;
    time_t time_in, time_out;

    scanf("%d:%d %d-%d-%d", &input_time.tm_hour, &input_time.tm_min, &input_time.tm_mday, &input_time.tm_mon, &input_time.tm_year);
    scanf("%d:%d %d-%d-%d", &output_time.tm_hour, &output_time.tm_min, &output_time.tm_mday, &output_time.tm_mon, &output_time.tm_year);

    input_time.tm_mon -= 1;
    output_time.tm_mon -= 1;
    input_time.tm_year -= 1900;
    output_time.tm_year -= 1900;

// printing out every component to check if i failed to input them
    printf("%d\n", price);
    printf("%ld:", input_time.tm_hour );
    printf("%ld ", input_time.tm_min );
    printf("%ld-", input_time.tm_mday );
    printf("%ld-", input_time.tm_mon );
    printf("%ld\n", input_time.tm_year );

    printf("%ld:", output_time.tm_hour );
    printf("%ld ", output_time.tm_min );
    printf("%ld-", output_time.tm_mday );
    printf("%ld-", output_time.tm_mon );
    printf("%ld\n", output_time.tm_year );
    
//using mktime
    time_in = mktime(&input_time);
    time_out = mktime(&output_time);

// print out the time in seconds form
    printf("%ld\n", time_in);
    printf("%ld\n", time_out);

// print out the time in the 'Sat Jul 15 07:15:01 2023' form
    printf(ctime(&time_in));
    printf(ctime(&time_out));
    
}

Here're my output, i got the return time printed right, but the rent time is all messed up, i keeps changing everytime i run the code

1st run:

550000        
17:30 11-5-123
7:15 15-6-123 
1592440040    
1689380101    
Thu Jun 18 07:27:20 2020
Sat Jul 15 07:15:01 2023

2nd run:

550000        
17:30 11-5-123
7:15 15-6-123 
-2085243656    
1689380101    
Mon Jan 09 19:07:20 2040
Sat Jul 15 07:15:01 2023
1

There are 1 answers

0
Craig Estey On

You have:

struct tm input_time;
struct tm output_time;

These are on the stack. So, they are uninitialized. The parts of the structs that you don't explicitly set can have random values.

This is because they take on whatever values just "happen" to be there from earlier parts of the execution of the program.

This is UB (undefined behavior).

To fix this, initialize all elements to zero:

struct tm input_time = { 0 };
struct tm output_time = { 0 };

Note that although you did check some values, some others (e.g. tm_isdst, tm_sec, etc.) were not initialized. These values are filled in by (e.g. localtime) but mktime [is finicky and] needs some more of them.

Also, some printf used %ld instead of %d.


On my system, the UB always produced consistent results. That's the nature of UB. It can work, work intermittantly, be incorrect, segfault.

So, to simulate the random behavior, I refactored the code to use rand to pre-seed the structs.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int opt_z;

void
timeget(struct tm *tm)
{

    unsigned char *bp = (unsigned char *) tm;
    for (int idx = 0;  idx < sizeof(struct tm);  ++idx) {
        // simulate properly initialized values
        if (opt_z)
            bp[idx] = 0;

        // simulate uninitialized value (i.e. random values)
        else
            bp[idx] = rand();
    }

    scanf("%d:%d %d-%d-%d",
        &tm->tm_hour, &tm->tm_min, &tm->tm_mday, &tm->tm_mon, &tm->tm_year);

    tm->tm_mon -= 1;
    tm->tm_year -= 1900;
}

void
timeout(const struct tm *tm)
{

    printf("%d:", tm->tm_hour);
    printf("%d ", tm->tm_min);
    printf("%d-", tm->tm_mday);
    printf("%d-", tm->tm_mon);
    printf("%d\n", tm->tm_year);
}

int
main(int argc,char **argv)
{
    int price;

    struct timespec ts;
    clock_gettime(CLOCK_REALTIME,&ts);
    srand(ts.tv_sec + ts.tv_nsec);

    --argc;
    ++argv;

    for (;  argc > 0;  --argc, ++argv) {
        char *cp = *argv;
        if (*cp != '-')
            break;

        cp += 2;
        switch (cp[-1]) {
        case 'z':
            opt_z = ! opt_z;
            break;
        }
    }

    scanf("%d", &price);

// NOTE/BUG: these are uninitialized
    struct tm input_time;
    struct tm output_time;

    time_t time_in, time_out;

    if (opt_z)
        printf("structs will be seeded with zeroes (initialized)\n");
    else
        printf("structs will be seeded with random values (uninitialized)\n");

    timeget(&input_time);
    timeget(&output_time);

    // printing out every component to check if i failed to input them
    printf("%d\n", price);
    timeout(&input_time);
    timeout(&output_time);

    //using mktime
    time_in = mktime(&input_time);
    time_out = mktime(&output_time);

    // print out the time in seconds form
    printf("%ld\n", time_in);
    printf("%ld\n", time_out);

    // print out the time in the 'Sat Jul 15 07:15:01 2023' form
    printf(ctime(&time_in));
    printf(ctime(&time_out));

    return 0;
}

Here is the input that I used to test:

55 17:30 11-06-2023 07:15 15-07-2023

Here is the "bad" output for 5 runs:


structs will be seeded with random values (uninitialized)
55
17:30 11-5-123
7:15 15-6-123
1566767832
3210324873
Sun Aug 25 17:17:12 2019
Thu Sep 24 08:54:33 2071

structs will be seeded with random values (uninitialized)
55
17:30 11-5-123
7:15 15-6-123
887606802
3740157022
Mon Feb 16 00:26:42 1998
Thu Jul  8 16:30:22 2088

structs will be seeded with random values (uninitialized)
55
17:30 11-5-123
7:15 15-6-123
394103670
-316448899
Mon Jun 28 05:14:30 1982
Tue Dec 22 04:31:41 1959

structs will be seeded with random values (uninitialized)
55
17:30 11-5-123
7:15 15-6-123
192016368
127026679
Sun Feb  1 04:52:48 1976
Thu Jan 10 01:11:19 1974

structs will be seeded with random values (uninitialized)
55
17:30 11-5-123
7:15 15-6-123
1519761782
3264962288
Tue Feb 27 15:03:02 2018
Sat Jun 17 17:58:08 2073

Running the program with -z a few times:


structs will be seeded with zeroes (initialized)
55
17:30 11-5-123
7:15 15-6-123
1686522600
1689423300
Sun Jun 11 18:30:00 2023
Sat Jul 15 08:15:00 2023

structs will be seeded with zeroes (initialized)
55
17:30 11-5-123
7:15 15-6-123
1686522600
1689423300
Sun Jun 11 18:30:00 2023
Sat Jul 15 08:15:00 2023

structs will be seeded with zeroes (initialized)
55
17:30 11-5-123
7:15 15-6-123
1686522600
1689423300
Sun Jun 11 18:30:00 2023
Sat Jul 15 08:15:00 2023

structs will be seeded with zeroes (initialized)
55
17:30 11-5-123
7:15 15-6-123
1686522600
1689423300
Sun Jun 11 18:30:00 2023
Sat Jul 15 08:15:00 2023

structs will be seeded with zeroes (initialized)
55
17:30 11-5-123
7:15 15-6-123
1686522600
1689423300
Sun Jun 11 18:30:00 2023
Sat Jul 15 08:15:00 2023