home ~ projects ~ socials

Get The Sunrise And Sunset Times For A Specific Location In Rust Including Daylight Saving Time

---
[dependencies]
chrono = "0.4.39"
chrono-tz = "0.10.0"
lazy_static = "1.5.0"
sunrise = "1.0.1"
tzf-rs = "0.4.9"
---

use chrono::DateTime;
use chrono_tz::Tz;
use lazy_static::lazy_static;
use sunrise::sunrise_sunset;
use tzf_rs::DefaultFinder;

lazy_static! {
  static ref FINDER: DefaultFinder = DefaultFinder::new();
}

fn main() {
  let lat = 30.332184;
  let long = -81.655647;
  println!(
    "Daylight Time Sunrise Example: {}", 
    sunrise_for_lat_long(lat, long, 2024, 11, 2)
  );
  println!(
    "Daylight Time Sunset Example: {}", 
    sunset_for_lat_long(lat, long, 2024, 11, 2)
  );
  println!(
    "Standard Sunrise Time Example: {}", 
    sunrise_for_lat_long(lat, long, 2024, 11, 3)
  );
  println!(
    "Standard Sunset Time Example: {}", 
    sunset_for_lat_long(lat, long, 2024, 11, 3)
  );
}

fn sunrise_for_lat_long(lat: f64, long: f64, year: i32, month: u32, day: u32) -> DateTime<Tz> {
  let tz: Tz = FINDER.get_tz_name(long, lat).parse().unwrap();
  let (sunrise_ts, _) = sunrise_sunset(
    lat, long, year, month, day
  );
  let dt = DateTime::from_timestamp(sunrise_ts, 0).expect("invalid timestamp").with_timezone(&tz);
  dt
}

fn sunset_for_lat_long(lat: f64, long: f64, year: i32, month: u32, day: u32) -> DateTime<Tz> {
  let tz: Tz = FINDER.get_tz_name(long, lat).parse().unwrap();
  let (_, sunset_ts) = sunrise_sunset(
    lat, long, year, month, day
  );
  let dt = DateTime::from_timestamp(sunset_ts, 0).expect("invalid timestamp").with_timezone(&tz);
  dt
}
Output:
Daylight Time Sunrise Example: 2024-11-02 07:42:04 EDT
Daylight Time Sunset Example: 2024-11-02 18:38:12 EDT
Standard Sunrise Time Example: 2024-11-03 06:42:52 EST
Standard Sunset Time Example: 2024-11-03 17:37:26 EST

Notes

  • This code panics if there's an issue (i.e. error handling could be improved)
  • Handles daylight saving time changes
  • From what I can tell it's not necessary to convert the date into UTC before running the sunrise_sunset function. There might be a use case though based on some time zones where that would be necessary, but I haven't figured out that edge case yet if it exists.
-- end of line --

References

  • The crate that does the main date handling

  • The crate that allows using named time zones for chrono's DateTime

  • A macro crate that helps speed up searching for time zones in chrono_tz when multiple searches are needed

  • The crate that does the calculation for sunrise and sunset given a specific lat/long

  • The create the provides time zones for specific lat/long coordinates