Time comes in a few kinds, and mixing them up causes most date bugs. Refingere gives each one its own type, so the checker keeps them apart.
Instant is a moment, the same everywhere - what &clock reads, what a log line records. Duration is how long something takes.Date, a TimeOfDay and a DateTime are what a calendar or a wall clock shows. They aren't moments until you say where: 09:30 in Warsaw and 09:30 in Tokyo are hours apart. TimeZone turns one into the other. A Date does calendar arithmetic the way people expect. Adding a month keeps the day when the month has it, and takes the month's last day when it doesn't. A date that doesn't exist is a DateError, never a date quietly moved. Dates compare and sort, and a range of them steps one day at a time, like next(). format writes them with YYYY, MM and DD, and times with hh, mm, ss and SSS.
toInstant puts a wall-clock time in a zone, and toDateTime reads a moment on a zone's clocks. A named zone follows daylight saving. A time that's skipped when clocks jump forward moves forward by the jump, and a time shown twice when they're turned back is the earlier of the two.
Named zones come from the host. A JavaScript host - --run, --test, a web page - knows every IANA zone. A WASI runtime knows none, so there TimeZone.named is a DateError, and only TimeZone.utc() and fixed offsets like TimeZone.fixed(Duration.hours(2.0)) work.
Date.today() and DateTime.now() read &clock for the moment and &timeZone for where. By default that's the host's own zone. A test injects both, so code that depends on today's date gives the same answer on every machine, at any hour. See Testing and Context.