# attotime: Accurate, flexible, and efficient time keeping
`attotime` is a Rust library for accurate, flexible, and efficient timekeeping, designed for applications where precision and performance are critical.
- **Accurate**: Supports exact arithmetic with attosecond-level precision over extensive time ranges, without sacrificing correctness or performance.
- **Efficient**: Represents time values as tick counts since an epoch, enabling compact storage and fast processing without conversion overhead.
- **Verified**: Key correctness properties have been formally proven using the [`Kani` model checker](https://model-checking.github.io/kani/), ensuring a high degree of reliability.
- **Portable**: The core functionality of the `attotime` library is `no_std`, such that it may be used even in bare metal environments.

With this fine degree of control and precision, `attotime` is suitable for all types of applications, from nanoseconds in embedded systems to femtoseconds in scientific computing, or picoseconds for precise orbit determination.

## Getting started
`attotime` requires the `cargo` build system for the Rust programming language to be present on your system. The library may be added as dependency for your Rust project by running `cargo add attotime`. Afterwards, it may be used directly by importing `attotime` into your Rust source code.

## Expressing time points
In `attotime`, time points are always bound to a specific timekeeping standard, indicated as `TimeScale`. One such example is Coordinated Universal Time (UTC). Time points may be constructed directly from some given datetime in the historic calendar:
```rust
use attotime::{UtcTime, Month};
let epoch = UtcTime::from_historic_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
```
Note that constructing time points from datetimes may fail, because the given arguments do not form a valid time-of-day, or because the given date did not occur in the historic calendar: `attotime` makes this explicit. Users must acknowledge this possibility by unwrapping the returned `Result` before being able to use the created `UtcTime`.

A wide variety of time scales may be encountered in the context of precise timekeeping.
`attotime` provides implementations for the most prevalent time scales: UTC, TAI, terrestrial time (TT), GPS time (GPST), and most other GNSS time scales.
Unix time is explicitly not included, as it is not a continuous time scale: the difference between two Unix times does not reflect the physically elapsed time, because leap seconds are not accounted for.
Where possible, times can be converted between time scales using the `into_time_scale()` function, or the equivalent `into_<scale>()` functions.
```rust
use attotime::{GalileoTime, GpsTime, TaiTime, UtcTime, Month, IntoTimeScale, Second};
let epoch_utc = UtcTime::from_historic_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tai = TaiTime::from_historic_datetime(2025, Month::August, 3, 20, 26, 19).unwrap();
let epoch_gps = GpsTime::from_historic_datetime(2025, Month::August, 3, 20, 26, 0).unwrap();
let epoch_galileo = GalileoTime::from_historic_datetime(2025, Month::August, 3, 20, 26, 0).unwrap();
assert_eq!(epoch_utc.into_time_scale(), epoch_tai);
assert_eq!(epoch_utc.into_gpst(), epoch_gps);
assert_eq!(epoch_utc.into_gst(), epoch_galileo);
```
If a desired time scale is not present, users may provide their own by implementing the `TimeScale` trait. To support calendrical functionality, it is additionally necessary to implement the `AbsoluteTimeScale` trait.

There is also support for subsecond datetime values:
```rust
use attotime::{UtcTime, TtTime, Month, Duration};
let epoch_utc = UtcTime::from_historic_datetime(2025, Month::August, 3, 20, 25, 42).unwrap();
let epoch_tt = TtTime::from_fine_historic_datetime(2025, Month::August, 3, 20, 26, 51, Duration::milliseconds(184)).unwrap();
assert_eq!(epoch_utc.into_tt(), epoch_tt);
```

## Expressing durations
Within `attotime`, the difference between two `TimePoint`s is expressed as a `Duration`:
```rust
use attotime::{UtcTime, Month, Duration};
let epoch1 = UtcTime::from_historic_datetime(2020, Month::September, 30, 23, 59, 58).unwrap();
let epoch2 = UtcTime::from_historic_datetime(2020, Month::October, 1, 0, 2, 3).unwrap();
let duration = epoch2 - epoch1;
assert_eq!(duration, Duration::seconds(125));
```

Leap second boundaries are handled seamlessly:
```rust
use attotime::{UtcTime, Month, Duration};
let epoch1 = UtcTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let epoch2 = UtcTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 60).unwrap();
let epoch3 = UtcTime::from_historic_datetime(2017, Month::January, 1, 0, 0, 0).unwrap();
assert_eq!(epoch2 - epoch1, Duration::seconds(1));
assert_eq!(epoch3 - epoch2, Duration::seconds(1));
assert_eq!(epoch3 - epoch1, Duration::seconds(2));
```
The same goes when a time scale does not apply leap seconds:
```rust
use attotime::{TaiTime, Month, Duration};
let epoch1 = TaiTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 59).unwrap();
let _ = TaiTime::from_historic_datetime(2016, Month::December, 31, 23, 59, 60).unwrap_err();
let epoch3 = TaiTime::from_historic_datetime(2017, Month::January, 1, 0, 0, 0).unwrap();
assert_eq!(epoch3 - epoch1, Duration::seconds(1));
```

As with `TimePoint`s, unit compatibility is checked at compile time, with conversions permit using the `into_unit()` method:
```rust
use attotime::{GpsTime, Month, Duration};
let epoch1 = GpsTime::from_historic_datetime(2024, Month::August, 13, 19, 30, 0).unwrap();
let epoch2 = epoch1 + Duration::hours(2);
let epoch3 = epoch1 + Duration::milliseconds(1);
assert_eq!(epoch2, GpsTime::from_historic_datetime(2024, Month::August, 13, 21, 30, 0).unwrap());
assert_eq!(epoch3, GpsTime::from_fine_historic_datetime(2024, Month::August, 13, 19, 30, 0, Duration::milliseconds(1)).unwrap());
```

## Comparison with `hifitime`, `chrono`, `time`, `jiff`, and `finetime`.
There are a multitude of high-quality Rust timekeeping crates out there already.
In particular, `chrono`, `time`, `jiff`, and `hifitime` will already cover most people's use cases.
Most users will be interested in `jiff`, `chrono` and `time`, which are highly suitable for day-to-day timekeeping.
They handle civilian time zones (which `attotime` does not) and integrate much better with the operating system: however, they do not permit high-accuracy timestamps in frequently-used scientific and engineering time scales, like GPS, TAI, and TT. This makes them unsuitable for astrodynamics, physics, and engineering.
For users that are not interested in such niche applications and time scales, any of `jiff`, `chrono`, and `time` will certainly handle your needs: `attotime` might as well, but is certainly not the only option.

On the other hand, `hifitime` does handle such specialist time scales (although, in turn, it does not cover civilian time scales beyond UTC).
Additionally, `hifitime` supports nanosecond precision and is validated against the timekeeping part of the SPICE astrodynamics library.
Yet, `hifitime`'s `Epoch` type is limited to nanosecond precision and uses a segmented time type that dynamically stores the underlying time standard used.
This introduces quite some complexity in what could be a simple tick counting type.
This complexity definitely does not affect its correctness at all: `hifitime` is well-validated.
However, it does affect the efficiency of the time representation used: `Epoch` always consists of at least an 80-bit `Duration` (on most systems, resulting in a 128-bit effective size) and an at minimum 8-bit `TimeScale`.
Additionally, this means that the `Epoch` type cannot easily be extended to admit subnanosecond accuracy: in some GNSS applications, such accuracy is becoming necessary.

`attotime` is meant to address these concerns: it efficiently stores the underlying time stamp as a simple tick count. This means that all arithmetic on time stamps reduces to simple arithmetic directly on the underlying tick count: as efficient as it would be when written by hand.
Additionally, the `attotime` `TimePoint` type is generic over the time scale used.
Conversion routines are written to support convenient and zero-overhead casting to other `TimePoint` times, where they are compatible.
Consequently, `attotime` is suitable for subnanosecond applications as well as for scenarios where a wide time range.

Finally, `attotime` is a successor to the `finetime` library (by the same author), which addresses the same concerns. Additionally, `finetime` is generic over the underlying tick count representation: indeed, it is more flexible than `attotime`.
However, this flexibility does come at an implementation and usability cost: for the general case - even in specialist applications.
When attosecond accuracy over a lifetime-of-the-universe time range with a 128-bit representation is fine, `attotime` is useful and provides more quality-of-life functionality.