{"id":32887362,"url":"https://github.com/geocrystal/sun_times","last_synced_at":"2026-07-02T09:31:44.545Z","repository":{"id":323137067,"uuid":"1089826951","full_name":"geocrystal/sun_times","owner":"geocrystal","description":"Simple Crystal library for calculating sunrise and sunset given latitude, longitude, and date","archived":false,"fork":false,"pushed_at":"2025-12-26T10:56:36.000Z","size":1294,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-27T22:42:32.226Z","etag":null,"topics":["astronomy","crystal","geolocation","solar","sunrise","sunset","timezone","twilight"],"latest_commit_sha":null,"homepage":"https://geocrystal.github.io/sun_times/","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/geocrystal.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-04T21:40:20.000Z","updated_at":"2025-12-26T10:56:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/geocrystal/sun_times","commit_stats":null,"previous_names":["geocrystal/sun_times"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/geocrystal/sun_times","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geocrystal%2Fsun_times","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geocrystal%2Fsun_times/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geocrystal%2Fsun_times/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geocrystal%2Fsun_times/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/geocrystal","download_url":"https://codeload.github.com/geocrystal/sun_times/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/geocrystal%2Fsun_times/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35041996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-02T02:00:06.368Z","response_time":173,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["astronomy","crystal","geolocation","solar","sunrise","sunset","timezone","twilight"],"created_at":"2025-11-09T22:00:42.694Z","updated_at":"2026-07-02T09:31:44.524Z","avatar_url":"https://github.com/geocrystal.png","language":"Crystal","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ☀️ sun_times\n\n[![Crystal CI](https://github.com/geocrystal/sun_times/actions/workflows/crystal.yml/badge.svg)](https://github.com/geocrystal/sun_times/actions/workflows/crystal.yml)\n[![GitHub release](https://img.shields.io/github/release/geocrystal/sun_times.svg)](https://github.com/geocrystal/sun_times/releases)\n[![Docs](https://img.shields.io/badge/docs-available-brightgreen.svg)](https://geocrystal.github.io/sun_times/)\n[![License](https://img.shields.io/github/license/geocrystal/sun_times.svg)](https://github.com/geocrystal/sun_times/blob/main/LICENSE)\n\nA simple [Crystal](https://crystal-lang.org) library for calculating 🌅 **sunrise** and 🌇 **sunset** given latitude, longitude, and date based on\nthe [NOAA Solar Calculator](https://gml.noaa.gov/grad/solcalc/) and formulas from\nJean Meeus' _Astronomical Algorithms (2nd Edition, 1998)_.\n\n## 📊 Accuracy\n\nThe library's astronomical constants and algorithms follow authoritative sources (NOAA, JPL, Meeus) and were verified manually against the NOAA Solar Calculator (\u003chttps://gml.noaa.gov/grad/solcalc/\u003e).\n\nVerification\n\n- A validation script (`samples/accuracy_check.cr`) compares calculated sunrise, sunset and solar noon against NOAA's apparent times for several locations.\n- The comparison was performed manually by running the script and checking the NOAA site for reference values.\n\nResults\n\n- Calculated times are within the margin of error and are effectively identical to NOAA's apparent times. Differences are typically under 1 minute.\n- Tested locations include New York, London, Tokyo and Sydney. Example: New York on 2025-11-05 matched NOAA apparent sunrise/sunset closely (06:31 / 16:47 local).\n\n## 📦 Installation\n\n1. Add the dependency to your `shard.yml`:\n\n   ```yaml\n   dependencies:\n     sun_times:\n       github: geocrystal/sun_times\n   ```\n\n2. Run `shards install`\n\n## 💻 Usage\n\n```crystal\nrequire \"sun_times\"\n\n# Example: Lviv, Ukraine\n# SunTime.new(latitude : Float64, longitude : Float64)\nsun = SunTimes::SunTime.new(49.8419, 24.0311)\nlocation = Time::Location.load(\"Europe/Kyiv\")\ndate = Time.local\n\nastronomical_dawn_time = sun.astronomical_dawn(date, location)\nnautical_dawn_time = sun.nautical_dawn(date, location)\ncivil_dawn_time = sun.civil_dawn(date, location)\nsunrise_time = sun.sunrise(date, location)\nsolar_noon_time = sun.solar_noon(date, location)\nsunset_time = sun.sunset(date, location)\ncivil_dusk_time = sun.civil_dusk(date, location)\nnautical_dusk_time = sun.nautical_dusk(date, location)\nastronomical_dusk_time = sun.astronomical_dusk(date, location)\ndaylight_length = sun.daylight_length(date, location)\n\nputs \"Timezone: #{location}\"\nputs \"Now:      #{date}\"\nputs\nputs \"=== Twilight Periods ===\"\nputs \"Astronomical dawn:  #{astronomical_dawn_time}\"\nputs \"Nautical dawn:      #{nautical_dawn_time}\"\nputs \"Civil dawn:         #{civil_dawn_time}\"\nputs \"Sunrise:            #{sunrise_time}\"\nputs \"Solar noon:         #{solar_noon_time}\"\nputs \"Sunset:             #{sunset_time}\"\nputs \"Civil dusk:         #{civil_dusk_time}\"\nputs \"Nautical dusk:      #{nautical_dusk_time}\"\nputs \"Astronomical dusk:  #{astronomical_dusk_time}\"\nputs \"\"\nputs \"=== Daylight ===\"\nputs \"Daylight:      #{daylight_length}\"\n```\n\nOutput:\n\n```\nTimezone: Europe/Kyiv\nNow:      2025-11-05 14:05:23 +02:00\n\n=== Twilight Periods ===\nAstronomical dawn:  2025-11-05 05:30:09 +02:00\nNautical dawn:      2025-11-05 06:07:40 +02:00\nCivil dawn:         2025-11-05 06:46:02 +02:00\nSunrise:            2025-11-05 07:20:19 +02:00\nSolar noon:         2025-11-05 12:07:24 +02:00\nSunset:             2025-11-05 16:54:29 +02:00\nCivil dusk:         2025-11-05 17:28:46 +02:00\nNautical dusk:      2025-11-05 18:07:08 +02:00\nAstronomical dusk:  2025-11-05 18:44:39 +02:00\n\n=== Daylight ===\nDaylight:      9h 34m 9s\n```\n\n![readme](https://github.com/geocrystal/sun_times/blob/main/samples/readme.png?raw=true)\n\nYou can also get all solar events as a NamedTuple using the `events` method, which is useful for serialization (e.g., JSON): 📋\n\n```crystal\nrequire \"json\"\nrequire \"sun_times\"\n\nsun = SunTimes::SunTime.new(49.8419, 24.0311)\nlocation = Time::Location.load(\"Europe/Kyiv\")\ndate = Time.local\n\nsun.events(date, location).to_json\n```\n\nOutput\n\n```json\n{\n  \"astronomical_dawn\":\"2025-11-05T05:30:09+02:00\",\n  \"nautical_dawn\":\"2025-11-05T06:07:40+02:00\",\n  \"civil_dawn\":\"2025-11-05T06:46:02+02:00\",\n  \"sunrise\":\"2025-11-05T07:20:19+02:00\",\n  \"solar_noon\":\"2025-11-05T12:07:24+02:00\",\n  \"sunset\":\"2025-11-05T16:54:29+02:00\",\n  \"civil_dusk\":\"2025-11-05T17:28:46+02:00\",\n  \"nautical_dusk\":\"2025-11-05T18:07:08+02:00\",\n  \"astronomical_dusk\":\"2025-11-05T18:44:39+02:00\"\n}\n```\n\n### 🌆 Twilight Periods\n\nThe library supports three types of twilight periods:\n\n- **Civil twilight** 🌅 (sun 6° below horizon): Enough light for most outdoor activities\n- **Nautical twilight** ⚓ (sun 12° below horizon): Horizon is still visible for navigation\n- **Astronomical twilight** 🔭 (sun 18° below horizon): Sky is dark enough for astronomical observations\n\n![image](https://github.com/geocrystal/sun_times/blob/main/samples/twilight_subcategories.png?raw=true)\n\n## 🚀 Performance\n\nThe library is fast as the speed of light! ⚡ Individual calculations are sub-microsecond, and the `events` method that computes all solar events is still under 4 microseconds per call.\n\nBenchmark results were obtained on Intel(R) Core(TM) i7-8550U (8) @ 4.00 GHz.\n\nYou can run the benchmark with:\n\n```bash\ncrystal run --release samples/benchmark.cr\n```\n\n## 🤝 Contributing\n\n1. Fork it (\u003chttps://github.com/geocrystal/sun_times/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## 👥 Contributors\n\n- [Anton Maminov](https://github.com/mamantoha) - creator and maintainer\n\n## 📄 License\n\nThis library is distributed under the MIT license. Please see the LICENSE file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeocrystal%2Fsun_times","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgeocrystal%2Fsun_times","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgeocrystal%2Fsun_times/lists"}