Can't get the boolean logic right, help!


#1

Hi all, I’ve been struggling with this code for some time now but I’m out of ideas and need help!

Basically, I have a program that gets uses a webhook to get weather data from Weather Underground. Specifically in this particular instance, I’m getting the astronomy information to get the sunset and sunrise time for each day so I can turn on a relay when the time is between sunset and sunrise. I’m using the sparktime library to set the variables “hour” and “minute” each time I loop through the code, and I have confirmed that it’s updating correctly. I’ve also been able to confirm via Publish events that I’m storing the correct sunrise and sunset hour and minute variables. My problem is simply that I can’t seem to get the code to set my “daytime” variable TRUE when the current time of day is between sunrise and sunset, and FALSE when between sunset and sunrise.

Here’s my current iteration:

if ((hour <= sunriseHour && minute <= sunriseMinute) || (hour >= sunsetHour && minute >= sunsetMinute))  
{
    daytime = false;
}
else {
    daytime = true;
}

Previously, I did the opposite:

//if ((hour >= sunriseHour && minute >= sunriseMinute) && (hour <= sunsetHour && minute <= sunsetMinute)) {
//    daytime = true;
//}
//else {
//    daytime = false;
//}

This had a strange side effect though: whenever the current MINUTE (not hour) was between the sunsetMinute and the sunriseMinute, daytime would be set to true. As sunset has been falling around the 45th minute and sunrise around the 15th minute here lately, I would see my output turn on for this odd 30-ish minute period. I’m wondering if perhaps this statement was evaluating as true because both conditions were false?

Apparently my boolean logic skills in C are rusty so I could use more eyes on this. Please let me know if I’ve left out any important details or if you want to see the complete code. Thanks!

-Dan


#2

I haven’t looked too close into your code since I usually tell people to spare themselves the hassle and just convert hh:mm:ss timestamps to seconds and just do this

  // start and stop need to be on same day otherwise extra care needs to be taken
  const int startSec = hStart*3600 + mStart*60 + sStart;
  const int stopSec  = hStop*3600  + mStop*60  + sStop;
  int localSec = Time.local() % 86400;  // keep the seconds of current day and drop date info
  
  if (startSec <= localSec && localSec < stopSec) {
    // time is between range
  }
  else {
    // time is outside range
  }

#3

both conditions include the edge state, so try eliminating the = comparisions from either the right or left of the || expression.


#4

That won’t do either since for the case (hour != sunriseHour && hour != sunsetHour) the minute needs to be taken out of the condition as it becomes irrelevant but will render your result wrong when taken into account.

You can write that out as extra conditions but it becomes rather cumbersome and messy IMHO.


Illustration:

if ((hour <= 6 && minute <= 15) || (hour >= 20 && minute >= 45))

The first term should render to true for 5:20 but it won’t just as 21:15 wouldn’t render the second term true although it should (= or not doesn’t change the fact)

The working condition would be tho’

if (hour < sunriseHour || hour == sunriseHour && minute < sunriseMinute || hour == sunsetHour && minute > sunsetMinute || hour > sunsetHour)

But as said, I find that :stuck_out_tongue_closed_eyes:

Doesn’t this look a lot better?

  daytime = (sunrise <= now && now < sunset);  // current time between sunrise and sunset?

#5

How is

hour < sunriseHour || hour == sunriseHour

different than

hour <= sunriseHour

? I would think that they would evaluate the same way, unless I’m misunderstanding how the less than or equal to expression evaluates in C versus mathematics.


#6

The problem here is that Weather Underground gives me the time in 24 hour format, so I would have to convert that to, say, Unix time…not sure how to do that?


#7

You need to consider && has precedence before || hence I can leave the parentheses out (similar to multiplications/divisions have precedence before additions/subtractions)

It is not

hour < sunriseHour || hour == sunriseHour 

but

(hour < sunriseHour) || (hour == sunriseHour && minute < sunriseMinute)

Where is the problem with that?
You have hours and minutes seperated already, so just add them up as shown above.

Just drop the const if these times change.


#8

Got it, I follow now. I’m trying the long and ugly method first, but I may give the unix time option a shot (note that I’m using actual unix time from NTP; I know it’s not a difficult conversion from hh:mm, I just didn’t want to add more conversions than I needed).


#9

converting to a timestamp is a synch with the right tools:

time_t tmConvert_t(int YYYY, byte MM, byte DD, byte hh, byte mm, byte ss)
{
  struct tm t;
  t.tm_year = YYYY-1900;
  t.tm_mon = MM - 1;
  t.tm_mday = DD;
  t.tm_hour = hh;
  t.tm_min = mm;
  t.tm_sec = ss;
  t.tm_isdst = 0;
  time_t t_of_day = mktime(&t);
  return t_of_day;
}

and you can do a simple test like this:

bool isDay(int riseHour, int riseMinute, int setHour, int setMinute)
{
  	time_t now_time = Time.local();
  	time_t rise_time = tmConvert_t(Time.year(now_time), Time.month(now_time), Time.day(now_time), riseHour, riseMinute, 0);
  	time_t set_time = tmConvert_t(Time.year(now_time), Time.month(now_time), Time.day(now_time), setHour,  setMinute, 0);
	return (now_time > rise_time && now_time < set_time);
}

#10

That’s a pretty slick method! The sparktime library I’m using actually returns unix time by default, so I could just directly set now_time to be the unix time returned from sparktime (no time_t conversion needed for that step). I may just give this a shot!


#11

Hmm, I’m not quite sure how this is any easier than what I suggested :confused:

Nevermind