2

Incomprehensible behavior of the function strptime():

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

double getPeriod(char * dateStart, char * dateStop) {
    struct tm tmStart, tmStop;
    time_t timeStampStart, timeStampStop;

    strptime(dateStart, "%Y-%m-%d %H:%M:%S", &tmStart);
    strptime(dateStop, "%Y-%m-%d %H:%M:%S", &tmStop);

    timeStampStart = mktime(&tmStart);
    timeStampStop = mktime(&tmStop);

    printf("%d\t%d\n", tmStart.tm_hour, tmStop.tm_hour);
}

int main()
{
    getPeriod("2016-12-05 18:14:35", "2016-12-05 18:18:34");
    return 0;
}

Output:

17  18

Why does this happen?

Compiler gcc (GCC) 6.2.1 OS Linux

jxh
  • 69,070
  • 8
  • 110
  • 193
Sergey
  • 23
  • 2
  • 1
    You need to initialize the `tm_isdst` member of `timeStampStart` and `timeStampStop` to -1. – user4815162342 Dec 05 '16 at 21:08
  • [Seems to work on GCC and Clang here](http://coliru.stacked-crooked.com/a/6b54f234cc33eb6c) – AndyG Dec 05 '16 at 21:09
  • @user4815162342: Oh man, that daylight savings time thing is always such a pain! And I think you meant for `tmStart` and `tmStop` – AndyG Dec 05 '16 at 21:15
  • This is my output screen: [link](http://hostingkartinok.com/show-image.php?id=fe6b82d83bf07875952d6af6a072a476) – Sergey Dec 05 '16 at 21:16
  • `mktime()`, needs to have all fields (expect `tm_yday` and `tm_wday` initialized. There are at _least_ 7 other fields, `tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec` **and** `tm_isdst`. Recommend `struct tm tmStart = { 0 };`. Some implementations have other fields. Uncertain if these other fields apply to gcc. – chux - Reinstate Monica Dec 05 '16 at 21:36
  • Yes, thank you, its work – Sergey Dec 05 '16 at 21:40
  • There is no C++ in this code, so it should not be tagged C++. – Pete Becker Dec 05 '16 at 21:42
  • @chux Others will be initialized by `strptime`. Still, initializing the whole struct is good practice. `tm_isdst` should probably be set to -1 and not to zero (unless one really means to specify DST as not in effect). – user4815162342 Dec 05 '16 at 21:43

1 Answers1

1

tmStart and tmStop are not initialized, so some fields will be uninitialized when passed to mktime. Thus, the behavior is technically undefined.

From the strptime man page (note the first two sentences):

In principle, this function does not initialize tm but only stores the values specified. This means that tm should be initialized before the call. Details differ a bit between different UNIX systems. The glibc implementation does not touch those fields which are not explicitly specified, except that it recomputes the tm_wday and tm_yday field if any of the year, month, or day elements changed.

jxh
  • 69,070
  • 8
  • 110
  • 193