I am experimenting with time_t variables, and this is the code in question:
#include <stdio.h>
#include <time.h>
#include <stdint.h>
struct tm epochtime;
time_t epochdate;
int main()
{
epochtime.tm_mday = 19;
epochtime.tm_mon = 10;
epochtime.tm_year = 2002;
epochtime.tm_hour = 0;
epochtime.tm_min = 0;
epochtime.tm_sec = 0 ;
epochdate = mktime(&epochtime);
printf("%ju\n",epochdate);
printf("%ju\n", (uint32_t)epochdate);
printf("%ju\n", (uint64_t)epochdate);
printf("%ju\n", (uintmax_t)epochdate);
printf("%Lf\n", epochdate);
printf("%Le\n", epochdate);
}
I am trying to print the epochtime of a given date. The code compiles and has no errors, but when I compare what I get printed to what I calculate on this website, the values are not the same. For this given values in the example above the code output is:
210453397503
210453397503
18446744073709551615
18446744073709551615
-1.#QNAN0e+000
-1.#QNAN0e
while the link says that value should be 1034985600. I have tried multiple printf format specifiers because I found multiple answers here on how to print time_t variables, but none of them seems to work for me. Any ideas why?
I suppose that you want to represent the date: October 19th, 2002 00:00:00, which corresponds to the epoch timestamp that you expect: 1034985600.
In such case, you are doing it wrong. Read the manual:
Broken-down time is stored in the structure tm, which is defined in <time.h> as follows:
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
Your year should be 2002 - 1900 = 102, and your month should be 9, not 10 (months start from 0 = January).
The correct code is:
#include <stdio.h>
#include <time.h>
#include <inttypes.h>
int main(void) {
struct tm epochtime = {
.tm_mday = 19,
.tm_mon = 9,
.tm_year = 102,
.tm_hour = 0,
.tm_min = 0,
.tm_sec = 0,
.tm_isdst = -1
};
time_t epochdate = mktime(&epochtime);
if (epochdate == (time_t)(-1)) {
perror("mktime failed");
return 1;
}
printf("%" PRIuMAX "\n", (uintmax_t)epochdate);
return 0;
}
Which correctly outputs 1034985600 as you expect.
The problem with your code is most likely that mktime is not able to correctly represent the "wrong" date you provide and returns -1, which you then print as unsigned and becomes a huge nonsensical number.
printf epochtime shows wrong values
There is no specified matching print specifier for time_t. All the printf() except printf("%ju\n", (uintmax_t)epochdate); can lead to undefined behavior (UB).
... multiple answers here on how to print time-t variables, but none of them seems to work for me. Any ideas why?
time_t is a type capable of representing times.
The range and precision of times representable in clock_t and time_t are implementation-defined. C17dr § 7.27.1 4
Print using a cast. As time_t is very commonly a signed integer type, cast to a wide signed type:
time_t t;
time(&t);
printf("%jd", (intmax_t) t);
// or pre-C99
printf("%ld", (long) t);
or for wide portability at the small risk of losing some precision,
printf("%f", (double) t);
printf("%ju\n", (uintmax_t)epochdate); --> 18446744073709551615 is certainly the result of mktime(&epochtime); returning -1 due to a conversion error, likely due to range error with epochtime.tm_year = 2002;. .tm_year is the year since 1900. #pmg
Best to zero out epochtime first to initialize all members - there may be more than 9.
struct tm epochtime = {0};
epochtime.tm_mday = 19;
epochtime.tm_mon = 10 - 1; // Months since January
epochtime.tm_year = 2002 - 1900; // Year since 1900
epochtime.tm_isdst = -1; // Let system daylight daylight time for that date
epochdate = mktime(&epochtime); // epochtime is assumed here to be a local time
Related
I use mktime64 to convert a clock time into a jiffies value.
// year, mon, day, hour, min, sec
unsigned long my_jiffies = mktime64(2020, 2, 24, 3, 2, 50);
The output from the above code is: 1582513370
How can I convert that jiffies value back to clock time?
[This answer is for the Linux kernel since linux-kernel was tagged in the question.]
mktime64 is nothing to do with jiffies. It converts the date specified by its parameters to the number of seconds (ignoring leap seconds) since 1970-01-01 00:00:00 (Unix time since the epoch if the parameters are for GMT).
The returned time64_t value can be converted back to year, month, day, hours, minutes, seconds using the time64_to_tm function in the kernel. It has this prototype:
void time64_to_tm(time64_t totalsecs, int offset, struct tm *result);
The offset parameter is a local timezone offset in seconds (number of seconds east of GMT). It should be set to 0 to undo the conversion done by mktime64.
Note that the tm_year member is set to the calculated year minus 1900 and the tm_mon member is set to the calculated month minus 1, so you could implement an unmktime64 function as follows:
void unmktime64(time64_t totalsecs,
int *year, unsigned int *month, unsigned int *day,
unsigned int *hour, unsigned int *minute, unsigned int *second)
{
struct tm tm;
time64_to_tm(totalsecs, 0, &tm);
*year = tm.tm_year + 1900;
*month = tm.tm_mon + 1;
*day = tm.tm_mday;
*hour = tm.tm_hour;
*minute = tm.tm_min;
*second = tm.tm_sec;
}
I am trying to code a function which populates a struct tm from year, month, day, hour and minutes values.
The application deals with no time zone information, i.e., we assume that the input data time zone matches with the application and user time zone.
I have tried this:
void timeCreate(struct tm* pTm1, int year, int month, int day, int hour, int minute) {
pTm1->tm_year = year - 1900;
pTm1->tm_mon = month - 1;
pTm1->tm_mday = day;
pTm1->tm_hour = hour;
pTm1->tm_min = minute;
pTm1->tm_sec = 0;
pTm1->tm_isdst = -1;
mktime(pTm1);
}
If I don't do anything else, I get the CET time set by mktime (CET is my local timezone) and it seems that mktime changes the time and date, so it is no longer 2014/01/01 00:00 but the day before.
If I do this:
pTm1->tm_gmtoff = 0;
pTm1->tm_zone = "UTC";
Then I do not get any correction.
I have also seen the function gmtime() instead of mktime(). Which would be the "right" way of setting up this struct?
Also I get a random value for tm_wday, can that value be calculated automatically?
mktime only works with local time, and its behavior is constrained by the specification so that it cannot examine any nonstandard fields of struct tm like tm_gmtoff. And gmtime is not an analog of mktime but of localtime - it converts in the opposite direction. If you want a normalization/conversion of broken-down UTC time in struct tm format to time_t, you need to either use the nonstandard but widely available timegm function, or write it out yourself. Thankfully POSIX exactly specifies the formula:
tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
(tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
Note that if copied as written to C code, this is full of integer overflows, so some type promotions or other fixes need to be introduced to make it valid.
If you need the normalization aspect timegm also performs, but need it done portably without depending on the nonportable timegm, you can just call gmtime_r after using the above formula to invert it and get a normalized result.
Do I have to populate tm_gmtoff and tm_zone?
Which would be the "right" way of setting up this struct?
For portable code, yes.
The C spec has
"The tm structure shall contain at least the following members, in any order." (C spec) --> struct tm has at least the following 9 members:
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
And may include others like tm_gmtoff, tm_zone, tm_msec, etc.
The mktime function converts the broken-down time, expressed as local time, in the structure pointed to by timeptr into a calendar time value with the same encoding as that of the values returned by the time function. The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to the ranges indicated above. ...
... On successful completion, the values of the tm_wday and tm_yday components of the structure are set appropriately, and the other components are set to represent the specified calendar time, but with their values forced to the ranges indicated above; the final value of tm_mday is not set until tm_mon and tm_year are determined.
C17dr § 7.27.2.3 2
Since mktime() is only specified to ignore tm_wday and tm_yday, all other members may contribute to the result. There is no C spec that limits the result to 7 of the above required members.
Good programing practice would zero out all members not explicitly initialized/assigned before calling mktime().
void timeCreate(struct tm* pTm1, int year, int month, int day, int hour, int minute) {
memset(pTm1, 0, sizeof *pTm1); // Zero all members.
pTm1->tm_year = year - 1900;
pTm1->tm_mon = month - 1;
pTm1->tm_mday = day;
pTm1->tm_hour = hour;
pTm1->tm_min = minute;
pTm1->tm_sec = 0;
pTm1->tm_isdst = -1;
mktime(pTm1);
// recommend to return the result of mktime() so caller can ID invalid timestamps.
}
If you code is used on a sub-set of platforms, it may get away without such zeroing assignments.
timeStruct #0x13b123b0 tm
tm_hour 0 int
tm_isdst 0 int
tm_mday 1 int
tm_min 0 int
tm_mon 0 int
tm_sec 33 int
tm_wday 4 int
tm_yday 0 int
tm_year 70 int
This is my struct as represented by QTcreators memory watch.
with this as parameter to a call of mktime()
struct tm *timeStruct;
//[...]
time_t timeOrigin = mktime(timeStruct);
timeOrigin becomes -1.
There are questions out here asking for the same.
But they all were solved by the hint, that the tm_year field is not years since 1970 but years since 1900. I'm aware of this and also respecting it.
What confuses me further is:
man pages like: http://linux.die.net/man/3/mktime
explain that mktime doesn't change the structs members if it returns -1. In my case it did adjust in previous cases tm_wday and tm_yday, while returning -1.
I can't find any error regarding this by reading stderr, after mktime returning -1 aswell.
So whats going on here?
mktime returns -1 because the tm structure values, interpreted as a time and date expressed in local time, fall outside the valid range. As quoted from the man page: If the specified broken-down time cannot be represented as calendar time (seconds since the Epoch), mktime() returns (time_t)-1 and does not alter the members of the broken-down time structure.
You are probably located east of Greenwich, meaning that 1/1/1970 0:00:00 local time falls before the beginning of the Unix Epoch that started on 1/1/1970 0:00:00 UTC.
mktime expects a pointer of type struct tm as it's first argument.
Here is an example, how you can use it:
#include <stdio.h>
#include <time.h>
int main(void)
{
struct tm tm = *localtime(&(time_t){time(NULL)});
printf("Today is %s", asctime(&tm));
tm.tm_mon -= 100; // tm_mon is now outside its normal range
time_t t = mktime(&tm); // recalculate tm
printf("100 months ago was %s", asctime(&tm));
}
I have two date and time strings separately in variables. I need to calculate the difference between these 2 date and time values in milliseconds. How to get that in C. The solution should work across platforms(at least windows and unix).
char date1[] = {"26/11/2015"};
char time1[] = {"20:22:19"};
char date2[] = {"26/11/2015"};
char time2[] = {"20:23:19"};
First I need to save this into some time structure and then compare 2 time structures to get the difference. What is the time structure which is available in C Library to do this.
Use mktime() and difftime()
The mktime function returns the specified calendar time encoded as a value of type time_t. If the calendar time cannot be represented, the function returns the value (time_t)(-1). C11dr §7.27.2.3 4
The difftime function returns the difference expressed in seconds as a double §7.27.2.2 2
#include <time.h>
#include <stdlib.h>
#include <string.h>
time_t parse_dt(const char *mdy, const char *hms) {
struct tm tm;
memset(&tm, 0, sizeof tm);
if (3 != sscanf(mdy, "%d/%d/%d", &tm.tm_mon, &tm.tm_mday, &tm.tm_year)) return -1;
tm.tm_year -= 1900;
tm.tm_mday++;
if (3 != sscanf(hms, "%d:%d:%d", &tm.tm_hour, &tm.tm_min, &tm.tm_sec)) return -1;
tm.tm_isdst = -1; // Assume local time
return mktime(&tm);
}
int main() {
// application
char date1[] = { "26/11/2015" };
char time1[] = { "20:22:19" };
char date2[] = { "26/11/2015" };
char time2[] = { "20:23:19" };
time_t t1 = parse_dt(date1, time1);
time_t t2 = parse_dt(date2, time2);
if (t1 == -1 || t2 == -1) return 1;
printf("Time difference %.3f\n", difftime(t2, t1) * 1000.0);
return 0;
}
Output
Time difference 60000.000
from the man page for mktime()
this is the prototype for mktime()
time_t mktime(struct tm *tm);
this is the description of the function mktime()
The mktime() function takes an argument representing
broken-down time which is a representation separated into year, month,
day, and so on.
Broken-down time is stored in the structure tm which is defined in
<time.h> as follows:
struct tm {
int tm_sec; /* seconds */
int tm_min; /* minutes */
int tm_hour; /* hours */
int tm_mday; /* day of the month */
int tm_mon; /* month */
int tm_year; /* year */
int tm_wday; /* day of the week */
int tm_yday; /* day in the year */
int tm_isdst; /* daylight saving time */
};
The members of the tm structure are:
tm_sec The number of seconds after the minute, normally in the range
0 to 59, but can be up to 60 to allow for leap seconds.
tm_min The number of minutes after the hour, in the range 0 to 59.
tm_hour The number of hours past midnight, in the range 0 to 23.
tm_mday The day of the month, in the range 1 to 31.
tm_mon The number of months since January, in the range 0 to 11.
tm_year The number of years since 1900.
tm_wday The number of days since Sunday, in the range 0 to 6.
tm_yday The number of days since January 1, in the range 0 to 365.
tm_isdst A flag that indicates whether daylight saving time is in
effect at the time described. The value is positive if day‐
light saving time is in effect, zero if it is not, and nega‐
tive if the information is not available.
The mktime() function converts a broken-down time structure, expressed
as local time, to calendar time representation. The function ignores
the values supplied by the caller in the tm_wday and tm_yday fields.
The value specified in the tm_isdst field informs mktime() whether or
not daylight saving time (DST) is in effect for the time supplied in
the tm structure: a positive value means DST is in effect; zero means
that DST is not in effect; and a negative value means that mktime()
should (use timezone information and system databases to) attempt to
determine whether DST is in effect at the specified time.
The mktime() function modifies the fields of the tm structure as fol‐
lows: tm_wday and tm_yday are set to values determined from the con‐
tents of the other fields; if structure members are outside their valid
interval, they will be normalized (so that, for example, 40 October is
changed into 9 November); tm_isdst is set (regardless of its initial
value) to a positive value or to 0, respectively, to indicate whether
DST is or is not in effect at the specified time. Calling mktime()
also sets the external variable tzname with information about the cur‐
rent timezone.
If the specified broken-down time cannot be represented as calendar
time (seconds since the Epoch), mktime() returns (time_t) -1 and does
not alter the members of the broken-down time structure.
==========================================
this is from the man page for difftime()
this is the prototype:
double difftime(time_t time1, time_t time0);
This is the description:
The difftime() function returns the number of seconds elapsed between
time time1 and time time0, represented as a double. Each of the times
is specified in calendar time, which means its value is a measurement
(in seconds) relative to the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
to get the result in seconds. To get the results in milliseconds, multiply by 1000.0
time_t rawtime;
struct tm *mytm;
time_t result;
time(&rawtime);
mytm=localtime(&rawtime);
mytm->tm_mon=month-1;
mytm->tm_mday=day;
mytm->tm_year=year-1900;
mytm->tm_sec=0;
mytm->tm_min=0;
mytm->tm_hour=0;
result = mktime(mytm);
Above code snippet,I'm expecting result to display the no.of seconds lapsed since 1970,jan-1st for the given date. DD/MM/YYYY stored in day ,month,year
But i'm getting compile error
error: dereferencing pointer to incomplete type
You need
#include <time.h>
in your file to fix the error about incomplete type.
Edit: Given a day, month, year to find the time in seconds since Jan 1 1970 to midnight on that day:
struct tm mytm = { 0 };
time_t result;
mytm.tm_year = year - 1900;
mytm.tm_mon = month - 1;
mytm.tm_mday = day;
result = mktime(&mytm);
if (result == (time_t) -1) {
/* handle error */
} else {
printf("%lld\n", (long long) result);
}
Note the in ISO C, mktime() returns an integral value of type time_t that represents the time in the struct tm * argument, but the meaning of such an integral value is not necessarily "seconds since Jan 1, 1970". It need not be in seconds at all. POSIX mandates that time(), mktime(), etc., return seconds since Jan 1, 1970, so you should be OK. I mention the above for completeness.
The "time" function returns the number of seconds since Jan 1 1970 UTC. You do not need to call any other functions. The time_t type is just an integer type, it's probably equivalent to int.
Dietrich is correct, however if you wished to add the number of seconds since the Epoch in a formatted string with other date info, you should consider using strftime().