0

I am trying to get the local time in seconds (unix epoch) when a timezone is set. For e.g.

1643371200 is 2022-01-28 12:00:00 with UTC0

this can be read via gettimeofday(tv, NULL) as seconds with the timeval struct.
Now let's say I set my local timezone to Europe/Berlin via setenv("TZ","CET-1CEST,M3.5.0,M10.5.0/3",1).

When I use

localtime_r(&now, &local_tv);
char strftime_buf[64];
strftime(strftime_buf, sizeof(strftime_buf), "%c", &local_tv);
printf("get local time: %s", strftime_buf);

this prints 2022-01-28 13:00:00 as expected (+1h).
Now I used mktime(&local_tv) as I thought this will give me my local time in seconds. But it's still 1643371200 (12:00:00). And when I use mktime() with gettimeofday() I get 1 hour less, so 11:00:00 ...

ddomnik
  • 3
  • 2
  • 1
    Unix time like 1643371200 is *always* UTC. When you call `localtime` it applies your local time zone as part of converting from 1643371200 to a local, human-readable time. And when you call `mktime`, it strips your local time zone back off. – Steve Summit Jul 06 '22 at 14:52
  • @SteveSummit I know, but how can I get or convert my local time to seconds? – ddomnik Jul 06 '22 at 14:53
  • Using `mktime`, just like you did. – Steve Summit Jul 06 '22 at 14:54
  • @SteveSummit but `mktime` gives it in UTC, but I want it in local time. – ddomnik Jul 06 '22 at 15:02
  • Re "*I thought this will give me my local time in seconds.*", `mktime(&local_tv)` *does* give you the local time in seconds. Specifically, the number of seconds since 1970-01-01T00:00:00+0000 on Linux. So what exactly do you want? – ikegami Jul 06 '22 at 15:21
  • Re "*when I use mktime() with gettimeofday() I get ...*", huh, the value returned by `gettimeofday` isn't compatible with `mktime`. Not just semantically; the types are completely incompatible. – ikegami Jul 06 '22 at 15:26
  • @ikegami `mktime()` gives me the local time in seconds in UTC0. E.g. `gettimeofday()` gives 1643371200 and `localtime_r()` gives 1643374800 but as other format. So why is `mktime()` giving me 1643371200 when used with `localtime_r()` ? – ddomnik Jul 06 '22 at 15:38
  • Re "*localtime_r()*", gives 1643374800 No it doesn't – ikegami Jul 06 '22 at 15:41
  • I guess it's time to ask, *Why* do you want "local time in seconds"? What are you going to do with this number if you can compute it? – Steve Summit Jul 06 '22 at 15:51
  • @ikegami so then how do I get 1643374800 ? Because that's what I need. – ddomnik Jul 06 '22 at 15:52
  • For most purposes, "local time in seconds" is either useless or meaningless. For most purposes, a since-the-epoch time like 1643371200 is, as I said earlier, always UTC. There's not much you can do with a since-the-epoch local time. – Steve Summit Jul 06 '22 at 15:52
  • Since "local time in seconds" is not commonly used, there is no standard way to get it. One way would be to call `localtime`, then do `now - local_tv.tm_gmtoff`. But beware, the `tm_gmtoff` field is not standard, either. – Steve Summit Jul 06 '22 at 15:54
  • What is 1643374800? Are you asking for the number of seconds since 1970-01-01 00:00:00 local time? If so, see ujpdate to my answer. – ikegami Jul 06 '22 at 16:13

1 Answers1

1

So why is mktime() giving me 1643371200 when used with localtime_r()

2022-01-28T13:00:00+01:00 is 1643371200 seconds later than 1970-01-01T00:00:00+00:00, the epoch used on Linux.

mktime is literally the inverse operation of localtime, so of course mktime(localtime(time)) gives time.

                time /
             gettimeofday
                  |
+-----------------+-----------------+
|                 |                 |
|                 v                 |
|             Epoch time            |
|                 |                 |
|          +------+------+          |
|          |             |          |
|          v             v          |
|      localtime       gmtime       |
|          |             |          |
|          v             v          |
|     Broken down     Broken down   |
|     local time      UTC+0 time    |
|          |             |          |
|          v             v          |
|       mktime /     _mkgmtime* /   |
|      timelocal*     timegm*       |
|          |             |          |
+----------+             +----------+

how do I get 1643374800 ?

You appear to want the number of seconds since 1970-01-01T00:00:00 local time.

If you want this, you are doing something wrong. There is no need for this value.[1]

To find the number of seconds between two times, start by converting them to epoch times if they aren't already. Then simply subtract one from the other.

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

int main( void ) {
   setenv( "TZ", "Europe/Berlin", 1 );
   tzset();

   struct tm base_tm = {
      .tm_sec    = 0,             /* Seconds (0-60) */
      .tm_min    = 0,             /* Minutes (0-59) */
      .tm_hour   = 0,             /* Hours (0-23) */
      .tm_mday   = 1,             /* Day of the month (1-31) */
      .tm_mon    = 1 - 1,         /* Month (0-11) */
      .tm_year   = 1970 - 1900,   /* Year - 1900 */
      //.tm_wday = ,              /* Day of the week (0-6, Sunday = 0) */
      //.tm_yday = ,              /* Day in the year (0-365, 1 Jan = 0) */
      .tm_isdst  = -1             /* Daylight saving time */
   };

   time_t base_epoch = mktime( &base_tm );

   time_t now_epoch = 1643371200l;  // time( NULL );

   printf( "%" PRIi64 "\n", (int64_t)( now_epoch - base_epoch ) );  // 1643374800
}

  1. It might be useful in correcting something that was done incorrectly.
ikegami
  • 367,544
  • 15
  • 269
  • 518