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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ 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).

## [Unreleased]

### Added

- Time scale conversion functions in FFI (`tempoch_jd_to_tt`, `tempoch_tt_to_jd`, `tempoch_jd_to_mjd`, `tempoch_mjd_to_jd`, `tempoch_jd_to_tai`, `tempoch_tai_to_jd`, `tempoch_jd_to_tdb`, `tempoch_tdb_to_jd`, `tempoch_jd_to_tcg`, `tempoch_tcg_to_jd`, `tempoch_jd_to_tcb`, `tempoch_tcb_to_jd`, `tempoch_jd_to_gps`, `tempoch_gps_to_jd`, `tempoch_jd_to_jde`, `tempoch_jde_to_jd`, `tempoch_jd_to_unix`, `tempoch_unix_to_jd`, `tempoch_jd_add_days`, `tempoch_jd_difference`, `tempoch_jd_difference_qty`, `tempoch_jd_add_qty`).
- `TempochScale` enum in FFI to enumerate all supported time scales.

### Changed

- Improved formatting and consistency in FFI time conversion implementations.

## [0.3.0 - 2026-02-19]

### Added
Expand Down
92 changes: 92 additions & 0 deletions tempoch-ffi/include/tempoch_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,29 @@ enum tempoch_status_t
typedef int32_t tempoch_status_t;
#endif // __cplusplus

// Scale label for the `tempoch_jd_to_scale()` / `tempoch_scale_to_jd()` dispatch.
//
enum TempochScale
#ifdef __cplusplus
: int32_t
#endif // __cplusplus
{
TEMPOCH_SCALE_JD = 0,
TEMPOCH_SCALE_MJD = 1,
TEMPOCH_SCALE_TDB = 2,
TEMPOCH_SCALE_TT = 3,
TEMPOCH_SCALE_TAI = 4,
TEMPOCH_SCALE_TCG = 5,
TEMPOCH_SCALE_TCB = 6,
TEMPOCH_SCALE_GPS = 7,
TEMPOCH_SCALE_UT = 8,
TEMPOCH_SCALE_JDE = 9,
TEMPOCH_SCALE_UNIX_TIME = 10,
};
#ifndef __cplusplus
typedef int32_t TempochScale;
#endif // __cplusplus

// A time period in Modified Julian Date, suitable for C interop.
typedef struct tempoch_period_mjd_t {
double start_mjd;
Expand Down Expand Up @@ -160,6 +183,75 @@ tempoch_status_t tempoch_period_mjd_intersection(struct tempoch_period_mjd_t a,
// Compute the duration of a period as a `QttyQuantity` in days.
qtty_quantity_t tempoch_period_mjd_duration_qty(struct tempoch_period_mjd_t period);

// Convert a Julian Date (TT) to TDB (Barycentric Dynamical Time).
double tempoch_jd_to_tdb(double jd);

// Convert TDB back to Julian Date (TT).
double tempoch_tdb_to_jd(double tdb);

// Convert a Julian Date (TT) to TT (Terrestrial Time). Identity—included for completeness.
double tempoch_jd_to_tt(double jd);

// Convert TT back to Julian Date (TT). Identity.
double tempoch_tt_to_jd(double tt);

// Convert a Julian Date (TT) to TAI (International Atomic Time).
double tempoch_jd_to_tai(double jd);

// Convert TAI back to Julian Date (TT).
double tempoch_tai_to_jd(double tai);

// Convert a Julian Date (TT) to TCG (Geocentric Coordinate Time).
double tempoch_jd_to_tcg(double jd);

// Convert TCG back to Julian Date (TT).
double tempoch_tcg_to_jd(double tcg);

// Convert a Julian Date (TT) to TCB (Barycentric Coordinate Time).
double tempoch_jd_to_tcb(double jd);

// Convert TCB back to Julian Date (TT).
double tempoch_tcb_to_jd(double tcb);

// Convert a Julian Date (TT) to GPS Time.
double tempoch_jd_to_gps(double jd);

// Convert GPS Time back to Julian Date (TT).
double tempoch_gps_to_jd(double gps);

// Convert a Julian Date (TT) to UT (Universal Time UT1).
double tempoch_jd_to_ut(double jd);

// Convert UT back to Julian Date (TT).
double tempoch_ut_to_jd(double ut);

// Convert a Julian Date (TT) to JDE (Julian Ephemeris Day — semantic alias of JD(TT)).
double tempoch_jd_to_jde(double jd);

// Convert JDE back to Julian Date (TT).
double tempoch_jde_to_jd(double jde);

// Convert a Julian Date (TT) to Unix Time (seconds since 1970-01-01T00:00:00 UTC, ignoring leap seconds).

double tempoch_jd_to_unix(double jd);

// Convert Unix Time back to Julian Date (TT).
double tempoch_unix_to_jd(double unix);

// Return ΔT = TT − UT1 in seconds for a given Julian Date.
//
// Uses the piecewise polynomial/tabular model from tempoch-core.
double tempoch_delta_t_seconds(double jd);

// Generic JD → any scale dispatch.
//
// Returns the value in the target time scale. Prefer the individual functions
// (`tempoch_jd_to_tdb`, etc.) when the target scale is known at compile time.
double tempoch_jd_to_scale(double jd, TempochScale scale);

// Generic any scale → JD dispatch.
double tempoch_scale_to_jd(double value, TempochScale scale);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
184 changes: 183 additions & 1 deletion tempoch-ffi/src/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use crate::error::TempochStatus;
use chrono::{DateTime, NaiveDate, Utc};
use qtty::Days;
use qtty_ffi::{QttyQuantity, UnitId};
use tempoch::{JulianDate, ModifiedJulianDate, TimeInstant, JD, MJD};
use tempoch::{
JulianDate, ModifiedJulianDate, Time, TimeInstant, UniversalTime, GPS, JD, JDE, MJD, TAI, TCB,
TCG, TDB, TT, UT,
};

// ═══════════════════════════════════════════════════════════════════════════
// C-repr types
Expand Down Expand Up @@ -307,6 +310,185 @@ pub extern "C" fn tempoch_period_mjd_duration_qty(period: crate::TempochPeriodMj
QttyQuantity::new(period.end_mjd - period.start_mjd, UnitId::Day)
}

// ═══════════════════════════════════════════════════════════════════════════
// Time scale conversions (JD ↔ TDB, TT, TAI, TCG, TCB, GPS, UT, JDE, UnixTime)
// ═══════════════════════════════════════════════════════════════════════════

/// Convert a Julian Date (TT) to TDB (Barycentric Dynamical Time).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_tdb(jd: f64) -> f64 {
JulianDate::new(jd).to::<TDB>().value()
}

/// Convert TDB back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_tdb_to_jd(tdb: f64) -> f64 {
Time::<TDB>::new(tdb).to::<JD>().value()
}

/// Convert a Julian Date (TT) to TT (Terrestrial Time). Identity—included for completeness.
#[no_mangle]
pub extern "C" fn tempoch_jd_to_tt(jd: f64) -> f64 {
JulianDate::new(jd).to::<TT>().value()
}

/// Convert TT back to Julian Date (TT). Identity.
#[no_mangle]
pub extern "C" fn tempoch_tt_to_jd(tt: f64) -> f64 {
Time::<TT>::new(tt).to::<JD>().value()
}

/// Convert a Julian Date (TT) to TAI (International Atomic Time).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_tai(jd: f64) -> f64 {
JulianDate::new(jd).to::<TAI>().value()
}

/// Convert TAI back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_tai_to_jd(tai: f64) -> f64 {
Time::<TAI>::new(tai).to::<JD>().value()
}

/// Convert a Julian Date (TT) to TCG (Geocentric Coordinate Time).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_tcg(jd: f64) -> f64 {
JulianDate::new(jd).to::<TCG>().value()
}

/// Convert TCG back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_tcg_to_jd(tcg: f64) -> f64 {
Time::<TCG>::new(tcg).to::<JD>().value()
}

/// Convert a Julian Date (TT) to TCB (Barycentric Coordinate Time).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_tcb(jd: f64) -> f64 {
JulianDate::new(jd).to::<TCB>().value()
}

/// Convert TCB back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_tcb_to_jd(tcb: f64) -> f64 {
Time::<TCB>::new(tcb).to::<JD>().value()
}

/// Convert a Julian Date (TT) to GPS Time.
#[no_mangle]
pub extern "C" fn tempoch_jd_to_gps(jd: f64) -> f64 {
JulianDate::new(jd).to::<GPS>().value()
}

/// Convert GPS Time back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_gps_to_jd(gps: f64) -> f64 {
Time::<GPS>::new(gps).to::<JD>().value()
}

/// Convert a Julian Date (TT) to UT (Universal Time UT1).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_ut(jd: f64) -> f64 {
JulianDate::new(jd).to::<UT>().value()
}

/// Convert UT back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_ut_to_jd(ut: f64) -> f64 {
Time::<UT>::new(ut).to::<JD>().value()
}

/// Convert a Julian Date (TT) to JDE (Julian Ephemeris Day — semantic alias of JD(TT)).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_jde(jd: f64) -> f64 {
JulianDate::new(jd).to::<JDE>().value()
}

/// Convert JDE back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_jde_to_jd(jde: f64) -> f64 {
Time::<JDE>::new(jde).to::<JD>().value()
}

/// Convert a Julian Date (TT) to Unix Time (seconds since 1970-01-01T00:00:00 UTC, ignoring leap seconds).
#[no_mangle]
pub extern "C" fn tempoch_jd_to_unix(jd: f64) -> f64 {
JulianDate::new(jd).to::<tempoch::UnixTime>().value()
}

/// Convert Unix Time back to Julian Date (TT).
#[no_mangle]
pub extern "C" fn tempoch_unix_to_jd(unix: f64) -> f64 {
Time::<tempoch::UnixTime>::new(unix).to::<JD>().value()
}

/// Return ΔT = TT − UT1 in seconds for a given Julian Date.
///
/// Uses the piecewise polynomial/tabular model from tempoch-core.
#[no_mangle]
pub extern "C" fn tempoch_delta_t_seconds(jd: f64) -> f64 {
let ut: UniversalTime = JulianDate::new(jd).to::<UT>();
ut.delta_t().value()
}

/// Scale label for the `tempoch_jd_to_scale()` / `tempoch_scale_to_jd()` dispatch.
///
/// cbindgen:prefix-with-name
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TempochScale {
JD = 0,
MJD = 1,
TDB = 2,
TT = 3,
TAI = 4,
TCG = 5,
TCB = 6,
GPS = 7,
UT = 8,
JDE = 9,
UnixTime = 10,
}

/// Generic JD → any scale dispatch.
///
/// Returns the value in the target time scale. Prefer the individual functions
/// (`tempoch_jd_to_tdb`, etc.) when the target scale is known at compile time.
#[no_mangle]
pub extern "C" fn tempoch_jd_to_scale(jd: f64, scale: TempochScale) -> f64 {
match scale {
TempochScale::JD => jd,
TempochScale::MJD => tempoch_jd_to_mjd(jd),
TempochScale::TDB => tempoch_jd_to_tdb(jd),
TempochScale::TT => tempoch_jd_to_tt(jd),
TempochScale::TAI => tempoch_jd_to_tai(jd),
TempochScale::TCG => tempoch_jd_to_tcg(jd),
TempochScale::TCB => tempoch_jd_to_tcb(jd),
TempochScale::GPS => tempoch_jd_to_gps(jd),
TempochScale::UT => tempoch_jd_to_ut(jd),
TempochScale::JDE => tempoch_jd_to_jde(jd),
TempochScale::UnixTime => tempoch_jd_to_unix(jd),
}
}

/// Generic any scale → JD dispatch.
#[no_mangle]
pub extern "C" fn tempoch_scale_to_jd(value: f64, scale: TempochScale) -> f64 {
match scale {
TempochScale::JD => value,
TempochScale::MJD => tempoch_mjd_to_jd(value),
TempochScale::TDB => tempoch_tdb_to_jd(value),
TempochScale::TT => tempoch_tt_to_jd(value),
TempochScale::TAI => tempoch_tai_to_jd(value),
TempochScale::TCG => tempoch_tcg_to_jd(value),
TempochScale::TCB => tempoch_tcb_to_jd(value),
TempochScale::GPS => tempoch_gps_to_jd(value),
TempochScale::UT => tempoch_ut_to_jd(value),
TempochScale::JDE => tempoch_jde_to_jd(value),
TempochScale::UnixTime => tempoch_unix_to_jd(value),
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down