#!/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 - Math calculation") print(" calc - Unit conversion") print(" calc until - Time until date") print(" calc pct - 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()