1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
extern crate chrono;
use chrono::{Date,NaiveDate,Utc,DateTime,Duration};
const HOUR_ANGLE_TO_MINUTES_FACTOR:f64 = 4.0;
pub fn sun_times(date: Date<Utc>, latitude:f64, longitude:f64, elevation:f64) -> (DateTime<Utc>,DateTime<Utc>){
const ARGUMENT_OF_PERIHELION: f64 = 102.9372;
let elevation_correction = -2.076*(elevation.sqrt())/60.0;
let jan_2000 = Date::<Utc>::from_utc(NaiveDate::from_ymd(2000,1,1),Utc);
let time_since_2000:Duration = date.signed_duration_since(jan_2000);
let mean_solar_time = (time_since_2000.num_days() as f64) + 0.0008 - (longitude/360.0);
let solar_mean_anomaly = (357.5291 + 0.98560028 * mean_solar_time) % 360.0;
let center = 1.9148*solar_mean_anomaly.to_radians().sin()+0.0200*(2.0*solar_mean_anomaly).to_radians().sin() + 0.0003*(3.0*solar_mean_anomaly).to_radians().sin();
let ecliptic_longitude = (solar_mean_anomaly+center+180.0+ARGUMENT_OF_PERIHELION) % 360.0;
let declination = (ecliptic_longitude.to_radians().sin() * (23.44f64).to_radians().sin()).asin();
let hour_angle = (((-0.83 + elevation_correction).to_radians().sin()-(latitude.to_radians().sin()*declination.sin()))/(latitude.to_radians().cos()*declination.cos())).acos().to_degrees();
let solar_transit = mean_solar_time + 0.0053 * solar_mean_anomaly.to_radians().sin() - 0.0069 * (2.0*ecliptic_longitude).to_radians().sin();
let solar_transit_date = jan_2000 + Duration::days(solar_transit.round() as i64);
let solar_transit_date = solar_transit_date.and_hms(12,0,0) + Duration::seconds( ((solar_transit * 24.0 * 60.0 * 60.0) % (24.0 * 60.0 * 60.0)).round() as i64 );
let minutes = Duration::minutes((hour_angle*HOUR_ANGLE_TO_MINUTES_FACTOR).round() as i64);
let set = solar_transit_date + minutes;
let rise = solar_transit_date - minutes;
(rise,set)
}