{"id":17674710,"url":"https://github.com/eltonchou/eorzeaenv","last_synced_at":"2026-04-02T22:06:40.622Z","repository":{"id":33421499,"uuid":"158142501","full_name":"EltonChou/EorzeaEnv","owner":"EltonChou","description":"Final Fantasy XIV weather","archived":false,"fork":false,"pushed_at":"2024-09-11T14:05:49.000Z","size":630,"stargazers_count":16,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-11T01:51:35.678Z","etag":null,"topics":["ff14","ffxiv","final-fantasy-xiv","finalfantasyxiv","python","python-library","python3","weather-forecast"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/EorzeaEnv/","language":"Python","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/EltonChou.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2018-11-19T00:54:44.000Z","updated_at":"2024-10-03T02:02:26.000Z","dependencies_parsed_at":"2024-09-11T12:10:30.678Z","dependency_job_id":"664c8ab2-7930-4ad9-9bed-2f870c9ddce8","html_url":"https://github.com/EltonChou/EorzeaEnv","commit_stats":{"total_commits":220,"total_committers":2,"mean_commits":110.0,"dds":"0.24545454545454548","last_synced_commit":"6ab57b3824a0edd17d80a4b9fc91c697a349180a"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EltonChou%2FEorzeaEnv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EltonChou%2FEorzeaEnv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EltonChou%2FEorzeaEnv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EltonChou%2FEorzeaEnv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EltonChou","download_url":"https://codeload.github.com/EltonChou/EorzeaEnv/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230542289,"owners_count":18242332,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["ff14","ffxiv","final-fantasy-xiv","finalfantasyxiv","python","python-library","python3","weather-forecast"],"created_at":"2024-10-24T07:08:37.029Z","updated_at":"2026-04-02T22:06:40.616Z","avatar_url":"https://github.com/EltonChou.png","language":"Python","readme":"[![Pypi](https://img.shields.io/pypi/v/eorzeaenv.svg?style=flat-square)](https://pypi.org/project/EorzeaEnv/)\n[![Pypi](https://img.shields.io/pypi/pyversions/eorzeaenv.svg?style=flat-square)](https://pypi.org/project/EorzeaEnv/)\n[![Build Status](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Factions-badge.atrox.dev%2FEltonChou%2FEorzeaEnv%2Fbadge\u0026style=flat-square)](https://github.com/EltonChou/EorzeaEnv/actions)\n![PyPI - Downloads](https://img.shields.io/pypi/dm/EorzeaEnv?style=flat-square)\n[![codecov](https://codecov.io/gh/EltonChou/EorzeaEnv/branch/master/graph/badge.svg?token=U9US0CQUTI)](https://codecov.io/gh/EltonChou/EorzeaEnv)\n\n# EorzeaEnv\n\n+ [CHANGELOG](https://github.com/EltonChou/EorzeaEnv/blob/master/CHANGELOG.md)\n\n## Installation\n```\npip install eorzeaenv\n```\n\n## Usage\n```py\nfrom EorzeaEnv import EorzeaLang, EorzeaTime, EorzeaWeather, EorzeaPlaceName\n```\n\n### Eorzea Language enum\n```py\nsupport_langs = [\n    EorzeaLang.EN,\n    EorzeaLang.JA,\n    EorzeaLang.DE,\n    EorzeaLang.FR,\n    EorzeaLang.ZH_SC,\n    EorzeaLang.ZH_TC,\n    EorzeaLang.KO,\n]\n```\n\n### Eorzea Time\n\n```sh\n\u003e\u003e\u003e EorzeaTime.now()\n'EorzeaTime(Sixth Embral Moon, 11, 21, 56, Phase:0.50, Althyk)'\n\n\u003e\u003e\u003e EorzeaTime.now().moon\n'Sixth Embral Moon'\n\n\u003e\u003e\u003e EorzeaTime.now().sun\n11\n\n\u003e\u003e\u003e EorzeaTime.now().hour\n21\n\n\u003e\u003e\u003e EorzeaTime.now().minute\n56\n\n\u003e\u003e\u003e EorzeaTime.now().phase\n0.50\n\n\u003e\u003e\u003e EorzeaTime.now().guardian\n'Althyk'\n```\n+ Get the unix timestamp (int not float)\n```sh\n\u003e\u003e\u003e EorzeaTime.now().get_unix_time()\n1661114514\n```\n+ Get the eorzea timestamp (int not float)\n```sh\n\u003e\u003e\u003e EorzeaTime.now().get_eorzea_time()\n34177649220\n```\n\n### Weather Forecast\n+ Using period as tuple or list\n```python\n# defalut step value is 5\n# This method return a generator if you need to re-use it save the values as `tuple` or `list`.\nt = tuple(EorzeaTime.weather_period(step=3))\n\n# Use EorzeaPlaceName to ensure the place is valid or\n# you can directly pass the place string to forecast.\nplace_name = EorzeaPlaceName('Eureka Pyros')\n\n# Defalut lang is 'en'\n# Defalut strict is `True` for strict mode `False` for fuzzy mode.\n# eg. `eurekaa puros` is valid in fuzzy mode.\n\n# In fuzzy mode, you can set the cutoff score to prevent unexpected place name to be passed.\n# default value is 80. (100 \u003e= value \u003e= 0)\nEorzeaWeather.set_fuzzy_cutoff(95)\n\nweather_en = EorzeaWeather.forecast(place_name, t, strict=True)\nweather_ja = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.JA, strict=True)\nweather_de = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.DE, strict=True)\nweather_fr = EorzeaWeather.forecast(place_name, t, lang=EorzeaLang.FR, strict=True)\n```\n```sh\n\u003e\u003e\u003e print(weather_en)\n['Thunder', 'Snow', 'Blizzards']\n\n\u003e\u003e\u003e print(weather_ja)\n['雷', '雪', '吹雪']\n\n\u003e\u003e\u003e print(weather_de)\n['Gewittrig', 'Schnee', 'Schneesturm']\n\n\u003e\u003e\u003e print(weather_fr)\n['Orages', 'Neige', 'Blizzard']\n```\n+ Using period in for-loop\n```py\nweather_en = []\nfor t in EorzeaTime.weather_period(step=3):\n    w = EorzeaWeather.forecast('Eureka Pyros', t)\n    weather_en.append(w)\n```\n```sh\n\u003e\u003e\u003e print(weather_en)\n['Thunder', 'Snow', 'Blizzards']\n```\n+ Provide a desired base time to calculate.\n```py\nfor t in EorzeaTime.weather_period(step=3, from_=datetime(2025, 10, 25).timestamp()):\n    w = EorzeaWeather.forecast('Eureka Pyros', t)\n    print(w)\n```\n+ Using period generator directly\n```py\nweathers = EorzeaWeather.forecast('Eureka Pyros', EorzeaTime.weather_period(step=3))\n```\n```sh\n\u003e\u003e\u003e print(weathers)\n['Thunder', 'Snow', 'Blizzards']\n```\n\n### Eorzea place name\n\nAn instance of EorzeaPlaceName would be always a valid place name in this pacakge.\n\nAn invalid place name will raises `InvalidEorzeaPlaceName` error.\n\n```py\nplace_name = EorzeaPlaceName(\n    'The Ruby Sea',\n    # `False` to fuzzy mode, default is `True`\n    strict=True,\n    # Stricted scope for validation of place name.\n    # default is all supports locale.\n    locale_scopes=[\n        EorzeaLang.EN,\n        EorzeaLang.JA,\n        EorzeaLang.FR,\n        EorzeaLang.DE],\n    # Used in fuzzy mode to cut-off the result under the score.\n    # default is `80`.\n    fuzzy_cutoff=80\n)\n```\n```sh\n\u003e\u003e\u003e place_name\nEorrzeaPlaceName('The Ruby Sea')\n\n\u003e\u003e\u003e print(place_name)\n'The Ruby Sea`\n```\n\nBelowings are valid place names in strict mode with full locale scopes (default settings).\n```py\nEorzeaPlaceName('The Ruby Sea') # valid `The Ruby Sea`\nEorzeaPlaceName('the ruby sea') # valid `The Ruby Sea`\nEorzeaPlaceName('ruby sea') # valid `The Ruby Sea`\nEorzeaPlaceName('rubinsee') # valid `Rubinsee`\nEorzeaPlaceName('紅玉海') # valid `紅玉海`\n```\n\nWith stricted scopes.\n```py\nscopes = [EorzeaLang.JA, EorzeaLang.DE]\n\nEorzeaPlaceName('The Ruby Sea', locale_scopes=scopes) # raises error\nEorzeaPlaceName('the ruby sea', locale_scopes=scopes) # raises error\nEorzeaPlaceName('ruby sea', locale_scopes=scopes) # raises error\nEorzeaPlaceName('rubinsee', locale_scopes=scopes) # valid `Rubinsee`\nEorzeaPlaceName('紅玉海', locale_scopes=scopes) # valid `紅玉海`\n```\n\nIn fuzzy mode.\n```py\nEorzeaPlaceName('the ruby see', strict=False) # valid `The Ruby Sea`\nEorzeaPlaceName('ruby see', strict=False) # valid `The Ruby Sea`\nEorzeaPlaceName('rubisee', strict=False) # valid `Rubinsee`\nEorzeaPlaceName('紅玉貝', strict=False) # raises error\nEorzeaPlaceName('紅玉貝', strict=False, fuzzy_cutoff=66) # valid `紅玉海`\n```\n\n### Eorzea rainbow predict\n\nUse EorzeaRainbow to predict when will the rainbow appears.\n\n```py\nfrom datetime import datetime\n\nfrom EorzeaEnv import EorzeaPlaceName, EorzeaRainbow, EorzeaTime, EorzeaWeather\n\nrainbow_times: list[datetime] = []\n\nplace = EorzeaPlaceName(\"東ラノシア\")\nthe_rainbow = EorzeaRainbow(place_name=place)\n\n\nfor t in EorzeaTime.weather_period(step='inf'):\n    the_rainbow.observe(t, EorzeaWeather.forecast(place, t, raw=True))\n    if the_rainbow.is_appear:\n        rainbow_times.append(datetime.fromtimestamp(t.get_unix_time()))\n    if len(rainbow_times) == 20:\n        break\n\nprint(rainbow_times)\n```\n\n### Eorzea Aurora predict\n\nUse `EorzeaAurora` to predict when Aurora appears. Aurora only occurs in\nCoerthas Western Highlands and Old Sharlayan. Use the provided place constants\nfrom `EorzeaEnv.places`.\n\n```py\nfrom datetime import datetime\n\nfrom EorzeaEnv import EorzeaAurora, EorzeaTime, EorzeaWeather\nfrom EorzeaEnv.places import COERTHAS_WESTERN_HIGHLANDS\n\naurora = EorzeaAurora(COERTHAS_WESTERN_HIGHLANDS)\naurora_times: list[datetime] = []\n\nfor t in EorzeaTime.weather_period(step='inf'):\n    aurora.observe(t, EorzeaWeather.forecast(COERTHAS_WESTERN_HIGHLANDS, t, raw=True))\n    if aurora.is_appear:\n        aurora_times.append(datetime.fromtimestamp(t.get_unix_time()))\n    if len(aurora_times) == 20:\n        break\n\nprint(aurora_times)\n```\n\n### Eorzea Diamond Dust predict\n\nUse `EorzeaDiamondDust` to predict when Diamond Dust appears. It only occurs\nin Coerthas Western Highlands. Diamond Dust appears when:\n\n1. Weather transitions from non-Fair Skies to Fair Skies at ET 08:00 (dust visible ET 08:00–10:00).\n2. Weather is Fair Skies at ET 00:00 (dust visible ET 06:00–08:00).\n\n```py\nfrom datetime import datetime\n\nfrom EorzeaEnv import EorzeaDiamondDust, EorzeaTime, EorzeaWeather\nfrom EorzeaEnv.places import COERTHAS_WESTERN_HIGHLANDS\n\ndd = EorzeaDiamondDust(COERTHAS_WESTERN_HIGHLANDS)\ndust_times: list[datetime] = []\n\nfor t in EorzeaTime.weather_period(step='inf'):\n    dd.observe(t, EorzeaWeather.forecast(COERTHAS_WESTERN_HIGHLANDS, t, raw=True))\n    if dd.is_appear:\n        dust_times.append(datetime.fromtimestamp(t.get_unix_time()))\n    if len(dust_times) == 20:\n        break\n\nprint(dust_times)\n```\n\n### Errors\n```py\nfrom EorzeaEnv.errors import \\\n    EorzeaEnvError, \\\n    InvalidEorzeaPlaceName, \\\n    WeatherRateDataError\n```\n\n```\nException\n    |- EorzeaEnvError\n        |- InvalidEorzeaPlaceName\n        |- WeatherRateDataError\n```\n\n## Thanks\n- [Rogueadyn-SaintCoinach](https://github.com/Rogueadyn/SaintCoinach)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feltonchou%2Feorzeaenv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feltonchou%2Feorzeaenv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feltonchou%2Feorzeaenv/lists"}