Skip to content

Instantly share code, notes, and snippets.

@thevickypedia
Last active March 14, 2023 02:18
Show Gist options
  • Save thevickypedia/11c9d5c1ae37811dcdbf0837b81eb09d to your computer and use it in GitHub Desktop.
Save thevickypedia/11c9d5c1ae37811dcdbf0837b81eb09d to your computer and use it in GitHub Desktop.
Get all timezone names, descriptions and GMT offsets
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