Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[submodule "tempoch"]
path = tempoch
url = git@github.com:Siderust/tempoch.git
branch = helpers
[submodule "qtty-cpp"]
path = qtty-cpp
url = https://github.com/Siderust/qtty-cpp.git
15 changes: 12 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,28 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.5.0] - 2026-05-18

### Breaking

- Removed `EncodedTime<S, F>::to_time()` / `to_time_with()` from the public C++ API; decode scalar
transport values into canonical storage using `Time<S>::from_encoded(encoded)` /
`Time<S>::from_encoded_with(encoded, ctx)` (parity with Rust `Time::to_j2000s()` after dropping the
historical aliases).

## [0.4.0] - 2026-05-15

### Added

- `include/tempoch/legacy_time.hpp` with opt-in deprecated aliases for pre-redesign names such as `UTC`, `JulianDate`, `MJD`, `TT`, `TAI`, `TDB`, `TCG`, `TCB`, `UT`, `JDE`, and `GPS`.
- New FFI exception mappings in `include/tempoch/ffi_core.hpp` for generic conversion failures and invalid format identifiers via `ConversionFailedError` and `InvalidFormatIdError`.

### Changed

- Refactored the public time model around explicit physical scales and external encodings: `Time<scale::S>` represents canonical instants, while `EncodedTime<S, F>` covers representations such as `JulianDate<scale::TT>`, `ModifiedJulianDate<scale::UTC>`, `UnixTime`, and `GpsTime`.
- `include/tempoch/time.hpp`, `time_base.hpp`, `scales.hpp`, and `period.hpp` now expose the split scale/format API, including `TimeContext` for UT1 and historical UTC conversions.
- `Period<T>` is now generalized across supported time representations through `TimeTraits`, with the default period type moved to `Period<ModifiedJulianDate<scale::TT>>`.
- README, Doxygen docs, examples, and tests were migrated from implicit aliases (`UTC`, `JulianDate`, `MJD`, `TT`) to the explicit typed API and conversion flow.
- `JulianDate::from_utc(...)`, `MJD::from_utc(...)`, `to_utc()`, `to_mjd()`, `to_jd()`, and direct `+=` / `-=` arithmetic are part of the supported ergonomic surface on top of the typed core.
- `Period<T>` remains generalized across supported time representations through `TimeTraits`.
- README, Doxygen docs, examples, and tests were updated to show the ergonomic TT-default workflow first, with the explicit typed API kept available for advanced mixed-scale use.
- Updated the vendored `tempoch` and `qtty-cpp` submodules to the snapshots used by this branch.

## [0.3.1] - 2026-05-11
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.15)
project(tempoch_cpp VERSION 0.4.0 LANGUAGES CXX)
project(tempoch_cpp VERSION 0.5.0 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -176,6 +176,7 @@ endforeach()
# Test executables with Google Test
set(TEST_SOURCES
tests/main.cpp
tests/test_headers.cpp
tests/test_time.cpp
tests/test_period.cpp
)
Expand Down
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,35 @@ git submodule update --init --recursive
#include <iostream>
#include <qtty/qtty.hpp>
#include <tempoch/tempoch.hpp>
#include <tempoch/formats/jd.hpp>
#include <tempoch/formats/mjd.hpp>
#include <tempoch/scales/utc.hpp>

int main() {
using namespace tempoch;

CivilTime civil{2026, 7, 15, 22, 0, 0};
auto utc = Time<scale::UTC>::from_civil(civil);
auto tt = utc.to<scale::TT>();

auto jd_tt = tt.to<format::JD>();
auto jd_tt = JulianDate<scale::TT>::from_utc(civil);
auto mjd_tt = ModifiedJulianDate<scale::TT>::from_jd(jd_tt);
auto utc = Time<scale::TT>::from_encoded(jd_tt).to<scale::UTC>();
auto jd_utc = utc.to<format::JD>();
auto mjd_tt = tt.to<format::MJD>();

std::cout << "Civil UTC : " << civil << "\n";
std::cout << "JD(TT) : " << jd_tt << "\n";
std::cout << "JD(UTC) : " << jd_utc << "\n";
std::cout << "MJD(TT) : " << mjd_tt << "\n";

Period<ModifiedJulianDate<scale::TT>> observing_window(
mjd_tt,
mjd_tt + qtty::Hour(12.0));
Period observing_window(mjd_tt, mjd_tt + qtty::Hour(12.0));
std::cout << "Duration: " << observing_window.duration<qtty::Hour>() << "\n";
}
```

The public headers are now split by concept:

- `tempoch/scales/*.hpp` for physical/civil time-axis tags and scale traits
- `tempoch/formats/*.hpp` for encoding tags and format traits
- `tempoch/tempoch.hpp` as the full umbrella include

### Durations and Arithmetic

Time arithmetic uses `qtty-cpp` quantities. Subtracting two times returns a typed duration, and adding or subtracting a quantity shifts the time value.
Expand All @@ -87,13 +92,11 @@ auto dt = jd1 - jd0;
std::cout << dt.to<qtty::Hour>() << "\n";
```

## Migration Notes
## API Notes

- Old `JulianDate` means `JulianDate<scale::TT>`.
- Old `MJD` means `ModifiedJulianDate<scale::TT>`.
- Old `TT` means `Time<scale::TT>`, not a JD-valued wrapper.
- Old `UTC` civil construction is now `CivilTime` plus `Time<scale::UTC>::from_civil(...)`.
- Legacy names remain available only through opt-in shim headers such as `tempoch/legacy_time.hpp`.
- Default astronomy-facing code should use TT-based `JulianDate`, `MJD`, and `Period`.
- Civil construction is available directly through `JulianDate<scale::TT>::from_utc(...)` and `ModifiedJulianDate<scale::TT>::from_utc(...)`.
- The explicit typed core remains available through `Time<scale::S>` and `EncodedTime<S, F>` for mixed-scale work.

## Documentation

Expand Down
25 changes: 13 additions & 12 deletions docs/mainpage.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ time primitives. It wraps the Rust-based
| **`Time<scale::S>`** | Canonical instant on a physical timescale, stored as split J2000 seconds |
| **`EncodedTime<S, F>`** | Typed external encoding such as `JulianDate<scale::TT>` or `ModifiedJulianDate<scale::UTC>` |
| **`TimeContext`** | Explicit context for UT1 and historical UTC routes |
| **`Period<T>`** | Inclusive `[start, end]` interval over any supported time representation |
| **`Period<T>`** | Half-open `[start, end)` interval over any supported time representation |
| **Exception hierarchy** | All FFI status codes map to typed C++ exceptions |
| **Header-only** | Drop into any project — no separate compilation step |

Expand All @@ -26,18 +26,19 @@ time primitives. It wraps the Rust-based

```cpp
#include <tempoch/tempoch.hpp>
#include <tempoch/formats/jd.hpp>
#include <tempoch/formats/mjd.hpp>
#include <tempoch/scales/utc.hpp>
#include <iostream>

int main() {
using namespace tempoch;

CivilTime civil{2026, 7, 15, 22, 0, 0};
auto utc = Time<scale::UTC>::from_civil(civil);
auto tt = utc.to<scale::TT>();

auto jd_tt = tt.to<format::JD>();
auto jd_tt = JulianDate<scale::TT>::from_utc(civil);
auto mjd_tt = ModifiedJulianDate<scale::TT>::from_jd(jd_tt);
auto utc = Time<scale::TT>::from_encoded(jd_tt).to<scale::UTC>();
auto jd_utc = utc.to<format::JD>();
auto mjd_tt = tt.to<format::MJD>();

std::cout << "Civil UTC : " << civil << "\n";
std::cout << "JD(TT) : " << jd_tt << "\n";
Expand Down Expand Up @@ -76,17 +77,17 @@ int main() {
## Modules

- `tempoch/tempoch.hpp` — umbrella include for the full public API
- `tempoch/time.hpp` — `CivilTime`, `Time<scale::S>`, `JulianDate<scale::S>`, `ModifiedJulianDate<scale::S>`
- `tempoch/scales/scales.hpp` — scale tag index header
- `tempoch/formats/formats.hpp` — format tag index header
- `tempoch/time.hpp` — `CivilTime`, TT-default `JulianDate` / `MJD`, explicit `Time<scale::S>`, and `TimeContext`
- `tempoch/period.hpp` — `Period` interval type
- `tempoch/ffi_core.hpp` — FFI helpers and exception hierarchy

## Migration Notes

- Old `JulianDate` means `JulianDate<scale::TT>`.
- Old `MJD` means `ModifiedJulianDate<scale::TT>`.
- Old `TT` means `Time<scale::TT>`.
- Old `UTC` civil construction is now `CivilTime` plus `Time<scale::UTC>::from_civil(...)`.
- Legacy names are available only through opt-in compatibility headers.
- Default astronomy-facing code should use TT-based `JulianDate`, `MJD`, and `Period`.
- Civil construction is available directly through `JulianDate<scale::TT>::from_utc(...)` and `ModifiedJulianDate<scale::TT>::from_utc(...)`.
- The explicit typed core remains available through `Time<scale::S>` and `EncodedTime<S, F>` for mixed-scale work.

---

Expand Down
2 changes: 1 addition & 1 deletion examples/02_scales.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int main() {
auto ctx = TimeContext::with_builtin_eop();

auto jd_tt = JulianDate<scale::TT>::J2000();
auto tt = jd_tt.to_time();
auto tt = Time<scale::TT>::from_encoded(jd_tt);
auto tai = tt.to<scale::TAI>();
auto utc = tt.to<scale::UTC>().to_civil();
auto ut1 = tt.to_with<scale::UT1>(ctx);
Expand Down
16 changes: 6 additions & 10 deletions examples/03_formats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,30 @@
#include <iostream>
#include <tempoch/tempoch.hpp>

// Well-known fixed values (from tempoch-core::constats).
static constexpr double UNIX_EPOCH_JD = 2'440'587.5; // 1970-01-01 JD
static constexpr double UNIX_EPOCH_MJD = 40'587.0; // 1970-01-01 MJD

int main() {
using namespace tempoch;

// J2000 epoch as canonical TT, then viewed through encodings.
auto j2000_tt = JulianDate<scale::TT>::J2000().to_time();
auto j2000_tt = Time<scale::TT>::from_encoded(JulianDate<scale::TT>::J2000());

// Sample TT instant: J2000 + 123 456.789 s.
auto sample_tt = j2000_tt + qtty::Second(123'456.789);

// J2000 from JulianDate constructor (mirrors JulianDate::<TT>::try_new(J2000_JD_TT)).
// J2000 from JD scalar (matches Rust example using `j2000_jd_tt()`).
JulianDate<scale::TT> j2000_from_jd{constants::j2000_jd_tt()};

// Unix epoch from JD value.
JulianDate<scale::TT> unix_epoch_jd{UNIX_EPOCH_JD};
// Unix epoch from JD value (ABI-stable constants wrapper).
JulianDate<scale::TT> unix_epoch_jd{constants::unix_epoch_jd()};

// Half-day after J2000 via JD.
JulianDate<scale::TT> half_day_jd{constants::j2000_jd_tt() + 0.5};

// Unix epoch from MJD value.
ModifiedJulianDate<scale::TT> unix_epoch_mjd{UNIX_EPOCH_MJD};
ModifiedJulianDate<scale::TT> unix_epoch_mjd{constants::unix_epoch_mjd()};

// Unix time from seconds (mirrors UnixTime::try_new(Second::new(1_700_000_000.25))).
UnixTime ux{1'700'000'000.25};
auto utc_from_ux = ux.to_time().to_civil();
auto utc_from_ux = Time<scale::UTC>::from_encoded(ux).to_civil();

std::cout << std::fixed << std::setprecision(9);
std::cout << "J2000 TT JD : " << j2000_tt.to<format::JD>() << "\n";
Expand Down
2 changes: 1 addition & 1 deletion examples/06_runtime_tables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ int main() {

// ── Unix timestamp roundtrip ─────────────────────────────────────────────
UnixTime ux{1'700'000'000.0};
auto utc_from_ux = ux.to_time().to_civil();
auto utc_from_ux = Time<scale::UTC>::from_encoded(ux).to_civil();
auto back = Time<scale::UTC>::from_civil(utc_from_ux).to<format::Unix>();

std::cout << std::fixed << std::setprecision(3);
Expand Down
2 changes: 1 addition & 1 deletion examples/07_conversions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ int main() {

// Start from a Unix timestamp (mirrors UnixTime::try_new(1_700_000_000.25)).
UnixTime ux{1'700'000'000.25};
auto utc = ux.to_time().to_civil();
auto utc = Time<scale::UTC>::from_encoded(ux).to_civil();

// Convert across continuous scales.
auto tai = ux.to<scale::TAI>();
Expand Down
6 changes: 3 additions & 3 deletions include/tempoch/civil_time.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* @file civil_time.hpp
* @brief UTC date-time breakdown struct.
*
* Forward-declared in scales.hpp and fully defined here to avoid circular
* dependencies.
* Included by the public time headers and kept separate to avoid circular
* dependencies between the civil carrier and the scale/format tag headers.
*/

#include "ffi_core.hpp"
Expand All @@ -31,7 +31,7 @@ struct CivilTime {
uint8_t day; ///< Day of month [1, 31].
uint8_t hour; ///< Hour [0, 23].
uint8_t minute; ///< Minute [0, 59].
uint8_t second; ///< Second [0, 59].
uint8_t second; ///< Second [0, 60] (60 only during a positive leap second).
uint32_t nanosecond; ///< Nanosecond [0, 999 999 999].

/// Default constructor: J2000 epoch noon-like civil representation.
Expand Down
6 changes: 6 additions & 0 deletions include/tempoch/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ namespace constants {
/// J2000.0 epoch as a Julian Date in TT (2 451 545.0).
inline double j2000_jd_tt() noexcept { return tempoch_const_j2000_jd_tt(); }

/// Unix epoch as Julian Date on the UTC axis (`1970-01-01` midnight UTC).
inline double unix_epoch_jd() noexcept { return tempoch_const_unix_epoch_jd(); }

/// Unix epoch as Modified Julian Day on the UTC axis (`40 587.0`).
inline double unix_epoch_mjd() noexcept { return tempoch_const_unix_epoch_mjd(); }

/// Length of a Julian year in days (365.25 days).
inline double julian_year_days() noexcept { return tempoch_const_julian_year_days(); }

Expand Down
15 changes: 15 additions & 0 deletions include/tempoch/formats/base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "../ffi_core.hpp"
#include <qtty/qtty.hpp>
#include <type_traits>

namespace tempoch {

template <typename T> struct is_format : std::false_type {};
template <typename T> inline constexpr bool is_format_v = is_format<T>::value;

template <typename F> struct FormatTraits;
template <typename F> inline constexpr tempoch_format_tag_t format_tag_v = FormatTraits<F>::ffi_tag;

} // namespace tempoch
12 changes: 12 additions & 0 deletions include/tempoch/formats/formats.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

/**
* @file formats/formats.hpp
* @brief Time-format tag types for the tempoch C++ API.
*/

#include "gps.hpp"
#include "j2000s.hpp"
#include "jd.hpp"
#include "mjd.hpp"
#include "unix.hpp"
19 changes: 19 additions & 0 deletions include/tempoch/formats/gps.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "base.hpp"

namespace tempoch {

namespace format {
struct GPS {};
} // namespace format

template <> struct is_format<format::GPS> : std::true_type {};

template <> struct FormatTraits<format::GPS> {
using quantity_type = qtty::Second;
static constexpr tempoch_format_tag_t ffi_tag = TEMPOCH_FORMAT_TAG_T_GPS;
static constexpr const char *name() { return "GPS"; }
};

} // namespace tempoch
19 changes: 19 additions & 0 deletions include/tempoch/formats/j2000s.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "base.hpp"

namespace tempoch {

namespace format {
struct J2000s {};
} // namespace format

template <> struct is_format<format::J2000s> : std::true_type {};

template <> struct FormatTraits<format::J2000s> {
using quantity_type = qtty::Second;
static constexpr tempoch_format_tag_t ffi_tag = TEMPOCH_FORMAT_TAG_T_J2000_SECONDS;
static constexpr const char *name() { return "J2000s"; }
};

} // namespace tempoch
19 changes: 19 additions & 0 deletions include/tempoch/formats/jd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "base.hpp"

namespace tempoch {

namespace format {
struct JD {};
} // namespace format

template <> struct is_format<format::JD> : std::true_type {};

template <> struct FormatTraits<format::JD> {
using quantity_type = qtty::Day;
static constexpr tempoch_format_tag_t ffi_tag = TEMPOCH_FORMAT_TAG_T_JD;
static constexpr const char *name() { return "JD"; }
};

} // namespace tempoch
19 changes: 19 additions & 0 deletions include/tempoch/formats/mjd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include "base.hpp"

namespace tempoch {

namespace format {
struct MJD {};
} // namespace format

template <> struct is_format<format::MJD> : std::true_type {};

template <> struct FormatTraits<format::MJD> {
using quantity_type = qtty::Day;
static constexpr tempoch_format_tag_t ffi_tag = TEMPOCH_FORMAT_TAG_T_MJD;
static constexpr const char *name() { return "MJD"; }
};

} // namespace tempoch
Loading
Loading