Skip to content

Commit 6ad1755

Browse files
authored
Merge pull request #3 from Siderust/extend-ffi
feat: add FFI-backed time scales and conversion traits for various ti…
2 parents b4bc764 + bfa0f0d commit 6ad1755

9 files changed

Lines changed: 587 additions & 81 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# Artifacts
2+
build*/
3+
coverage*/
4+
15
# Prerequisites
26
*.d
37

CHANGELOG.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Changelog
2+
3+
All notable changes to this project will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Added
11+
12+
- `CivilTime` struct for UTC date-time breakdown, replacing forward declaration in scales.
13+
- Supports construction from individual components and conversion to/from C FFI `tempoch_utc_t`.
14+
- Stream operator support for formatted output as YYYY-MM-DD HH:MM:SS[.nnnnnnnnn].
15+
- `TimeScaleTraits` specializations for multiple time scales:
16+
- `JDScale` — Julian Date (days since −4712‑01‑01T12:00 TT)
17+
- `MJDScale` — Modified Julian Date (JD − 2 400 000.5)
18+
- `UTCScale` — UTC (internally represented as MJD days)
19+
- `TTScale` — Terrestrial Time
20+
- `TAIScale` — International Atomic Time
21+
- `TDBScale` — Barycentric Dynamical Time
22+
- `TCGScale` — Geocentric Coordinate Time
23+
- `TCBScale` — Barycentric Coordinate Time
24+
- `GPSScale` — GPS Time
25+
- `UTScale` — Universal Time (UT1)
26+
- `JDEScale` — Julian Ephemeris Date
27+
- `UnixTimeScale` — Unix (POSIX) time
28+
- Type aliases for convenience:
29+
- `using JulianDate = Time<JDScale>`
30+
- `using MJD = Time<MJDScale>`
31+
- `using TDB = Time<TDBScale>`
32+
- `using TT = Time<TTScale>`
33+
- `using TAI = Time<TAIScale>`
34+
- `using TCG = Time<TCGScale>`
35+
- `using TCB = Time<TCBScale>`
36+
- `using GPS = Time<GPSScale>`
37+
- `using UT = Time<UTScale>`
38+
- `using UniversalTime = Time<UTScale>`
39+
- `using JDE = Time<JDEScale>`
40+
- `using UnixTime = Time<UnixTimeScale>`
41+
- Local CI runner script (`run-ci.sh`) that executes lint, build, test, and coverage checks.
42+
- Code coverage reporting to CI pipeline via gcovr (XML and HTML reports).
43+
- `.gitignore` entries for build outputs and coverage artifacts.
44+
45+
### Changed
46+
47+
- Reorganized codebase to separate `CivilTime` definition into dedicated header (`civil_time.hpp`) to resolve circular dependencies.
48+
- Refactored `scales.hpp` to include full `CivilTime` definition and improve template specialization organization.
49+
- Updated `time_base.hpp` to use new `civil_time.hpp` header.
50+
51+
### Fixed
52+
53+
- Fixed clang-format violations in header files.
54+
- Resolved incomplete type errors in clang-tidy by properly completing `CivilTime` definition before use in template specializations.
55+
- Improved include chain to ensure all FFI-backed time scale conversions are properly typed and compiled.
56+
57+
## [0.1.0]
58+
59+
- Initial C++ wrapper for tempoch FFI library.
60+
- Core `Time<S>` class template with FFI-backed time scale dispatch.
61+
- Period arithmetic and interval operations.
62+
- Example programs demonstrating time scale conversions and period operations.

coverage.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<?xml version='1.0' encoding='UTF-8'?>
2+
<!DOCTYPE coverage SYSTEM 'http://cobertura.sourceforge.net/xml/coverage-04.dtd'>
3+
<coverage line-rate="0.8235294117647058" branch-rate="0.31896551724137934" lines-covered="126" lines-valid="153" branches-covered="37" branches-valid="116" complexity="0.0" timestamp="1772305310" version="gcovr 7.0"><sources><source>.</source></sources><packages><package name="include.tempoch" line-rate="0.923728813559322" branch-rate="0.4155844155844156" complexity="0.0"><classes><class name="civil_time_hpp" filename="include/tempoch/civil_time.hpp" line-rate="1.0" branch-rate="1.0" complexity="0.0"><methods/><lines><line number="37" hits="1" branch="false"/><line number="38" hits="1" branch="false"/><line number="39" hits="1" branch="false"/><line number="44" hits="7" branch="false"/><line number="46" hits="7" branch="false"/><line number="47" hits="7" branch="false"/><line number="50" hits="4" branch="false"/><line number="51" hits="4" branch="false"/><line number="55" hits="3" branch="false"/><line number="56" hits="6" branch="false"/><line number="57" hits="3" branch="false"/></lines></class><class name="ffi_core_hpp" filename="include/tempoch/ffi_core.hpp" line-rate="0.6086956521739131" branch-rate="0.2857142857142857" complexity="0.0"><methods/><lines><line number="29" hits="2" branch="false"/><line number="37" hits="0" branch="false"/><line number="45" hits="0" branch="false"/><line number="53" hits="1" branch="false"/><line number="61" hits="1" branch="false"/><line number="62" hits="1" branch="false"/><line number="72" hits="24" branch="false"/><line number="73" hits="24" branch="true" condition-coverage="100% (2/2)"><conditions><condition number="0" type="jump" coverage="100%"/></conditions></line><line number="74" hits="22" branch="false"/><line number="76" hits="2" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="77" hits="2" branch="true" condition-coverage="40% (2/5)"><conditions><condition number="0" type="jump" coverage="40%"/></conditions></line><line number="78" hits="0" branch="false"/><line number="79" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="80" hits="0" branch="false"/><line number="81" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="82" hits="1" branch="false"/><line number="83" hits="1" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="84" hits="1" branch="false"/><line number="85" hits="1" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="86" hits="0" branch="false"/><line number="87" hits="0" branch="true" condition-coverage="0% (0/6)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="88" hits="0" branch="true" condition-coverage="0% (0/2)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="90" hits="2" branch="false"/></lines></class><class name="period_hpp" filename="include/tempoch/period.hpp" line-rate="1.0" branch-rate="0.6" complexity="0.0"><methods/><lines><line number="69" hits="2" branch="false"/><line number="83" hits="12" branch="false"/><line number="84" hits="12" branch="false"/><line number="88" hits="11" branch="false"/><line number="92" hits="2" branch="false"/><line number="95" hits="3" branch="false"/><line number="98" hits="2" branch="false"/><line number="120" hits="12" branch="false"/><line number="121" hits="12" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="122" hits="12" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="131" hits="2" branch="false"/><line number="133" hits="2" branch="true" condition-coverage="75% (3/4)"><conditions><condition number="0" type="jump" coverage="75%"/></conditions></line><line number="135" hits="2" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="139" hits="1" branch="false"/></lines></class><class name="scales_hpp" filename="include/tempoch/scales.hpp" line-rate="1.0" branch-rate="1.0" complexity="0.0"><methods/><lines><line number="97" hits="3" branch="false"/><line number="98" hits="3" branch="false"/><line number="102" hits="3" branch="false"/><line number="103" hits="3" branch="false"/><line number="104" hits="3" branch="false"/><line number="107" hits="4" branch="false"/><line number="110" hits="1" branch="false"/><line number="111" hits="1" branch="false"/><line number="116" hits="2" branch="false"/><line number="117" hits="2" branch="false"/><line number="138" hits="2" branch="false"/><line number="139" hits="2" branch="false"/><line number="143" hits="2" branch="false"/><line number="144" hits="2" branch="false"/><line number="146" hits="2" branch="false"/><line number="332" hits="3" branch="false"/><line number="336" hits="1" branch="false"/></lines></class><class name="time_base_hpp" filename="include/tempoch/time_base.hpp" line-rate="1.0" branch-rate="0.5" complexity="0.0"><methods/><lines><line number="29" hits="2" branch="false"/><line number="31" hits="2" branch="false"/><line number="32" hits="2" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="33" hits="2" branch="false"/><line number="36" hits="1" branch="false"/><line number="38" hits="1" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="39" hits="2" branch="false"/><line number="42" hits="1" branch="false"/><line number="44" hits="1" branch="false"/><line number="45" hits="1" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="46" hits="1" branch="false"/><line number="49" hits="1" branch="false"/><line number="51" hits="1" branch="true" condition-coverage="50% (2/4)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="52" hits="2" branch="false"/><line number="92" hits="88" branch="false"/><line number="107" hits="6" branch="false"/><line number="108" hits="6" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="114" hits="74" branch="false"/><line number="122" hits="4" branch="false"/><line number="146" hits="8" branch="false"/><line number="147" hits="8" branch="false"/><line number="149" hits="8" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="150" hits="8" branch="false"/><line number="156" hits="1" branch="false"/><line number="157" hits="1" branch="false"/><line number="159" hits="1" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="160" hits="1" branch="false"/><line number="172" hits="10" branch="false"/><line number="173" hits="10" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="174" hits="10" branch="false"/><line number="179" hits="4" branch="false"/><line number="180" hits="4" branch="false"/><line number="181" hits="4" branch="false"/><line number="182" hits="4" branch="false"/><line number="183" hits="4" branch="false"/><line number="184" hits="1" branch="false"/><line number="190" hits="4" branch="false"/><line number="191" hits="4" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="197" hits="1" branch="false"/><line number="198" hits="1" branch="false"/><line number="205" hits="2" branch="false"/><line number="206" hits="2" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="207" hits="2" branch="false"/><line number="214" hits="1" branch="false"/><line number="215" hits="1" branch="false"/><line number="221" hits="2" branch="false"/><line number="222" hits="2" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="227" hits="1" branch="false"/><line number="228" hits="1" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="259" hits="24" branch="false"/><line number="261" hits="24" branch="false"/><line number="267" hits="5" branch="false"/><line number="269" hits="5" branch="false"/></lines></class></classes></package><package name="qtty-cpp.include.qtty" line-rate="0.4" branch-rate="0.1282051282051282" complexity="0.0"><classes><class name="ffi_core_hpp" filename="qtty-cpp/include/qtty/ffi_core.hpp" line-rate="0.4" branch-rate="0.1282051282051282" complexity="0.0"><methods/><lines><line number="39" hits="0" branch="false"/><line number="47" hits="0" branch="false"/><line number="55" hits="0" branch="false"/><line number="56" hits="0" branch="false"/><line number="64" hits="0" branch="false"/><line number="81" hits="14" branch="false"/><line number="82" hits="14" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="83" hits="14" branch="false"/><line number="86" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="87" hits="0" branch="true" condition-coverage="0% (0/5)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="88" hits="0" branch="false"/><line number="89" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="90" hits="0" branch="false"/><line number="91" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="92" hits="0" branch="false"/><line number="93" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="94" hits="0" branch="false"/><line number="95" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="96" hits="0" branch="false"/><line number="97" hits="0" branch="true" condition-coverage="0% (0/4)"><conditions><condition number="0" type="jump" coverage="0%"/></conditions></line><line number="99" hits="0" branch="false"/><line number="163" hits="50" branch="false"/><line number="166" hits="16" branch="false"/><line number="169" hits="36" branch="false"/><line number="186" hits="7" branch="false"/><line number="212" hits="7" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="213" hits="7" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="215" hits="7" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="217" hits="7" branch="true" condition-coverage="50% (1/2)"><conditions><condition number="0" type="jump" coverage="50%"/></conditions></line><line number="219" hits="7" branch="false"/></lines></class></classes></package><package name="qtty-cpp.include.qtty.units" line-rate="1.0" branch-rate="1.0" complexity="0.0"><classes><class name="time_hpp" filename="qtty-cpp/include/qtty/units/time.hpp" line-rate="1.0" branch-rate="1.0" complexity="0.0"><methods/><lines><line number="73" hits="1" branch="false"/><line number="101" hits="1" branch="false"/><line number="105" hits="2" branch="false"/><line number="109" hits="10" branch="false"/><line number="141" hits="1" branch="false"/></lines></class></classes></package></packages></coverage>

include/tempoch/civil_time.hpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#pragma once
2+
3+
/**
4+
* @file civil_time.hpp
5+
* @brief UTC date-time breakdown struct.
6+
*
7+
* Forward-declared in scales.hpp and fully defined here to avoid circular
8+
* dependencies.
9+
*/
10+
11+
#include "ffi_core.hpp"
12+
#include <iomanip>
13+
#include <ostream>
14+
15+
namespace tempoch {
16+
17+
/**
18+
* @brief UTC date-time breakdown.
19+
*
20+
* A simple value type mirroring the C `tempoch_utc_t` struct.
21+
*
22+
* @code
23+
* tempoch::CivilTime noon(2000, 1, 1, 12, 0, 0);
24+
* auto jd = tempoch::JulianDate::from_utc(noon);
25+
* @endcode
26+
*/
27+
struct CivilTime {
28+
int32_t year; ///< Gregorian year (astronomical year numbering).
29+
uint8_t month; ///< Month [1, 12].
30+
uint8_t day; ///< Day of month [1, 31].
31+
uint8_t hour; ///< Hour [0, 23].
32+
uint8_t minute; ///< Minute [0, 59].
33+
uint8_t second; ///< Second [0, 60] (leap-second aware).
34+
uint32_t nanosecond; ///< Nanosecond [0, 999 999 999].
35+
36+
/// Default constructor: J2000 epoch noon-like civil representation.
37+
CivilTime()
38+
: year(2000), month(1), day(1), hour(12), minute(0), second(0),
39+
nanosecond(0) {}
40+
41+
/**
42+
* @brief Construct from civil UTC components.
43+
*/
44+
CivilTime(int32_t y, uint8_t mo, uint8_t d, uint8_t h = 0, uint8_t mi = 0,
45+
uint8_t s = 0, uint32_t ns = 0)
46+
: year(y), month(mo), day(d), hour(h), minute(mi), second(s),
47+
nanosecond(ns) {}
48+
49+
/// Convert to the C FFI struct.
50+
tempoch_utc_t to_c() const {
51+
return {year, month, day, hour, minute, second, nanosecond};
52+
}
53+
54+
/// Create from the C FFI struct.
55+
static CivilTime from_c(const tempoch_utc_t &c) {
56+
return CivilTime(c.year, c.month, c.day, c.hour, c.minute, c.second,
57+
c.nanosecond);
58+
}
59+
};
60+
61+
/// Stream CivilTime as YYYY-MM-DD HH:MM:SS[.nnnnnnnnn].
62+
inline std::ostream &operator<<(std::ostream &os, const CivilTime &u) {
63+
const char prev = os.fill();
64+
os << u.year << '-' << std::setfill('0') << std::setw(2)
65+
<< static_cast<int>(u.month) << '-' << std::setw(2)
66+
<< static_cast<int>(u.day) << ' ' << std::setw(2)
67+
<< static_cast<int>(u.hour) << ':' << std::setw(2)
68+
<< static_cast<int>(u.minute) << ':' << std::setw(2)
69+
<< static_cast<int>(u.second);
70+
if (u.nanosecond != 0)
71+
os << '.' << std::setw(9) << u.nanosecond;
72+
os.fill(prev);
73+
return os;
74+
}
75+
76+
} // namespace tempoch

0 commit comments

Comments
 (0)