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
12 changes: 12 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 2
ColumnLimit: 80
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: All
AllowShortEnumsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AlwaysBreakTemplateDeclarations: MultiLine
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "tempoch"]
path = tempoch
url = git@github.com:Siderust/tempoch.git
[submodule "qtty-cpp"]
path = qtty-cpp
url = https://github.com/Siderust/qtty-cpp.git
23 changes: 15 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,17 @@ if(WIN32)
endif()
add_dependencies(tempoch_ffi build_tempoch_ffi)

# qtty-cpp integration (provides unit types for duration<>)
add_subdirectory(qtty-cpp)

# Header-only C++ wrapper library
add_library(tempoch_cpp INTERFACE)
target_include_directories(tempoch_cpp INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${TEMPOCH_FFI_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(tempoch_cpp INTERFACE tempoch_ffi)
target_link_libraries(tempoch_cpp INTERFACE tempoch_ffi qtty_cpp)
add_dependencies(tempoch_cpp build_tempoch_ffi)

# Doxygen documentation
Expand All @@ -77,13 +80,17 @@ if(TEMPOCH_BUILD_DOCS)
set(TEMPOCH_DOXYFILE_OUT ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile.tempoch_cpp)
configure_file(${TEMPOCH_DOXYFILE_IN} ${TEMPOCH_DOXYFILE_OUT} @ONLY)

add_custom_target(docs
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/docs/doxygen
COMMAND ${DOXYGEN_EXECUTABLE} ${TEMPOCH_DOXYFILE_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM
)
if(NOT TARGET docs)
add_custom_target(docs
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/docs/doxygen
COMMAND ${DOXYGEN_EXECUTABLE} ${TEMPOCH_DOXYFILE_OUT}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMENT "Generating API documentation with Doxygen"
VERBATIM
)
else()
message(STATUS "Top-level 'docs' target already exists; skipping creation to avoid conflict with subprojects")
endif()
else()
message(STATUS "Doxygen not found; 'docs' target will not be available")
endif()
Expand Down
103 changes: 55 additions & 48 deletions examples/time_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,62 @@
* ./build/time_example
*/

#include <tempoch/tempoch.hpp>
#include <iostream>
#include <iomanip>
#include <iostream>
#include <qtty/qtty.hpp>
#include <tempoch/tempoch.hpp>

int main() {
using namespace tempoch;

// ---------------------------------------------------------------
// UTC → JulianDate → MJD round-trip
// ---------------------------------------------------------------
UTC utc(2026, 7, 15, 22, 0, 0);
std::cout << "UTC: " << utc.year << "-"
<< std::setfill('0') << std::setw(2) << (int)utc.month << "-"
<< std::setw(2) << (int)utc.day << " "
<< std::setw(2) << (int)utc.hour << ":"
<< std::setw(2) << (int)utc.minute << ":"
<< std::setw(2) << (int)utc.second << "\n";

auto jd = JulianDate::from_utc(utc);
std::cout << "JD: " << std::fixed << std::setprecision(6) << jd.value() << "\n";

auto mjd = MJD::from_jd(jd);
std::cout << "MJD: " << std::fixed << std::setprecision(6) << mjd.value() << "\n";

auto utc2 = mjd.to_utc();
std::cout << "Back: " << utc2.year << "-"
<< std::setfill('0') << std::setw(2) << (int)utc2.month << "-"
<< std::setw(2) << (int)utc2.day << " "
<< std::setw(2) << (int)utc2.hour << ":"
<< std::setw(2) << (int)utc2.minute << ":"
<< std::setw(2) << (int)utc2.second << "\n\n";

// ---------------------------------------------------------------
// J2000 epoch and Julian centuries
// ---------------------------------------------------------------
auto j2000 = JulianDate::J2000();
std::cout << "J2000.0: " << j2000.value() << "\n";
std::cout << "Centuries since J2000: " << jd.julian_centuries() << "\n\n";

// ---------------------------------------------------------------
// Period intersection
// ---------------------------------------------------------------
Period night(60200.0, 60200.5);
Period obs(60200.2, 60200.8);
auto overlap = night.intersection(obs);
std::cout << "Night: [" << night.start_mjd() << ", " << night.end_mjd() << "]\n";
std::cout << "Obs: [" << obs.start_mjd() << ", " << obs.end_mjd() << "]\n";
std::cout << "Overlap: [" << overlap.start_mjd() << ", " << overlap.end_mjd() << "]\n";
std::cout << "Overlap duration: " << overlap.duration_days() * 24.0 << " hours\n";

return 0;
using namespace tempoch;

// ---------------------------------------------------------------
// UTC → JulianDate → MJD round-trip
// ---------------------------------------------------------------
UTC utc(2026, 7, 15, 22, 0, 0);
std::cout << "UTC: " << utc << "\n";

auto jd = JulianDate::from_utc(utc);
std::cout << "JD: " << std::fixed << std::setprecision(6) << jd << "\n";

auto mjd = MJD::from_jd(jd);
std::cout << "MJD: " << std::fixed << std::setprecision(6) << mjd << "\n";

auto utc2 = mjd.to_utc();
std::cout << "Back: " << utc2 << "\n\n";

// ---------------------------------------------------------------
// J2000 epoch and Julian centuries
// ---------------------------------------------------------------
auto j2000 = JulianDate::J2000();
std::cout << "J2000.0: " << j2000 << "\n";
std::cout << "Centuries since J2000: " << jd.julian_centuries() << "\n\n";

// ---------------------------------------------------------------
// Period intersection (MJD — explicit MJD wrappers required)
// ---------------------------------------------------------------
Period night(MJD(60200.0), MJD(60200.5));
Period obs(MJD(60200.2), MJD(60200.8));
auto overlap = night.intersection(obs);
std::cout << "Night: " << night << "\n";
std::cout << "Obs: " << obs << "\n";
std::cout << "Overlap: " << overlap << "\n";
std::cout << "Overlap duration: " << overlap.duration<qtty::Hour>() << "\n\n";

// ---------------------------------------------------------------
// Period<UTC> — start/end expressed directly as civil UTC
// ---------------------------------------------------------------
Period utc_semester(UTC(2026, 1, 1), UTC(2026, 7, 1));
std::cout << "Semester (UTC): " << utc_semester << "\n";
std::cout << " duration: " << utc_semester.duration() << "\n\n";

// ---------------------------------------------------------------
// Period<JulianDate> — start/end as Julian Dates
// ---------------------------------------------------------------
auto jd_start = JulianDate::from_utc(UTC(2026, 1, 1));
auto jd_end = JulianDate::from_utc(UTC(2026, 7, 1));
Period jd_semester(jd_start, jd_end);
std::cout << "Semester (JD): " << jd_semester << "\n";
std::cout << " duration: " << jd_semester.duration() << "\n";

return 0;
}
43 changes: 23 additions & 20 deletions include/tempoch/ffi_core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,39 +26,40 @@ namespace tempoch {
*/
class TempochException : public std::runtime_error {
public:
explicit TempochException(const std::string& msg) : std::runtime_error(msg) {}
explicit TempochException(const std::string &msg) : std::runtime_error(msg) {}
};

/**
* @brief A required output pointer was null.
*/
class NullPointerError : public TempochException {
public:
explicit NullPointerError(const std::string& msg) : TempochException(msg) {}
explicit NullPointerError(const std::string &msg) : TempochException(msg) {}
};

/**
* @brief UTC conversion failed (date out of range or invalid).
*/
class UtcConversionError : public TempochException {
public:
explicit UtcConversionError(const std::string& msg) : TempochException(msg) {}
explicit UtcConversionError(const std::string &msg) : TempochException(msg) {}
};

/**
* @brief The period is invalid (start > end).
*/
class InvalidPeriodError : public TempochException {
public:
explicit InvalidPeriodError(const std::string& msg) : TempochException(msg) {}
explicit InvalidPeriodError(const std::string &msg) : TempochException(msg) {}
};

/**
* @brief The two periods do not intersect.
*/
class NoIntersectionError : public TempochException {
public:
explicit NoIntersectionError(const std::string& msg) : TempochException(msg) {}
explicit NoIntersectionError(const std::string &msg)
: TempochException(msg) {}
};

// ============================================================================
Expand All @@ -68,22 +69,24 @@ class NoIntersectionError : public TempochException {
/**
* @brief Check a tempoch_status_t and throw the appropriate exception on error.
*/
inline void check_status(tempoch_status_t status, const char* operation) {
if (status == TEMPOCH_STATUS_T_OK) return;
inline void check_status(tempoch_status_t status, const char *operation) {
if (status == TEMPOCH_STATUS_T_OK)
return;

std::string msg = std::string(operation) + " failed: ";
switch (status) {
case TEMPOCH_STATUS_T_NULL_POINTER:
throw NullPointerError(msg + "null output pointer");
case TEMPOCH_STATUS_T_UTC_CONVERSION_FAILED:
throw UtcConversionError(msg + "UTC conversion failed");
case TEMPOCH_STATUS_T_INVALID_PERIOD:
throw InvalidPeriodError(msg + "invalid period (start > end)");
case TEMPOCH_STATUS_T_NO_INTERSECTION:
throw NoIntersectionError(msg + "periods do not intersect");
default:
throw TempochException(msg + "unknown error (" + std::to_string(status) + ")");
}
std::string msg = std::string(operation) + " failed: ";
switch (status) {
case TEMPOCH_STATUS_T_NULL_POINTER:
throw NullPointerError(msg + "null output pointer");
case TEMPOCH_STATUS_T_UTC_CONVERSION_FAILED:
throw UtcConversionError(msg + "UTC conversion failed");
case TEMPOCH_STATUS_T_INVALID_PERIOD:
throw InvalidPeriodError(msg + "invalid period (start > end)");
case TEMPOCH_STATUS_T_NO_INTERSECTION:
throw NoIntersectionError(msg + "periods do not intersect");
default:
throw TempochException(msg + "unknown error (" + std::to_string(status) +
")");
}
}

} // namespace tempoch
Loading