Skip to content

Instantly share code, notes, and snippets.

@deontologician
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deontologician/fc85b0ad35a7c3bbadef to your computer and use it in GitHub Desktop.
Save deontologician/fc85b0ad35a7c3bbadef to your computer and use it in GitHub Desktop.
hextime
#!/usr/bin/env python
# Josh's homespun hexidecimal time
# | power | Name | equivalent | SI seconds | std equiv | kind |
# |-------+---------+--------------+-------------+-------------+------|
# | 0 | second | - | 1 second | 1 second | time |
# | 1 | whisp | 16 seconds | 16 seconds | ~1/4 minute | time |
# | 2 | yobun | 16 whisps | 256 seconds | ~4 minutes | time |
# | 3 | clock | 16 yobuns | 4Kis | ~1 hour | time |
# | 4 | loday | 16 clocks | 64Kis | ~18 hours | date |
# | 5 | tolfdag | 16 lodays | 1Mis | ~12 days | date |
# | 6 | banyon | 16 tolfdagar | 16Mis | ~6 months | era |
# | 7 | octavum | 16 banyons | 256Mis | ~8.5 years | era |
# | 8 | era | 16 octava | 1Bis | ~136 years | era |
# | 9 | age | 16 eras | 16Bis | ~2177 years | era |
import time
from datetime import datetime
from math import ceil
units = {
0: ("second", "seconds"),
1: ("whisp", "whisps"),
2: ("yobun", "yobuns"),
3: ("clock", "clocks"),
4: ("loday", "lodays"),
5: ("tolfdag", "tolfdagar"),
6: ("banyon", "banyons"),
7: ("octavum", "octava"),
8: ("era", "eras"),
9: ("age", "ages"),
}
tolfdag_names = [
"Hydrogen",
"Helium",
"Lithium",
"Beryllium",
"Boron",
"Carbon",
"Nitrogen",
"Oxygen",
"Fluorine",
"Neon",
"Sodium",
"Magnesium",
"Aluminum",
"Silicon",
"Phosphorous",
"Sulfur",
]
class HexUnit(int):
def __add__(self, other):
if isinstance(other, HexUnit):
if self.exponent == other.exponent:
return type(self)(super().__add__(other))
elif self.exponent < other.exponent:
return type(self)(self + other**(other.exponent))
else:
return other.__add__(self)
else:
return super().__add__(other)
def __repr__(self):
return "{}({})".format(type(self).__name__, self)
def downcast_factory(cur_exp, target_exp, targetname):
slide_amt = cur_exp - target_exp
downcast_type = globals()[targetname.title()]
def _downcast(self):
return downcast_type(self << (4 * slide_amt))
_downcast.__name__ = targetname
return _downcast
def get_downcasts(exponent):
downcasts = {}
for exp in range(exponent-1, -1, -1):
target_name = unit_data[exp]['name']
downcasts[target_name] = downcast_factory(exponent, exp, target_name)
return downcasts
unit_data = [
{"name": "second",
"exponent": 0,
"kind": "time"},
{"name": "whisp",
"exponent": 1,
"kind": "time"},
{"name": "yobun",
"exponent": 2,
"kind": "time"},
{"name": "clock",
"exponent": 3,
"kind": "time"},
{"name": "loday",
"exponent": 4,
"kind": "date"},
{"name": "tolfdag",
"exponent": 5,
"plural": "tolfdagar",
"kind": "date"},
{"name": "banyon",
"exponent": 6,
"kind": "era"},
{"name": "octavum",
"exponent": 7,
"plural": "octava",
"kind": "era"},
{"name": "era",
"exponent": 8,
"kind": "era"},
{"name": "age",
"exponent": 9,
"kind": "era"},
]
# Metaprogrammming trick to create a unit class for each
for metadata in unit_data:
classname = metadata['name'].title()
metadata.update(get_downcasts(metadata['exponent']))
globals()[classname] = type(classname, (HexUnit,), metadata)
class HexInstant:
def __init__(self, unix_seconds):
self._unix_seconds = unix_seconds
results = [(unix_seconds >> (4 * p)) % 16 for p in range(0, 11)]
self.second = Second(results[0])
self.whisp = Whisp(results[1])
self.yobun = Yobun(results[2])
self.clock = Clock(results[3])
self.loday = Loday(results[4])
self.tolfdag = Tolfdag(results[5])
self.banyon = Banyon(results[6])
self.octavum = Octavum(results[7])
self.era = Era(results[8])
self.age = Age(results[9])
def __str__(self):
return "{!s},{!s},{!s}".format(
self.hexera(), self.hexdate(), self.hextime()
)
def __repr__(self):
return "{!s} {} {!s}".format(
self.hextime(), self.hexdate().medium_format(), self.hexera())
def hextime(self):
return HexTime(self.clock, self.yobun, self.whisp, self.second)
def hexdate(self):
return HexDate(self.tolfdag, self.loday)
def hexera(self):
return HexEra(self.age, self.era, self.octavum, self.banyon)
def next(self, power):
val = ((self._unix_seconds >> 4 * power) + 1) << 4 * power
return datetime.fromtimestamp(val)
class HexEra:
def __init__(self, age, era, octavum, banyon):
self.age = age
self.era = era
self.octavum = octavum
self.banyon = banyon
def __repr__(self):
return ("{banyon}{banyon_ord} banyon of the "
"{octavum}{octavum_ord} octavum of the "
"{era}{era_ord} era".format(
banyon=self.banyon+1, banyon_ord=ordinal(self.banyon+1),
octavum=self.octavum+1,
octavum_ord=ordinal(self.octavum+1),
era=self.era+1, era_ord=ordinal(self.era+1),
))
def __str__(self):
return '{:X}{:X}{:X}{:X}'.format(
self.age, self.era, self.octavum, self.banyon)
class HexDate:
def __init__(self, tolfdag, loday):
self.loday = loday
self.tolfdag = tolfdag
def __str__(self):
return "{:X}{:X}".format(self.tolfdag, self.loday)
def __repr__(self):
return "{}{} loday of the {} tolfdag".format(
self.loday+1, ordinal(self.loday+1), self.tolfdag_name)
def medium_format(self):
return "{} {}{}".format(
self.tolfdag_name[:3], self.loday+1, ordinal(self.loday+1))
@property
def tolfdag_name(self):
return tolfdag_names[self.tolfdag]
class HexTime:
def __init__(self, clock, yobun, whisp, second):
self.clock = clock
self.yobun = yobun
self.whisp = whisp
self.second = second
def __str__(self):
return '{:X}:{:X}{:X}{:X}'.format(
self.clock, self.yobun, self.whisp, self.second)
def __repr__(self):
return ("{} {}, {} {}, {} {}"
" and {} {}".format(
self.clock, pluralize(self.clock, 3),
self.yobun, pluralize(self.yobun, 2),
self.whisp, pluralize(self.whisp, 1),
self.second, pluralize(self.second, 0)))
def nice_duration(duration):
'''Formats a duration nicely in human terms'''
seconds = duration.seconds % 60
minutes = (duration.seconds // 60) % 60
hours = (duration.seconds // 3600) % 24
years = int(duration.days // 365.25)
years_in_days = ceil(years * 365.25)
month_in_days = 365.25 / 12
remaining_days = duration.days - years_in_days
months = int(remaining_days // month_in_days)
months_in_days = months * month_in_days
remaining_days -= months_in_days
weeks_in_days = 7
weeks = int(remaining_days // weeks_in_days)
remaining_days -= weeks * weeks_in_days
days = int(remaining_days)
outs = [(years, "year"), (months, "month"), (weeks, "week"),
(days, "day"), (hours, "hour"), (minutes, "minute"),
(seconds, "second")]
relevant = ((val, unit) for val, unit in outs if val != 0)
def fmt(x):
return "{} {}".format(*x)
return " ".join(fmt(pluralize_noun(*x)) for x in relevant)
def pluralize_noun(value, noun):
if value == 1:
return (value, noun)
else:
return (value, noun+'s')
def pluralize(value, power):
if value == 1:
return units[power][0]
else:
return units[power][1]
def ordinal(value):
if value in (11, 12, 13):
return 'th'
elif value % 10 == 1:
return 'st'
elif value % 10 == 2:
return 'nd'
elif value % 10 == 3:
return 'rd'
else:
return 'th'
if __name__ == '__main__':
seconds = int(time.time())
instant = HexInstant(seconds)
print('time: {0!r} ({0!s})'.format(instant.hextime()))
print('date: {0!r} [{0!s}]'.format(instant.hexdate()))
print('era: {0!r} <{0!s}>'.format(instant.hexera()))
print('summary: {0!s} or {0!r}'.format(instant))
print('loday', instant.loday + 2, 'begins in',
nice_duration(instant.next(4) - datetime.now()))
print(' {:%c}'.format(instant.next(4)))
print('The', instant.hexdate().tolfdag_name, 'tolfdag begins in',
nice_duration(instant.next(5) - datetime.now()))
print(' {:%c}'.format(instant.next(5)))
print('next banyon begins in', nice_duration(instant.next(6) - datetime.now()))
print(' {:%c}'.format(instant.next(6)))
print('next octavum begins in', nice_duration(instant.next(7) - datetime.now()))
print(' {:%c}'.format(instant.next(7)))
print('next era begins in', nice_duration(instant.next(8) - datetime.now()))
print(' {:%c}'.format(instant.next(8)))
print('next age begins in', nice_duration(instant.next(9) - datetime.now()))
print(' {:%c}'.format(instant.next(9)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment