9

I have looked at the examples here on using ephem to calculate sunrise and sunset, and have that working great.

I get in trouble when I try to calculate the midpoint between those two times. Here's what I have:

import datetime
import ephem

o = ephem.Observer()
o.lat, o.long, o.date = '37.0625', '-95.677068', datetime.datetime.utcnow()
sun = ephem.Sun(o)
print "sunrise:", o.previous_rising(sun), "UTC"
print "sunset:",o.next_setting(sun), "UTC"
print "noon:",datetime.timedelta((o.next_setting(sun)-o.previous_rising(sun))/2)

I get:

sunrise: 2010/11/2 12:47:40 UTC
sunset: 2010/11/2 23:24:25 UTC
noon: 5:18:22.679044

That's where I'm stuck. I'm a python beginner and frankly not much of a programmer in general.

Any suggestions would be most welcome!

Peter Nazarenko
  • 411
  • 1
  • 7
  • 16
Lorin Rivers
  • 7,912
  • 1
  • 18
  • 9

4 Answers4

9

Solar noon is not the mean of sunrise and sunset (see equation of time for the explanation). The ephem package has methods for getting transit times which you should use instead:

>>> import ephem
>>> o = ephem.Observer()
>>> o.lat, o.long = '37.0625', '-95.677068'
>>> sun = ephem.Sun()
>>> sunrise = o.previous_rising(sun, start=ephem.now())
>>> noon = o.next_transit(sun, start=sunrise)
>>> sunset = o.next_setting(sun, start=noon)
>>> noon
2010/11/6 18:06:21
>>> ephem.date((sunrise + sunset) / 2)
2010/11/6 18:06:08

Note that noon today is 13 seconds later (at your location) than the mean of sunrise and sunset.

(The line of code ephem.date((sunrise + sunset) / 2) shows how you could easily manipulate dates in the ephem package, if it were the right thing to do.)

Gareth Rees
  • 64,967
  • 9
  • 133
  • 163
  • Your sunrise calculation doesn't "work" if you're far enough north (or south) that the sun didn't rise today... (e.g. today is July 8., but last sunrise was May 17 :-) – thebjorn Jul 08 '11 at 10:37
  • Yes, I see the problem: `ephem.AlwaysUpError: 'Sun' is still above the horizon at 2011/7/8 00:04:58` – Gareth Rees Jul 08 '11 at 10:50
2

If using ephem is not a hard requirement, I recently wrote a library called daylight which has a native function for solar noon directly.

>>> import daylight, pytz
>>> from datetime import datetime
>>> sun = daylight.Sunclock(37.0625, -95.677068)
>>> t = sun.solar_noon(datetime.utcnow().timestamp())
>>> datetime.utcfromtimestamp(t)
datetime.datetime(2020, 6, 4, 18, 20, 54)

Not that above time is in UTC. For a more appropriate timezone, say EST, you can do:

>>> tz = pytz.timezone('EST')
>>> tz_offset = tz.utcoffset(datetime.utcnow()).total_seconds()/3600
>>> sun = daylight.Sunclock(37.0625, -95.677068, tz_offset)
>>> t = sun.solar_noon(datetime.utcnow().timestamp())
>>> datetime.utcfromtimestamp(t).astimezone(tz)
datetime.datetime(2020, 6, 3, 7, 50, 54, tzinfo=<StaticTzInfo 'EST'>)

or do this for a particular date, say May 21st 2020

>>> t = sun.solar_noon(datetime(2020, 5, 21).timestamp())
>>> datetime.utcfromtimestamp(t)
datetime.datetime(2020, 5, 20, 18, 19, 14)
chaitan94
  • 2,153
  • 1
  • 18
  • 19
0

I realize that this was answered long ago. But from the answer for those who may use any code or don't quite understand Python, there is the simple explanation for the purpose of the Equation of Time. Your mean solar transit (noon) occurs at your longitudinal location. This means that knowing your longitude you can find your mean solar transit just by dividing your longitude by 15.0 and subtract that value from 12, which will be a result in GMT or UTC if you prefer, to give hours decimal time. Your true solar transit is a result of subtracting the equation of time from the mean. Normally you would need to compute this anyway to get sunrise and sunset times as is shown in the wikipedia formula. But thanks for the python package info as I'm having a bit of trouble with sunpy package. There is a great program on bitbucket here https://bitbucket.org/cmcqueen1975/sundials/wiki/Home

Douglas G. Allen
  • 2,203
  • 21
  • 20
0

Average of two numbers is sum of the numbers divided by two, not by dividing length of day light by two. That could also work if you add that to the o.previous_rising(sun), but that should be same as taking direct average (should not matter that we are averageing datetime objects)

Tony Veijalainen
  • 5,447
  • 23
  • 31