I compile C using the C99 version, and I want to try and output the timezone of the given time.
The IDE I use gives GMT+0 as the timezone, but I want to somehow output it with struct tm.
So I followed the instructions from this answer and made this program:
#include <stdio.h>
#include <time.h>
int main()
{
time_t present = time(NULL);
struct tm now = *localtime(&present);
now.tm_mon += 1;
now.tm_year += 1900;
struct tm t = {0};
localtime_r(&present, &t);
printf("%i/%i/%i %i:%i:%i from %s\n", now.tm_mon, now.tm_mday, now.tm_year, now.tm_hour, now.tm_min, now.tm_sec, t.tm_zone);
}
And it seems like I got 2 errors here:
implicit declaration of function 'localtime_r' is invalid in C99
no member named 'tm_zone' in 'struct tm'
So I checked the IDE Manual, and find that localtime_r actually exists, and is part of the <time.h> library.
So now I'm wondering if the IDE's confused or something. I don't know how to fix it either.
This might get closed as it might "need debugging details", but read more.
Because of this whole situation, how can I get the timezone (maybe even the offset) in C99 and get it to be outputted with printf()?
First, localtime_r is not part of the standard library - it's an extension offered by some implementations, and by default its declaration is not exposed in those implementations. To make it available, you'll have to define the macro _POSIX_SOURCE before including time.h to make it available. An easy way to do that is on the command line, like so:
gcc -o tz -D_POSIX_SOURCE -std=c11 -pedantic -Wall -Werror tz.c
otherwise, just define it in your source before including time.h:
#define _POSIX_SOURCE
#include <stdio.h>
#include <time.h>
Secondly, if all you're interested in is the local time zone then there's an easier way to do this - get the current time:
time_t t = time( NULL );
then use both localtime and gmtime to get the broken down time for the current time zone and UTC:
struct tm *local = localtime( &t );
struct tm *zulu = gmtime( &t );
Then compute the difference between the tm_hour members of local and zulu, and that's your time zone.
int tz = zulu->tm_hour - local->tm_hour;
You'll want to check local->tm_isdst to account for daylight savings, but that should at least get you started.
Related
For a computer security assignment, I have to modify the time function in order to return a specific date. I need the time function to return a date between Jan 1st, 2016 and June 15th, 2018. I then use these commands to overload and hook into the time function:
gcc -Wall -fPIC -shared -o newtime.so newtime.c -ldl
export LD_PRELOAD=$PWD/newtime.so
Here is my modified version of the time function:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <time.h>
time_t time (time_t *t)
{
long int seconds = 1485907200;
time_t modifiedTime = (time_t) seconds;
return modifiedTime;
}
Whenever I run this implementation, it says that the date being returned is December 31, 1969 19:00:00. Am I just formatting the time since the Linux Epoch incorrectly or am I making a more serious mistake? I have tried using a regular int instead of a long int, and still experience the same issues. Some insight into my mistake would be very helpful.
You're not implementing the entire functionality of time(). The code your interposing on may use functionality that you have not implemented.
Per the C standard:
7.27.2.4 The time function (note the bolded part):
Synopsis
#include <time.h>
time_t time(time_t *timer);
Description
The time function determines the current calendar time. The encoding
of the value is unspecified.
Returns
The time function returns the implementation's best approximation to
the current calendar time. The value (time_t)(-1) is returned if the
calendar time is not available. If timer is not a null pointer, the
return value is also assigned to the object it points to.
A full implementation, based on your code:
time_t time (time_t *t)
{
long int seconds = 1485907200;
time_t modifiedTime = (time_t) seconds;
if ( t )
{
*t = modifiedTime;
}
return modifiedTime;
}
In fact, there is no problem in the code that you presented. I tested it with the following basic program:
#include <stdio.h>
#include <time.h>
int main(void)
{
printf("%ld\n", (long) time(NULL));
}
So I just run LD_PRELOAD=./newtime.so ./test and I get the expected result.
However, the date command doesn't make call to the time function. It calls instead int clock_gettime(clockid_t clk_id, struct timespec *tp). So you should better re-implement them both if you would like to cover this case.
May be a simple implementation like the following one (It works fine with date):
int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
if(tp) {
tp->tv_sec = 1485907200;
tp->tv_nsec = 0;
}
return 0;
}
If you get a date different from your expectation, it could be related to your time zone.
Incomprehensible behavior of the function strptime():
#define _XOPEN_SOURCE
#include <stdio.h>
#include <time.h>
double getPeriod(char * dateStart, char * dateStop) {
struct tm tmStart, tmStop;
time_t timeStampStart, timeStampStop;
strptime(dateStart, "%Y-%m-%d %H:%M:%S", &tmStart);
strptime(dateStop, "%Y-%m-%d %H:%M:%S", &tmStop);
timeStampStart = mktime(&tmStart);
timeStampStop = mktime(&tmStop);
printf("%d\t%d\n", tmStart.tm_hour, tmStop.tm_hour);
}
int main()
{
getPeriod("2016-12-05 18:14:35", "2016-12-05 18:18:34");
return 0;
}
Output:
17 18
Why does this happen?
Compiler gcc (GCC) 6.2.1
OS Linux
tmStart and tmStop are not initialized, so some fields will be uninitialized when passed to mktime. Thus, the behavior is technically undefined.
From the strptime man page (note the first two sentences):
In principle, this function does not initialize tm but only stores the values specified. This means that tm should be initialized before the call. Details differ a bit between different UNIX systems. The glibc implementation does not touch those fields which are not explicitly specified, except that it recomputes the tm_wday and tm_yday field if any of the year, month, or day elements changed.
Working on an Ubuntu 12.04.3 LTS box, I just noticed that localtime() and localtime_r() behave differently when the system's timezone changes during the lifetime of a process: localtime() picks up the timezone change immediately, whereas localtime_r() does not, it seems to stick to what was the timezone at the launch of the process. Is this expected behavior? I haven't seen this covered anywhere.
More precisely, when I use the following code ...
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
int main() {
while (1) {
time_t t = time(NULL);
struct tm *tm = localtime(&t);
printf("localtime:%02d/%02d/%02d-%02d:%02d:%02d\n",
tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sleep(1);
}
return 0;
}
... and change the timezone from UTC via ...
# echo 'Europe/Berlin' > /etc/timezone
# sudo dpkg-reconfigure --frontend noninteractive tzdata
... then the code produces the following, ...
localtime:10/04/2013-01:11:33
localtime:10/04/2013-01:11:34
localtime:10/04/2013-01:11:35
localtime:10/03/2013-23:11:36
localtime:10/03/2013-23:11:37
localtime:10/03/2013-23:11:38
... but if I use:
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
int main() {
while (1) {
time_t t = time(NULL);
struct tm local_tm;
struct tm *tm = localtime_r(&t, &local_tm);
printf("localtime_r:%02d/%02d/%02d-%02d:%02d:%02d\n",
tm->tm_mon + 1, tm->tm_mday, tm->tm_year + 1900,
tm->tm_hour, tm->tm_min, tm->tm_sec);
sleep(1);
}
return 0;
}
... then there's no change when doing a similar timezone change:
localtime_r:10/04/2013-01:15:37
localtime_r:10/04/2013-01:15:38
localtime_r:10/04/2013-01:15:39
localtime_r:10/04/2013-01:15:40
localtime_r:10/04/2013-01:15:41
localtime_r:10/04/2013-01:15:42
UPDATE: adding a call to tzset() before invoking localtime_r() produces the expected behavior. Whether that's clear from the spec/manpage or not (see discussion below) is a question for mentalhealth.stackexchange.com...
See this following documentation:
The localtime() function converts the calendar time timep to
broken-down time representation, expressed relative to the user's
specified timezone. The function acts as if it called tzset(3) and
sets the external variables tzname with information about the current
timezone, timezone with the difference between Coordinated Universal
Time (UTC) and local standard time in seconds, and daylight to a
nonzero value if daylight savings time rules apply during some part of
the year. 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. It need not set tzname, timezone,
and daylight.
From: http://linux.die.net/man/3/localtime_r
So as far as I can tell, it appears that the code is working as I'd expect.
Edited to add more from the same documentation:
According to POSIX.1-2004, localtime() is required to behave as though
tzset(3) was called, while localtime_r() does not have this
requirement. For portable code tzset(3) should be called before
localtime_r().
We are using /usr/xpg4/bin as default path in our profile.
We are printing the output of variable "curr_date" here:
lt = time(NULL);
ltime=localtime(localtime(<));
strftime(curr_date,sizeof(curr_date),"%m/%d/%y%C",ltime);
We get the output as "06/27/13Thu Jun 27 02:39:34 PDT" instead of "06/27/1320".
Do you know what should be the format specifiers that should work here?
Thanks
The use of /usr/xpg4/bin in your $PATH only selects the standard compliant commands, it does not change function calls in your programs to use the standards compliant versions.
As described in the Solaris standards(5) man page there are various #defines and compiler flags you need to use to specify compliance for various standards.
For instance, taking your code snippet and expanding it to this standalone test program:
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
int main(int argc, char **argv)
{
time_t lt;
struct tm *ltime;
char curr_date[80];
lt = time(NULL);
ltime = localtime(<);
strftime(curr_date, sizeof(curr_date), "%m/%d/%y%C", ltime);
printf("%s\n", curr_date);
return 0;
}
Then compiling with the different flags shows the different behavior:
% cc -o /tmp/strftime /tmp/strftime.c
% /tmp/strftime
06/30/13Sun Jun 30 20:28:00 PDT 2013
% cc -xc99 -D_XOPEN_SOURCE=600 -o /tmp/strftime /tmp/strftime.c
% /tmp/strftime
06/30/1320
The default mode is backwards compatible with the traditional Solaris code, the second form requests compliance with the C99 and XPG6 (Unix03) standards.
Have a good look at the code between call to strftime() and printing curr_date. You're overwriting curr_data somewhere, because the start of what you print is correct. Might also be something fishy with memory management of curr_data; how is it defined, did you allocate memory for curr_data?
Set a breakpoint right after strftime() and you'll see it holds the expected/correct string.
I am getting some warnings when compiling a C program on OSX 10.6.5, which seem to be quite critical.
extras.c:15: warning: implicit declaration of function ‘time’
extras.c: In function ‘outlog’:
extras.c:363: warning: implicit declaration of function ‘ctime’
The corresponding lines are as follows:
Lines 13-15:
RANDNUMGEN = gsl_rng_alloc(gsl_rng_taus);
long t1;
(void) time(&t1);
Lines 360-363:
if (LOG==NULL) { LOG=stdout;}
TVAL = time(NULL);
char* TIMESTRING = ctime(&TVAL);
I believe the program was originally written for Linux, so I wonder if there is a difference between time and ctime on the two platforms?
Verify that the C files contains:
#include <time.h>
somewhere around the top.
Also,
long t1;
time(t1);
is pretty lousy code, the argument to time() has type time_t*, so that should read
time_t t1;
time(&t1);