Reputation: 4771
I'm wondering if there is a python function/module that calculates the local time after midnight (or local solar time) given the UTC time and longitude? It doesn't need to take into account daylight saving time.
Thanks in advance.
Upvotes: 13
Views: 15100
Reputation: 4774
For a very simple function & very very approximated local time: Time variation goes from -12h to +12h and longitude goes from -180 to 180. Then:
import datetime as dt
def localTimeApprox(myDateTime, longitude):
"""Returns local hour approximation"""
return myDateTime+dt.timedelta(hours=(longitude*12/180))
Sample calling: localTimeApprox(dt.datetime(2014, 7, 9, 20, 00, 00), -75)
Returns: datetime.datetime(2014, 7, 9, 15, 0)
Upvotes: 3
Reputation: 414207
Using ephem
's sidereal_time()
method:
import ephem # pip install pyephem (on Python 2)
# pip install ephem (on Python 3)
def solartime(observer, sun=ephem.Sun()):
sun.compute(observer)
# sidereal time == ra (right ascension) is the highest point (noon)
hour_angle = observer.sidereal_time() - sun.ra
return ephem.hours(hour_angle + ephem.hours('12:00')).norm # norm for 24h
Note: ephem.hours
is a float number that represents an angle in radians and converts to/from a string as "hh:mm:ss.ff".
For comparison, here's the "utc + longitude" formula:
import math
from datetime import timedelta
def ul_time(observer):
utc_dt = observer.date.datetime()
longitude = observer.long
return utc_dt + timedelta(hours=longitude / math.pi * 12)
from datetime import datetime
# "solar time" for some other cities
for name in ['Los Angeles', 'New York', 'London',
'Paris', 'Moscow', 'Beijing', 'Tokyo']:
city = ephem.city(name)
print("%-11s %11s %s" % (name, solartime(city),
ul_time(city).strftime('%T')))
# set date, longitude manually
o = ephem.Observer()
o.date = datetime(2012, 4, 15, 1, 0, 2) # some utc time
o.long = '00:00:00.0' # longitude (you could also use a float (radians) here)
print("%s %s" % (solartime(o), ul_time(o).strftime('%T')))
Los Angeles 14:59:34.11 14:44:30
New York 17:56:31.27 17:41:27
London 22:52:02.04 22:36:58
Paris 23:01:56.56 22:46:53
Moscow 1:23:00.33 01:07:57
Beijing 6:38:09.53 06:23:06
Tokyo 8:11:17.81 07:56:15
1:00:00.10 01:00:01
Upvotes: 14
Reputation: 6606
Or if you want to go even shorter, you could use NOAA's low-accuracy equations:
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
from math import pi, cos, sin
def solar_time(dt, longit):
return ha
def main():
if len(sys.argv) != 4:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
gamma = 2 * pi / 365 * (dt.timetuple().tm_yday - 1 + float(dt.hour - 12) / 24)
eqtime = 229.18 * (0.000075 + 0.001868 * cos(gamma) - 0.032077 * sin(gamma) \
- 0.014615 * cos(2 * gamma) - 0.040849 * sin(2 * gamma))
decl = 0.006918 - 0.399912 * cos(gamma) + 0.070257 * sin(gamma) \
- 0.006758 * cos(2 * gamma) + 0.000907 * sin(2 * gamma) \
- 0.002697 * cos(3 * gamma) + 0.00148 * sin(3 * gamma)
time_offset = eqtime + 4 * longit
tst = dt.hour * 60 + dt.minute + dt.second / 60 + time_offset
solar_time = datetime.combine(dt.date(), time(0)) + timedelta(minutes=tst)
print solar_time
if __name__ == '__main__':
main()
Upvotes: 9
Reputation: 6606
Trying again, with ephem. I included latitude and elevation as arguments, but they are not needed of course. You can just call them 0
for your purposes.
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
import ephem
def hour_angle(dt, longit, latit, elev):
obs = ephem.Observer()
obs.date = dt.strftime('%Y/%m/%d %H:%M:%S')
obs.lon = longit
obs.lat = latit
obs.elevation = elev
sun = ephem.Sun()
sun.compute(obs)
# get right ascention
ra = ephem.degrees(sun.g_ra) - 2 * ephem.pi
# get sidereal time at greenwich (AA ch12)
jd = ephem.julian_date(dt)
t = (jd - 2451545.0) / 36525
theta = 280.46061837 + 360.98564736629 * (jd - 2451545) \
+ .000387933 * t**2 - t**3 / 38710000
# hour angle (AA ch13)
ha = (theta + longit - ra * 180 / ephem.pi) % 360
return ha
def main():
if len(sys.argv) != 6:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude] [latitude] [elev]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
latit = float(sys.argv[4])
elev = float(sys.argv[5])
# get hour angle
ha = hour_angle(dt, longit, latit, elev)
# convert hour angle to timedelta from noon
days = ha / 360
if days > 0.5:
days -= 0.5
td = timedelta(days=days)
# make solar time
solar_time = datetime.combine(dt.date(), time(12)) + td
print solar_time
if __name__ == '__main__':
main()
Upvotes: 2
Reputation: 6606
I took a look at Jean Meeus' Astronomical Algorithms. I think you might be asking for local hour angle, which can be expressed in time (0-24hr), degrees (0-360) or radians (0-2pi).
I'm guessing you can do this with ephem. But just for the heck of it, here's some python:
#!/usr/local/bin/python
import sys
from datetime import datetime, time, timedelta
from math import pi, sin, cos, atan2, asin
# helpful constant
DEG_TO_RAD = pi / 180
# hardcode difference between Dynamical Time and Universal Time
# delta_T = TD - UT
# This comes from IERS Bulletin A
# ftp://maia.usno.navy.mil/ser7/ser7.dat
DELTA = 35.0
def coords(yr, mon, day):
# @input year (int)
# @input month (int)
# @input day (float)
# @output right ascention, in radians (float)
# @output declination, in radians (float)
# get julian day (AA ch7)
day += DELTA / 60 / 60 / 24 # use dynamical time
if mon <= 2:
yr -= 1
mon += 12
a = yr / 100
b = 2 - a + a / 4
jd = int(365.25 * (yr + 4716)) + int(30.6 * (mon + 1)) + day + b - 1524.5
# get sidereal time at greenwich (AA ch12)
t = (jd - 2451545.0) / 36525
# Calculate mean equinox of date (degrees)
l = 280.46646 + 36000.76983 * t + 0.0003032 * t**2
while (l > 360):
l -= 360
while (l < 0):
l += 360
# Calculate mean anomoly of sun (degrees)
m = 357.52911 + 35999.05029 * t - 0.0001537 * t**2
# Calculate eccentricity of Earth's orbit
e = 0.016708634 - 0.000042037 * t - 0.0000001267 * t**2
# Calculate sun's equation of center (degrees)
c = (1.914602 - 0.004817 * t - .000014 * t**2) * sin(m * DEG_TO_RAD) \
+ (0.019993 - .000101 * t) * sin(2 * m * DEG_TO_RAD) \
+ 0.000289 * sin(3 * m * DEG_TO_RAD)
# Calculate the sun's radius vector (AU)
o = l + c # sun's true longitude (degrees)
v = m + c # sun's true anomoly (degrees)
r = (1.000001018 * (1 - e**2)) / (1 + e * cos(v * DEG_TO_RAD))
# Calculate right ascension & declination
seconds = 21.448 - t * (46.8150 + t * (0.00059 - t * 0.001813))
e0 = 23 + (26 + (seconds / 60)) / 60
ra = atan2(cos(e0 * DEG_TO_RAD) * sin(o * DEG_TO_RAD), cos(o * DEG_TO_RAD)) # (radians)
decl = asin(sin(e0 * DEG_TO_RAD) * sin(o * DEG_TO_RAD)) # (radians)
return ra, decl
def hour_angle(dt, longit):
# @input UTC time (datetime)
# @input longitude (float, negative west of Greenwich)
# @output hour angle, in degrees (float)
# get gregorian time including fractional day
y = dt.year
m = dt.month
d = dt.day + ((dt.second / 60.0 + dt.minute) / 60 + dt.hour) / 24.0
# get right ascention
ra, _ = coords(y, m, d)
# get julian day (AA ch7)
if m <= 2:
y -= 1
m += 12
a = y / 100
b = 2 - a + a / 4
jd = int(365.25 * (y + 4716)) + int(30.6 * (m + 1)) + d + b - 1524.5
# get sidereal time at greenwich (AA ch12)
t = (jd - 2451545.0) / 36525
theta = 280.46061837 + 360.98564736629 * (jd - 2451545) \
+ .000387933 * t**2 - t**3 / 38710000
# hour angle (AA ch13)
ha = (theta + longit - ra / DEG_TO_RAD) % 360
return ha
def main():
if len(sys.argv) != 4:
print 'Usage: hour_angle.py [YYYY/MM/DD] [HH:MM:SS] [longitude]'
sys.exit()
else:
dt = datetime.strptime(sys.argv[1] + ' ' + sys.argv[2], '%Y/%m/%d %H:%M:%S')
longit = float(sys.argv[3])
ha = hour_angle(dt, longit)
# convert hour angle to timedelta from noon
days = ha / 360
if days > 0.5:
days -= 0.5
td = timedelta(days=days)
# make solar time
solar_time = datetime.combine(dt.date(), time(12)) + td
print solar_time
if __name__ == '__main__':
main()
Upvotes: 4