I am trying to determine the time difference between two times, which i represent as unsigned integers (in a sturct) as follows:
unsigned int day;
unsigned int month;
unsigned int year;
unsigned int hour;
unsigned int mins;
unsigned int seconds;
i can work out the time difference in minutes between two times that occur on the same day easily enough using: This isn't my exact code, this is just the logic behind it.
time1 = hours*3600 + mins*60 + seconds;
time1 = hours2*3600 + mins2*60 + seconds2;
//time2 will always be less than time1
time_diff_secs = time1_secs - time2_secs;
time_diff_mins = time_diff_secs / 60;
time_diff_secs = time_diff_secs % 60;
this produces this output:
Time mayday was issued: 13 Hours 4 Mins 0 Seconds
Time mayday was recieved: 13 Hours 10 Mins 0 Seconds
Time between sending and receiving: 6.00Mins
which is correct, but when I have two times that are on different days I get this as the result:
Time mayday was issued: 23 Hours 0 Mins 0 Seconds
Time mayday was recieved: 0 Hours 39 Mins 38 Seconds
Time between sending and receiving: 71581448.00Mins
This is obviously incorrect, I am not sure how to progress from here, the actual result should be 40mins, not 71.5million.
Another way to do it using the standard C library, the only advantage of this is you do not have to worry about your dates overlapping years, or problems with overlapping month boundaries + leap year nonsense:
unsigned int day;
unsigned int month;
unsigned int year;
unsigned int hour;
unsigned int mins;
unsigned int seconds;
time_t conv(void)
{
time_t retval=0;
struct tm tm;
tm.tm_mday=day;
tm.tm_mon=month -1;
tm.tm_year=year - 1900;
tm.tm_hour=hour;
tm.tm_min=mins;
tm.tm_sec=seconds;
tm.tm_isdst=-1;
retval=mktime(&tm);
return retval;
}
int main()
{
time_t start=0;
time_t end=0;
time_t diff=0;
// assign day, month, year ... for date1
start=conv();
// assign day, month, year ... for date2
end=conv();
if(start>end)
diff=start - end;
else
diff=end - start;
printf("seconds difference = %ld\n", diff);
return 0;
}
You are getting an underflow. Try this (works regardless of whether the variables are signed or unsigned):
if (time1_secs < time2_secs) {
// New day. Add 24 hours:
time_diff_secs = 24*60*60 + time1_secs - time2_secs;
} else {
time_diff_secs = time1_secs - time2_secs;
}
time_diff_mins = time_diff_secs / 60;
time_diff_secs = time_diff_secs % 60;
Change
time_diff_secs = time1_secs - time2_secs;
to
time_diff_secs = abs(time1_secs - time2_secs) % 86400;
This will force it to be the minimum time difference between both times and will work even if you add days, months, etcetera to the time_diff_secs calculation.
Related
I am trying to find differentiation between two date(i.e. 14:49:41 and 15:50:42) using below code:
Action()
{
struct tm {
int tm_sec;
int tm_min;
int tm_hour;
};
int rc; // return code
struct tm date1;
struct tm date2;
long time_difference; // the number of time ticks (seconds) that separate date1 and date2.
int hours, minutes, seconds;
// Save example dates to a parameter.
// capture these values using web_reg_save_param or similar.
// date format: hh:mm:ss
lr_save_string("14:49:41", "Param_Date1");
lr_save_string("15:50:42", "Param_Date2");
// Read the values from the string into the date variables
rc = sscanf(lr_eval_string("{Param_Date1}"), "%d:%d:%d",&date1.tm_hour, &date1.tm_min, &date1.tm_sec);
// Repeat the above steps for Date2
rc = sscanf(lr_eval_string("{Param_Date2}"), "%d:%d:%d", &date2.tm_hour, &date2.tm_min, &date2.tm_sec);
time_difference = mktime(&date2) - mktime(&date1);
lr_output_message("Total number of seconds difference: %d", time_difference);
// Calculate time difference in hours, minutes and seconds.
hours = time_difference/3600;
time_difference = time_difference - (hours * 3600);
minutes = time_difference/60;
time_difference = time_difference - (minutes * 60);
seconds = time_difference;
lr_output_message("Hours: %d, Minutes: %d, Seconds: %d", hours, minutes, seconds);
return 0;
}
Actual output should return : Hours: 1, Minutes: 1, Seconds: 1
But output returns : Hours: 0, Minutes: 0, Seconds: 0
Please help me fix this problem. Or Else any other alternative achieve it?
hours, minutes and seconds should not be declared as Integers as you are dividing the value by 3600. If you declare them as floating point numbers it may work. Other than that everything looks good
The difference between two times in seconds is easy to compute:
int secs1 = ((time1.hour * 60) + time1.min) * 60 + time1.sec;
int secs1 = ((time2.hour * 60) + time2.min) * 60 + time2.sec;
int sec_dif = secs1 - secs2;
Or this way:
int sec_dif =
((time1.hour - time2.hour) * 60 + (time1.min - time2.min)) * 60 + (time1.min - time2.min);
int min_dif = sec_dif / 60;
int hour_dif = sec_dif / (60 * 60);
No need to bother with converting the times into time_t types.
I'm working through an example for Advanced Programming in the Unix Environment and the following questions was asked:
If the process time is stored as a 32bit signed integer, and the system counts 100 ticks per second, after how many days will the value overflow?
void proc_ovf()
{
int sec = 60;
int min = 60;
int hour = 24;
int tick = 100;
int epoch_time = (((INT_MAX / (sec * tick)) / min) / hour);
struct tm * timeinfo;
time_t epoch_time_as_proc_t = epoch_time;
timeinfo = localtime(&epoch_time_as_proc_t);
printf("3] overflow date of proc: %s", asctime(timeinfo));
}
Is the following solution a reasonable calculation for how many days before overflow?
(((INT_MAX / (sec * tick)) / min) / hour)
This calculation yielded 248 days.
248 days looks good.
But your code doesn't. Your variables have the wrong names. They should be:
int ticks_per_second = 100;
int seconds_per_minute = 60;
int minutes_per_hour = 60;
int hours_per_day = 24;
int ticks = INT_MAX;
int seconds = ticks / ticks_per_second;
int minutes = seconds / seconds_per_minute;
int hours = minutes / minutes_per_hour;
int days = hours / hours_per_day;
printf("overflow after %d days\n", days);
The above code takes care of mentioning the measurement units. Can you see how nicely the measurement units cancel out in each line of the second part of the code?
I need a function that can calculate the difference between two datetime (year, month, day, hours, minute, seconds). and then return the difference in the same format.
int main (){
struct datetime dt_from;
init_datetime(&dt_from, 1995, 9, 15, 10, 40, 15);
struct datetime dt_to;
init_datetime(&dt_to, 2004, 6, 15, 10, 40, 20);
struct datetime dt_res;
datetime_diff(&dt_from, &dt_to, &dt_res);
return 0;
}
void datetime_diff(struct datetime *dt_from, struct datetime *dt_to
, struct datetime *dt_res) {
//What can I do here to calculate the difference, and get it in the dt_res?
}
Please have a look and try this example which uses time.h and should be portable. It calculates the difference in days between the dates in your question. You can change the program a little so that it works the way you want.
#include <stdio.h>
#include <time.h>
#include <math.h>
int main() {
time_t start_daylight, start_standard, end_daylight, end_standard;;
struct tm start_date = {0};
struct tm end_date = {0};
double diff;
printf("Start date: ");
scanf("%d %d %d", &start_date.tm_mday, &start_date.tm_mon, &start_date.tm_year);
printf("End date: ");
scanf("%d %d %d", &end_date.tm_mday, &end_date.tm_mon, &end_date.tm_year);
/* first with standard time */
start_date.tm_isdst = 0;
end_date.tm_isdst = 0;
start_standard = mktime(&start_date);
end_standard = mktime(&end_date);
diff = difftime(end_standard, start_standard);
printf("%.0f days difference\n", round(diff / (60.0 * 60 * 24)));
/* now with daylight time */
start_date.tm_isdst = 1;
end_date.tm_isdst = 1;
start_daylight = mktime(&start_date);
end_daylight = mktime(&end_date);
diff = difftime(end_daylight, start_daylight);
printf("%.0f days difference\n", round(diff / (60.0 * 60 * 24)));
return 0;
}
Test
Start date: 15 9 1995
End date: 15 6 2004
3195 days difference
Or even simpler for non-interactive code and with standard or daylight savings time:
#include <stdio.h>
#include <time.h>
#include <math.h>
int main()
{
time_t start_daylight, start_standard, end_daylight, end_standard;;
struct tm start_date = {0};
struct tm end_date = {0};
double diff;
start_date.tm_year = 1995;
start_date.tm_mon = 9;
start_date.tm_mday = 15;
start_date.tm_hour = 10;
start_date.tm_min = 40;
start_date.tm_sec = 15;
end_date.tm_mday = 15;
end_date.tm_mon = 6;
end_date.tm_year = 2004;
end_date.tm_hour = 10;
end_date.tm_min = 40;
end_date.tm_sec = 20;
/* first with standard time */
start_date.tm_isdst = 0;
end_date.tm_isdst = 0;
start_standard = mktime(&start_date);
end_standard = mktime(&end_date);
diff = difftime(end_standard, start_standard);
printf("%.0f days difference\n", round(diff / (60.0 * 60 * 24)));
/* now with daylight time */
start_date.tm_isdst = 1;
end_date.tm_isdst = 1;
start_daylight = mktime(&start_date);
end_daylight = mktime(&end_date);
diff = difftime(end_daylight, start_daylight);
printf("%.0f days difference\n", round(diff / (60.0 * 60 * 24)));
return 0;
}
Here is the basic idea:
Convert your datetime into an integral type (preferable long long or unsigned long long) which represents your datetime value as it's smallest unit (second in your case). How to achieve that? Easy transform the single values into seconds and add everything together. (seconds + minutes * 60 + hours * 3600 ...)
Do this for both values and then subtract the integer values.
Now convert the single integer value, the time difference, back to a datetime. How? Start with the biggest unit (years) and divide the difference by the amount of seconds within one year (60 * 60 * 24 * 365). Now you know how many years are in between your two datetimes. Take the rest and divide it by the amount of seconds per month, and so on...
(Obviously I ignored everything rather complicated, like daylight saving time for example)
However I would highly recommend using struct tm from time.h as mentioned in the comments. It is portable and you can use difftime.
#include <stdio.h>
int main(void)
{
int days, hours, mins;
float a, b, c, total, temp, tempA, tempB;
a = 3.56;
b = 12.50;
c = 9.23;
total = a+b+c;
days = total / 24;
temp = total/24 - days;
hours = temp * 24;
tempA = temp*24 - hours;
mins = tempA*60;
while (hours >= 24)
{
hours= hours-24;
days +=1;
}
while ( mins >= 60)
{
mins=mins-60;
hours +=1;
}
printf("days:%d\n", days);
printf("hours:%d\n", hours);
printf("mins:%d\n", mins);
return 0;
}
I wanted to convert decimal hours to real time and I can do it fine but I wanted to increase days hours if the hours is beyond 24 and if mins is beyond 60mins.
the while loop does subtract and it does print out the new value but the hours / days aren't getting compounded.
It was 1 day 1 hour 77mins
I wanted it to read 1 day 2 hours 17mins
but I'm getting 1 day 1 hour 17 mins.
Using the modulus operator will make your life much easier: it will give the remainder of a division.
int total;
/* a=; b=; c=; assignments */
total = a+b+c;
mins = total % 60;
total /= 60;
hours = total % 24;
days = total / 24;
Here is a simpler implementation of what you are trying to do:
void TimeFix(int &days, int &hours, int &mins)
{
hours += mins/60;
mins %= 60;
days += hours/24;
hours %= 24;
}
Running your program I'm getting:
days:1
hours:1
mins:17
and that's what I expect considering that total should be 25.29.
It works fine, your math is just a little off. (= (+ 3.56 12.50 9.23) 25.29), not 26.29.
Instead of a while loop you can use division:
days += hours / 24
hours %= 24
Also, do your minutes-to-hours stuff before your hours-to-days stuff.
What's the simplest way to calculate the number of minutes until 9pm (being today or tomorrow)?
Was looking over mktime() but seemed a hassle to get the day # and month, dealing with all that.
Just calculate the delta to today's 9pm. If it's negative, add 24hrs to get the delta to tomorrow's 9pm.
#include <stdio.h>
#include <time.h>
int main(int argc, char* argv[]) {
struct tm* tm;
time_t ts=time(NULL);
if(tm=localtime(&ts)) {
long int delta;
tm->tm_hour = 21;
tm->tm_min = 0;
tm->tm_sec = 0;
delta = mktime(tm) - ts;
if(delta<0) {
delta+=24*60*60;
}
printf("%d minutes til (next)9pm\n",delta/60);
}
return 0;
}
This will give you the minutes until 9pm.:
time_t currenttime;
time_t ninePM;
struct tm * timeinfo;
int minutesUntilNine;
// Fill currenttime + convert to struct tm
time ( ¤ttime );
timeinfo = localtime ( &rawtime );
// Check for after 9pm...
if (timeinfo->tm_hour >= 21) // Are we after 9pm?
timeinfo->tm_day++; // increment our day
// Set timeinfo to the time you want...
timeinfo->tm_sec = 0;
timeinfo->tm_min = 0;
timeinfo->tm_hour = 21; // 9pm
ninePM = mktime( timeinfo );
minutesUntilNine = (ninePM - currenttime) / 60;
A simple way is to calculate the number of hours and minutes (given what the time is now, plus the fact that there are 24 hours in a day), and multiply the number of hours by 60 to make it a number of minutes. Alternatively, instead of using a 24-hour clock to express the time, use a 1440 minute clock: it's easy to subtract one time from another, to get a time difference.
Here it is (output in seconds...)
#include <stdio.h>
#include <time.h>
int main(void)
{
double dt = 0.0f;
time_t ti = time(NULL);
time_t tf;
struct tm *pt_actual = localtime(&ti);
struct tm t_actual = *pt_actual;
struct tm t_target = *pt_actual;
t_target.tm_hour = 21; // 09:00 pm
t_target.tm_min = 0;
tf = mktime(&t_target);
dt = difftime(tf, ti);
if (dt < 0)
dt += (24*60*60); // if negative, just consider **next** 9pm target, add a day
printf("difftime = %f seconds\n", dt );
return 0;
}
The guy's asking for the simplest way. All your ways are unnecessarily complex. Just use modular arithmetic:
#include <stdio.h>
#include <time.h>
#define TARGET_TIME 21*60 // 9:00 PM, in format HH * 60 + MM
int main(int argc, char* argv[])
{
struct tm* tm;
time_t ts = time(NULL);
int minutes_until_9pm;
tm = localtime(&ts);
minutes_until_9pm = 24*60 - (tm->tm_min + tm->tm_hour * 60 + TARGET_TIME)%(24*60);
//alternatively, the following is slightly faster
//minutes_until_9pm = 24*60 - (tm->tm_min + tm->tm_hour * 60 + TARGET_TIME) + (tm->tm_min+tm->tm_hour*60+TARGET_TIME>24*60?24*60:0);
printf("%d minutes til (next)9pm\n", minutes_until_9pm);
return 0;
}
If you know your timezone , it all becomes even simpler:
#include <stdio.h>
#include <time.h>
#define TARGET_TIME 21*60 // 9:00 PM, in format HH * 60 + MM
#define TIMEZONE (-6) // This is CST; replace with your own timezone
int main(int argc, char* argv[])
{
int minutes_until_9pm = 24*60 - (time(NULL)/60 + TARGET_TIME + (24+TIMEZONE)*60)%(24*60);
printf("%d minutes til (next)9pm\n", minutes_until_9pm);
return 0;
}
What's going on here is that, modulo one day, we're getting number of minutes since midnight. Then we're adding 9:00 PM to get the the number of minutes since 9:00 PM. Then we're subtracting that from 24 hours to get the number of minutes until the next 9:00 PM.
If you need higher accuracy (i.e. rounded to the nearest number of minutes, rather than simply number of minutes), simply subtract (tm->tm_sec>=30?0:1) from minutes_until_9pm, or replace time(NULL)/60 with (time(NULL)+30)/60, respectively.
C99 version:
#include <math.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
struct tm now = *localtime(&(time_t){ time(NULL) });
struct tm then = now;
then.tm_hour = 21;
then.tm_min = 0;
then.tm_sec = 0;
int dt = ((int)round(
difftime(mktime(&then), mktime(&now)) / 60) + 24 * 60) % (24 * 60);
printf("time till 9pm: %i minutes\n", dt);
}
The more profound, if less helpful, answer is that there is no simple answer.
How do you even know that today will have a 9pm? OK, sure, I'm sure all the time zones that exist never skip 21:00, but they skip hours in the middle of the night once a year.
Calendrics is a disaster of complexity. Beware.