【问题标题】:Sunrise and Sunset time in PythonPython的日出日落时间
【发布时间】:2016-12-23 12:21:36
【问题描述】:

我目前正在开展一个项目,该项目会在触发某些与光相关的活动时通知用户。我已经完成了与光有关的部分。因此,我需要找到一种有效的方法来在 python 中检索日出和日落时间,因为整个脚本都是用 python 编写的。我知道有几个其他语言的库,我想知道在 python 中最方便的方法是什么。

我想应该是这样的:

if(sunrise<T<sunset) and (light<threshold):
    notifyUser()

我很感激这里的任何帮助,祝你好运。

【问题讨论】:

  • 注意;是多余的,最好写成if (sunrise &lt; T &lt; sunset) and (light &lt; threshold):
  • 真实数据。我只是想对我试图在那里编写的伪代码给出一个想法。感谢您的反馈!

标签: python datetime time raspberry-pi


【解决方案1】:

您也可以尝试使用suntime。下面是他们文档中的一个示例:

import datetime
from suntime import Sun, SunTimeException

latitude = 51.21
longitude = 21.01

sun = Sun(latitude, longitude)

# Get today's sunrise and sunset in UTC
today_sr = sun.get_sunrise_time()
today_ss = sun.get_sunset_time()
print('Today at Warsaw the sun raised at {} and get down at {} UTC'.
      format(today_sr.strftime('%H:%M'), today_ss.strftime('%H:%M')))

# On a special date in your machine's local time zone
abd = datetime.date(2014, 10, 3)
abd_sr = sun.get_local_sunrise_time(abd)
abd_ss = sun.get_local_sunset_time(abd)
print('On {} the sun at Warsaw raised at {} and get down at {}.'.
      format(abd, abd_sr.strftime('%H:%M'), abd_ss.strftime('%H:%M')))

【讨论】:

    【解决方案2】:

    进一步改进@Wojciech Jakubas answer,这是基准(省略时区):

    # boilerplate
    from datetime import date, datetime, timezone, timedelta
    import pytz
    import time
    from suntime import Sun, SunTimeException
    from suntimes import SunTimes
    import sunriset
    import astral, astral.sun
    
    latitude = 6.2088
    longitude = 106.8456
    altitude = 0
    tz_name = 'Asia/Jakarta'
    for_date = date(2021, 4, 6)
    
    %%timeit
    # print('====== suntime ======')
    sun = Sun(latitude, longitude)
    today_sr = sun.get_sunrise_time(for_date)
    today_ss = sun.get_sunset_time(for_date)
    # 20.3 µs ± 90.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    %%timeit
    # print('====== suntimes ======')
    sun2 = SunTimes(longitude=longitude, latitude=latitude, altitude=altitude)
    today_sr = sun2.riseutc(for_date)
    today_ss = sun2.setutc(for_date)
    # 83 µs ± 261 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    %%timeit
    # print('====== sunriset ======')
    df = sunriset.to_pandas(for_date, latitude, longitude, 0, 1)
    for index, row in df.iterrows():
        today_sr = row['Sunrise']
        today_ss = row['Sunset']
        break
    # 28.7 ms ± 126 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %%timeit
    # print('====== astral ======')
    l = astral.LocationInfo('Custom Name', 'My Region', tz_name, latitude, longitude)
    today_sr = astral.sun.sunrise(l.observer, date=for_date)
    today_sr = astral.sun.sunset(l.observer, date=for_date)
    # 64.3 µs ± 292 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    

    要转换为本地 time zone (UTC+X),请使用:

    # with known region name
    tz_name = 'Asia/Jakarta'
    tz = pytz.timezone(tz_name)
    today_sr.astimezone(tz)
    
    # with known time different
    time_different = 7
    tz = datetime.timezone(datetime.timedelta(hours=time_different))
    today_sr.astimezone(tz)
    

    结论:

    1. 使用suntime
    2. 如果您确实需要一年的数据并且不关心速度,请尝试sunriset,因为它会输出一年。
    3. sunriset 需要从源代码中手动编辑才能解决单次
    4. sunriset 输出在timedelta 中,因此无法直接使用.astimezone 进行转换。

    【讨论】:

      【解决方案3】:

      这也可以使用skyfield 库来完成。这是一个使用当前版本 (1.39) 的简短示例,改编自 the documentation

      from skyfield import almanac, api
      
      ts = api.load.timescale()
      eph = api.load('de421.bsp')
      
      # Location
      bluffton = api.wgs84.latlon(+40.8939, -83.8917)
      
      # Times between which to look for sunrises and sunsets
      t0 = ts.utc(2018, 9, 12, 4)
      t1 = ts.utc(2018, 9, 13, 4)
      
      times, is_sunrise = almanac.find_discrete(t0, t1, almanac.sunrise_sunset(eph, bluffton))
      

      time 将包含t0t1 之间的日出/日落时间,如果是日出,is_sunrise 中的对应值将为 1,如果是日落,则为 0。

      【讨论】:

        【解决方案4】:

        我比较了几个包(suntime、suntimes、sunriset、astral)以及它们返回的时间日出和日落时间。它们都返回本地时间,但您也可以轻松获得 UTC 时间。 结果如下:

        from datetime import date, datetime, timezone, timedelta
        import pytz
        import time
        from suntime import Sun, SunTimeException
        from suntimes import SunTimes
        import sunriset
        import astral, astral.sun
        
        latitude = 52.0691667
        longitude = 19.4805556
        altitude = 0
        tz_poland = pytz.timezone('Europe/Warsaw')
        tz_name = 'Europe/Warsaw'
        for_date = date(2021, 4, 6)
        print('====== suntime ======')
        abd = for_date
        sun = Sun(latitude, longitude)
        today_sr = sun.get_sunrise_time()
        today_ss = sun.get_sunset_time()
        print(today_sr.astimezone(tz_poland))
        print(today_ss.astimezone(tz_poland))
        print('====== suntimes ======')
        sun2 = SunTimes(longitude=longitude, latitude=latitude, altitude=altitude)
        day = datetime(for_date.year, for_date.month, for_date.day)
        print(sun2.risewhere(day, tz_name))
        print(sun2.setwhere(day, tz_name))
        print('====== sunriset ======')
        local = datetime.now()
        utc = datetime.utcnow()
        local_tz = float(((local - utc).days * 86400 + round((local - utc).seconds, -1))/3600)
        number_of_years = 1
        start_date = for_date
        df = sunriset.to_pandas(start_date, latitude, longitude, 2, number_of_years)
        for index, row in df.iterrows():
            print(row['Sunrise'])
            print(row['Sunset'])
            break
        print('====== astral ======')
        l = astral.LocationInfo('Custom Name', 'My Region', tz_name, latitude, longitude)
        s = astral.sun.sun(l.observer, date=for_date)
        print(s['sunrise'].astimezone(tz_poland))
        print(s['sunset'].astimezone(tz_poland))
        

        然后返回:

        ====== suntime ======
        2021-04-06 06:05:00+02:00
        2021-04-06 19:16:00+02:00
        ====== suntimes ======
        2021-04-06 06:04:34.000553+02:00
        2021-04-06 19:17:16.000613+02:00
        ====== sunriset ======
        0 days 06:02:52.093465
        0 days 19:16:49.892350
        ====== astral ======
        2021-04-06 06:03:39.792229+02:00
        2021-04-06 19:17:01.188463+02:00
        

        请注意只有 suntimes 包支持高度。

        【讨论】:

        • 有人想添加%%timeit 基准以处理多个日期时间数据吗?
        • 在我的 answer 上完成基准测试
        【解决方案5】:

        上面的Astral 包示例似乎过时了。

        下面是Astral v2.2 的示例,用于加利福尼亚州圣何塞机场位置。

        首先,设置观察者的位置:

        from astral import LocationInfo
        loc = LocationInfo(name='SJC', region='CA, USA', timezone='America/Los_Angeles',
                           latitude=37.3713439, longitude=-121.944675)
        print(loc)
        # LocationInfo(name='SJC', region='CA, USA', timezone='America/Los_Angeles',
        #   latitude=37.3713439, longitude=-121.944675)
        print(loc.observer)
        # Observer(latitude=37.3713439, longitude=-121.944675, elevation=0.0)
        

        注意:

        • 只有纬度、经度和时区很重要。
        • 名称和地区只是标签。

        接下来,计算该观察者在所需日期(例如,下面的 2021-01-15)的太阳信息:

        import datetime
        from astral.sun import sun
        s = sun(loc.observer, date=datetime.date(2021, 1, 15), tzinfo=loc.timezone)
        for key in ['dawn', 'dusk', 'noon', 'sunrise', 'sunset']:
            print(f'{key:10s}:', s[key])
        

        输出:

        dawn      : 2021-01-15 06:52:04.342105-08:00
        dusk      : 2021-01-15 17:42:59.471441-08:00
        noon      : 2021-01-15 12:17:05-08:00
        sunrise   : 2021-01-15 07:21:04.877697-08:00
        sunset    : 2021-01-15 17:13:58.467348-08:00
        

        注意事项:

        • 如果未指定时区,则默认为 UTC。
        • 正午是太阳正午——太阳在观察者位置穿过子午线的时间。
        • Astral 是 NOAA 发布的 Excel sheets 的实现。

        【讨论】:

          【解决方案6】:

          查看astral。这是一个稍作修改的example from their docs

          >>> from astral import Astral
          >>> city_name = 'London'
          >>> a = Astral()
          >>> a.solar_depression = 'civil'
          >>> city = a[city_name]
          >>> sun = city.sun(date=datetime.date(2009, 4, 22), local=True)
          
          >>> if (sun['sunrise'] < T < sun['sunset']) and (light < threshold):
          >>>    notifyUser()
          

          如果您使用类似此示例的内容,请记住将city_name 和提供的日期更改为city.sun

          【讨论】:

          • 那么,Astral 以哪种格式返回这些时间?比如定义后:now = datetime.datetime.now();我可以使用 if (sun['sunrise']
          • 这使用规定的日期。如果日期取自时间序列的 DateTime 索引怎么办?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-16
          • 1970-01-01
          • 2010-10-16
          • 1970-01-01
          相关资源
          最近更新 更多