Add dates, gratitude, calc, timer - dates.py: Important dates and anniversaries - gratitude.py: Gratitude log - calc.py: Calculator and unit converter - timer.py: Countdown and stopwatch - 31 tools total!
This commit is contained in:
140
tools/calc.py
Executable file
140
tools/calc.py
Executable file
@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
calc - Quick calculator and unit converter
|
||||
|
||||
Math and conversions from the command line.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import math
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Common conversions
|
||||
CONVERSIONS = {
|
||||
# Length
|
||||
'km_to_mi': lambda x: x * 0.621371,
|
||||
'mi_to_km': lambda x: x * 1.60934,
|
||||
'm_to_ft': lambda x: x * 3.28084,
|
||||
'ft_to_m': lambda x: x * 0.3048,
|
||||
'in_to_cm': lambda x: x * 2.54,
|
||||
'cm_to_in': lambda x: x / 2.54,
|
||||
|
||||
# Weight
|
||||
'kg_to_lb': lambda x: x * 2.20462,
|
||||
'lb_to_kg': lambda x: x / 2.20462,
|
||||
'oz_to_g': lambda x: x * 28.3495,
|
||||
'g_to_oz': lambda x: x / 28.3495,
|
||||
|
||||
# Temperature
|
||||
'c_to_f': lambda x: x * 9/5 + 32,
|
||||
'f_to_c': lambda x: (x - 32) * 5/9,
|
||||
|
||||
# Volume
|
||||
'l_to_gal': lambda x: x * 0.264172,
|
||||
'gal_to_l': lambda x: x * 3.78541,
|
||||
|
||||
# Data
|
||||
'mb_to_gb': lambda x: x / 1024,
|
||||
'gb_to_mb': lambda x: x * 1024,
|
||||
'gb_to_tb': lambda x: x / 1024,
|
||||
'tb_to_gb': lambda x: x * 1024,
|
||||
}
|
||||
|
||||
def calculate(expr: str):
|
||||
"""Evaluate a math expression."""
|
||||
# Add math functions to namespace
|
||||
namespace = {
|
||||
'sqrt': math.sqrt,
|
||||
'sin': math.sin,
|
||||
'cos': math.cos,
|
||||
'tan': math.tan,
|
||||
'log': math.log,
|
||||
'log10': math.log10,
|
||||
'exp': math.exp,
|
||||
'pi': math.pi,
|
||||
'e': math.e,
|
||||
'abs': abs,
|
||||
'pow': pow,
|
||||
'round': round,
|
||||
}
|
||||
|
||||
try:
|
||||
result = eval(expr, {"__builtins__": {}}, namespace)
|
||||
print(f"= {result}")
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
|
||||
def convert(value: float, conversion: str):
|
||||
"""Convert between units."""
|
||||
if conversion in CONVERSIONS:
|
||||
result = CONVERSIONS[conversion](value)
|
||||
units = conversion.split('_to_')
|
||||
print(f"{value} {units[0]} = {result:.4f} {units[1]}")
|
||||
else:
|
||||
print(f"Unknown conversion: {conversion}")
|
||||
print("Available:", ', '.join(CONVERSIONS.keys()))
|
||||
|
||||
def time_until(target: str):
|
||||
"""Calculate time until a date."""
|
||||
try:
|
||||
if len(target) == 10: # YYYY-MM-DD
|
||||
target_date = datetime.strptime(target, "%Y-%m-%d")
|
||||
else:
|
||||
target_date = datetime.strptime(target, "%Y-%m-%d %H:%M")
|
||||
|
||||
diff = target_date - datetime.now()
|
||||
|
||||
if diff.total_seconds() < 0:
|
||||
print("That date has passed")
|
||||
return
|
||||
|
||||
days = diff.days
|
||||
hours, rem = divmod(diff.seconds, 3600)
|
||||
minutes = rem // 60
|
||||
|
||||
print(f"Time until {target}:")
|
||||
print(f" {days} days, {hours} hours, {minutes} minutes")
|
||||
except:
|
||||
print("Date format: YYYY-MM-DD or YYYY-MM-DD HH:MM")
|
||||
|
||||
def percentage(part: float, whole: float):
|
||||
"""Calculate percentage."""
|
||||
pct = (part / whole) * 100
|
||||
print(f"{part} / {whole} = {pct:.2f}%")
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:")
|
||||
print(" calc <expression> - Math calculation")
|
||||
print(" calc <value> <conversion> - Unit conversion")
|
||||
print(" calc until <YYYY-MM-DD> - Time until date")
|
||||
print(" calc pct <part> <whole> - Percentage")
|
||||
print("")
|
||||
print("Examples:")
|
||||
print(" calc '2 + 2'")
|
||||
print(" calc 'sqrt(16) + pi'")
|
||||
print(" calc 100 km_to_mi")
|
||||
print(" calc 72 f_to_c")
|
||||
print(" calc until 2026-12-31")
|
||||
print("")
|
||||
print("Conversions:", ', '.join(sorted(CONVERSIONS.keys())))
|
||||
return
|
||||
|
||||
cmd = sys.argv[1]
|
||||
|
||||
if cmd == 'until' and len(sys.argv) > 2:
|
||||
time_until(' '.join(sys.argv[2:]))
|
||||
|
||||
elif cmd == 'pct' and len(sys.argv) > 3:
|
||||
percentage(float(sys.argv[2]), float(sys.argv[3]))
|
||||
|
||||
elif len(sys.argv) == 3 and sys.argv[2] in CONVERSIONS:
|
||||
convert(float(sys.argv[1]), sys.argv[2])
|
||||
|
||||
else:
|
||||
# Treat as expression
|
||||
expr = ' '.join(sys.argv[1:])
|
||||
calculate(expr)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user