4

So I need to specifically use struct tm to print out my birthday, which I did successfully. However, I am also required to use strftime() to print it in different formats. That's where I encounter my problem, as strftime() only recognizes pointer parameters.

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

int main(){

    struct tm str_bday;
    time_t time_bday;
    char buffer[15];

    str_bday.tm_year = 1994 - 1900 ;
    str_bday.tm_mon = 7 - 1;
    str_bday.tm_mday = 30;
    str_bday.tm_hour = 12;
    str_bday.tm_min = 53;
    time_bday = mktime(&str_bday);
    if(time_bday == (time_t)-1)
        fprintf(stdout,"error\n");
    else
        {
        fprintf(stdout,"My birthday in second is: %ld \n",time_bday);
        fprintf(stdout,"My birthday is: %s\n", ctime(&time_bday));//Wed July 22 12:53:00 1998
        strftime(buffer,15,"%d/%m/%Y",time_bday);
        fprintf(stdout,"My birthday in D/M/Y format is %s",buffer);
        }
    return 0;
}

The errors are:

Error:  passing argument 4 of ‘strftime’ makes pointer from integer without a cast

    expected ‘const struct tm * restrict’ but argument is of type ‘time_t’

Can someone please tell me how to fix it?

EDIT: Changing time_bday to &str_bday works! But now the program outputs random time and date every time I run it.

EDIT: Instead of fprintf() after strftime(), I used puts(buffer), and it worked perfectly. Also, changing buffer[15] to buffer[30] as I have hours, minutes and seconds.

Duc Nguyen
  • 87
  • 2
  • 9
  • Well since it takes a `struct tm*`, have you tried passing it a pointer to a `struct tm`? Try passing `&str_bday` instead of `time_bday`. – Felix Guo Apr 16 '18 at 02:09
  • @FelixGuo Oh yeah, thank you! But now, every time I run this program, it showed up a different date and time though – Duc Nguyen Apr 16 '18 at 02:15
  • 1
    Not sure why you'd be getting inconsistent results (with which output)? However, you're not setting all the fields of `str_bday`. You could try setting it with C99-style syntax `const struct tm str_bday = { .tm_year = 98, .tm_mon = 7, /* ... */ };` Or if that's correct enough for `ctime()` to work, you could get a round-trip conversion from `gmtime()`. – Davislor Apr 16 '18 at 02:27
  • I trust your actual birthday is on a wholly different date. It wouldn't be advisable to post your real one on the internet (though there are worse bits of information to include in a question on SO). – Jonathan Leffler Apr 16 '18 at 02:31

2 Answers2

5

By looking at strftime's prototype, you can see that you should pass a const struct tm* as last argument:

size_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr);

which would be &str_bday instead of time_bday in your case.

struct tm has a couple of fields you are not initializing and thus take indeterminate values, resulting in the time jumps you're seeing. You can initialize all fields to zero with struct tm str_bday = {0}, before inserting your values.

a3f
  • 8,517
  • 1
  • 41
  • 46
  • 1
    Since `str_bday` is constant data known at compile time, I would recommend `static const struct str_bday = { .tm_year = 98, .tm_month = 7, /* ... */ };`. – Davislor Apr 16 '18 at 03:38
  • Failing that, a structure with `static` storage class is initialized to all-bits-zero, so at least that would give reproducible resuls. The portable way to guarantee zero-initialized automatic storage is `memset()` and the way to guarantee zero-initiialized dynamic storage is `calloc()`. – Davislor Apr 16 '18 at 03:40
0

mktime(&str_bday); depends upon the various members1 of struct tm in its calculation of time_t.

First initializing members to 0 is good practice.

// struct tm str_bday;
struct tm str_bday = { 0 };

OP's code fails to initialize some members, like tm_sec, which certainly contribute to an errant result.

Yet it is also important to initialize all relevant members. OP's code does not assign tm_isdst and with struct tm str_bday = { 0 }, this is like

str_bday.tm_isdst = 0; // Set time stamp to **standard** time.

The trouble with this is that in OP's school, the daylight time setting for that date is certainly daylight time.

// add
str_bday.tm_isdst = -1; // Let mktime() determine DST setting
// or if one knowns it is daylight time.
str_bday.tm_isdst = 1; // Set time stamp to **daylight** time.
// or if one knowns it is standard time.
str_bday.tm_isdst = 0; // Set time stamp to **standard** time.

The error should be apparent in the printing of ctime(&time_bday)

// My birthday is: Sat Jul 30 13:53:00 1994
My birthday is: Sat Jul 30 12:53:00 1994

Corrected code

#include <locale.h>
#include <time.h>
int main() {

  struct tm str_bday = { 0 };
  time_t time_bday;
  char buffer[15];

  str_bday.tm_year = 1994 - 1900;
  str_bday.tm_mon = 7 - 1;
  str_bday.tm_mday = 30;
  str_bday.tm_hour = 12;
  str_bday.tm_min = 53;
  str_bday.tm_isdst = -1;
  time_bday = mktime(&str_bday);

  strftime(buffer, sizeof buffer, "%d/%m/%Y", &str_bday);
  if (time_bday == (time_t) -1) {
    fprintf(stdout, "error\n");
  } else {
    // Do not assume `long`.  Better to cast to a wide type. 
    fprintf(stdout, "My birthday in second is: %lld \n", (long long) time_bday);
    fprintf(stdout, "My birthday is: %s", ctime(&time_bday));
    // strftime(buffer,15,"%d/%m/%Y",time_bday);
    strftime(buffer, sizeof buffer, "%d/%m/%Y", &str_bday);
    fprintf(stdout, "My birthday in D/M/Y format is %s\n", buffer);
  }
  return 0;
}

1 Members tm_wday and tm_yday do not contribute to the calculation, but are updated.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256