How to get current hour (time of day) in linux kernel space - c

I'm writing a kernel module that checks to see if the time is between two specified hours, and disables input if it is. This has to do with me wanting to make sure I go to bed early. (I know I could also use any number of different techniques including cron etc, but I wanted to learn kernel programming...)
As a first version, I therefore check if the current hour is between start and end, which are set via parameters to the module.
My question is therefore : How do I get the current hour? I have no access to the usual time functions in the standard library because I am in kernel space. I'm guessing that I should be using do_gettimeofday() for this, but that only gives me seconds and nanoseconds, and I need hours in the current day.
Thanks.

time_to_tm function can be of your help, which returns the structure tm. Timezone available in variable sys_tz, it can help you to set your offset properly to get local time.

To get the local time in kernel, add the below code snippet your kernel driver:
struct timeval time;
unsigned long local_time;
do_gettimeofday(&time);
local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
rtc_time_to_tm(local_time, &tm);
printk(" # (%04d-%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);

This works well for me:
#include <linux/time.h>
...
/* getnstimeofday - Returns the time of day in a timespec */
void getnstimeofday(struct timespec *ts)
For getting usual time format you can use:
printk("TIME: %.2lu:%.2lu:%.2lu:%.6lu \r\n",
(curr_tm.tv_sec / 3600) % (24),
(curr_tm.tv_sec / 60) % (60),
curr_tm.tv_sec % 60,
curr_tm.tv_nsec / 1000);

Converting the do_gettimeofday result to an hour is pretty simple, since it starts at midnight GMT.
time_t t = time(0);
time_t SecondsOfDay = t % (24*60*60);
time_t HourGMT = SecondsOfDay / (60*60);
Then adjust for your local timezone

We can use clock_gettime function with CLOCK_REALTIME as the type of clock.
Reference http://linux.die.net/man/3/clock_gettime
Just doing a strace on date executable gives us an idea to get the current date in the kernel mode.

Related

How to format system time in C?

I'm working on an element of a program that fetches the system time in (24 hour time) hours and minutes, and formats it as HH:MM and stores it in an array. The minutes also have to be incremented by 1. This is my code:
strftime (timeh,10,"%H:",formtime);
strftime (timem,10,"%M",formtime);
timem1 = atoi(timem);
++timem1;
itoa(timem1, timem, 10);
strcpy(time, timeh);
strcat(time, timem);
I tested it by simply having it print out time, and this was the output of printf("%s", time):
5. (the time was 1:04 AM)
Individually, the hours print as nothing (at 1:08 AM), and the minutes print correctly.
What can I do to make the array time hold the properly formatted HH:MM time?
Thanks for all your suggestions
If I read you question right, you should be able to do it with:
formtime->tm_min++; /* Additional checks needed. */
strftime(time, 10, "%H:%M", formtime);
Rather than trying to adjust the minutes directly and having to worry about wrapping at the hour, you should adjust the time by 60 seconds before splitting it into a struct tm for formatting:
time_t now;
time(&now);
now += 60;
strftime(buffer, sizeof(buffer), "%H:%M", localtime(&now));
Note that calling your array time is not a good idea, as that will conflict with the standard function time used to get the current time.

Getting Duration

I'm trying to measure duration of something.
when it start I call start_time = time(NULL);
when it ends:
time_t a_time = time(NULL) - start_time;
struct tm * ts = localtime(&a_time);
char time_buff[32];
memset (time_buff,0,32);
sprintf (time_buff, "Duration: %02d:%02d:%02d", ts->tm_hour, ts->tm_min, ts->tm_sec);
The problem is that ts->tm_hour is always 2.
Please advise.
Thanks,
Nahum
The function localtime converts the time to a complete date and time. You better convert it to days, hours and minutes yourself though divisions and modulo operations.
do you eventualy live in a country where the time is 2 hours away from UTC time ?
replace your call to localtime() (which is in your current timezone) by a call to gmtime().
Why not use a function that returns the amount of milliseconds elapsed (clock or gettimeofday) and then convert to hour/min/sec?

C - gettimeofday for computing time?

do you know how to use gettimeofday for measuring computing time? I can measure one time by this code:
char buffer[30];
struct timeval tv;
time_t curtime;
gettimeofday(&tv, NULL);
curtime=tv.tv_sec;
strftime(buffer,30,"%m-%d-%Y %T.",localtime(&curtime));
printf("%s%ld\n",buffer,tv.tv_usec);
This one is made before computing, second one after. But do you know how to subtracts it?
I need result in miliseconds
To subtract timevals:
gettimeofday(&t0, 0);
/* ... */
gettimeofday(&t1, 0);
long elapsed = (t1.tv_sec-t0.tv_sec)*1000000 + t1.tv_usec-t0.tv_usec;
This is assuming you'll be working with intervals shorter than ~2000 seconds, at which point the arithmetic may overflow depending on the types used. If you need to work with longer intervals just change the last line to:
long long elapsed = (t1.tv_sec-t0.tv_sec)*1000000LL + t1.tv_usec-t0.tv_usec;
The answer offered by #Daniel Kamil Kozar is the correct answer - gettimeofday actually should not be used to measure the elapsed time. Use clock_gettime(CLOCK_MONOTONIC) instead.
Man Pages say - The time returned by gettimeofday() is affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the system time). If you need a monotonically increasing clock, see clock_gettime(2).
The Opengroup says - Applications should use the clock_gettime() function instead of the obsolescent gettimeofday() function.
Everyone seems to love gettimeofday until they run into a case where it does not work or is not there (VxWorks) ... clock_gettime is fantastically awesome and portable.
<<
If you want to measure code efficiency, or in any other way measure time intervals, the following will be easier:
#include <time.h>
int main()
{
clock_t start = clock();
//... do work here
clock_t end = clock();
double time_elapsed_in_seconds = (end - start)/(double)CLOCKS_PER_SEC;
return 0;
}
hth
No. gettimeofday should NEVER be used to measure time.
This is causing bugs all over the place. Please don't add more bugs.
Your curtime variable holds the number of seconds since the epoch. If you get one before and one after, the later one minus the earlier one is the elapsed time in seconds. You can subtract time_t values just fine.

How can I get the current time in milliseconds using C?

How might I get the current time in milliseconds in C? I am doing following to get the time in seconds:
struct tm ptm;
now = time(NULL);
localtime_r(&now,ptm);
myTime= (ptm->tm_hour * 3600) + (ptm->tm_min * 60) + (ptm->tm_sec);
Looking at time.h, struct tm does not have the millisecond member in it.
On Unix, use gettimeofday() to get the answer in microseconds and scale to milliseconds.
Or use POSIX clock_gettime() to get the answer in nanoseconds and scale to milliseconds.
I use ftime for time tracking (link text)

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