Javascript or Python - How do I figure out if it's night or day?
Asked Answered
H

4

22

any idea how I figure out if it's currently night/day or sunrise/dawn based on time and location of the user?

I haven't found anything useful that I could use within either the client or backend.

What makes it tricky is the hour doesn't necessarily define if it is night and day, this depends pretty much on the year, month, day, hour and geo coordinates.


For clarification... to emulate something like this.

enter image description here


A way to approximate this would be very useful as well.


Hope that someone can help!

Hydrophilic answered 23/2, 2013 at 19:15 Comment(6)
Can you please define what night and day means? It can be between them and how it is called then?Metre
Night and Day are very fuzzy concepts. Unless you have a criteria in mind that you can use to delineate the two, it can't be solved.Heavensent
@SerbanRazvan: day when sun is above horizion, night when sun is below horizon, sunset/surise when sun is on the horizionHydrophilic
from the dusk till dawn ;) good question by the way, I think google people challenged already on it, case I have skin on gmail which shows me night or day depending on hours, but it is still very much approximated.Grandmotherly
This piqued my interest and I'm bored and I'm going to write a nice JS library for it.Lagunas
possible duplicate of How can I compute sunrise/sunset times?Millan
G
12

Note to Python 3 users: I just tried the code below using Python 3.8.6 and it works in that version, too. I had to convert the print statements into print() function calls, but that was all.

I noticed that the example implementation of tzinfo classes is different from what's in the Python 2 documentation, but using the example tzinfo classes in the tzinfo_example.py file referenced in the latest documentation worked just fine (but so did the older 2.x versions).

You can download a Python 3 version of the sunriseset.py file shown below from here.


You can do as I did and use this public domain Sun.py module to compute the position of the sun relative to positions on the Earth. (Warning: it contains tab characters and assumes tabs are every 8 characters.) It's pretty old, but has continued to work well for me for many years. I made a few superficial modifications to it to be more up-to-date with Python 2.7, such as making the few classes in it new-style, but for the most part it's unchanged.

Here's one module I created, called sunriseset.py, which shows how to use it to calculate the sunrise and sunset times for a specific location given its geographic coordinates and timezone. The referenced timezone module is an implementation of the tzinfo abstract base class described in the datetime module's documentation on tzinfoobjects.

# -*- coding: iso-8859-1 -*-
import datetime
import timezone  # concrete tzinfo subclass based on the Python docs
import math
from Sun import Sun

__all__ = ['getsuninfo', 'Place']

class Place(object):
    def __init__(self, name, coords, tz=timezone.Pacific):
        self.name = name        # string
        self.coords = coords    # tuple (E/W long, N/S lat)
        self.tz = tz            # tzinfo constant

def _hoursmins(hours):
    """Convert floating point decimal time in hours to integer hrs,mins"""
    frac,h = math.modf(hours)
    m = round(frac*60, 0)
    if m == 60: # rounded up to next hour
        h += 1; m = 0
    return int(h),int(m)

def _ymd(date):
    """Return y,m,d from datetime object as tuple"""
    return date.timetuple()[:3]

def getsuninfo(location, date=None):
    """Return local datetime of sunrise, sunset, and length of day in hrs,mins)"""
    if date == None:
        querydate = datetime.date.today()
    else: # date given should be datetime instance
        querydate = date

    args = _ymd(querydate) + location.coords
    utcrise, utcset = Sun().sunRiseSet(*args)
    daylength = Sun().dayLength(*args)
    hrs,mins = _hoursmins(daylength)

    risehour, risemin = _hoursmins(utcrise)
    sethour, setmin   = _hoursmins(utcset)

    # convert times to timedelta values (ie from midnight utc of the date)
    midnight = datetime.datetime(tzinfo=timezone.utc, *_ymd(querydate))
    deltarise = datetime.timedelta(hours=risehour, minutes=risemin)
    utcdatetimerise = midnight+deltarise
    deltaset = datetime.timedelta(hours=sethour, minutes=setmin)
    utcdatetimeset  = midnight+deltaset

    # convert results from UTC time to local time of location
    localrise = utcdatetimerise.astimezone(location.tz)
    localset  = utcdatetimeset.astimezone(location.tz)

    return localrise, localset, hrs, mins

if __name__ == "__main__":
    import datetime, timezone

    def unittest(location, testdate):
        risetime, settime, hrs, mins = getsuninfo(location, testdate)

        print "Location:", location.name
        print "Date:", testdate.strftime("%a %x")
        print risetime.strftime("Sunrise %I:%M %p"), settime.strftime("- Sunset %I:%M %p (%Z)")
        print "daylight: %d:%02d" % (hrs,mins)
        print

    place = Place("My House", (-121.990278, 47.204444), timezone.Pacific)

    # test dates just before and after DST transitions
    print "pre 2007"
    print "========="
    unittest(place, datetime.date(2006, 4, 1))
    unittest(place, datetime.date(2006, 4, 2))
    unittest(place, datetime.date(2006, 10, 28))
    unittest(place, datetime.date(2006, 10, 29))

    print "2007"
    print "========="
    unittest(place, datetime.date(2007, 3, 10))
    unittest(place, datetime.date(2007, 3, 11))
    unittest(place, datetime.date(2007, 11, 3))
    unittest(place, datetime.date(2007, 11, 4))
Gametangium answered 23/2, 2013 at 19:25 Comment(1)
If the link to the Sun.py module in my answer ever breaks, here's another copy.Gametangium
G
11

A concise description of an algorithm to calculate the sunrise and sunset is provided by the United States Naval Observatory, available here:

http://edwilliams.org/sunrise_sunset_algorithm.htm

In addition to providing the date and location, you also need to select a Zenith angle (at which the sun will be considered to have "risen" or "set") - the page linked has several options.


Update

Because the linked page is no longer available, I am quoting its text below. Note that the formulae included are in a pseudo-code-like form, rather than JavaScript.

Source:
    Almanac for Computers, 1990
    published by Nautical Almanac Office
    United States Naval Observatory
    Washington, DC 20392

Inputs:
    day, month, year:      date of sunrise/sunset
    latitude, longitude:   location for sunrise/sunset
    zenith:                Sun's zenith for sunrise/sunset
      offical      = 90 degrees 50'
      civil        = 96 degrees
      nautical     = 102 degrees
      astronomical = 108 degrees

    NOTE: longitude is positive for East and negative for West
        NOTE: the algorithm assumes the use of a calculator with the
        trig functions in "degree" (rather than "radian") mode. Most
        programming languages assume radian arguments, requiring back
        and forth convertions. The factor is 180/pi. So, for instance,
        the equation RA = atan(0.91764 * tan(L)) would be coded as RA
        = (180/pi)*atan(0.91764 * tan((pi/180)*L)) to give a degree
        answer with a degree input for L.


1. first calculate the day of the year

    N1 = floor(275 * month / 9)
    N2 = floor((month + 9) / 12)
    N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3))
    N = N1 - (N2 * N3) + day - 30

2. convert the longitude to hour value and calculate an approximate time

    lngHour = longitude / 15

    if rising time is desired:
      t = N + ((6 - lngHour) / 24)
    if setting time is desired:
      t = N + ((18 - lngHour) / 24)

3. calculate the Sun's mean anomaly

    M = (0.9856 * t) - 3.289

4. calculate the Sun's true longitude

    L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634
    NOTE: L potentially needs to be adjusted into the range [0,360) by adding/subtracting 360

5a. calculate the Sun's right ascension

    RA = atan(0.91764 * tan(L))
    NOTE: RA potentially needs to be adjusted into the range [0,360) by adding/subtracting 360

5b. right ascension value needs to be in the same quadrant as L

    Lquadrant  = (floor( L/90)) * 90
    RAquadrant = (floor(RA/90)) * 90
    RA = RA + (Lquadrant - RAquadrant)

5c. right ascension value needs to be converted into hours

    RA = RA / 15

6. calculate the Sun's declination

    sinDec = 0.39782 * sin(L)
    cosDec = cos(asin(sinDec))

7a. calculate the Sun's local hour angle

    cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude))

    if (cosH >  1) 
      the sun never rises on this location (on the specified date)
    if (cosH < -1)
      the sun never sets on this location (on the specified date)

7b. finish calculating H and convert into hours

    if if rising time is desired:
      H = 360 - acos(cosH)
    if setting time is desired:
      H = acos(cosH)

    H = H / 15

8. calculate local mean time of rising/setting

    T = H + RA - (0.06571 * t) - 6.622

9. adjust back to UTC

    UT = T - lngHour
    NOTE: UT potentially needs to be adjusted into the range [0,24) by adding/subtracting 24

10. convert UT value to local time zone of latitude/longitude

    localT = UT + localOffset
Germinative answered 23/2, 2013 at 19:31 Comment(0)
W
7

PyEphem can be used to calculate the time to the next sunrise and sunset. Building upon a blog post I found and the documentation of rise-set, your problem can be solved as follows. Lets assume I am your user, and my location is Oldenburg (Oldb), Germany.

import ephem

user = ephem.Observer()
user.lat = '53.143889'    # See wikipedia.org/Oldenburg
user.lon = '8.213889'     # See wikipedia.org/Oldenburg
user.elevation = 4        # See wikipedia.org/Oldenburg
user.temp = 20            # current air temperature gathered manually
user.pressure = 1019.5    # current air pressure gathered manually

next_sunrise_datetime = user.next_rising(ephem.Sun()).datetime()
next_sunset_datetime = user.next_setting(ephem.Sun()).datetime()

# If it is daytime, we will see a sunset sooner than a sunrise.
it_is_day = next_sunset_datetime < next_sunrise_datetime
print("It's day." if it_is_day else "It's night.")

# If it is nighttime, we will see a sunrise sooner than a sunset.
it_is_night = next_sunrise_datetime < next_sunset_datetime
print("It's night." if it_is_night else "It's day.")

Notes

  • For some reason lat and lon need to be strings but ephem does not complain if they are floats.
  • For best results, you might want to get the current air temperature and air pressure.

Prerequisites

This should work with at least Python 2.7 (with pip-2.7 install pyephem) and Python 3.2 (with pip-3.2 install ephem).

Make sure to have a network time protocol client running on the system. E.g. on Debian Linux:

$ sudo apt-get install ntp
$ sudo /etc/init.d/ntp start

Make sure to have the correct timezone set on your system. E.g. on Debian Linux:

$ sudo dpkg-reconfigure tzdata
Wiese answered 6/5, 2013 at 18:56 Comment(0)
P
1

You can use prayer api wich contain all data with a great precision about sunset and sunrise and then compare them to the actual time by user localistation , Api Link

You can use this function to determine if is it day or night with just longitude and latitude

CODE

from timezonefinder import TimezoneFinder
import requests
from datetime import datetime, timezone
import pytz

def TimeEstimation(lat,lng):
    '''function to check DAY/NIGHT for a particular localisation'''
    obj = TimezoneFinder()
    result = obj.timezone_at(lng=lng, lat=lat)
    timezone =  pytz.timezone(result)
    hour = str(datetime.now(timezone).hour)
    minute = str(datetime.now(timezone).minute)
    
    actual_time = datetime.strptime(hour+":"+minute,'%H:%M')
    
    #asking salat api to get sunset and sunrise time based on longitude and latitude
    
    response = requests.get("https://api.pray.zone/v2/times/today.json?longitude="+str(lng)+"&latitude="+str(lat)+"&elevation=0")
    api_data = response.json()
    sunset = api_data.get("results").get("datetime")[0].get("times").get("Sunset")
    sunset=datetime.strptime(sunset,'%H:%M')
    
    sunrise = api_data.get("results").get("datetime")[0].get("times").get("Imsak")
    sunrise=datetime.strptime(sunrise,'%H:%M')

    if actual_time >= sunset or actual_time <= sunrise:
        print("is night")
        return(False)

    else:
        print("is day")
        return(True)
Piglet answered 21/10, 2021 at 12:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.