Using standard mktime() function from time.h library
tm Tm;
Tm.tm_year = 46;
Tm.tm_mon = 3-1; // since month start with zero
Tm.tm_mday = 23;
Tm.tm_hour = 9;
Tm.tm_min = 3;
Tm.tm_sec = 38;
uint32_t epoch = mktime(&Tm);
epoch is 1458651818
going to: http://www.epochconverter.com and entering 1458651818
outputs:
Tue 22 Mar 2016 09:03:38 AM EDT GMT-4:00 DST
I am setting day Tm.tm_day = 23;, not 22, why is my epoch converting to 23rd? What is the recommended way to fix it?
I'm not sure what answer you were expecting.
I assume your Tm type is actually a struct tm.
When you set
Tm.tm_year = 46;
you are asking for the year 1946.
When you set
Tm.tm_mon = 3;
you are asking for April. (tm_mon is 0-based.)
I assume you meant
Tm.tm_mday = 23;
(There is no tm_day member in struct tm.)
As Joachim Pileborg mentioned, for best results when calling mktime you should also set
Tm.tm_isdst = -1;
Finally, most systems measure time since 1970. So 1946 is a negative time. So when you assign mktime's return value to an unsigned epoch variable, you're not going to get the right answer.
When I modify your code to assign mktime's return value to a time_t variable, and print it, like this:
time_t epoch = mktime(&Tm);
printf("%ld\n", (long)epoch);
I get -747654982, which is what I'd expect. (I'm on U.S. Eastern time; if you're in a different time zone you'll get a slightly different value.)
If you want to compute a time_t ("epoch") value for today's date, in 2016, use
Tm.tm_year = 2016 - 1900;
(which will give it the value 116).
One more question: Are you sure when you ran this code it computed epoch as 1458651818? 1458651818 corresponds to yesterday! It has nothing to do with the year 1946, and it's not the answer I'd expect based on your uint32_t mistake, either.
(By the way, what system are you using? Not all systems necessarily use a base year of 1970.)
The C language does not specify the epoch year and leaves it up to library implementation. I was assuming the EPOCH is 1970, but the particular library I was using sets their epoch to 1900. This resolved the issue.
Related
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));
}
In my embedded Linux application I have a "tick count" counter that increases 1 each 10 nanoseconds counting from 1st January 00:00:00 of 2014.
I want to be able to, picking the current value of the "tick count" counter, print it as the current date-time (year, month, day, hour, minute, second and millisecond) of my system already considering things such as leap year, February having 28/29 days, etc. and this using pure C methods (from time.h etc.).
But I don't know how to do it... For now I have the equivalent value in seconds, so I know how many seconds since the start date-time have passed, but not how to go from that to the current date-time value with everything adjusted, only in Qt which is not available (and the internet wasn't much of a help in this case till what could I understood of the explanations in cplusplus.com and etc.)
Any help appreciated.
Use gmtime().
Simply divide the tick count to get the whole number of seconds and add an offset to change the epoch from Jan 1, 2014 to Jan 1, 1970.
void print_time(unsigned long long tick_count) {
static const unsigned long ticks_per_sec = 100000000L;
static const time_t epoch_delta = 16071L*24*60*60;
time_t seconds = tick_count/ticks_per_sec + epoch_delta;
unsigned long fraction = tick_count%ticks_per_sec;
struct tm tm = *gmtime(&seconds);
printf("%4d-%02d-%02d %02d:%02d:%02d.%03lu\n",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
fraction/10000);
}
[After Accept Edit]
OP comments "I tried to use the methods from time.h and I was unsuccessful as well as that it considers the count of time since 1970, which is not my situation"
Another approach is to use mktime(). This is less dependent on issues brought up by #DavidEisenstat. It relies on the tm_sec field being an int of sufficient width (like 32 bits) to cover years 2014 to 2082. mktime() takes out-of-range fields and adjusts them to the expected ranges. Should tm_sec be 16-bit, some simple adjustments could be had to tm_mday, tm_hour, tm_min, tm_sec instead.
void print_time2(unsigned long long tick_count) {
static const unsigned long ticks_per_sec = 100000000L;
unsigned long fraction = tick_count%ticks_per_sec;
unsigned long long secondsFromJan12014 = tick_count/ticks_per_sec;
struct tm tm = {0};
tm.tm_year = 2014 - 1900;
tm.tm_mday = 1;
tm.tm_sec = secondsFromJan12014;
if (mktime(&tm) == (time_t)(-1)) Handle_Failure();
printf("%4d-%02d-%02d %02d:%02d:%02d.%03lu\n",
tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
fraction/10000);
}
First, converting nanoseconds to seconds are trivial.
Second, adding the right number of seconds since the right epoch 1970-01-01 you will have to know how many seconds there were from the epoch UTC 2014-01-01 00:00:00. The date command at the Linux prompt will tell you this:
date -u -d "2014-01-01 00:00" +%s
1388534400
So you will simply have to do something like:
time_t current = 1388534400+my_10_nano_time_function()/100000000;
Once you have your correct time_t value you can use all functions like localtime, gmtime and strftime.
However, as time_t is in seconds you will have to calculates the milliseconds yourself,
something like:
(my_10_nano_time_function()%/100000000)/100000
I have a variable which represents a date in number of days since Jan 1 1990. Does anybody know how I can do that? I'm working with MCS 8051, so I can't use any scripts, standard library functions or memory allocation (malloc or calloc). Also this is not a homework. Any help will be appreciated.
I'll give you a tip:
$ date --date 'jan 1 1990' +%s
631148400
This is the 'epoch date' of Jan 1 1990; expressed in seconds since the Unix epoch. Note this only valid for POSIX systems.
Now, that you made it clear that there are no standard library functions available, you'd probably want to use pre-calculated epoch time as a start and add days * 86400 to it.
Sadly, I guess that you will not have integer types large enough to handle that arithmetic. Since:
log(633826800, 2) = approx. 29.23951342
You'd need at least 32-bit type to hold the value of the Unix epoch itself.
For example, if you had a 32-bit uint32_t type, you could:
uint32_t days_to_epoch_date(int days)
{
uint32_t ret = 631148400L; /* value for Jan 1 1990 */
ret += 86400 * days;
return ret;
}
If you need to use a different epoch or scale, the values will be different but the method will remain the same. Well, as long as the time measure is linear.
The following example is no longer correct with the new information but I'm leaving it in case anyone being able to use the standard library could find it.
For the code to be portable, you'd first want to assemble the epoch date in a struct tm:
#include <time.h>
time_t epoch_time_to_time_t(unsigned int days_since_epoch)
{
struct tm t = {0};
t.tm_mday = 1;
t.tm_mon = 0; /* Jan */
t.tm_year = 90; /* since 1900 */
t.tm_isdst = -1;
/* ... */
}
Then, as permitted by *7.23.2.3 The mktime function:
2 […] 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.
…add the number of days to the struct tm, and use mktime() to obtain the final time_t:
time_t epoch_time_to_time_t(unsigned int days_since_epoch)
{
/* ... */
t.tm_mday += days_since_epoch;
return mktime(&t);
}
There is a book that collects a huge amount of date and time calculation details and algorithms, that is almost certainly worth checking out. It is supported by source code in standard C (probably C89, certainly not newer).
Standard C Date/Time Library: Programming the World's Calendars and Clocks by Lance Latham, CMP, 1998, ISBN 978-0879304966.
If you needed to start from scratch with date arithmetic, this would be a great resource if only because calenders are full of special cases that are easy to miss.
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().