I have a problem to well understand what'is happening here.
I'm tring to activate a relay base on time with the user selected schedule.
The problem is when the stop time is after midnight and the start if before.
My function to check if it is the moment to toggle is:
bool lightsOn = false;
void checkOnOff() {
//Check time for ON/OFF the ligth
struct tm *curTime = getTime();
unsigned int now = curTime->tm_hour * 100 + curTime->tm_min;
unsigned int start = config.ligths_on_time.tm_hour * 100 + config.ligths_on_time.tm_min;
unsigned int stop = config.ligths_off_time.tm_hour * 100 + config.ligths_off_time.tm_min;
if ( (now >= start || now < stop) && (now <= stop) ) { //<-- this line is hard to have it in mind
if(!lightsOn) enableLights();
} else {
if(lightsOn) disableLights();
}
}
void enableLights() { //the same for disableLights() but with false, reverse HIGH/LOW and 0
lightsOn = true;
digitalWrite(EXTRA_LED_PIN, HIGH);
digitalWrite(ON_OFF_RELAY_PIN, HIGH);
sendLightsOnOffToServer(1);
Serial.println(F("Lights enabled."));
}
struct tm *getTime() {
//if (NTP_TIME_SETTED) {
time_t now = time(nullptr);
//gmtime_r(&now, &timeinfo); //utc
return localtime(&now);
//}
}
Is someone can explain to me how to do that ?
Adjust the stop time by 24 hours if it is smaller than start
Adjust the now time by 24 hours if the stop time is tomorrow, and the ON_OFF state is ON, and now < start.
Re-order your logic to use the ON_OFF state to determine whether to check for start or stop
#define HOUR 100
#define DAY (HOUR * 24)
#define ON true
#define OFF false
unsigned int now = curTime->tm_hour * HOUR +
curTime->tm_min ;
unsigned int start = config.ligths_on_time.tm_hour * HOUR +
config.ligths_on_time.tm_min;
unsigned int stop = config.ligths_off_time.tm_hour * HOUR +
config.ligths_off_time.tm_min;
// Fix-up stop and now time to account for stop in next day
if( stop < start)
{
stop += DAY ;
if( ON_OFF == ON && now < start )
{
now += DAY ;
}
}
// If OFF, check for start condition
if( ON_OFF == OFF && now >= start )
{
enableLight() ;
}
// ... otherwise if ON, check for stop condition
else if( ON_OFF == ON && now >= stop )
{
disableLight() ;
}
Related
everyone, I am using, P10 Dot Matrix Display with Arduino Uno. I am using P10 Library from this link. P10_LED and I need to display the one-hour countdown on the display module. The given library uses TimerOne library. So for countdown i am using MsTimer2 library which usese timer2 of arduino.
When I individually run both of the libraries, my scrolling on the display is perfect and my timer library also generates a pure 1sec interrupt. Now what I did is the added both the library in my project and I am doing the countdown. But now suddenly my MsTimer2 doesn't generate pure 1sec.
Here is the code.
#include <MsTimer2.h>
#include <TimerOne.h>
#include"SPI.h"
#include <ledP10.h>
LedP10 myled;
uint8_t minute = 0, second = 0, hour = 1;
volatile bool xIsCountDone = false;
volatile bool xIsInterruptOcuured = false;
char time_buff[100];
void setup()
{
Serial.begin(9600);
myled.init(3,4,8,9 ,3);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
//myled.showmsg_single_scroll("this is single led test",2,8,0);
MsTimer2::set(1000, count);
MsTimer2::start();
}
void loop() {
if (xIsInterruptOcuured == true)
{
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
xIsInterruptOcuured = false;
}
}
void count(){
second--;
if (second <= 0 || second > 59)
{
second = 59;
minute--;
if (minute <= 0 || minute > 59)
{
minute = 59;
hour--;
if (hour <= 0 || hour > 12)
{
xIsCountDone =true;
}
}
}
Serial.println(millis());
xIsInterruptOcuured = true;
}
In the interrupt routine, I am printing millis() to see at after how many ms the interrupt occurs. The results are something like this.
15:33:02.684 -> 1199
15:33:04.371 -> 2396
15:33:06.059 -> 3592
15:33:07.746 -> 4783
15:33:09.434 -> 5986
15:33:11.121 -> 7181
15:33:12.855 -> 8379
15:33:14.543 -> 9578
15:33:16.230 -> 10768
15:33:17.918 -> 11974
15:33:19.605 -> 13168
15:33:21.292 -> 14365
15:33:22.980 -> 15562
15:33:24.667 -> 16751
15:33:26.402 -> 17955
When I use only MsTimer2 library the results are something like this.
15:37:21.241 -> 998
15:37:22.226 -> 1998
15:37:23.257 -> 2998
15:37:24.241 -> 3998
15:37:25.226 -> 4998
15:37:26.257 -> 5998
15:37:27.241 -> 6998
15:37:28.225 -> 7998
15:37:29.257 -> 8998
15:37:30.241 -> 9998
15:37:31.225 -> 10998
15:37:32.256 -> 11998
15:37:33.241 -> 12998
15:37:34.225 -> 13998
15:37:35.256 -> 14998
My guess, it's happening because of the TimerOne library but I couldn't find the solution. In ledP10.cpp there is a callback method for timer1 and it contains loops and may line of code. But is timer1 interrupts priority is higher than timer2? But according to the ATmega328p datasheet, the vector no. for Timer2 is less than Timer1. Doesn't that mean Timer2 has a higher priority? My ultimate goal is to do the one-hour countdown. Any help with this problem or any additional information i am missing which will be useful or any other solution other than using timer2 interrupt will be appreciated.
Regards.
EDIT
Here is the code I used with millis() and gave me around 12min difference.
uint8_t new_buff[100];
unsigned long startMillis; //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000; //the value is a number of milliseconds
uint8_t minute = 0, second = 0, hour = 1;
char time_buff[100];
void setup()
{
myled.init(3,4,8,9,3);
Serial.begin(9600);
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
//Serial.println((char*)time_buff);
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = millis();
}
void loop() {
currentMillis = millis(); //get the current "time" (actually the number of milliseconds since the program started)
if (currentMillis - startMillis >= period) //test whether the period has elapsed
{
Serial.println(millis());
second--;
startMillis = currentMillis; //IMPORTANT to save the start time of the current LED state.
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
startMillis = currentMillis;
}
}
This answer targets your example using millis(). You can avoid accumulating errors over time, by not setting the next update relative to the current time. Rather just increment it by one second each time. This way, it does not matter if your main loop gets blocked by an interrupt for some milliseconds.
Also note that you don't have to save hours, minutes and seconds separately, you can just calculate them:
unsigned long nextMillis = 1000;
unsigned long targetTime = 1 * 60 * 60 * 1000; // 1 hour in milliseconds
void setup(){
myled.init(3,4,8,9,3);
Serial.begin(9600);
updateMyLed(0);
}
void updateMyLed( unsigned long elapsedTime ){
char buffer[100];
unsigned long timeLeftInSeconds = (targetTime - elapsedTime) / 1000;
uint8_t hour = timeLeftInSeconds / 3600;
timeLeftInSeconds -= hour * 3600;
uint8_t minute = timeLeftInSeconds / 60;
uint8_t second = timeLeftInSeconds - (minute * 60);
sprintf((char*)buffer, " %d%d:%d%d:%d%d", (hour/10), (hour%10), (minute/10), (minute%10), (second/10), (second%10));
myled.showmsg_single_static((char*)buffer, 0);
}
void loop() {
if( millis() >= nextMillis ){
updateMyLed(nextMillis);
nextMillis += 1000;
}
}
In the Arduino world, some libraries are disabling the interrupts.
This happens with all WS2812 LEDS and also yours. Without disabling interrupts, there would be a timing problem with the external devices.
So, you should never use interrupts or library with interrupts, if you use another one who will disable the interrupts.
Do you want use the P10 library? You can, but do not use interrupts in your code. Do not add other libraries like IR_remote, since it will not work correctly.
Back to your problem, just update your timer in the loop. And do not wait until the a second is over to update your time by 1 second! This will always be more than 1second.
You can for example convert the millis to seconds seconds = millis() / 1000;.
Your loop could be so:
void loop() {
currentSeconds = millis() / 1000; //get the current "time" (actually the number of milliseconds since the program started)
if (currentSeconds != savedSeconds) //test whether the period has elapsed
{
savedSeconds = currentSeconds;
Serial.println(millis());
second--;
if (second <=0 || second > 59) {
second = 59;
minute--;
if (minute <=0 || minute > 59) {
minute = 59;
hour--;
if (hour <= 0 || hour > 12) {
hour = 0;
}
}
}
sprintf((char*)time_buff, " %d%d:%d%d:%d%d", (hour/10), (hour%10),(minute/10), (minute%10),(second/10), (second%10));
myled.showmsg_single_static((char*)time_buff, 0);
}
}
i am currently working in a ardunio alarm clock project without and rtc for school. I have a problem with my hour variable not increasing and my conditionals that checks it.
This code mostly works i can set time in hr and minutes but when the timer reaches 59 minutes the hour doesnt increase by 1. The second code that has been posted is the bit where the problem lies. Any tips/help would be appreciated.
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <EEPROM.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
const int numofMenus = 4;
int currentMenu = 0;
String menu[4][2] = {{"Set hour", "hr"}, {"Set minutes", "min"}, {"Set alarm", "o"}, {"Current Time", "ha"}};
int parameters[24];
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.noBlink();
}
void loop() {
inputAction();
if (currentMenu == 0)
{
printScreen();
}
if (currentMenu == 1)
{
printScreen();
}
if (currentMenu == 2)
{
printScreen();
}
if (currentMenu == 3)
{
int hr = parameters[0];
int mn = minute(parameters[1]);
int sec = second();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
if (parameters[1] >= 0 && parameters[1] <= 59 && sec < 59) {
parameters[0];
printtime(parameters[0]);
}
else if (parameters[1] == 59 && second() == 59) {
if (parameters[0]>=0 && parameters[0]<24){
parameters[0];
printtime(parameters[0]++);
//delay(1000);}
/*else if (parameters[0] == 24){
parameters[0]= 0;
printtime(parameters[0]);
}*/
}
}
lcd.print(":");
if (sec >= 0 && sec < 59) {
printtime(parameters[1]);
}
else if (sec == 59) {
parameters[1];
printtime(parameters[1]++);
delay(1000);
}
lcd.print(":");
printtime(sec);
/* if (sec == 60) {
mn+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}
if (mn == 60) {
hr+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}*/
delay (100);
}
}
void inputAction() {
uint8_t buttons = lcd.readButtons();
if (buttons & BUTTON_UP) {
if (currentMenu == 0) {
currentMenu = numofMenus - 1;
} else {
currentMenu--;
}
} else if (buttons & BUTTON_DOWN) {
if (currentMenu == numofMenus - 1) {
currentMenu = 0;
} else {
currentMenu++;
}
} else if (buttons & BUTTON_RIGHT) {
parameters[currentMenu]++;
} else if (buttons & BUTTON_LEFT) {
parameters[currentMenu]--;
}
}
void printScreen() {
lcd.clear();
lcd.print(menu[currentMenu][0]);
lcd.setCursor(0, 1);
lcd.print(parameters[currentMenu]);
lcd.print(" ");
lcd.print(menu[currentMenu][1]);
delay(100);
}
void printtime(int data) {
if (data >= 0 && data < 10) {
lcd.print('0');
}
lcd.print(data);
}
I don't think it is a good strategy to throw all those delays in the code. If you want to work with an RTC, you need to be mindful of those delays as they will affect the functionality of your program. If you don't account for delay properly, they will accumulate as errors. An error of 100 msecs will be seen as error in seconds easily within days.
I did not go through your code because it is hard to understand. I propose you have a look at this code which should be placed in your loop() function:
delay(100);
parameters = parameters + 100;
long rtcSeconds = parameters / 1000;
int seconds = (int) (rtcSeconds % 60); // Range 0 . 59 units: Secs
int minutes = (int)(((rtcSeconds - seconds) / 60) % 60); // Range 0 . 59 units: Mins
int hours = (int) (((rtcSeconds - minutes*60 - seconds) / (3600)) % 24); // Range 0 . 23 units: Hrs
I am using your parameters[0] field to keep track of the time in your syste, in milliseconds units. The field increases every 100 msecs as you see. You can recover the different time values using a combination of the modulus (%) and division operations. Now, I know you need to increase the time in your program. To do so, it is easy:
If you want to increase one second, do this: parameters[0] += 1000;
If you want to increase one minute, do this: parameters[0] += 1000 * 60;
If you want to increase one hour, do this: parameters[0] += 1000 * 3600;
Now, you might need to work with long variables as int have a limited range. You also need to watch for the time roll over when you change your time. If you are decreasing the time, you need to watch pramaters[0] doesn't become negative. In case it does, you need to add 3600 * 24 * 1000 msecs to force it jump one day ahead (3600 * 24 is one day in seconds). I hope you understand this is not a solution to your problem but an alternative approach using a little bit of a simpler code structure.
I've spent a good hour on this, but I can't create a formula that works for my c program. (I have a new programmer).
I have to convert UTC time to its respective time in a particular city. My code works perfectly except here. Here it gives me the wrong answer. I can't wrap my head around it (I created a formula but it makes no sense to me).
In my program, time is entered as 24 hour time. 9AM = 900, 12PM = 1200, 12am = 0 etc.
If we are asked to convert 2359 to Eucla time (UTC +845) my program outputs 804. The correct answer is 844.
I figured out how to calculate 844, but I make no sense of it.
2359 + 845 = 3204 (adding the timezone offset 845 to the UTC time)
3204 - 60 = 3144 (minus 60 for some reason [I followed my time overflow formula]
3144 - 2400 = 2400 (minus 2400 because time cannot be more than 2359)
How my program works
First plus UTC and offset time
calculatedTime = UTC + offset;
Then under that
if (calculatedTime < 2359) {
calculatedTime = calculatedTime - 2400;
}
I also have another function which checks for overflow time underneath
if (((calculatedTime > 59) && (calculatedTime < 99)) || ((calculatedTime > 159) && (calculatedTime < 199))) {
// All the way to 2359
calculatedTime = calculatedTime - 60 + 100;
}
You need to separate the time into hours and minutes. Then add the time zone offsets to the hours and minutes separately. Handle roll-over. Finally, recombine the hours and minutes into the final answer.
Like this:
int main(void)
{
// inputs
int time = 2359;
int zone = 845;
// separate hours and minutes
int timeHours = time / 100;
int timeMinutes = time % 100;
int zoneHours = zone / 100;
int zoneMinutes = zone % 100;
// add the hours and minutes
int hours = timeHours + zoneHours;
int minutes = timeMinutes + zoneMinutes;
// handle the rollover conditions
if (minutes > 60) {
minutes -= 60;
hours++;
}
if (hours > 24) {
hours -= 24;
}
// recombine the hours and minutes
int adjustedTime = hours * 100 + minutes;
printf("%d\n", adjustedTime);
}
Note that this code only works for timezones with positive offsets. You'll need to figure out how to make it work for negative time zones.
OP's code has various off-by-one errors.
// if (((calculatedTime > 59) && (calculatedTime < 99)) ||
// ((calculatedTime > 159) && (calculatedTime < 199))) {
if (((calculatedTime > 59) && (calculatedTime < 100)) ||
((calculatedTime > 159) && (calculatedTime < 200))) {
// if (hours > 24) {
// hours -= 24;
// }
if (hours >= 24) {
hours -= 24;
}
Also code has more clarity using values like 60, 100
if (((calculatedTime >= 60) && (calculatedTime < 100)) ||
((calculatedTime >= 60*2) && (calculatedTime < 100*2))) {
Yet OP's approach fails with negative numbers.
To cope with positive and negative time values, split the "hhmm" time into a hours and minutes. Look for conditions of "minute" overflow. I recommend 2 helper functions to split and combine results.
#include <stdio.h>
#include <stdlib.h>
void hhmm_split(int hhmm, int *hour, int *min) {
*hour = hhmm / 100;
*min = hhmm % 100;
}
/* `min` may be outside the primary range of (-60 ... 60) */
int hhmm_combine(int hour, int min) {
hour += min / 60;
min %= 60;
if (hour < 0 && min > 0) {
min -= 60;
hour++;
} else if (hour > 0 && min < 0) {
min += 60;
hour--;
}
hour %= 24;
return hour * 100 + min;
}
Test code
void hhmm_add(int t1, int t2) {
int t1_hh, t1_mm, t2_hh, t2_mm;
hhmm_split(t1, &t1_hh, &t1_mm);
hhmm_split(t2, &t2_hh, &t2_mm);
int sum = hhmm_combine(t1_hh + t2_hh, t1_mm + t2_mm);
printf("t1:% 05d + t2:% 05d = sum:% 05d\n", t1, t2, sum);
}
int main(void) {
hhmm_add(2359, 845);
hhmm_add(2359, -845);
hhmm_add(-2359, 845);
hhmm_add(-2359, -845);
}
Output:
t1: 2359 + t2: 0845 = sum: 0844
t1: 2359 + t2:-0845 = sum: 1514
t1:-2359 + t2: 0845 = sum:-1514
t1:-2359 + t2:-0845 = sum:-0844
In the following code example (which compiles and runs):
typedef struct BASIC_TIME {
int hh;
int mm;
int ss;
} BasicTime_t;
typedef struct DEVICE {
// id, settings, etc
BasicTime_t last_checked;
BasicTime_t check_interval;
} Device_t;
BasicTime_t GetTimeNow(void) {
BasicTime_t now;
// Code to get real-time - differs from platform to platform
// Edge case for this example:
now.hh = 23;
now.mm = 55;
now.ss = 00;
return now;
}
int TimeGrEq(BasicTime_t a, BasicTime_t b) {
// is time a >= time b (i.e. is a later than b) ?
// Question - is there a more elegant way to write this function?
if (a.hh < b.hh) {
return 0;
}
if (a.hh > b.hh) {
return 1;
} else { // must be same hour
if (a.mm > b.mm) {
return 1;
}
if (a.mm < b.mm) {
return 0;
} else { //must be same minute
if (a.ss > b.ss) {
return 1;
}
if (a.ss < b.ss) {
return 0;
} else { // must be the same time!
return 1;
}
}
}
}
BasicTime_t AddTime (BasicTime_t t1, BasicTime_t t2) {
BasicTime_t result;
// Question is there an elegant way to do this?
result.hh = t1.hh + t2.hh;
result.mm = t1.mm + t2.mm;
result.ss = t1.ss + t2.ss;
if (result.ss >= 60) {
result.ss = result.ss % 60;
result.mm++;
}
if (result.mm >= 60) {
result.mm = result.mm % 60;
result.hh++;
}
if (result.hh >= 24) {
result.hh = result.hh % 24;
//We loose any day carry when crossing midnight
//unless we add another variable
}
return result;
}
void ReadDevice(Device_t device) {
//code to read and log data from the device -
//e.g. a temperature sensor
device.last_checked = GetTimeNow();
printf("Device Checked - Next Should be 10 Minutes From Now\n");
}
int IsItTime(BasicTime_t last_checked, BasicTime_t interval) {
BasicTime_t now = GetTimeNow();
BasicTime_t next = AddTime(last_checked, interval);
if (TimeGrEq(now, next)) {
return 1;
}
return 0;
}
int main(void) {
Device_t sensor;
// to illustrate an edge case example:
sensor.last_checked.hh = 23;
sensor.last_checked.mm = 53;
sensor.last_checked.ss = 0;
sensor.check_interval.hh = 0;
sensor.check_interval.mm = 10;
sensor.check_interval.ss = 0;
while(1) {
if (IsItTime(sensor.last_checked, sensor.check_interval)) {
// In this edge case IsItTime will evaluate TRUE in error
// Question - In ANSI C is there a smart / best practice
// way to detect midnight roll-over in a custom time
// struct without extra day flags or variables?
// Question - How should the test be "debounced" given
// that the loop will execute many times during
// the 1 second interval (is it possible to do it
// without adding further "done" flags that have to
// be cleared later?)
ReadDevice (sensor);
}
}
return -1;
}
In ANSI C is there a smart / best practice way to detect midnight roll-over in a custom time struct without extra day flags or variables?
Question - How should the test be "debounced" given that the loop will execute many times during the 1 second interval (is it possible to do it without adding further "done" flags that have to be cleared later?
How can the time operations code be improved - see inline comments?
Definitely use time_t with an epoch reference. As a 32 bit value in seconds from the reference time it allows > < >= and <= expressions to be language native rather than needing special treatment.
For a schedule that may start and finish in the same day, or may start today and finish tomorrow (or start yesterday and finish today), and is only described in terms of 24 hour time, there are 6 possible patterns to consider with reference to now : as illustrated and extensively commented in the following code:
.
void ScheduleOperate(BlockNode *b) {
tm* now_tm;
tm* temp_tm;
time_t start;
time_t end;
time_t zero_today;
time_t now;
time_t temp;
temp = time(NULL);
temp_tm = localtime(&temp);
temp_tm->tm_hour = 0;
temp_tm->tm_min = 0;
temp_tm->tm_sec = 0;
zero_today = mktime(temp_tm);
now = time(NULL);
now_tm = localtime(&now);
uint8_t target_state = UINT8_INIT;
uint8_t today_num = now_tm->tm_wday;
uint8_t yesterday_num = ((today_num - 1) + 7) % 7;
switch (b->block_type) {
case SCH_START_STOP: {
// convert start and end times to time_t values
start = zero_today + b->settings.sch.time_start;
end = zero_today + b->settings.sch.time_end;
// Determine the pattern - a schedule contained within today (end >= start) or one that
// crosses midnight (end < start).
if (end >= start) { //schedule contained within this 24hr period
// is today an active day?
//XXX align day num conversion
if (b->settings.sch.days[today_num] == 1) {
// Could be in 1 of 3 periods
// 1 - before start time (start > now && end >= now)
// 2 - during the active period (start < now && end >= now)
// 3 - after the active period (start < now && end < now)
if (start > now && end >= now) target_state = 0;
if (start <= now && end > now) target_state = 1;
if (start <= now && end < now) target_state = 0;
}
} else {
if (end < start) {
//schedule must cross midnight
// Could be in 1 of 3 periods
// 1 - yesterday was active and it started yesterday and is still running
// 2 - if it was active yesterday it is now finished, and not yet time to start again
// 3 - in the next active period that will continue past the next midnight
// was yesterday an active day? (ie. active period started yesterday)
if (b->settings.sch.days[yesterday_num] == 1) {
// start an active period from yesterday that should be still running
if (start >= now && end > now) target_state = 1;
// time to turn it off?
if (start >= now && end < now) target_state = 0;
}
// is today active?
if (b->settings.sch.days[today_num]) {
if (start <= now && end < now) target_state = 1;
}
}
}
if (target_state == 1 && b->active == 0) { //all conditions met, go active
b->active = 1;
b->last_update = now;
EventMsg(b->block_id, E_ACT);
}
if (target_state == 0 && b->active == 1) { //deact
b->active = 0;
b->last_update = now;
EventMsg(b->block_id, E_DEACT);
}
break;
}
I am currently trying to create a program where the user gives two values (times, hh:mm:ss) and gets the difference between the two times. This works, if one would only use 12h formats; however, using the 24h format is a must.
My current time struct looks like the following:
typedef struct time {
int hours;
int minutes;
int seconds;
} time;
And my current function to calculate the difference looks like this:
time calculateTimeDiff(time time1, time time2) {
time timeResult;
timeResult.hours = time1.hours - time2.hours;
if(time1.minutes != 00 && time2.minutes != 00) {
timeResult.minutes = time1.minutes - time2.minutes;
}
else {
timeResult.minutes = 00;
}
if(time1.seconds != 00 && time2.seconds != 00) {
timeResult.seconds = time1.seconds - time2.seconds;
}
else {
timeResult.seconds = 00;
}
while(timeResult.seconds > 60) {
timeResult.seconds -= 60;
timeResult.minutes += 1;
}
while(timeResult.minutes > 60) {
timeResult.minutes -= 60;
timeResult.hours += 1;
}
return timeResult;
}
My attempts to support the 24h format have been to add 12 hours to the time if the hours "exceed" the 12 hour format, and to divide the time by two (haven't been far from complete shots in the dark, just to see what works and what wouldn't work). However, this has only resulted in getting incorrect results.
Any and all answers appreciated!
How to get the time difference between two times (24h format)
Although code could use many if-then-else's as in OP's code, it would be simple to convert the h:m:s time into seconds, subtract, and convert back to h:m:s. So I recommend a re-write:
typedef struct time {
int hours;
int minutes;
int seconds;
} time;
long time_sec(time t) {
return (t.hours * 60L + t.minutes)*60 + t.seconds;
}
time sec_time(long s) {
time t;
t.hours = s / 3600;
s %= 3600;
t.minutes = s / 60;
t.seconds = s %= 60;
return t;
}
time calculateTimeDiff(time time1, time time2) {
long t1 = time_sec(time1);
long t2 = time_sec(time2);
long diff = t1 - t2;
return sec_time(diff);
}
#include <stdio.h>
void test(time t1, time t2) {
printf("t1: %3d:%3d:%3d, ", t1.hours, t1. minutes, t1.seconds);
printf("t2: %3d:%3d:%3d, ", t2.hours, t2. minutes, t2.seconds);
time t3 = calculateTimeDiff(t1, t2);
printf("t1-t2: %3d:%3d:%3d, ", t3.hours, t3. minutes, t3.seconds);
t3 = calculateTimeDiff(t2, t1);
printf("t2-t1: %3d:%3d:%3d\n", t3.hours, t3. minutes, t3.seconds);
}
int main(void) {
test((time){14,00,00}, (time){13,00,00});
test((time){22,00,00}, (time){04,00,00});
}
Output
t1: 14: 0: 0, t2: 13: 0: 0, t1-t2: 1: 0: 0, t2-t1: -1: 0: 0
t1: 22: 0: 0, t2: 4: 0: 0, t1-t2: 18: 0: 0, t2-t1: -18: 0: 0
Note that the difference may result in negative values for the members of time returned in calculateTimeDiff().
You can change to time structure instead of both start and end time integer value
#include<iostream>
using namespace std;
void difftime(int startTime, int iRecordEndTime)
{
int duration_min = 0;
cout<<"iRecordEndTime = "<<iRecordEndTime<<endl;
cout<<"startTime = "<<startTime<<endl;
if ( (iRecordEndTime/100 < startTime/100) || ((iRecordEndTime/100 == startTime/100) && (iRecordEndTime%100 <= startTime%100)) )
{
duration_min = ((iRecordEndTime / 100 + 24)*60 + iRecordEndTime%100) - ((startTime/100)*60 + startTime%100);
}
else
{
duration_min = (iRecordEndTime / 100 - startTime/100)*60 + (iRecordEndTime%100 - startTime%100);
}
cout<<"duration_min = "<<duration_min<<endl;
}
int main()
{
cout<<"enter the start time Hour:Minutes xxxx"<<endl;
int startTime{0};
cin>>startTime;
cout<<"enter the End time Hour:Minutes xxxx"<<endl;
int iRecordEndTime{0};
cin>>iRecordEndTime;
difftime(startTime, iRecordEndTime );
}
Output
enter the start time Hour:Minutes xxxx\
2300\
enter the End time Hour:Minutes xxxx\
0000\
iRecordEndTime = 0\
startTime = 2300\
duration_min = 60