2

I'm checking time about every minute, but don't have a good way to check whether I'm in this 'on' mode of operation. I want to be 'on' 2hours before daylight up until 1 hour before sunset. If I continuously check using next_rising() and next_setting(), the moment the sun rises, my logic seems to fail because after that point it starts computing the sunrise for tomorrow. My is_daytime() is broken.

def is_daytime():                                                               
  """                                                                           
  Returns whether we should operate in the 'daytime' mode.  Note that this      
  mode is shifted earlier to begin before sunrise and end before sunset.      
  """                                                                           
  # Get the localized hour of the day                                           
  now = datetime.datetime.now()                                                 

  # Get the next sunrise/sunset                                                 
  here.date = now                                           
  sunrise = ephem.localtime(here.next_rising(ephem.Sun))                        
  sunset = ephem.localtime(here.next_setting(ephem.Sun))                        

  sunrise_shift = datetime.timedelta(hours=START_BEFORE_SUNSRISE_HR)     
  sunset_shift = datetime.timedelta(hours=END_BEFORE_SUNSET_HR)          

  # Return whether it is some amount of time before sunrise AND sunset                      
  return ((sunrise - now) < sunrise_shift) and ((sunset - now) < sunset_shift)  

Edit: Updated after reading solution

# Dependencies
import time
import datetime
import pytz
import ephem

# Choose your location for sunrise/sunset calculations                          
MY_TIMEZONE = "America/Los_Angeles"
MY_LONGITUDE = '37.7833'  # +N
MY_LATITUDE = '-122.4167' # +E
MY_ELEVATION = 0          # meters   

# Choose when to start and stop relative to sunrise and sunset                  
START_BEFORE_SUNSRISE_HR = 1                                             
END_BEFORE_SUNSET_HR = 1 

here = ephem.Observer()                                                                                                          

def is_daytime():
  """                                                                           
  Returns whether we should operate in the 'daytime' mode.  Note that this      
  mode is shifted earlier to begin before sunrise and end before sunset.       

  Assumes sunset NEVER comes after midnight                                     
  """                                                                           
  # Get the localized hour of the day                                           
  now = datetime.datetime.now()                                                 

  # Get the next sunrise/sunset                                                 
  here.date = now                                                               
  next_sunrise = ephem.localtime(here.next_rising(ephem.Sun()))                 
  next_sunset = ephem.localtime(here.next_setting(ephem.Sun()))                 

  sunrise_shift = datetime.timedelta(hours=START_BEFORE_SUNSRISE_HR)     
  sunset_shift = datetime.timedelta(hours=END_BEFORE_SUNSET_HR)          

  # If it's daytime                                                             
  if (next_sunset < next_sunrise):                                              
    return (now < (next_sunset - sunset_shift))                                 
  # Otherwise it's nighttime                                                    
  else:                                                                         
    return ((next_sunrise - sunrise_shift) < now)    


def main():                                                                     
  # Configure the timezone                                                      
  pytz.timezone(MY_TIMEZONE)                                                                 

  # Configure the ephem object
  here.lat = MY_LATITUDE                                          
  here.lon = MY_LONGITUDE                                                   
  here.elevation = MY_ELEVATION 

  while True:
    if is_daytime():
      print "It's daytime!"                                              
    time.sleep(60)                                                              

if __name__ == '__main__':                                                      
  main()
tarabyte
  • 17,837
  • 15
  • 76
  • 117
  • Please [edit] your question to include the complete output (including the **full text** of any errors/tracebacks you are getting), the desired output, and an [MCVE](http://stackoverflow.com/help/mcve) of how you are calling this function. As it stands now, this question is very unclear. – MattDMo Sep 28 '14 at 23:07

1 Answers1

3

the moment the sun rises, my logic seems to fail because after that point it starts computing the sunrise for tomorrow.

Think through the logic. What are the cases?

  • Before both sunrise and sunset. In that case, you only need to check <= sunrise-2H; the check for sunset-1H is irrelevant, but harmless.
  • Between sunrise and sunset. In that case, you only need to check <= sunset-1H; the check for sunrise-2H is not only irrelevant, but harmful.
  • After both sunrise and sunset. This is actually the same as the first case. (In San Francisco, sunset never comes after midnight and sunrise never comes before, but if you want your code to work in, say, Oulo, it might be a problem.)

So, how do you know which case you're in? Simple. If sunset > sunrise, you're in case 1 or 3; just check sunrise-2H; otherwise, you're in case 2, just check sunset-1H.

What if you go even farther north than Oulo? For example, in Rovaniemi, in early of June, the next sunset is a month away. Does that mean you want your program to stay on all month? Or that you want to pick an arbitrary time to start up and shut down (e.g., start 2 hours before "midnight" and end an hour after)? Whatever rule you come up with, I think ephem has enough data for you to write it. Or, if you don't know, at least test the code and see what rule it is applying, so you can document that. (I'm guessing people who live up there are used to looking at the docs for time-related programs like this…)

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • true, true. i appreciate the thoughts and realize this question is less about computer science than it is just plain old common sense! i was originally looking for this to be encapsulated in the ephem module somehow but could not find anything in their docs – tarabyte Sep 29 '14 at 00:03
  • @tarabyte: Well, most problems aren't about inventing or researching a clever algorithm, they're just about common sense (and turning common sense into code). Anyway, I've never used `ephem`, but I can guess why they provide `next_rising(datetime)` instead of `today_rising(date)`. Even without cities where sunrise/sunset crosses midnight, you can easily have a sunrise at, say, 01:55, in which case "2 hours before sunrise today" is actually yesterday, which makes your logic more complicated. – abarnert Sep 29 '14 at 00:57
  • @tarabyte: PS, I like the way you turned my explanation into "it's daytime" vs. "it's nighttime". Speaking of common sense, how did I miss that much simpler way of putting it? – abarnert Sep 29 '14 at 00:58
  • @tarabyte: note: make sure to handle `AlwaysUpError`, `NeverUpError` exceptions – jfs Oct 03 '14 at 06:59