Skip to content

Commit 1be4ca6

Browse files
updating calculate_daylight for processing tables of timestamps
1 parent a9cb466 commit 1be4ca6

File tree

2 files changed

+30
-32
lines changed

2 files changed

+30
-32
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ requires = ["setuptools>=60", "setuptools-scm>=8.0", "wheel"]
33

44
[project]
55
name = "sun-angles"
6-
version = "1.4.0"
6+
version = "1.5.0"
77
description = "calculates solar zenith and azimuth and daylight hours"
88
readme = "README.md"
99
authors = [
@@ -16,7 +16,7 @@ classifiers = [
1616
dependencies = [
1717
"numpy",
1818
"rasters",
19-
"solar-apparent-time"
19+
"solar-apparent-time>=1.4.0"
2020
]
2121

2222
requires-python = ">=3.10"

sun_angles/calculate_daylight.py

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,45 @@
55
from datetime import datetime
66
from dateutil import parser
77
import pandas as pd
8+
9+
from solar_apparent_time import solar_day_of_year_for_longitude
10+
811
from .SHA_deg_from_DOY_lat import SHA_deg_from_DOY_lat
912
from .daylight_from_SHA import daylight_from_SHA
1013

1114
def calculate_daylight(
15+
time_UTC: Union[datetime, str, list, np.ndarray] = None,
16+
geometry: SpatialGeometry = None,
1217
day_of_year: Union[Raster, np.ndarray, int] = None,
1318
lat: Union[Raster, np.ndarray, float] = None,
14-
SHA_deg: Union[Raster, np.ndarray, float] = None,
15-
time_UTC: Union[datetime, str, list, np.ndarray] = None,
16-
geometry: SpatialGeometry = None
19+
lon: Union[Raster, np.ndarray, float] = None,
20+
SHA_deg: Union[Raster, np.ndarray, float] = None
1721
) -> Union[Raster, np.ndarray]:
1822
"""
1923
Calculate the number of daylight hours for a given day and location.
2024
21-
This function is highly flexible and can be used in several ways depending on the information you have:
25+
This function flexibly computes daylight hours based on the information provided:
2226
23-
- If you already know the sunrise hour angle (`SHA_deg`), provide it directly and the function will return the daylight hours for that value.
24-
- If you do not provide `SHA_deg`, the function will compute it using the day of year (`day_of_year`) and latitude (`lat`).
25-
- If you do not provide `lat` but do provide a `geometry` object, the function will extract the latitude from `geometry.lat`.
26-
- If you do not provide `day_of_year` but do provide `time_UTC`, the function will convert the provided UTC time(s) to day of year. `time_UTC` can be a single datetime, a string, or an array/list of datetimes or strings.
27+
- If `SHA_deg` (sunrise hour angle in degrees) is provided, it is used directly to compute daylight hours.
28+
- If `SHA_deg` is not provided, it is calculated from `day_of_year` and `lat` (latitude in degrees).
29+
- If `lat` is not provided but a `geometry` object is given, latitude is extracted from `geometry.lat`.
30+
- If `day_of_year` is not provided but `time_UTC` is given, the function converts the UTC time(s) to day of year, accounting for longitude if available.
2731
2832
Parameters
2933
----------
34+
time_UTC : Union[datetime, str, list, np.ndarray], optional
35+
Datetime(s) in UTC. Used to determine `day_of_year` if not provided. Accepts a single datetime, a string, or an array/list of datetimes or strings.
36+
Example: `time_UTC=['2025-06-21', '2025-12-21']` or `time_UTC=datetime(2025, 6, 21)`
37+
geometry : SpatialGeometry, optional
38+
Geometry object containing latitude (and optionally longitude) information. Used if `lat` or `lon` are not provided.
3039
day_of_year : Union[Raster, np.ndarray, int], optional
3140
Day of year (1-366). Can be a Raster, numpy array, or integer. If not provided, will be inferred from `time_UTC` if available.
3241
lat : Union[Raster, np.ndarray, float], optional
3342
Latitude in degrees. Can be a Raster, numpy array, or float. If not provided, will be inferred from `geometry` if available.
43+
lon : Union[Raster, np.ndarray, float], optional
44+
Longitude in degrees. Can be a Raster, numpy array, or float. If not provided, will be inferred from `geometry` if available.
3445
SHA_deg : Union[Raster, np.ndarray, float], optional
3546
Sunrise hour angle in degrees. If provided, it is used directly and other parameters are ignored.
36-
time_UTC : datetime, str, list, or np.ndarray, optional
37-
Datetime(s) in UTC. Used to determine `day_of_year` if `day_of_year` is not provided. Accepts a single datetime, a string, or an array/list of datetimes or strings.
38-
Example: `time_UTC=['2025-06-21', '2025-12-21']` or `time_UTC=datetime(2025, 6, 21)`
39-
geometry : SpatialGeometry, optional
40-
Geometry object containing latitude information. If `lat` is not provided, latitude will be extracted from `geometry.lat`.
4147
4248
Returns
4349
-------
@@ -61,24 +67,16 @@ def calculate_daylight(
6167
# If latitude is not provided, try to extract from geometry
6268
if lat is None and geometry is not None:
6369
lat = geometry.lat
70+
71+
if lon is None and geometry is not None:
72+
lon = geometry.lon
73+
74+
if day_of_year is None:
75+
day_of_year = solar_day_of_year_for_longitude(
76+
time_UTC=time_UTC,
77+
lon=lon
78+
)
6479

65-
# If DOY is not provided, try to extract from time_UTC
66-
if day_of_year is None and time_UTC is not None:
67-
def to_doy(val):
68-
if isinstance(val, str):
69-
val = parser.parse(val)
70-
return int(pd.Timestamp(val).dayofyear)
71-
72-
# Handle array-like or single value
73-
if isinstance(time_UTC, (list, np.ndarray)):
74-
day_of_year = np.array([to_doy(t) for t in time_UTC])
75-
else:
76-
day_of_year = to_doy(time_UTC)
77-
78-
# Ensure day_of_year is a numpy array if it's a list (for downstream math)
79-
if isinstance(day_of_year, list):
80-
day_of_year = np.array(day_of_year)
81-
# Compute SHA_deg using DOY and latitude
8280
SHA_deg = SHA_deg_from_DOY_lat(day_of_year, lat)
8381

8482
# Compute daylight hours from SHA_deg

0 commit comments

Comments
 (0)