Skip to content

Instantly share code, notes, and snippets.

@goodtune
Created August 10, 2017 08:10
Show Gist options
  • Save goodtune/0d3bb4bb17d0fed7660d8094cd2a57fc to your computer and use it in GitHub Desktop.
Save goodtune/0d3bb4bb17d0fed7660d8094cd2a57fc to your computer and use it in GitHub Desktop.
Calculate suitable playing hours for sport for any point on the planet at any point in time.

daylight.py

This requires solartime==0.1b.

See test_daylight.py for an example.

from collections import namedtuple
import pytz
from dateutil.relativedelta import relativedelta
from dateutil.rrule import MINUTELY, rrule
from first import first
from solartime import SolarTime
PlayableHours = namedtuple('PlayableHours', 'start stop')
class SportTime(SolarTime):
def hours_of_play_utc(self, date, latitude, longitude, am=None, pm=None):
"""
Calculate dawn time in the UTC timezone.
:param date: Date to calculate for.
:type date: datetime.date
:param latitude: Latitude - Northern latitudes should be positive
:type latitude: float
:param longitude: Longitude - Eastern longitudes should be positive
:type longitude: float
:param am: Elevation when it becomes light enough (default 18)
:type am: float
:param pm: Elevation when it becomes too dark (default 10)
:type pm: float
:rtype: :class:`PlayableHours`
"""
if am is None:
am = 18
if pm is None:
pm = 10
def _light_enough_to_start(t):
return self.solar_elevation(t, latitude, longitude) > am
def _too_dark_to_continue(t):
return self.solar_elevation(t, latitude, longitude) < pm
# Some time after sunrise, the sun will be high enough in the sky that
# we'll be able to play.
sunrise = self.sunrise_utc(date, latitude, longitude)
sunrise += relativedelta(microsecond=0, second=0, minutes=1)
start = first(
rrule(MINUTELY, dtstart=sunrise),
key=_light_enough_to_start,
)
# Some time before sunset, the sun will be low enough in the sky that
# we'll want to stop playing if we don't have artificial lighting.
sunset = self.sunset_utc(date, latitude, longitude)
sunset += relativedelta(microsecond=0, second=0)
stop = first(
rrule(MINUTELY, dtstart=sunset, interval=-1),
key=_too_dark_to_continue,
)
return PlayableHours(start, stop)
def hours_of_play(self, date, latitude, longitude, am=None, pm=None,
tz=pytz.utc):
"""
Calculate dawn time in the UTC timezone.
:param date: Date to calculate for.
:type date: datetime.date
:param latitude: Latitude - Northern latitudes should be positive
:type latitude: float
:param longitude: Longitude - Eastern longitudes should be positive
:type longitude: float
:param am: Elevation when it becomes light enough (default 18)
:type am: float
:param pm: Elevation when it becomes too dark (default 10)
:type pm: float
:param tz: Time zone to use in return value
:type tz: timezone or str
:rtype: :class:`PlayableHours`
"""
if isinstance(tz, basestring):
tz = pytz.timezone(tz)
start, stop = self.hours_of_play_utc(date, latitude, longitude, am, pm)
return PlayableHours(start.astimezone(tz), stop.astimezone(tz))
from datetime import date
from dateutil.rrule import DAILY, rrule
from daylight import SportTime
sun = SportTime()
# Youth Touch World Cup
for d in rrule(DAILY, dtstart=date(2018, 8, 8), count=4):
hours = sun.hours_of_play(d, 2.896206, 101.684743, tz='Asia/Kuala_Lumpur')
print u"YTWC\t%s\t%s" % hours
# Touch World Cup
for d in rrule(DAILY, dtstart=date(2019, 4, 29), count=6):
hours = sun.hours_of_play(d, 2.896206, 101.684743, tz='Asia/Kuala_Lumpur')
print u"TWC\t%s\t%s" % hours
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment