feat: extend math engine: currencies, timezones, finance, cooking by antonreshetov · Pull Request #715 · massCodeIO/massCode

added 29 commits

March 29, 2026 10:10
- `workdays in 3 weeks` → 15 workdays
- `workdays from April 12 to June 15` → N workdays
- `March 3 to March 7 in workdays` → N workdays
- `2 workdays after March 3` → date
- `date to timestamp` → unix timestamp
- `date as iso8601` → ISO 8601 string
- `2019-04-01T15:30:00 to date` → parsed date
- `1733823083000 to date` → millisecond timestamp auto-detection
…in, time difference

- Airport codes: LAX, JFK, SYD, NRT, CDG, FRA, etc.
- Country names: Japan, Germany, Thailand, etc.
- City aliases: Seattle, Boston, Miami, etc.
- `date in Vancouver` → date-only display in timezone
- `time difference between Seattle and Moscow` → hours
- `difference between PDT & AEST` → hours
- `5.5 minutes as timespan` → 5 min 30 s
- `72 days as timespan` → 10 weeks 2 days
- `5.5 minutes as laptime` → 00:05:30
- `3h 5m 10s` shorthand input → stacked time units
- `03:04:05` laptime input → parsed as hours + minutes + seconds
- Laptime arithmetic: `03:04:05 + 01:02:03 as laptime` → 04:06:08
- `7:30 to 20:45` → 13 hours 15 min
- `4pm to 3am` → 11 hours (wraps around midnight)
- `9am to 5pm` → 8 hours
- Rounding: negative numbers, to 0 dp, to nearest 1, pi to 10 digits
- Fix: 'to N dp' now preserves N digits in output (not capped by default precision)
- Percentages: 0%, 100%, 200%, edge cases
- Fractions: 0.25 as fraction, -0.5 as fraction
- Multipliers: 0x, fractional multiplier
- Currency: euros/rubles words, implicit rate with EUR, reverse order
- Format directives: 0 in hex/bin, 0.001 in sci, mixed hex+bin input
- Conditionals: if with and, expression in condition, expression in postfix if
- Calendar: Q1/Q2/Q4, 0 days between, months/years from now/ago
- Clock intervals: midnight crossing, 12am/12pm, same time
- Timespans: 0 seconds, 1.5 hours, singular form
- min/max, half, midpoint, random, gcd/lcm
- permutations/combinations, clamp, proportions (rule of three)
- Timecode format HH:MM:SS:FF with `at/@ N fps` (default 24 fps)
- `frame`/`frames` and `fps` units registered in math.js
- Timecode → frames conversion: `00:30:10:00 @ 24 fps in frames`
- Timecode arithmetic: `03:10:20:05 at 30 fps + 50 frames`
- fps calculations: `30 fps * 3 minutes`
- Compound interest: yearly/monthly/quarterly compounding
- Interest only, ROI, annual return, present value
- Mortgage: daily/monthly/annual/total repayment and interest
- `0b101101 as base 8` → 0o55
- `0x2D as base 2` → 0b101101
- `hex(99)` → 0x63, `bin(0x73)` → 0b1110011, `int(0o55)` → 45
- Large numbers: B/bn (billion), T/tn (trillion), trillion word
- Comments: parenthesis comments `$999 (for iPhone)`, end-of-line `// comment`
- Parenthesis stripping safely skips function calls like sin(x)
- `density of yogurt` → 1.06 g/cm³
- `300g butter in cups` → mass-to-volume conversion
- `10 cups olive oil in grams` → volume-to-mass conversion
- ~120 cooking substances with densities
- Expand fiat currencies from 27 to 166 (all from open.er-api.com)
- Add 21 cryptocurrencies via CoinGecko API (BTC, ETH, SOL, DOGE, etc.)
- Prefixed dollar symbols: US$, NZ$, CA$, AU$, HK$, S$, NT$
- Custom exchange rates: `50 EUR in USD at 1.05 USD/EUR`
- CoinGecko + fiat fetched in parallel with 1h cache
14 fixture files covering all math engine features:
- arithmetic, variables, percentages, aggregates, rounding
- math functions, conditionals, units, currency
- fractions/multipliers, calendar, timezones, timespans
- finance, misc functions, cooking
- 4 real-world scenarios: budget, travel, cooking, dev
- Single formatMathDate() for all date outputs (timezone, calendar, arithmetic)
- DateFormatStyle: 'numeric' | 'short' | 'long' (configurable via setFormatSettings)
- Options: timeZone, timeZoneName, dateOnly for context-specific formatting
- Remove separate formatTimeZoneDate function
- All dates now respect user locale consistently
- Date format preference: numeric, short, long
- Separate refresh buttons for fiat currencies and crypto rates
- IPC handlers for forced refresh (ignores cache)
- i18n keys for new preferences
- numericBlock stores value + unit name
- Aggregates sum only if all entries have same unit
- Mixed units → aggregate returns null (cannot sum)
- $100 + $200 + $50 → sum = 350 USD
- Unit info extracted from math.js rawResult for block tracking

@antonreshetov antonreshetov changed the title feat: extend math engine — currencies, timezones, finance, cooking, UX fixes feat: extend math engine: currencies, timezones, finance, cooking

Mar 29, 2026
- P1: merge partial rates with existing cache instead of overwriting
- P2: show error toast on fiat refresh failure (was showing success)
- P2: finance evaluator uses user locale for formatting
- P2: cooking evaluator uses user locale for formatting
- P2: cooking classifier supports all volume units (pints, quarts, etc.)

@antonreshetov

- useMathEngine.integration.test.ts (66) — multi-line, variables, aggregates, errors
- useMathEngine.math.test.ts (229) — arithmetic, rounding, percentages, conditionals
- useMathEngine.units.test.ts (59) — unit conversion, area/volume, css, rates
- useMathEngine.currency.test.ts (22) — currency symbols, prefixes, modifiers
- useMathEngine.timezones.test.ts (28) — timezone display, conversion, difference
- useMathEngine.calendar.test.ts (47) — calendar, workdays, timestamps, timespans
- useMathEngine.domain.test.ts (17) — finance, cooking
- Shared setup in mathEngineTestUtils.ts

@antonreshetov