Last active
March 14, 2023 02:18
-
-
Save thevickypedia/11c9d5c1ae37811dcdbf0837b81eb09d to your computer and use it in GitHub Desktop.
Get all timezone names, descriptions and GMT offsets
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
from collections.abc import Generator | |
from threading import Thread | |
from typing import List, Union, NoReturn, Dict | |
import pandas | |
import requests | |
import yaml | |
from jarvis.modules.exceptions import EgressErrors | |
from jarvis.modules.logger.custom_logger import logger | |
from jarvis.modules.models import models | |
models.fileio.timezones = os.path.join('fileio', 'timezones.yaml') | |
def get_existing() -> List[pandas.DataFrame]: | |
"""Loads the backup file for timezones and converts it to a list of dataframes. | |
Returns: | |
List[pandas.DataFrame]: | |
List of dataframes. | |
""" | |
with open(models.fileio.timezones) as file: | |
existing = yaml.load(stream=file, Loader=yaml.FullLoader) | |
return [pandas.DataFrame(existing)] | |
def update_existing(tables: List[pandas.DataFrame]) -> NoReturn: | |
"""Update existing backup file for timezones. | |
Args: | |
tables: Takes list of dataframes as an argument. | |
""" | |
zone_list = [] | |
for table in tables: | |
headers = [header.lower().replace(' ', '_') for header in table] | |
for row in table.values: | |
timezone = {} | |
for key, value in zip(headers, row): | |
timezone[key] = value | |
zone_list.append(timezone) | |
with open(models.fileio.timezones, 'w') as file: | |
yaml.dump(data=zone_list, stream=file, Dumper=yaml.SafeDumper) | |
class TimeZones: | |
"""Wrapper to get information about all timezones. | |
>>> TimeZones | |
""" | |
def __init__(self): | |
"""Instantiates the object.""" | |
self._all = None | |
self.base_url = "https://gisgeography.com/world-time-zone-map" | |
def get_table(self) -> Union[bool, List[pandas.DataFrame]]: | |
"""Get table information from a public URL and convert it to a dataframe. | |
Returns: | |
Union[bool, List[pandas.DataFrame]]: | |
Returns a list of dataframes or False if failed to get tables from URL. | |
""" | |
try: | |
res = requests.get(url=self.base_url) | |
except EgressErrors as error: | |
logger.error(error) | |
return False | |
try: | |
tables = pandas.read_html(res.text) | |
except pandas.errors.ParserError as error: | |
logger.error(error) | |
return False | |
return tables | |
def parse_dataframe(self, get_zones: bool = False, get_names: bool = False) -> \ | |
Union[Generator[Dict], Generator[str]]: | |
"""Parses the dataframe to yield an iterable of zone names, description or all together. | |
Args: | |
get_zones: Get timezones. | |
get_names: Get timezone names. | |
Yields: | |
Union[Generator[Dict], Generator[str]]: | |
Yields either a string or a dictionary. | |
""" | |
if tables := self.get_table(): | |
Thread(target=update_existing, args=(tables,)).start() | |
else: | |
tables = get_existing() | |
if get_zones: | |
for table in tables: | |
for row in table.values: | |
yield row[0] | |
return | |
if get_names: | |
for table in tables: | |
for row in table.values: | |
yield row[1] | |
return | |
for table in tables: | |
headers = [header.lower().replace(' ', '_') for header in table] | |
for row in table.values: | |
timezone = {} | |
for key, value in zip(headers, row): | |
timezone[key] = value | |
yield timezone | |
@property | |
def all_zone_names(self): | |
"""Returns list of timezones.""" | |
if not (table := self.parse_dataframe(get_zones=True)): | |
return False | |
return list(table) | |
@property | |
def all_zone_desc(self): | |
"""Returns list of timezone names.""" | |
if not (table := self.parse_dataframe(get_names=True)): | |
return False | |
return list(table) | |
@property | |
def all(self): | |
"""Returns all information reg timezones.""" | |
if not (table := self.parse_dataframe()): | |
return False | |
return list(table) | |
@all.setter | |
def all(self, value): | |
"""Set value to the property all in case existing information is loaded.""" | |
self._all = value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment