Dates (Chrono)
Chrono (almasix.chrono) is Almasix’s Carbon-class date library. It subclasses
Python’s datetime, so it works anywhere a datetime is accepted, and every
“mutating” method returns a new instance.
Helpers now() and today() return Chrono. Prefer Chrono in application code;
reach for raw datetime only when an external API demands it.
Creating instances
Section titled “Creating instances”from almasix.chrono import Chrono
Chrono.now()Chrono.utcnow()Chrono.today()Chrono.tomorrow()Chrono.yesterday()Chrono.parse("2024-06-15 14:30:00")Chrono.parse("+3 days")Chrono.create(2024, 6, 15, 14, 30, 0)Chrono.create_from_format("%Y/%m/%d", "2024/06/15")Chrono.fromtimestamp(1_700_000_000)parse accepts ISO-8601 strings, a few relative phrases (now, today,
+2 hours), RFC 2822 timestamps, datetime / date objects, and unix
timestamps.
Timezones
Section titled “Timezones”Chrono instances are timezone-aware (default UTC).
from datetime import UTC
paris = Chrono.now("Europe/Paris")utc = paris.utc() # same instant, UTC offsetwall = paris.timezone(UTC) # keep wall-clock fields, change tz labelconverted = paris.set_timezone("America/New_York") # convert the instantAdding and subtracting
Section titled “Adding and subtracting”moment = Chrono.parse("2024-01-31")
moment.add_days(1)moment.sub_hours(3)moment.add(weeks=2, hours=5)moment.sub(months=1)Month arithmetic clamps the day (Jan 31 + 1 month → Feb 29/28).
Boundaries
Section titled “Boundaries”moment.start_of_day()moment.end_of_month()moment.start_of_week() # Monday by defaultmoment.end_of_quarter()moment.start_of_year()Also: start_of_hour / end_of_hour, start_of_minute / end_of_minute,
start_of_decade / end_of_decade, start_of_century / end_of_century.
Comparisons
Section titled “Comparisons”a = Chrono.parse("2024-06-01")b = Chrono.parse("2024-06-02")
a.lt(b) # Truea.between(a, b) # Truea.is_weekend()a.is_today()b.is_future()Aliases mirror Carbon where useful: equal_to, greater_than_or_equal_to, etc.
a.diff_in_days(b) # 1.0a.diff_for_humans(b) # "1 day ago"b.diff_for_humans(a) # "in 1 day"a.diff_for_humans(b, absolute=True) # "1 day"Formatting
Section titled “Formatting”moment.to_date_string() # 2024-06-15moment.to_time_string() # 14:30:00moment.to_datetime_string() # 2024-06-15 14:30:00moment.to_iso_string()moment.format("%A, %d %B %Y")Helpers
Section titled “Helpers”from almasix.support.helpers import now, today, set_test_now
now() # Chronotoday() # Chrono at 00:00:00Testing: freeze and travel
Section titled “Testing: freeze and travel”from almasix.chrono import Chrono, freeze, travel_to, travel, return_time
travel_to("2020-01-01")assert Chrono.now().year == 2020travel(2, unit="days")return_time()
with freeze("2021-05-05"): assert Chrono.today().year == 2021# wall clock restoredset_test_now on both Chrono and the support helpers talks to the same clock,
so ORM code that calls now() freezes with your tests.
Try it in your app
Section titled “Try it in your app”Use Chrono in a Smith command, a controller, or a test:
from almasix.chrono import Chrono, freeze
print(Chrono.now().add_days(3).to_date_string())
with freeze("2021-05-05"): assert Chrono.today().year == 2021Run the command from your app root (python smith …) or assert the freeze
inside your test suite.