How to make hour, minute offset flags in C programming - c

I am using C on Unix. The program displays the time and I am trying to figure out how to offset the current time in minutes and hours.
This part of the code
while ( ( let = getopt(argc, argv, "alo:vh")) != -1 ) {
switch (let) {
case 'o': offset = atoi(optarg); break; }
and later in this part:
void clock(int sig, int time_expires)
{
time_t now;
struct tm *dateinfo;
(void) time(&now);
now = now + offset;
dateinfo = localtime( &now ); }
Makes an -o offset, which offsets the current time by a certain amount of seconds. For example, -o590 would offset the current time by 590 seconds.
I am trying to figure out how to do this same thing only with an -h flag that offsets the time by a certain amount of hours (like -h6 offsets the time by 6 hours) or by a -m flag which offsets the time by minutes.
I have tried dividing the current -o flag by 60 or 360 but that is not working. Can anyone point me in the right directions here?

To change time_t by so many hours, minutes, seconds in a portable fashion without relying on time_t is some integer type of seconds since 1970, use mktime()
time_t adjust(time_t t, int hour, int minute, int second) {
struct tm *dateinfo;
dateinfo = localtime(&t);
if (dateinfo == NULL) return (time_t) -1;
dateinfo->tm_hour += hour;
dateinfo->tm_min += minute;
dateinfo->tm_sec += second;
return mktime(dateinfo);
}

The time_t structure defines the number of seconds since Jan 1, 1970 UTC.
If you want to add n minutes you should do:
now+= n*60
And for n hours you should:
now+= n*3600
Alternatively you can use struct tm and access directly to the time quanta you wish to modify.
struct tm {
int tm_sec; /* seconds, range 0 to 59 */
int tm_min; /* minutes, range 0 to 59 */
int tm_hour; /* hours, range 0 to 23 */
int tm_mday; /* day of the month, range 1 to 31 */
int tm_mon; /* month, range 0 to 11 */
int tm_year; /* The number of years since 1900 */
int tm_wday; /* day of the week, range 0 to 6 */
int tm_yday; /* day in the year, range 0 to 365 */
int tm_isdst; /* daylight saving time */
};

Related

C Get Date Sometimes Wrong By 1 Day

So finally after a lot of time googling I've been able to create a function that gets current date and convert it to string then write to buffer in C. But I noticed sometimes the day is off by 1? So for example today is may 4, but it may return may 5
Here is my code
void getCurrentDateTime(char * buffer)
{
time_t t = time(NULL);
struct tm *tm = localtime(&t);
char bufForOut[64] = { 0 };
strftime(bufForOut, sizeof(bufForOut), "%c", tm);
strcpy(buffer,bufForOut);
}
I call it like
char hi[64] = { 0 }
getCurrentDateTime(hi);
print(hi);

Custom time struct to time_t

In my current project I have a C struct to hold a timestamp, which looks like this:
struct timestamp {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t second;
}
Now I want to calculate the difference between two of these timestamps in seconds. For now I'm converting my timestamp struct to the C standard struct struct tm (defined in <time.h>). Then I convert the struct to time_t with mtkime(), which takes a pointer to a struct tm and returns a time_t. And difftime() to calculate the difference between two time_t's in seconds.
I don't want to write my own difftime(), since I do not want to deal with leapyears or even worse leap seconds by myself, and I don't use the struct tm in my code because it holds a lot of values I don't frequently need (like week-day or year-day).
Here is an example, what I do at the moment:
void customTimestampToStructTM(struct customTimestamp *in, struct tm *out) {
out->tm_year = in->year;
out->tm_mon = in->mon;
out->tm_mday = in->day;
out->tm_hour = in->hour;
out->tm_min = in->min;
out->tm_sec = in->sec;
}
void someFunction() {
struct customTimestamp c1;
struct customTimestamp c2;
// Fill c1 and c2 with data here.
struct tm tmpC1;
struct tm tmpC2;
customTimestampToStructTM(&c1, &tmpC1);
customTimestampToStructTM(&c2, &tmpC2);
double diffInSeconds = difftime(mktime(tmpC1), mktime(tmpC2));
// Use diffInSeconds
}
This works, but seem incredibly inefficient. How can I speed this up? I read here that mktime doesn't use the other fields in the struct tm - except for isdst. Is there a convenient way to convert my struct to time_t, without using struct tm as a bridge and without the need to deal with leapyears/seconds?
To clarify: time_t holds dates in amount of milliseconds passed since a specific date (1 Jan 1970).
mktime [and localtime] are non-trivial for all edge cases. They're also highly optimized, so you're unlikely to do better speedwise.
So, just use them [doing the fast fill of (e.g.) struct tm temp you're already doing].
But, a speedup is to add time_t tod to your struct. Fill it from mktime once when you create your struct. This can save many repetitive/duplicate calls to mktime.
You can even defer the mktime call (i.e. only some of your structs may need it). Set tod to a sentinel value (e.g. -2). When you actually need to use tod, fill it from mktime if tod is the sentinel value
I shall assume the timestamps always refer to UTC time, in which case Daylight Savings Time does not apply (and you'll want to specify tm.isdst = 0).
(I suspect that it would be optimal in this case to have the time_t in UTC, but the broken-down fields in local time. Below, I'll just assume that the local timezone is UTC, with no DST changes.)
Personally, I'd save both the time_t and the split fields, and use helper functions to set/modify the timestamps.
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
struct timestamp {
time_t packed;
int16_t year;
int8_t month;
int8_t day;
int8_t hour;
int8_t min;
int8_t sec;
};
static inline int set_timestamp_time(struct timestamp *const ref, const time_t when)
{
struct tm temp = { 0 };
if (!gmtime_r(&when, &temp))
return ERANGE; /* Year didn't fit. */
ref->packed = when;
ref->year = temp.tm_year + 1900;
ref->month = temp.tm_mon + 1;
ref->day = temp.tm_mday;
ref->hour = temp.tm_hour;
ref->min = temp.tm_min;
ref->sec = temp.tm_sec;
return 0;
}
static inline int set_timestamp(struct timestamp *const ref,
const int year, const int month, const int day,
const int hour, const int min, const int sec)
{
struct tm temp = { 0 };
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = min;
temp.tm_sec = sec;
/* We assume timestamps are in UTC, and Daylight Savings Time does not apply. */
temp.tm_isdst = 0;
ref->packed = mktime(&temp);
ref->year = temp.tm_year + 1900;
ref->month = temp.tm_mon + 1;
ref->day = temp.tm_mday;
ref->hour = temp.tm_hour;
ref->min = temp.tm_min;
ref->sec = temp.tm_sec;
return 0;
}
set_timestamp() sets the timestamp based on split fields (year, month, day, hour, minute, second), whereas set_timestamp_time() sets it based on POSIX time. Both functions always update all timestamp fields.
This allows fast access to both the Unix time, and the split fields, but uses slightly more memory (8 bytes per timestamp, typically; 160 megabytes additional memory for 20 million records).
If you do not need the exact number of seconds between two timestamps, but only use the time_t to compare whether one is before or after another, then I recommend using a single int64_t to describe your timestamps:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
/* Timestamps can be compared as integers, like POSIX time_t's.
* The difference between two timestamps is at least their
* difference in seconds, but may be much larger.
*
* Zero is not a valid timestamp!
*/
typedef int64_t timestamp;
#define TIMESTAMP_YEAR(t) ((int64_t)(t) / 67108864)
#define TIMESTAMP_MONTH(t) (((uint32_t)(t) >> 22) & 15)
#define TIMESTAMP_DAY(t) (((uint32_t)(t) >> 17) & 31)
#define TIMESTAMP_HOUR(t) (((uint32_t)(t) >> 12) & 31)
#define TIMESTAMP_MIN(t) (((uint32_t)(t) >> 6) & 63)
#define TIMESTAMP_SEC(t) ((uint32_t)(t) & 63)
static inline time_t timestamp_time(const timestamp t, struct tm *const tm_to)
{
struct tm temp = { 0 };
time_t result;
uint32_t u = t & 67108863U;
temp.tm_sec = u & 63; u >>= 6;
temp.tm_min = u & 63; u >>= 6;
temp.tm_hour = u & 31; u >>= 5;
temp.tm_mday = u & 31; u >>= 5;
temp.tm_mon = u - 1;
temp.tm_year = ((int64_t)t / 67108864) - 1900;
/* UTC time, thus Daylight Savings Time does not apply. */
temp.tm_isdst = 0;
result = mktime(&temp);
if (tm_to)
*tm_to = temp;
return result;
}
static inline double difftimestamp(const timestamp t1, const timestamp t2)
{
return difftime(timestamp_time(t1, NULL), timestamp_time(t2, NULL));
}
static inline timestamp set_timestamp_time(const time_t when, struct tm *const tm_to)
{
struct tm temp = { 0 };
if (!gmtime_r(&when, &temp))
return 0;
if (tm_to)
*tm_to = temp;
return (int64_t)67108864 * ((int64_t)temp.tm_year + 1900)
+ (int64_t)((temp.tm_mon + 1) << 22)
+ (int64_t)(temp.tm_mday << 17)
+ (int64_t)(temp.tm_hour << 12)
+ (int64_t)(temp.tm_min << 6)
+ (int64_t)temp.tm_sec;
}
static inline timestamp set_timestamp(const int year, const int month, const int day,
const int hour, const int min, const int sec,
struct tm *const tm_to, time_t *const time_to)
{
struct tm temp = { 0 };
temp.tm_year = year - 1900;
temp.tm_mon = month - 1;
temp.tm_mday = day;
temp.tm_hour = hour;
temp.tm_min = min;
temp.tm_sec = sec;
temp.tm_isdst = 0; /* Since timestamps are in UTC, Daylight Savings Time does not apply. */
if (time_to)
*time_to = mktime(&temp);
if (tm_to)
*tm_to = temp;
return (int64_t)67108864 * ((int64_t)temp.tm_year + 1900)
+ (int64_t)((temp.tm_mon + 1) << 22)
+ (int64_t)(temp.tm_mday << 17)
+ (int64_t)(temp.tm_hour << 12)
+ (int64_t)(temp.tm_min << 6)
+ (int64_t)temp.tm_sec;
}
The idea here is that you can compare two timestamps trivially; a < b if and only if timestamp a is before b; a == b if and only if the timestamps refer to the same second, and a > b if and only if a is after b. At the same time, the accessor macros TIMESTAMP_YEAR(a), TIMESTAMP_MONTH(a), TIMESTAMP_DAY(a), TIMESTAMP_HOUR(a), TIMESTAMP_MIN(a), and TIMESTAMP_SEC(a) allow very fast access to the individual date and time components. (On typical Intel/AMD 64-bit hardware, it may be even faster than accessing byte-sized fields.)
The difftimestamp() function yields the exact number of seconds between two timestamps, but it is quite slow. (As I mentioned, this approach is best only if you don't need this, or only need it rarely.)
timestamp_time() converts a timestamp to a time_t, optionally saving the struct tm fields to a specified pointer (if not NULL).
set_timestamp_time() returns a timestamp based on a time_t. If the year does not fit in an int, it will return 0 (which is NOT a valid timestamp). If the second parameter is not NULL, the corresponding struct tm is stored there.
set_timestamp() returns a timestamp based on year, month, day, hour, minute, and second. If they refer to an impossible date or time, they are corrected (by mktime()). If the seventh parameter is not NULL, the resulting struct tm is stored there. If the eighth parameter is not NULL, then the resulting time_t is stored there.

Convert a human readable Date to a GMT date

I have a human readable date which is in local time. I need to convert this human readable time to a GMT time in a human readable form.
The human readable date I have is 30th March 2014 02:59.
When I convert the time to GMT I'm expecting the time to be 01:59 on the 30th but my conversion still comes out as 2:59.
I believe the only way to do the conversion is to convert the human time to an epoch and then convert this back to gmtime but doing this I still get 2:59.
Below is the code I am using:
struct tm t;
struct tm *gmtTimeStruct;
time_t t_of_day;
int year = atoi(date);
int month = atoi(date+5);
int day = atoi(date+8);
int hour = atoi(time);
int minutes = atoi(time+3);
char * gmtHumanTime = NULL;
printf("Year: %i Month: %i Day: %i Hour: %i Minutes: %i\n", year, month, day, hour, minutes);
t.tm_year = year - 1900;
t.tm_mon = month - 1;
t.tm_mday = day;
t.tm_hour = hour;
t.tm_min = minutes;
t.tm_sec = 59;
t.tm_isdst = 0;
t_of_day = mktime(&t);
printf("Epoch time: %ld\n", t_of_day);
gmtTimeStruct = gmtime(&t_of_day);
asprintf(&gmtHumanTime, "%s:%s", gmtTimeStruct->tm_hour, gmtTimeStruct->tm_min);
printf("GMT Human Time: %s", gmtHumanTime);
UPDATE 1
I've also tried change the t.tm_isdst flag from 0,1 and -1 to see if anything changes and it doesn't seem to. I know mktime has an issue with this flag as it can't always work out whether the time needs ammending due to DST or not but I'm not sure if timegm has the same issue.
Here's your problem:
The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect, zero if Daylight Saving Time is not in effect, and less than zero if the information is not available.
By setting t.tm_isdst = 0; in your code, you are explicitly specifying that there is no daylight saving in effect. You should have provided a negative value.
Reference: http://www.cplusplus.com/reference/ctime/tm/
(Also, shouldn't the format string near the bottom be "%d:%02d"instead of "%s:%s"?)
EDIT
Sorry, I didn't notice you'd tried different values of tm_isdst. Perhaps it would help if you simplified your code a bit. This works perfectly on my system:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
struct tm t, *gmtTimeStruct, *localTimeStruct;
time_t t_of_day;
char *gmtHumanTime, *localHumanTime;
t.tm_year = 2014 - 1900;
t.tm_mon = 3 - 1;
t.tm_mday = 30;
t.tm_hour = 2;
t.tm_min = 59;
t.tm_sec = 59;
t.tm_isdst = -1;
t_of_day = mktime(&t);
gmtTimeStruct = gmtime(&t_of_day);
asprintf(&gmtHumanTime, "%d:%d", gmtTimeStruct->tm_hour, gmtTimeStruct->tm_min);
printf("GMT Human Time: %s\n", gmtHumanTime);
localTimeStruct = localtime(&t_of_day);
asprintf(&localHumanTime, "%d:%d", localTimeStruct->tm_hour, localTimeStruct->tm_min);
printf("Local Human Time: %s\n", localHumanTime);
return 0;
}
Output:
GMT Human Time: 1:59
Local Human Time: 2:59
Try compiling this on your system and see what you get. (Perhaps there is something wrong with your system's time zone setting?)

Convert struct array to struct?

I have a struct array (Training data[10]) that contains some data that I want to pass to functions.
int convertTime(Time time)
{
minutes = time.seconds * 60;
// Takes data from data[0].time.seconds and converts them to minutes.
// My only problem is that I am being asked send a struct to this function, but I have to send the array because that's where all my data is stored
return minutes;
}
typedef struct
{
int seconds;
} Time;
typedef struct
{
Time time;
double distance;
} Training;
Training data[10];
Training input;
scanf("%d %lf", input.time.seconds, input.distance);
data[0].time.seconds = input.time.seconds;
data[0].distance = input.distance;
So now data[0].time.seconds and data[0].distance contains all data I need. I just have to pass data[0].time.seconds to the function, but in my assignment I am prompted to send the struct Time to the function, and I don't understand that since Time is only storing temporary data? It's the stored data that I want to send to the function.
How do I convert seconds to hours, minutes and seconds?
time.hours = seconds / 3600;
time.minutes = (seconds - time.hours * 3600) / 60;
time.seconds = seconds - 3600 * time.hours - 60 * time.minutes;
This seems to be right in my eyes but it fails. hours is correctly calculated but not minutes and sconds :(
To pass the structure, name it in the call:
some_function(data[0].time); // By value
other_function(&data[0].time); // By address
Both functions get passed the Time value contained in the data[0] element of your array of Training structures.
Suppose you have a value which is the number of seconds since midnight. And suppose you define another structure with hours/minutes/seconds, you can set this clock structure as follows,
typedef struct
{
int hours;
int minutes;
int seconds;
} Clock;
You can print this structure, either to a char buffer, or to stdout,
char*
clockPrint(Clock* timep,char *stringbuf)
{
if(stringbuf)
sprintf(stringbuf,"%02d:%02d:%02d",(timep)->seconds,(timep)->minutes,(timep)->seconds);
else
printf("%02d:%02d:%02d",(timep)->seconds,(timep)->minutes,(timep)->seconds);
return stringbuf;
}
Extracting hours, minutes, and seconds from an epoch time or a number of seconds since midnight can be done,
int //return days...
TimeSet(Clock* timep, int epoch)
{
(timep)->seconds = (epoch) % 60;
(timep)->minutes = (epoch/60) % 60;
(timep)->hours = (epoch/60/60) % 24;
int days;
return days = (epoch/60/60/24);
}
Should you want to obtain hours, minutes, or seconds from this clock value,
void
TimeGet(Clock* timep, int* hoursp, int* minutesp, int* secondsp)
{
if(hoursp) *hoursp = (timep)->hours;
if(minutesp) *minutesp = (timep)->minutes;
if(secondsp) *secondsp = (timep)->seconds;
return;
}
Since you have stored a Time in your Date struct, which contains a number of seconds (presumably since midnight), and you have an array of some number of these Date's defined,
Training data[10];
Training input;
You can use scanf to read your seconds and distance values. And as stated, you can then place your input into your data[0] element,
//scanf wants pointers to int and float data
float distance;
printf("enter: seconds distance "); fflush(stdout);
scanf("%d %lf", &(input.time.seconds), &distance);
//you can then store the distance into your input struct double
input.distance = distance;
data[0].time.seconds = input.time.seconds;
data[0].distance = input.distance;
You could also use gettimeofday(3) or clock_gettime(2) to grab the current time (seconds since epoch),
struct timeval tv;
gettimeofday(&tv,NULL); //posix.1-2001 function, seconds
input.time.seconds = tv.tv_sec;
//or
struct timespec ts;
clock_gettime(CLOCK_REALTIME,&ts); //posix.1-2008 function, seconds
input.time.seconds = ts.tv_sec;
Then you can separate your seconds into hours, minutes, and seconds,
Clock clk;
int hours, minutes, seconds;
TimeSet(&clk, data[0].time.seconds);
TimeGet(&clk, &hours, &minutes, &seconds);
Or you can format a string for printing, or print to stdout,
char clockbuffer[30];
clockPrint(&clk,NULL);
printf("time (HH:MM:SS): %s\n", clockPrint(&clk,clockbuffer));

Need to get Saturdays date of the week in linux C

I am trying to get Saturday's date of the week in Linux C. Using the function time and localtime, I got today's date and time details. How to proceed further to get Saturday's date?
#include <time.h>
#include <stdio.h>
#include <string.h>
int main()
{
char date[20];
struct tm *curr_tm = NULL;
time_t curr_time;
curr_time = time(NULL);
curr_tm = localtime(&curr_time);
curr_tm->tm_wday = 6;
//Refers to saturday.
printf("new date %d\t%d\t%d\n", curr_tm->tm_mday, curr_tm->tm_mon, curr_tm->tm_year+1900);
return 1;
}
How should I proceed with this?
struct tm orig;
// ...
// struct tm correctly set with everything within range.
orig.tm_mday += 6 - orig.tm_wday;
mktime(&orig);
tm_mday is the number of days since Sunday. Thus, 6 minus that is the number of days until Saturday (if today is Saturday it does nothing). This puts the structure out of range, which mktime fixes.
EDIT:
curr_time->tm_mday += 6 - curr_time->tm_wday;
mktime(curr_time);
Based on your code, the following will get you the next Saturday (today if it's Saturday).
#include <time.h>
#include <stdio.h>
#include <string.h>
int main() {
char date[20];
struct tm *curr_tm = NULL;
time_t curr_time;
curr_time = time(NULL);
curr_tm = localtime(&curr_time);
// Add the difference between todays day of week and Saturday, then re-make.
curr_tm->tm_mday += 6 - curr_tm->tm_wday;
mktime (curr_tm);
printf("new date %d\t%d\t%d\n",
curr_tm->tm_mday, curr_tm->tm_mon+1, curr_tm->tm_year+1900);
return 1;
}
You can replace the curr_tm->tm_mday += 6 - curr_tm->tm_wday; line with:
curr_tm->tm_mday += (curr_tm->tm_wday == 6) ? 7 : 6 - curr_tm->tm_wday;
to get next Saturday even if today is Saturday.

Resources