year not displaying on linux - c

Hope someone can help. I am fixing a problem in someone’s’ C code that was written a long time ago and he has since moved on.
The piece of code outputs the timestamp of a particular file. The code works fine when run on windows but when it is run on Linux it displays the Year incorrectly. The year is not displaying on linux, it shows 35222. Does anyone have any idea what is the problem here?
Thanks
Windows output:
Source file: test.dtl, Created: Mon, 27 May, 2013 at 16:13:20
Linux output:
Source file: test.dtl, Created: Mon, 27 May, 35222 at 16:13:20
The function in C code:
void SummaryReport ( report_t *report, char *dtlName)
{
LogEntry(L"SummaryReport entry\n");
int i;
wchar_t *rootStrType,*localStr,timeStr[48];
wchar_t fileBuff[64];
struct tm *timeVals;
timeVals = localtime (&logHdr.date);
wcsftime (timeStr,47,L"%a, %#d %b, %Y at %X",timeVals);
/* Print the header information */
DisplayReportFile (report);
ReportEntry (report,L" Filesystem Audit Summary Report\n\n");
ReportEntry (report,L"Source file: %s, Created: %ls\n\n",dtlName,timeStr);
ReportEntry (report,L"Server: %ls",srvrName);
…
}

Verified on a minimal example and it "works-for-me". Does this show the right time?
#include <wchar.h>
#include <time.h>
int main() {
wchar_t timeStr[48];
struct tm *timeVals;
time_t now = time(NULL);
timeVals = localtime(&now);
wcsftime(timeStr, 47, L"%a, %#d %b, %Y at %X", timeVals);
wprintf(timeStr);
return 0;
}
If yes, check the file itself - if you're sharing the filesystem, maybe there's some weird issue with the file timestamp itself? (or with understanding the fs metadata)

In case wcsftime() itself calls localtime(), insure the results of your call are not corrupted.
struct tm timeVals;
timeVals = *localtime (&logHdr.date);
wcsftime (timeStr,47,L"%a, %#d %b, %Y at %X", &timeVals);
localtime() saves its results in a static struct tm somewhere. The address (pointer) to that location is returned. Subsequent calls to localtime() or gmtime() alter the struct tm. I suspect the call to wcsftime() indirectly does that in Linux.
BTW: localtime() could return NULL, so safer code would check the localtime() return value.
Your may want to look into the localtime_s()

Related

localtime() and gmtime() giving exactly the same output

ADDENDUM:
I followed the suggestion provided and replaced calls to gmtime and localtime with calls to gmtime_r and localtime_r and everything worked as expected. The updated source code is as follows:
int main()
{
time_t tmi;
time(&tmi);
struct tm utcTime, localTime;
gmtime_r(&tmi, &utcTime);
localtime_r(&tmi, &localTime);
displayStructTm(&utcTime, "UTC");
displayStructTm(&localTime, "Local Time");
return (0);
}
Original Post:
I am making calls to gmtime() and localtime(), passing the same time_t value to both. However, I am getting the same result.
Here is my source code:
#include <stdio.h>
#include <time.h>
void displayStructTm(const struct tm* tmPtr, const char*label) {
printf("\n%s\n", label);
printf("tm_sec: %d\n", tmPtr->tm_sec);
printf("tm_hour: %d\n", tmPtr->tm_hour);
printf("tm_min: %d\n", tmPtr->tm_min);
printf("tm_mday: %d\n", tmPtr->tm_mday);
printf("tm_mon: %d\n", tmPtr->tm_mon);
printf("tm_year: %d\n", tmPtr->tm_year);
printf("tm_wday: %d\n", tmPtr->tm_wday);
printf("tm_yday: %d\n", tmPtr->tm_yday);
printf("tm_isdst: %d\n", tmPtr->tm_isdst);
}
int main()
{
time_t tmi;
time(&tmi);
struct tm* utcTime = gmtime(&tmi);
struct tm* localTime = localtime(&tmi);
displayStructTm(utcTime, "UTC");
displayStructTm(localTime, "Local Time");
return (0);
}
The output is as follows. As can be seen, we get the same output in both cases.
UTC
tm_sec: 27
tm_hour: 3
tm_min: 21
tm_mday: 6
tm_mon: 4
tm_year: 122
tm_wday: 5
tm_yday: 125
tm_isdst: 0
Local Time
tm_sec: 27
tm_hour: 3
tm_min: 21
tm_mday: 6
tm_mon: 4
tm_year: 122
tm_wday: 5
tm_yday: 125
tm_isdst: 0
The return value points to a statically-allocated struct which might be overwritten by subsequent calls to any of the date and time functions. The localtime_r() function does the same, but stores the data in a user-supplied struct.
— man localtime
Since you call gmtime, then call localtime, before printing either, you're getting two pointers to the same struct, which only contains the second result. Either print each result immediately after the call, or use localtime_r and gmtime_r with pointers to struct tms that you have allocated yourself.
Two possibilities.
The local time zone of your system currently has an offset of 0.
utcTime and localTime are sharing the same memory.
localtime and gmtime return a pointer to the same struct every time. They may share the same memory. So utcTime and localTime might be the same.
You can check with printf("gm: %p local: %p", utcTime, localTime).
Use localtime_r and gmtime_r to avoid this.

Difference between mktime and timelocal

What is the difference between these two functions? It was my understanding that those should be the same: http://www.gnu.org/software/libc/manual/html_node/Broken_002ddown-Time.html.
I wrote this code to test the conversion (the Qt part is only for comparison):
#include <QCoreApplication>
#include <QDateTime>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QDateTime datetime(QDate(2012, 3, 25), QTime(5, 15));
qDebug("Timestamp: %lld.", datetime.toMSecsSinceEpoch()/1000L);
time_t timestamp;
tm* timeinfo = localtime(&timestamp);
timeinfo->tm_hour = 5;
timeinfo->tm_mday = 25;
timeinfo->tm_min = 15;
timeinfo->tm_mon = 2;
timeinfo->tm_year = 112;
timeinfo->tm_sec = 0;
qDebug("Timestamp: %ld.", timelocal(timeinfo));
return 0;
}
and found out that the output is:
Timestamp: 1332645300.
Timestamp: 1332645300.
which is what I'd expect. Then I replaced timelocal with mktime and found out that this was the output:
Timestamp: 1332645300.
Timestamp: 1332648900.
It seems like an hour was added (consider that my current timezone is GMT+2:00 and my locale is set to Italy). Why? What is the difference between the two and why mktime adds 1 hour to the date I set?
EDIT: I tested again and it seems that on Mac OS X (and iOS) timelocal is returning the same hour placed in the timeinfo structure, while mktime is actually adding an hour both in the returned time_t value and in the structure tm.
On Linux Kubuntu instead, with both functions I get that an hour is added to both the tm structure and the returned value.
Anyone who can explain why?
The man of OpenBSD's timelocal states:
timelocal is a deprecated interface that is equivalent to calling
mktime() with a negative value for tm_isdst
A negative value for tm_isdst means that timelocal doesn't take daylight saving time (DST) into account. It seems that QDateTime has troubles with DST as well.
mktime on the other hand, handles DST and this might explain the 1-hour difference on OS X.
Since timelocal is deprecated, it might have newer imlementations that deal with DST properly.

UTC to Time of the day in ANSI C?

how to convert the utc time to local time of the day?
You must use a mix of tzset() with time/gmtime/localtime/mktime functions.
Try this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
time_t makelocal(struct tm *tm, char *zone)
{
time_t ret;
char *tz;
tz = getenv("TZ");
setenv("TZ", zone, 1);
tzset();
ret = mktime(tm);
if(tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return ret;
}
int main(void)
{
time_t gmt_time;
time_t local_time;
struct tm *gmt_tm;
gmt_time = time(NULL);
gmt_tm = gmtime(&gmt_time);
local_time = makelocal(gmt_tm, "CET");
printf("gmt: %s", ctime(&gmt_time));
printf("cet: %s", ctime(&local_time));
return 0;
}
Basically, this program takes the current computer day as GMT (time(NULL)), and convert it to CET:
$ ./tolocal
gmt: Tue Feb 16 09:37:30 2010
cet: Tue Feb 16 08:37:30 2010
M. MARIE's answer does not in fact work for the question as posed: tzset() is POSIX, but not ANSI C as the title of the original question asked. There is no mention of it in either C90 or C99 (from searching the draft standards; I have no access to the final standards).
OP's question is perhaps a little vague as it is not clear what he means by "utc time", but presumably he means broken-down components, let's say filled into a struct tm.
It is possible in C99 to determine local TZ's offset from UTC by parsing the output of strftime("%z",...) (make sure that you call it with your own date values, as this offset will change over time); but this format-code is not available in C90, so AFAIK you're out of luck if you must conform to C90, unless you want to try to parse the output of strftime("%Z",...), but that's going to be fundamentally non-portable.
You then could convert your UTC components to time_t using mktime(), although they will be interpreted as in the local timezone; then apply the offset, and convert back to broken-down components using localtime(). You may run into edge cases around the time when your local timezone switches to and from DST (or when changes to your timezone's offset where effected), but this can be easily avoided by moving to a locale that does not use DST, or ameliorated by setting tm_dst to 0 when calling both strftime() and mktime().
Alternatively, don't restrict yourself to ANSI C.

How to get the date and time values in a C program?

I have something like this:
char *current_day, *current_time;
system("date +%F");
system("date +%T");
It prints the current day and time in the stdout, but I want to get this output or assign them to the current_day and current_time variables, so that I can do some processing with those values later on.
current_day ==> current day
current_time ==> current time
The only solution that I can think of now is to direct the output to some file, and then read the file and then assign the values of date and time to current_day and current_time. But I think this is not a good way. Is there any other short and elegant way?
Use time() and localtime() to get the time:
#include <stdio.h>
#include <time.h>
int main()
{
time_t t = time(NULL);
struct tm tm = *localtime(&t);
printf("now: %d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
}
strftime (C89)
Martin mentioned it, here's an example:
main.c
#include <assert.h>
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = time(NULL);
struct tm *tm = localtime(&t);
char s[64];
size_t ret = strftime(s, sizeof(s), "%c", tm);
assert(ret);
printf("%s\n", s);
return 0;
}
GitHub upstream.
Compile and run:
gcc -std=c89 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Sample output:
Thu Apr 14 22:39:03 2016
The %c specifier produces the same format as ctime.
One advantage of this function is that it returns the number of bytes written, allowing for better error control in case the generated string is too long:
RETURN VALUE
Provided that the result string, including the terminating null byte, does not exceed max bytes, strftime() returns the number of bytes (excluding the terminating null byte) placed in the array s. If the length of the result string (including the terminating null byte) would exceed max bytes, then strftime() returns 0, and the contents of the array are undefined.
Note that the return value 0 does not necessarily indicate an error. For example, in many locales %p yields an empty string. An empty format string will likewise yield an empty string.
asctime and ctime (C89, deprecated in POSIX 7)
asctime is a convenient way to format a struct tm:
main.c
#include <stdio.h>
#include <time.h>
int main(void) {
time_t t = time(NULL);
struct tm *tm = localtime(&t);
printf("%s", asctime(tm));
return 0;
}
Sample output:
Wed Jun 10 16:10:32 2015
And there is also ctime() which the standard says is a shortcut for:
asctime(localtime())
As mentioned by Jonathan Leffler, the format has the shortcoming of not having timezone information.
POSIX 7 marked those functions as "obsolescent" so they could be removed in future versions:
The standard developers decided to mark the asctime() and asctime_r() functions obsolescent even though asctime() is in the ISO C standard due to the possibility of buffer overflow. The ISO C standard also provides the strftime() function which can be used to avoid these problems.
C++ version of this question: How to get current time and date in C++?
Tested in Ubuntu 16.04.
time_t rawtime;
time ( &rawtime );
struct tm *timeinfo = localtime ( &rawtime );
You can also use strftime to format the time into a string.
To expand on the answer by Ori Osherov
You can use the WinAPI to get the date and time, this method is specific to Windows, but if you are targeting Windows only, or are already using the WinAPI then this is definitly a possibility1:
You can get both the time and date by using the SYSTEMTIME struct. You also need to call one of two functions (either GetLocalTime() or GetSystemTime()) to fill out the struct.
GetLocalTime() will give you the time and date specific to your time zone.
GetSystemTime() will give you the time and date in UTC.
The SYSTEMTIME struct has the following members:
wYear, wMonth, wDayOfWeek, wDay, wHour, wMinute, wSecond and wMilliseconds
You then need to just access the struct in the regular way
Actual example code:
#include <windows.h> // use to define SYSTEMTIME , GetLocalTime() and GetSystemTime()
#include <stdio.h> // For printf() (could otherwise use WinAPI equivalent)
int main(void) { // Or any other WinAPI entry point (e.g. WinMain/wmain)
SYSTEMTIME t; // Declare SYSTEMTIME struct
GetLocalTime(&t); // Fill out the struct so that it can be used
// Use GetSystemTime(&t) to get UTC time
printf("Year: %d, Month: %d, Day: %d, Hour: %d, Minute:%d, Second: %d, Millisecond: %d", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond, t.wMilliseconds); // Return year, month, day, hour, minute, second and millisecond in that order
return 0;
}
(Coded for simplicity and clarity, see the original answer for a better formatted method)
The output will be something like this:
Year: 2018, Month: 11, Day: 24, Hour: 12, Minute:28, Second: 1, Millisecond: 572
Useful References:
All the WinAPI documentation (most already listed above):
GetLocalTime()
GetSystemTime()
SYSTEMTIME
Time Functions
An extremely good beginners tutorial on this subject by ZetCode:
https://zetcode.com/gui/winapi/datetime/
Simple operations with datetime on Codeproject:
https://www.codeproject.com/Articles/5546/WinAPI-Simple-Operations-with-datetime
1: As mentioned in the comments in Ori Osherov's answer ("Given that OP started with date +%F, they're almost certainly not using Windows. – melpomene Sep 9 at 22:17") the OP is not using Windows, however since this question has no platform specific tag (nor does it mention anywhere that the answer should be for that particular system), and is one of the top results when Googling "get time in c" both answers belong here, some users searching for an answer to this question may be on Windows and therefore will be useful to them.
Timespec has day of year built in.
http://pubs.opengroup.org/onlinepubs/7908799/xsh/time.h.html
#include <time.h>
int get_day_of_year(){
time_t t = time(NULL);
struct tm tm = *localtime(&t);
return tm.tm_yday;
}`
The answers given above are good CRT answers, but if you want you can also use the Win32 solution to this. It's almost identical but IMO if you're programming for Windows you might as well just use its API (although I don't know if you are programming in Windows).
char* arrDayNames[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
SYSTEMTIME st;
GetLocalTime(&st); // Alternatively use GetSystemTime for the UTC version of the time
printf("The current date and time are: %d/%d/%d %d:%d:%d:%d", st.wDay, st.wMonth, st.wYear, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
printf("The day is: %s", arrDayNames[st.wDayOfWeek]);
Anyway, this is a Windows solution. I hope it will be helpful for you sometime!
I was using command line C-compiler to compile these and it completely drove me bonkers as it refused to compile.
For some reason my compiler hated that I was declaring and using the function all in one line.
struct tm tm = *localtime(&t);
test.c
test.c(494) : error C2143: syntax error : missing ';' before 'type'
Compiler Status: 512
First declare your variable and then call the function. This is how I did it.
char todayDateStr[100];
time_t rawtime;
struct tm *timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
strftime(todayDateStr, strlen("DD-MMM-YYYY HH:MM")+1,"%d-%b-%Y %H:%M",timeinfo);
printf("todayDateStr = %s ... \n", todayDateStr );
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct date
{
int month;
int day;
int year;
};
int calcN(struct date d)
{
int N;
int f(struct date d);
int g(int m);
N = 1461 * f(d) / 4 + 153 * g(d.month) / 5 + d.day;
if(d.year < 1700 || (d.year == 1700 && d.month < 3))
{
printf("Date must be after February 29th, 1700\n");
return 0;
}
else if(d.year < 1800 || (d.year == 1800 && d.month < 3))
N += 2;
else if(d.year < 1900 || (d.year == 1900 && d.month < 3))
N += 1;
return N;
}
int f(struct date d)
{
if(d.month <= 2)
d.year -= 1;
return d.year;
}
int g(int m)
{
if(m <=2)
m += 13;
else
m += 1;
return m;
}
int main(void)
{
int calcN(struct date d);
struct date d1, d2;
int N1, N2;
time_t t;
time(&t);
struct tm *now = localtime(&t);
d1.month = now->tm_mon + 1;
d1.day = now->tm_mday;
d1.year = now->tm_year + 1900;
printf("Today's date: %02i/%02i/%i\n", d1.month, d1.day, d1.year);
N1 = calcN(d1);
printf("Enter birthday (mm dd yyyy): ");
scanf("%i%i%i", &d2.month, &d2.day, &d2.year);
N2 = calcN(d2);
if(N2 == 0)
return 0;
printf("Number of days since birthday: %i\n", N1 - N2);
return 0;
}
#include <stdio.h>
int main() {
char *pts; /* pointer to time string */
time_t now; /* current time */
char *ctime();
(void) time(&now);
printf("%s", ctime(&now));
return(0);
}
Sample output:
Sat May 14 19:24:54 2022
This is the easiest way. I haven't even used time.h.
Be advised: The output produced has a newline at the end.
instead of files use pipes and if u wana use C and not C++ u can use popen like this
#include<stdlib.h>
#include<stdio.h>
FILE *fp= popen("date +F","r");
and use *fp as a normal file pointer with fgets and all
if u wana use c++ strings, fork a child, invoke the command and then pipe it to the parent.
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
string currentday;
int dependPipe[2];
pipe(dependPipe);// make the pipe
if(fork()){//parent
dup2(dependPipe[0],0);//convert parent's std input to pipe's output
close(dependPipe[1]);
getline(cin,currentday);
} else {//child
dup2(dependPipe[1],1);//convert child's std output to pipe's input
close(dependPipe[0]);
system("date +%F");
}
// make a similar 1 for date +T but really i recommend u stick with stuff in time.h GL
#include<stdio.h>
using namespace std;
int main()
{
printf("%s",__DATE__);
printf("%s",__TIME__);
return 0;
}

Converting between timezones in C

I need to convert time between timezones in C (on linux, so anything specific would do too).
I know my current time, local and UTC, I have the offset of the target time. I am trying to use mktime, gmtime, localtime and similar set of functions but still can't figure it out.
Thanks in advance.
As comments do not allow posting the code, posting as a separate answer.. If you know "local" time and "UTC" time, you can calculate the offset of the "other" time from your "local" time. Then you convert the struct tm into calendar time, add the desired number of seconds (being the offset of the target time), and convert it back to struct tm:
(edited to account for another scenario to use mktime's normalization)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
int main(int argc, char *argv) {
struct timeval tv_utc;
struct tm *local_tm, *other_tm;
/* 'synthetic' time_t to convert to struct tm for the other time */
time_t other_t_synt;
/* Other time is 1 hour ahead of local time */
int other_local_delta = 1*3600;
/* the below two lines are just to set local_tm to something */
gettimeofday(&tv_utc, NULL);
local_tm = localtime(&tv_utc.tv_sec);
printf("Local time: %s", asctime(local_tm));
#ifdef DO_NOT_WRITE_TO_LOCAL_TM
other_t_synt = mktime(local_tm) + other_local_delta;
#else
local_tm->tm_sec += other_local_delta;
/* mktime will normalize the seconds to a correct calendar date */
other_t_synt = mktime(local_tm);
#endif
other_tm = localtime(&other_t_synt);
printf("Other time: %s", asctime(other_tm));
exit(0);
}
You can use gmtime() and the tm structure to directly set this, provided you know the offsets.
If you know your local time and UTC, you know your local offset. Provided you also know the target offset, it's just a matter of setting tm_hour appropriate (and potentially flipping the day, too, if you go <0 or >23).
For some sample code, see this gmtime reference page. It shows offsetting based off time zone offsets.
Edit:
In response to the comments - you can also let mktime handle the shifting for you, which allows you to simplify this by converting back to a time_t. You can use something like:
time_t currentTime;
tm * ptm;
time ( &currentTime );
ptm = gmtime ( &rawtime );
ptm->tm_hour += hours_to_shift;
ptm->tm_minutes += minutes_to_shift; // Handle .5 hr timezones this way
time_t shiftedTime = mktime( ptm );
// If you want to go back to a tm structure:
tm * pShiftedTm = gmtime( &shiftedTime );
In all likelyhood, your operating system provides some support for this.
In unix derived OSs you might want to look at the man pages for asctime, asctime_r, ctime, ctime_r, difftime, gmtime, gmtime_r, localtime, localtime_r, mktime, timegm.

Resources