【问题标题】:Javascript or Python - How do I figure out if it's night or day?Javascript 或 Python - 我如何确定是白天还是黑夜?
【发布时间】:2013-02-09 06:31:05
【问题描述】:

知道如何根据用户的时间和位置确定当前是夜晚/白天还是日出/黎明?

我没有发现任何可以在客户端或后端使用的有用的东西。

棘手的是,小时不一定定义是白天还是黑夜,这在很大程度上取决于年、月、日、小时和地理坐标。


为了澄清......模仿这样的东西。


一种近似此值的方法也非常有用。


希望有人能帮忙!

【问题讨论】:

  • 你能定义一下白天和黑夜的含义吗?可以在它们之间,然后怎么称呼呢?
  • 夜晚和白天是非常模糊的概念。除非您心中有一个可以用来界定这两者的标准,否则它是无法解决的。
  • 从黄昏到黎明 ;) 顺便说一句,这是个好问题,我认为谷歌的人已经对此提出了挑战,如果我在 gmail 上有皮肤,它会根据时间显示我的夜晚或白天,但它仍然是非常接近。
  • 这引起了我的兴趣,我很无聊,我要为它写一个漂亮的 JS 库。

标签: javascript python geolocation timezone


【解决方案1】:

您可以使用包含所有关于日落和日出的精确数据的祈祷 API,然后通过用户本地化将它们与实际时间进行比较,Api Link

您可以使用此功能仅通过经度和纬度来确定是白天还是黑夜

代码

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)

【讨论】:

    【解决方案2】:

    Python 3 用户注意事项:我刚刚使用 Python 3.8.6 尝试了以下代码,它也适用于该版本。我不得不将print 语句转换为print() 函数调用,但仅此而已。

    我注意到 tzinfo 类的示例实现与 Python 2 文档中的不同,但使用 tzinfo_example.py 文件中的示例 tzinfo 类在 latest documentation 中引用的工作很好(但是这样旧的 2.x 版本)。

    您可以从here 下载下面显示的sunriseset.py 文件的 Python 3 版本。


    您可以像我一样使用这个公共域Sun.py 模块来计算太阳相对于地球位置的位置。 (警告:它包含制表符并假定制表符是每 8 个字符。)它已经很老了,但多年来一直对我很好。我对其进行了一些表面上的修改以使其与 Python 2.7 保持同步,例如使其中的少数类成为新样式,但大部分都没有改变。

    这是我创建的一个模块,名为sunriseset.py,它展示了如何使用它来计算特定位置的日出和日落时间,因为它的地理坐标和时区。引用的timezone 模块是datetime 模块文档tzinfoobjects 中描述的tzinfo 抽象基类的实现。

    # -*- 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))
    

    【讨论】:

    • 如果我的答案中指向 Sun.py 模块的链接断开,here's 另一个副本。
    【解决方案3】:

    美国海军天文台提供了计算日出和日落的算法的简明描述,可在此处获得:

    http://edwilliams.org/sunrise_sunset_algorithm.htm

    除了提供日期和位置外,您还需要选择天顶角(太阳将被视为“升起”或“落下”的天顶角)- 链接的页面有多个选项。


    更新

    由于链接页面不再可用,我在下面引用其文本。请注意,所包含的公式是类似伪代码的形式,而不是 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
    

    【讨论】:

      【解决方案4】:

      PyEphem 可用于计算下一次日出和日落的时间。在a blog post I foundthe documentation of rise-set 的基础上,您的问题可以解决如下。假设我是你的用户,我的位置是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.")
      

      注意事项

      • 出于某种原因,latlon 需要是字符串,但如果它们是浮点数,ephem 不会抱怨。
      • 为获得最佳结果,您可能需要获取当前气温和气压。

      先决条件

      这应该至少适用于 Python 2.7(使用 pip-2.7 install pyephem)和 Python 3.2(使用 pip-3.2 install ephem)。

      确保在系统上运行网络时间协议客户端。例如。在 Debian Linux 上:

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

      确保在您的系统上设置了正确的时区。例如。在 Debian Linux 上:

      $ sudo dpkg-reconfigure tzdata
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-11-07
        • 1970-01-01
        • 1970-01-01
        • 2021-04-14
        • 2012-04-04
        • 2021-07-19
        • 2021-12-27
        相关资源
        最近更新 更多