{"id":16684249,"url":"https://github.com/aligusnet/astro","last_synced_at":"2026-03-10T11:32:39.895Z","repository":{"id":59151013,"uuid":"66619370","full_name":"aligusnet/astro","owner":"aligusnet","description":"Amateur astronomical computations","archived":false,"fork":false,"pushed_at":"2021-05-23T23:02:40.000Z","size":224,"stargazers_count":17,"open_issues_count":4,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-19T17:39:31.130Z","etag":null,"topics":["astronomy","haskell"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aligusnet.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}},"created_at":"2016-08-26T05:31:26.000Z","updated_at":"2025-08-06T20:31:09.000Z","dependencies_parsed_at":"2022-09-22T08:42:24.483Z","dependency_job_id":null,"html_url":"https://github.com/aligusnet/astro","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/aligusnet/astro","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aligusnet%2Fastro","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aligusnet%2Fastro/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aligusnet%2Fastro/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aligusnet%2Fastro/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aligusnet","download_url":"https://codeload.github.com/aligusnet/astro/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aligusnet%2Fastro/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30332310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","haskell"],"created_at":"2024-10-12T14:42:49.925Z","updated_at":"2026-03-10T11:32:39.866Z","avatar_url":"https://github.com/aligusnet.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Amateur astronomical computations\n\n[![Build Status](https://travis-ci.org/aligusnet/astro.svg?branch=master)](https://travis-ci.org/aligusnet/astro)\n[![Coverage Status](https://coveralls.io/repos/github/aligusnet/astro/badge.svg)](https://coveralls.io/github/aligusnet/astro)\n[![Documentation](https://img.shields.io/badge/astro-documentation-blue.svg)](https://aligusnet.github.io/astro-docs/doc/index.html)\n[![Hackage](https://img.shields.io/hackage/v/astro.svg)](https://hackage.haskell.org/package/astro) \n\n\n## Usage\n\n### Install stack\n\nIt will take care of everything.\n\n[Get started with Stack](https://www.fpcomplete.com/haskell/get-started/)\n\n### Build the project\n\n    stack build\n\n### Run unit tests\n\n    stack test\n\n## Documentation\n\n### Useful types\n\n#### Decimal hours and Decimal degrees\n\nTypes to represent hours (used in celestial coordinate systems and as time zone) and degrees (used in coordinate systems).\n\n```haskell\nimport Data.Astro.Types\n\n-- 10h 15m 19.7s\ndh :: DecimalHours\ndh = fromHMS 10 15 19.7\n-- DH 10.255472222222222\n\n(h, m, s) = toHMS dh\n-- (10,15,19.699999999999562)\n\n\n-- 51°28′40″\ndd :: DecimalDegrees\ndd = fromDMS 51 28 40\n-- DD 51.477777777777774\n\n(d, m, s) = toDMS dd\n-- (51,28,39.999999999987494)\n```\n\n#### Geographic Coordinates\n\n```haskell\nimport Data.Astro.Types\n\n-- the Royal Observatory, Greenwich\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n-- GeoC {geoLatitude = DD 51.4778, geoLongitude = DD (-0.0014)}\n```\n\n### Time\n\nThe main time datetime type used in the library is `JulianDate` defined in `Data.Astro.Time.JulianDate`. JulianDate is just a number of days since noon of 1 January 4713 BC:\n\n```haskell\nimport Data.Astro.Time.JulianDate\n\n-- 2017-06-25 9:29:00 (GMT)\njd :: JulianDate\njd = fromYMDHMS 2017 6 25 9 29 0\n-- JD 2457929.895138889\n```\n\n`LocalCiviTime` and `LocalCivilDate` are Julian dates with time zones:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Types\n\n-- 2017-06-25 10:29:00 +0100 (BST)\nlct :: LocalCivilTime\nlct = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n-- 2017-06-25 10:29:00.0000 +1.0\n\nlctJD :: JulianDate\nlctJD = lctUniversalTime lct\n-- JD 2457929.895138889\n\nlctTZ :: DecimalHours\nlctTZ = lctTimeZone lct\n-- DH 1.0\n\nlcd :: LocalCivilDate\nlcd = lcdFromYMD (DH 1) 2017 6 25\n\nlcdJD :: JulianDate\nlcdJD = lcdDate lcd\n-- JD 2457929.5\n\nlcdTZ :: DecimalHours\nlcdTZ = lcdTimeZone lcd\n-- DH 1.0\n```\n\n### Celestial coordinate systems\n\nThe celestical coordinate systems are defined in `Data.Astro.Coordinate`.\n\nIf you would like to locate Sirius in the sky you need to know the altitude or 'how far up' angle in the sky and azimuth - 'how far round' angle from the north direction to the east. this describes the __Horizontal coordinate system__:\n\n![alt Horizontal coordinate system](https://upload.wikimedia.org/wikipedia/commons/f/f7/Azimuth-Altitude_schematic.svg \"Horizontal coordinate system\")\n\n\n```haskell\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\n\nhc :: HorizonCoordinates\nhc = HC (DD 30.5) (DD 180)\n-- HC {hAltitude = DD 30.0, hAzimuth = DD 180.0}\n```\n\nUnfortunately the Horizontal coordinate system values depend on the position of the observer. And it's not handy when you need to share coordinates of some celestial object with your friend in Japan.\n\nThe second coordinate system is the __Equatorial coordinate system__. This coordinate system uses the location of the centre of the Earth as the zero point so it does not depend on the observer's location.\n\nWe have two flavours of equatorial coordinates:\n\n* the first one uses the _vernal equinox_ as a starting direction for the 'how far round' coordinate (__right ascension, \u0026#x3B1;__),\n\n* the second one uses the _meridian_ instead of the vernal equinox (__hour angle__).\n\nWe can consider the second one as a transition coordinate system between the horizontal one and the 'true' equatorial one.\n\n\n```haskell\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\n\nec1 :: EquatorialCoordinates1\nec1 = EC1 (DD 71.7) (DH 8)\n-- EC1 {e1Declination = DD 71.7, e1RightAscension = DH 8.0}\n\nec2 :: EquatorialCoordinates2\nec2 = EC1 (DD 77.7) (DH 11)\n-- EC2 {e2Declination = DD 77.7, e2HoursAngle = DH 11.0}\n```\n\n#### Transformations\n\nSay, now is 2017-06-25 10:29 BST and we are somewhere near the Royal Observatory, Greenwich.\n\nLet convert the current location of the Sun in horizon coordinates (altitude: 49°18′21.77″, azimuth: 118°55′19.53″) to equatorial coordinates and back to horizon ones:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\nsunHC :: HorizonCoordinates\nsunHC = HC (fromDMS 49 18 21.77) (fromDMS 118 55 19.53)\n-- HC {hAltitude = DD 49.30604722222222, hAzimuth = DD 118.92209166666666}\n\nsunEC2 :: EquatorialCoordinates2\nsunEC2 = horizonToEquatorial (geoLatitude ro) sunHC\n-- EC2 {e2Declination = DD 23.378295912623855, e2HoursAngle = DH 21.437117068873537}\n\nsunEC1 :: EquatorialCoordinates1\nsunEC1 = EC1 (e2Declination sunEC2) (haToRA (e2HoursAngle sunEC2) (geoLongitude ro) (lctUniversalTime dt))\n-- EC1 {e1Declination = DD 23.378295912623855, e1RightAscension = DH 6.29383725890224}\n\n\nsunEC2' :: EquatorialCoordinates2\nsunEC2' = EC2 (e1Declination sunEC1) (raToHA (e1RightAscension sunEC1) (geoLongitude ro) (lctUniversalTime dt))\n-- EC2 {e2Declination = DD 23.378295912623855, e2HoursAngle = DH 21.437117068873537}\n\nsunHC' :: HorizonCoordinates\nsunHC' = equatorialToHorizon (geoLatitude ro) sunEC2'\n-- HC {hAltitude = DD 49.30604722222222, hAzimuth = DD 118.92209166666666}\n```\n\nYou can use function-shortcuts to simplify transformation EquatorialCoordinates1 \u003c-\u003e HorizonCoordinates: `ec1ToHC` and `hcToEC1`:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\nsunHC :: HorizonCoordinates\nsunHC = HC (fromDMS 49 18 21.77) (fromDMS 118 55 19.53)\n-- HC {hAltitude = DD 49.30604722222222, hAzimuth = DD 118.92209166666666}\n\nsunEC1 :: EquatorialCoordinates1\nsunEC1 = hcToEC1 ro (lctUniversalTime dt) sunHC\n-- EC1 {e1Declination = DD 23.378295912623855, e1RightAscension = DH 6.29383725890224}\n\nsunHC' :: HorizonCoordinates\nsunHC' = ec1ToHC ro (lctUniversalTime dt) sunEC1\n-- HC {hAltitude = DD 49.30604722222222, hAzimuth = DD 118.92209166666666}\n```\n\n### Stars\n\nThe ancient astronomers noted that there were 2 types of stars: some of them were fixed, travelling the same way across the sky every sidereal day and another were wanderers (planetai in ancient Greek).\n\nOf course, stars are not fixed, they are travelling with high speeds but distances to them are so high that their movement is very difficult to note. So we can assume that they are fixed for our purposes.\n\nGiven the \"fixed\" equatorial coordinates of the star we only need to transform them to the horizon coordinates to find out where the star in the sky.\n\nIn the example below we will use `Data.Astro.Star` module which defines equatorial coordinates of some stars:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\nimport Data.Astro.Star\n\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\n-- Calculate location of Betelgeuse\n\nbetelgeuseEC1 :: EquatorialCoordinates1\nbetelgeuseEC1 = starCoordinates Betelgeuse\n-- EC1 {e1Declination = DD 7.407064, e1RightAscension = DH 5.919529}\n\nbetelgeuseHC :: HorizonCoordinates\nbetelgeuseHC = ec1ToHC ro (lctUniversalTime dt) betelgeuseEC1\n-- HC {hAltitude = DD 38.30483892505852, hAzimuth = DD 136.75755644642248}\n```\n\n#### Rise and Set\n\n`Data.Astro.CelestialObject.RiseSet` module defines `RiseSet` type to represent time and azimuth of rise and set.\n\nLet calculate rise and set time of Rigel:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\nimport Data.Astro.Effects\nimport Data.Astro.CelestialObject.RiseSet\nimport Data.Astro.Star\n\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ntoday :: LocalCivilDate\ntoday = lcdFromYMD (DH 1) 2017 6 25\n\n-- Calculate location of Betelgeuse\n\nrigelEC1 :: EquatorialCoordinates1\nrigelEC1 = starCoordinates Rigel\n\nverticalShift :: DecimalDegrees\nverticalShift = refract (DD 0) 12 1012\n-- DD 0.5660098245614035\n\nrigelRiseSet :: RiseSetLCT\nrigelRiseSet = riseAndSetLCT ro today verticalShift rigelEC1\n-- RiseSet (2017-06-25 06:38:18.4713 +1.0,DD 102.51249855335433) (2017-06-25 17:20:33.4902 +1.0,DD 257.48750144664564)\n```\n\nAs we can see Rigel rose today at 06:38:18 and will set at 17:20:33, azimuths of rise and set 102.51° and 257.49° correspondingly.\n\nWe used `refract` function of `Data.Astro.Effects` module with reasonable default parameters to calculate vertical shift.\n\n### Planets\n\nThe planets is completely different story. We cannot assume that the planets have \"fixed\" location in equatorial coordinates like stars.\n\nWhat we can do is to describe details of the planets' orbit and calculate their positions at any given moment.\n\nPlanets and planet details are defined in `Data.Astro.Planet` module. `j2010PlanetDetails` returns details for the given planet.\nThis module also defines `planetPosition`, `planetDistance1` and `planetAngularDiameter` to calculate position of the given planet, distance to the planet and angular size of the planet correspondingly.\n\n`1` at the end of the `planetDistance1` means that this function uses not very precise method to do calculations. Sometimes there are `2`-methods available in the library, but not always.\n\nLet us do some planets-related calculations.\n\nDo some initialisation:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\nimport Data.Astro.Effects\nimport Data.Astro.CelestialObject.RiseSet\nimport Data.Astro.Planet\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\ntoday :: LocalCivilDate\ntoday = lcdFromYMD (DH 1) 2017 6 25\n\njupiterDetails :: PlanetDetails\njupiterDetails = j2010PlanetDetails Jupiter\n\nearthDetails :: PlanetDetails\nearthDetails = j2010PlanetDetails Earth\n\njupiterPosition :: JulianDate -\u003e EquatorialCoordinates1\njupiterPosition = planetPosition planetTrueAnomaly1 jupiterDetails earthDetails\n\n```\n\nCalculate Jupiter's coordinates:\n\n```haskell\njupiterEC1 :: EquatorialCoordinates1\njupiterEC1 = jupiterPosition (lctUniversalTime dt)\n-- EC1 {e1Declination = DD (-4.104626810672402), e1RightAscension = DH 12.863365504382228}\n\njupiterHC :: HorizonCoordinates\njupiterHC = ec1ToHC ro (lctUniversalTime dt) jupiterEC1\n-- HC {hAltitude = DD (-30.67914598469227), hAzimuth = DD 52.29376845044007}\n```\n\nAs be can see Jupiter is below the horizon now (the altitude is negative), that's unfortunate.\n\nNow let us calculate distance to Jupiter:\n\n```haskell\njupiterDistance :: AstronomicalUnits\njupiterDistance = planetDistance1 jupiterDetails earthDetails (lctUniversalTime dt)\n-- AU 5.193435872521039\n```\n\n1 Astronomical Unit is an average distance from the Earth to the Sun.\n\nand calculate an angular size now:\n\n```haskell\njupiterAngularSize :: DecimalDegrees\njupiterAngularSize = planetAngularDiameter jupiterDetails jupiterDistance\n-- DD 1.052289877865987e-2\n\ntoDMS jupiterAngularSize\n-- (0,0,37.88243560317554)\n```\n\n#### Rise and Set\n\nCalculate rise and set times of planets are not easy task, because planets change their equatorial coordinates during the day.\n\n`riseAndSet2` function of `Data.Astro.CelestialObject.RiseSet` module applies iterative approach: calculates rise and set date for midday coordinates and then recalculates rise time for rise coordinates and set for set coordinates obtained from the previous step:\n\n```haskell\nverticalShift :: DecimalDegrees\nverticalShift = refract (DD 0) 12 1012\n-- DD 0.5660098245614035\n\njupiterRiseSet :: RiseSetMB\njupiterRiseSet = riseAndSet2 0.000001 jupiterPosition ro verticalShift today\n-- RiseSet\n--    (Just (2017-06-25 13:53:27.3109 +1.0,DD 95.88943953535569))\n--    (Just (2017-06-25 01:21:23.5835 +1.0,DD 264.1289033612776))\n```\n\nWe can see now why at 10 am Jupiter is below horizon because it will rise only at 1:53 pm.\n\n\n### Sun\n\nSome examples of doing the Sun's related calculations:\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\nimport Data.Astro.Sun\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\ntoday :: LocalCivilDate\ntoday = lcdFromYMD (DH 1) 2017 6 25\n\njd :: JulianDate\njd = lctUniversalTime dt\n\nverticalShift :: DecimalDegrees\nverticalShift = refract (DD 0) 12 1012\n\n-- distance from the Earth to the Sun in kilometres\ndistance :: Double\ndistance = sunDistance jd\n-- 1.5206375976421073e8\n\n-- Angular Size\nangularSize :: DecimalDegrees\nangularSize = sunAngularSize jd\n-- DD 0.5244849215333616\n\n-- The Sun's coordinates\nec1 :: EquatorialCoordinates1\nec1 = sunPosition2 jd\n-- EC1 {e1Declination = DD 23.37339098989099, e1RightAscension = DH 6.29262026252748}\n\nhc :: HorizonCoordinates\nhc = ec1ToHC ro jd ec1\n-- HC {hAltitude = DD 49.312050979507404, hAzimuth = DD 118.94723825710143}\n\n\n-- Rise and Set\nriseSet :: RiseSetMB\nriseSet = sunRiseAndSet ro 0.833333 today\n-- RiseSet\n--    (Just (2017-06-25 04:44:04.3304 +1.0,DD 49.043237261724215))\n--    (Just (2017-06-25 21:21:14.4565 +1.0,DD 310.91655607595595))\n```\n\n\n### Moon\n\nThe Moon's related calculations. `Data.Astro.Moon` module defines 2 new types of functions we haven't seen before: `moonPhase` and `moonBrightLimbPositionAngle` which calculate the phase (the area of the visible segment expressed as a fraction of the whole disk) and the position-angle which is the angle of the midpoint of the illuminated limb measured eastwards from the north point of the disk.\n\n\n```haskell\nimport Data.Astro.Time.JulianDate\nimport Data.Astro.Coordinate\nimport Data.Astro.Types\nimport Data.Astro.Effects\nimport Data.Astro.CelestialObject.RiseSet\nimport Data.Astro.Moon\n\nro :: GeographicCoordinates\nro = GeoC (fromDMS 51 28 40) (-(fromDMS 0 0 5))\n\ndt :: LocalCivilTime\ndt = lctFromYMDHMS (DH 1) 2017 6 25 10 29 0\n\ntoday :: LocalCivilDate\ntoday = lcdFromYMD (DH 1) 2017 6 25\n\njd :: JulianDate\njd = lctUniversalTime dt\n\n-- distance from the Earth to the Moon in kilometres\nmdu :: MoonDistanceUnits\nmdu = moonDistance1 j2010MoonDetails jd\n-- MDU 0.9550170577020396\n\ndistance :: Double\ndistance = mduToKm mdu\n-- 367109.51199772174\n\n-- Angular Size\nangularSize :: DecimalDegrees\nangularSize = moonAngularSize mdu\n-- DD 0.5425033990980761\n\n-- The Moon's coordinates\nposition :: JulianDate -\u003e EquatorialCoordinates1\nposition = moonPosition1 j2010MoonDetails\n\nec1 :: EquatorialCoordinates1\nec1 = position jd\n-- EC1 {e1Declination = DD 18.706180658927323, e1RightAscension = DH 7.56710547682055}\n\nhc :: HorizonCoordinates\nhc = ec1ToHC ro jd ec1\n-- HC {hAltitude = DD 34.57694951316064, hAzimuth = DD 103.91119101451832}\n\n-- Rise and Set\nriseSet :: RiseSetMB\nriseSet = riseAndSet2 0.000001 position ro verticalShift today\n-- RiseSet\n--    (Just (2017-06-25 06:22:51.4858 +1.0,DD 57.81458864497365))\n--    (Just (2017-06-25 22:28:20.3023 +1.0,DD 300.4168238905249))\n\n-- Phase\nphase :: Double\nphase = moonPhase j2010MoonDetails jd\n-- 2.4716141948212922e-2\n\n\nsunEC1 :: EquatorialCoordinates1\nsunEC1 = sunPosition2 jd\n-- EC1 {e1Declination = DD 23.37339098989099, e1RightAscension = DH 6.29262026252748}\n\nlimbAngle :: DecimalDegrees\nlimbAngle = moonBrightLimbPositionAngle ec1 sunEC1\n-- DD 287.9869373767473\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faligusnet%2Fastro","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faligusnet%2Fastro","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faligusnet%2Fastro/lists"}