0

Why is it, that when i convert a struct tm to time_t via mktime and then this value back to a struct tm via localtime() it is not the same?

struct tm actualtime=get_RTC_time();
    sprintf(outtext,"==> %d-%d-%d %d:%d:%d\r\n",actualtime.tm_year,actualtime.tm_mon,actualtime.tm_mday,actualtime.tm_hour,actualtime.tm_min,actualtime.tm_sec);
    print(RS232,outtext);
    actualtime.tm_mon = actualtime.tm_mon-1;
    actualtime.tm_year = actualtime.tm_year-1900;
    time_t tmp=mktime(&actualtime);
    sprintf(outtext,"==> %d-%d-%d %d:%d:%d\r\n",actualtime.tm_year,actualtime.tm_mon,actualtime.tm_mday,actualtime.tm_hour,actualtime.tm_min,actualtime.tm_sec);
    print(RS232,outtext);
    sprintf(outtext,"==> %lld\r\n",(long long)tmp);
    print(RS232,outtext);
    tmp+=100;
    struct tm *alarm_time=gmtime(&tmp);
    sprintf(outtext,"==> %d-%d-%d %d:%d:%d\r\n",alarm_time->tm_year,alarm_time->tm_mon,alarm_time->tm_mday,alarm_time->tm_hour,alarm_time->tm_min,alarm_time->tm_sec);
    print(RS232,outtext);

In my code snippet i get the timestamp from a custom function get_RTC_time and i wanted to add 100 seconds to that timestamp, So i converted it to seconds via mktime(), added 100 seconds and then converted it back to a struct tm alarm_time timestamp, but alarm_time differs way more than 100 seconds from actualtime.

For example, when i get the timestamp 1900-1-27 9:59:41 from get_RTC_time and i convert it to a long I get 1919627533 and when i convert it back to a timestamp i get 130-9-30 21:52:13 and i do not know why.

I read through the manpage, but nothing really explained this behaviour to me

It also occured to me that mentioning, that this code should be is to be running on a microchip

the method get_RTC_time

struct tm get_RTC_time(void)
{
    
    RTC_Twi.chip = RTC_adr;
    RTC_Twi.addr[0] = 0x00;      // must be adjusted accordingly
    RTC_Twi.addr_length = sizeof (uint8_t); //in bit!!!!!!!!!!!!!
    RTC_Twi.buffer = &RTC_Array;
    RTC_Twi.length = 7;
    
    twi_master_read(RTC_3231_Interface,&RTC_Twi);
    uhrzeit.tm_sec = (RTC_Array[0] & 0x0f)+((RTC_Array[0] & 0xf0)>>4)*10;
    uhrzeit.tm_min = (RTC_Array[1] & 0x0f)+((RTC_Array[1] & 0xf0)>>4)*10;
    uhrzeit.tm_hour = (RTC_Array[2] & 0x0f)+((RTC_Array[2] & 0x10)>>4)*10+((RTC_Array[2]&0x20)>>5)*20; //24h Modus muss aktiv sein!!!
    uhrzeit.tm_wday = (RTC_Array[3] & 0x07);
    uhrzeit.tm_mday = (RTC_Array[4] & 0x0f)+((RTC_Array[4] & 0xf0)>>4)*10;
    uhrzeit.tm_mon = (RTC_Array[5] & 0x0f)+((RTC_Array[5] & 0x10)>>4)*10;
    uhrzeit.tm_year = (RTC_Array[6] & 0x0f)+((RTC_Array[6] & 0xf0)>>4)*10+((RTC_Array[5] & 0x80)>>7)*100 + 1900 ;

    return uhrzeit;
}
macman
  • 21
  • 6
  • `sprintf(outtext,"==> %d\r\n",tmp);` has wrong format spec `%d` for `long tmp`. It's not `long` anyway: it should be `time_t tmp`. So you could try `%lld` and `(long long)tmp`. – Weather Vane Nov 22 '22 at 21:36
  • Does the following answer help you get what you want? https://stackoverflow.com/questions/1859201/add-seconds-to-a-date – ChrisSc Nov 22 '22 at 21:39
  • true, i changed it to time_t, but the faulty format spec should not be the problem i think, since the conversion is not right... – macman Nov 22 '22 at 21:42
  • @ChrisSc sadly not, i still do not really understand, how to properly convert back and forth from `struct tm` to seconds and back to `struct tm` – macman Nov 22 '22 at 21:46
  • Can't reproduce. Your `localtime` may be broken, perhaps due to an invalid timezone. Try `gmtime` instead. – n. m. could be an AI Nov 22 '22 at 21:47
  • 1
    `get_RTC_time` is [may be] non-conforming. It produces a `tm_year` value of 1900. But, the standard functions expect `tm_year` to be "year - 1900". For the year 2022, we'd expect a `tm_year` of 122. So, you need to subtract 1900 from `tm_year` before passing it to `mktime`. When printing `tm_year` after `localtime`, you need to print `tm_year + 1900` – Craig Estey Nov 22 '22 at 21:47
  • @n.m. no sadly gmtime does not change the outcome – macman Nov 22 '22 at 21:52
  • @CraigEstey i edited my post above accordingly, but this sadly does not do the trick... the output is now `==> 1900-1-27 11:4:2 ==> 0-0-27 11:4:2 ==> 2088264738 ==> 136-2-4 17:32:18` – macman Nov 22 '22 at 21:57
  • Where does `get_RTC_time` come from? I did a web search and the quick references show it to be a [linux] kernel function? What is the prototype and/or documentation for this? What OS/environment is this in? – Craig Estey Nov 22 '22 at 22:00
  • no this is a custom function which reads a time value via `twi` interface from an external real time clock (situated on a microchip) and parses the result into a `struct tm` – macman Nov 22 '22 at 22:02
  • Like I said, `get_RTC_time` is non-conforming [screwy]. A tm_year value of 1900 would be 1900 + 1900 or 2800. For your two absolute time_t values, they are `tod=1919627533 tm_year=130/2030` and `tod=2088264738 tm_year=136/2036` As WeatherVane pointed out, you can't use `%d`. `time_t` is a `long`, so use `%ld` – Craig Estey Nov 22 '22 at 22:07
  • Another way to do this is to say `alarm_time = actualtime; alarm_time.tm_sec += 100; mktime(&alarm_time);`. – Steve Summit Nov 22 '22 at 22:08
  • @CraigEstey but didn't you say before it for a the year 2022 we would need a tm_year of 122 so wouldn't we need for the year 1900 the tm_year 0? – macman Nov 22 '22 at 22:13
  • @SteveSummit but shouldn't `tm_seconds` be between `0` and `59` if i add a ridiculus number of seconds to it wouldn't that break `localtim()` – macman Nov 22 '22 at 22:15
  • Yes, that's why if the real world year was 1900, tm_year would be 0. So, if you're getting something over 1000, the `get_RTC_time` isn't producing a real `tm` struct. Can you post the source for `get_RTC_time`? – Craig Estey Nov 22 '22 at 22:16
  • @CraigEstey done, but it is set up to parse the actual time values into the struct and not the expected ones, so truthfully said, `tm_day -1` and `tm_year-1900` should be done – macman Nov 22 '22 at 22:21
  • I found a datasheet: https://datasheets.maximintegrated.com/en/ds/DS3231.pdf And a tutorial: https://www.microchip.com/forums/m1191911.aspx Are these the correct pages? The latter is for PIC* [yecch!]. But, what are you using? – Craig Estey Nov 22 '22 at 22:27
  • @CraigEstey yes it seems, but the rtc is working fine, just the date needs to be calibrated, the clock itself runs fine. but i seriously do not think, that this funktion is the problem, i will try now without the function and a normal `struct tm` initialized by me and try to see if this will be converted properly back and forth – macman Nov 22 '22 at 22:32
  • 1
    Yes, that's what I mean by non-conforming. If it presents 1900 [instead of 0] for the real world year 1900. But, I don't see how we're getting 1900. For current time, we should see either 2022 or 122. – Craig Estey Nov 22 '22 at 22:33
  • _just the date needs to be calibrated_ I would expect the RTC chip starts with an absolute time value of 0, so that would be 01/01/1900-00:00:00 – Craig Estey Nov 22 '22 at 22:34
  • no since it is hooked up to a permanent battery supply which powers only the rtc even if the power on the whole board is out – macman Nov 22 '22 at 22:37
  • @CraigEstey i think, that you are right now (you knew it all along), with a normal time struct it works flawlessly, but since i now know where my error is, all that is left to do is thank you for your time and effort, have a good day :) – macman Nov 22 '22 at 22:41
  • Glad you found/realized the problem. Yes, I've confirmed experimentally that with standard tm structs, your adjustment code works fine. Good luck with the RTC. Happy Programming! – Craig Estey Nov 22 '22 at 22:47
  • @macman Sounds like youur problem is resolved, but for future reference: when you call `localtime`, you're guaranteed to get back a `struct tm` with `tm_sec` in the range 0..59 (or, under very rare circumstances, 60). But when you construct a `struct tm` to hand to `mktime`, you're allowed to use "denormalized" values for the date and time, and it will do the math for you to fix them up. See the [man page](https://linux.die.net/man/3/mktime): "if structure members are outside their valid interval, they will be normalized". – Steve Summit Nov 23 '22 at 12:24

0 Answers0