diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 9882fbb5..14032e77 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -4,6 +4,8 @@ on: push: branches: - main + tags: + - "v*" workflow_dispatch: jobs: @@ -15,13 +17,24 @@ jobs: with: submodules: "true" fetch-depth: 0 - - name: Inject version into mainpage.md + - name: Inject documentation version run: | - TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0-untagged") - TAG=$(echo "$TAG" | sed 's/^v//') - echo "Using version: $TAG" + CMAKE_VERSION=$(sed -nE 's/^project\(TimeShield VERSION ([^ ]+) .*/\1/p' CMakeLists.txt) + test -n "$CMAKE_VERSION" || { echo "Unable to determine CMake project version"; exit 1; } + if [ "$GITHUB_REF_TYPE" = "tag" ]; then + VERSION="${GITHUB_REF_NAME#v}" + if [ "$VERSION" != "$CMAKE_VERSION" ]; then + echo "Tag version $VERSION does not match CMake project version $CMAKE_VERSION" + exit 1 + fi + else + VERSION="$CMAKE_VERSION" + fi + test -n "$VERSION" || { echo "Unable to determine project version"; exit 1; } + echo "Documentation version: $VERSION" test -f docs/mainpage.md || { echo "mainpage.md not found!"; exit 1; } - sed -i "0,/VERSION_PLACEHOLDER/s//$TAG/" docs/mainpage.md + sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" docs/mainpage.md + sed -i -E "s/^PROJECT_NUMBER[[:space:]]*=.*/PROJECT_NUMBER = $VERSION/" Doxyfile - name: Generate Documentation uses: mattnotmitt/doxygen-action@edge - name: Publish generated content to GitHub Pages diff --git a/AGENTS.md b/AGENTS.md index 027aed59..72976f82 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -50,3 +50,19 @@ Header guard rules: `TIME_SHIELD_MQL5_HEADER____INCLUDED`. - Do not use guard names that start with an underscore, start with an underscore followed by an uppercase letter, or contain a double underscore. + +## Agent execution checklist + +Use the following order for repository changes and reviews: + +1. Inspect repository guidance and the current working tree before editing. +2. Review code, tests, build configuration, public documentation, and release metadata as separate concerns. +3. Build with CMake and the `MinGW Makefiles` generator. Keep build and test directories under `tmp/agent-work/`. +4. Run CTest in both Debug and Release configurations. Runtime test checks must remain active in Release builds. +5. Check C++11, C++14, and C++17 compatibility, installation consumers, and ODR tests when public headers change. +6. Treat MQL5 scripts as manual tests unless a MetaEditor compiler is available. Manual scripts report an aggregate pass/fail result. +7. Preserve convenient public aliases. Move an alias to an opt-in legacy header only when its legacy status is confirmed by history and documentation. +8. Keep documentation source templates version-neutral. Do not commit generated + documentation version substitutions; publish.yaml injects the effective version + during publication. +9. Finish with `git diff --check`, a status review, and a concise summary of remaining risks or unverified platform-specific checks. diff --git a/CHANGELOG.md b/CHANGELOG.md index 43c905c9..7e7bbec6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [v1.0.6] - 2026-04-23 +## [v1.0.6] - Unreleased - Added `ZonedClock` with reusable named-zone and fixed-offset local-time helpers and clarified timezone semantics. - Completed ISO week-date parsing support and formatter/parser round-trip coverage. - Added timeframe parsing helpers for trading and engineering strings in C++ and MQL5, with docs, examples, and tests. diff --git a/CMakeLists.txt b/CMakeLists.txt index a59c9ea8..10f8fb61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,9 @@ if(NOT DEFINED CMAKE_CXX_STANDARD) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) + add_library(time_shield INTERFACE) add_library(time_shield::time_shield ALIAS time_shield) @@ -18,9 +21,6 @@ target_include_directories( $ ) -include(GNUInstallDirs) -include(CMakePackageConfigHelpers) - set(TIME_SHIELD_ENABLE_NTP_CLIENT_DEFAULT ON) option(TIME_SHIELD_ENABLE_NTP_CLIENT "Enable NTP client" ${TIME_SHIELD_ENABLE_NTP_CLIENT_DEFAULT}) diff --git a/MQL5/Include/time_shield/constants.mqh b/MQL5/Include/time_shield/constants.mqh index 6d3d92f8..ff9a811e 100644 --- a/MQL5/Include/time_shield/constants.mqh +++ b/MQL5/Include/time_shield/constants.mqh @@ -137,7 +137,7 @@ namespace time_shield { const long MIN_PER_WEEK = 10080; ///< Minutes per week const long MIN_PER_10_DAY = 10*1440; ///< Minutes per 10 day const long MIN_PER_15_DAY = 15*1440; ///< Minutes per 15 day - const long MIN_PER_30_DAY = 15*1440; ///< Minutes per 30 day + const long MIN_PER_30_DAY = 30*1440; ///< Minutes per 30 day const long MIN_PER_MONTH = 40320; ///< Minutes per month (28 days) const long MAX_MOON_MIN = 42523; ///< Maximum lunar minutes @@ -160,7 +160,10 @@ namespace time_shield { const long MAX_YEAR = 292277022000; ///< Maximum representable year const long MIN_YEAR = -2967369602200; ///< Minimum representable year const long ERROR_YEAR = 9223372036854770000; ///< Error year value - const long MAX_TIMESTAMP = 9223371890843040000; ///< Maximum timestamp value + const long MAX_TIMESTAMP = 9223372005318775; ///< Maximum timestamp value in seconds + const long MIN_TIMESTAMP = -9223372005318775; ///< Minimum timestamp value in seconds + const long MAX_TIMESTAMP_MS = 9223372005318775999; ///< Maximum timestamp value in milliseconds + const long MIN_TIMESTAMP_MS = -9223372005318775000; ///< Minimum timestamp value in milliseconds const long ERROR_TIMESTAMP = 9223372036854770000; ///< Error timestamp value const double MAX_OADATE = 1.7976931348623158e+308; ///< Maximum representable oadate_t value const double AVG_DAYS_PER_YEAR = 365.25; ///< Average days per year diff --git a/MQL5/Scripts/time_shield/tests/test_eet_to_gmt.mq5 b/MQL5/Scripts/time_shield/tests/test_eet_to_gmt.mq5 index 0efdacd7..a71acf9c 100644 --- a/MQL5/Scripts/time_shield/tests/test_eet_to_gmt.mq5 +++ b/MQL5/Scripts/time_shield/tests/test_eet_to_gmt.mq5 @@ -11,6 +11,7 @@ void OnStart() { time_shield::init(); + bool is_ok = true; // Winter timestamp: 2024-01-15 12:00:00 EET datetime winter_eet = (datetime)time_shield::to_ts(2024, time_shield::JAN, 15, 12, 0, 0); @@ -19,8 +20,10 @@ void OnStart() { if (winter_gmt == winter_expected) Print("Winter conversion passed"); - else + else { Print("Winter conversion failed: ", winter_gmt, " != ", winter_expected); + is_ok = false; + } // Summer timestamp: 2024-07-15 12:00:00 EET (EEST) datetime summer_eet = (datetime)time_shield::to_ts(2024, time_shield::JUL, 15, 12, 0, 0); @@ -29,7 +32,11 @@ void OnStart() { if(summer_gmt == summer_expected) Print("Summer conversion passed"); - else + else { Print("Summer conversion failed: ", summer_gmt, " != ", summer_expected); + is_ok = false; + } + + Print(is_ok ? "EET to GMT tests passed" : "EET to GMT tests failed"); } diff --git a/MQL5/Scripts/time_shield/tests/test_time_zone_matrix.mq5 b/MQL5/Scripts/time_shield/tests/test_time_zone_matrix.mq5 index 8c341ec7..dcb82167 100644 --- a/MQL5/Scripts/time_shield/tests/test_time_zone_matrix.mq5 +++ b/MQL5/Scripts/time_shield/tests/test_time_zone_matrix.mq5 @@ -11,25 +11,34 @@ void OnStart() { time_shield::init(); + bool is_ok = true; datetime ist_local = (datetime)time_shield::to_ts(2024, time_shield::JUL, 15, 12, 0, 0); datetime expected_gmt = (datetime)time_shield::to_ts(2024, time_shield::JUL, 15, 6, 30, 0); datetime gmt_from_ist = time_shield::ist_to_gmt(ist_local); if(gmt_from_ist == expected_gmt) Print("IST -> GMT passed"); - else + else { Print("IST -> GMT failed: ", gmt_from_ist, " != ", expected_gmt); + is_ok = false; + } datetime myt_from_ist = time_shield::convert_time_zone(ist_local, time_shield::IST, time_shield::MYT); datetime expected_myt = (datetime)time_shield::to_ts(2024, time_shield::JUL, 15, 14, 30, 0); if(myt_from_ist == expected_myt) Print("IST -> MYT passed"); - else + else { Print("IST -> MYT failed: ", myt_from_ist, " != ", expected_myt); + is_ok = false; + } datetime kyiv_local = (datetime)time_shield::to_ts(2024, time_shield::JUL, 15, 12, 0, 0); if(time_shield::kyiv_to_gmt(kyiv_local) == time_shield::eet_to_gmt(kyiv_local)) Print("Kyiv alias passed"); - else + else { Print("Kyiv alias failed"); + is_ok = false; + } + + Print(is_ok ? "Time zone matrix tests passed" : "Time zone matrix tests failed"); } diff --git a/docs/groups.dox b/docs/groups.dox index c6e38c2c..42ceda94 100644 --- a/docs/groups.dox +++ b/docs/groups.dox @@ -106,7 +106,7 @@ for working with date-time structures, UNIX days, and various time units (hours, - Determine the start of the current year: \code{.cpp} - auto year_start = time_shield::start_of_year(current_timestamp()); + auto year_start = time_shield::start_of_year(time_shield::ts()); \endcode */ diff --git a/docs/groups_mql5.dox b/docs/groups_mql5.dox index ac4dffa5..06d0aca8 100644 --- a/docs/groups_mql5.dox +++ b/docs/groups_mql5.dox @@ -94,7 +94,7 @@ for working with date-time structures, UNIX days, and various time units (hours, - Determine the start of the current year: \code{.cpp} - auto year_start = time_shield::start_of_year(current_timestamp()); + auto year_start = time_shield::start_of_year(time_shield::ts()); \endcode */ diff --git a/include/time_shield.hpp b/include/time_shield.hpp index 64f0fec1..bbab8b18 100644 --- a/include/time_shield.hpp +++ b/include/time_shield.hpp @@ -53,7 +53,7 @@ namespace tshield = time_shield; /// \brief Main namespace for the Time Shield library. /// \details /// Contains all public types, constants, and functions of the library. -/// The API provides: +/// API coverage includes: /// - time and date structures /// - parsing and formatting /// - conversions between representations (seconds/milliseconds, calendar fields, etc.) diff --git a/include/time_shield/TimerScheduler.hpp b/include/time_shield/TimerScheduler.hpp index 7de06754..24972383 100644 --- a/include/time_shield/TimerScheduler.hpp +++ b/include/time_shield/TimerScheduler.hpp @@ -136,7 +136,7 @@ namespace time_shield { /// \brief Processes all timers that are ready to fire at the moment of the call. /// - /// The method is non-blocking: it does not wait for future timers. + /// Method is non-blocking and does not wait for future timers. /// It must not be called while the worker thread started by run() is /// active. void process(); @@ -204,7 +204,7 @@ namespace time_shield { /// \brief Stops the timer. /// - /// The operation is non-blocking: the method does not wait for a + /// Operation is non-blocking and does not wait for a /// running callback to finish. Use stop_and_wait() to synchronously /// wait for completion. void stop(); @@ -231,7 +231,7 @@ namespace time_shield { /// \brief Creates a single-shot timer that invokes the callback once. /// - /// The helper keeps the timer alive until the callback finishes. + /// Helper keeps the timer alive until the callback finishes. template static void single_shot(TimerScheduler& scheduler, std::chrono::duration interval, diff --git a/include/time_shield/ZonedClock.hpp b/include/time_shield/ZonedClock.hpp index 4c292712..0bc6662e 100644 --- a/include/time_shield/ZonedClock.hpp +++ b/include/time_shield/ZonedClock.hpp @@ -27,7 +27,7 @@ namespace time_shield { /// \brief Stores a target local-time context backed by a named zone or fixed UTC offset. /// - /// The class resolves the effective offset on demand. Named zones are recalculated + /// Class resolves the effective offset on demand. Named zones are recalculated /// for the requested UTC instant, while numeric offsets remain fixed. Current UTC time /// can come from the local realtime clock or from the global NTP service. class ZonedClock final { diff --git a/include/time_shield/constants.hpp b/include/time_shield/constants.hpp index b87ec308..7036075b 100644 --- a/include/time_shield/constants.hpp +++ b/include/time_shield/constants.hpp @@ -131,7 +131,7 @@ namespace time_shield { constexpr int64_t MIN_PER_WEEK = 10080; ///< Minutes per week constexpr int64_t MIN_PER_10_DAY = 10*1440; ///< Minutes per 10 day constexpr int64_t MIN_PER_15_DAY = 15*1440; ///< Minutes per 15 day - constexpr int64_t MIN_PER_30_DAY = 15*1440; ///< Minutes per 30 day + constexpr int64_t MIN_PER_30_DAY = 30*1440; ///< Minutes per 30 day constexpr int64_t MIN_PER_MONTH = 40320; ///< Minutes per month (28 days) constexpr int64_t MAX_MOON_MIN = 42523; ///< Maximum lunar minutes diff --git a/include/time_shield/date_time_conversions.hpp b/include/time_shield/date_time_conversions.hpp index 0a4f9681..622dd8b7 100644 --- a/include/time_shield/date_time_conversions.hpp +++ b/include/time_shield/date_time_conversions.hpp @@ -45,9 +45,9 @@ namespace time_shield { /// \return A date-time structure of type T1. template T1 to_date_time(T2 ts) { - // 9223372029693630000 - значение на момент 292277024400 от 2000 года - // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS - // Поэтому пришлось снизить до 9223371890843040000 + // 9223372029693630000 reaches year 292277024400 from the 2000 epoch. + // This value overflows the n_400_years * SEC_PER_400_YEARS calculation. + // The supported bound is reduced to 9223371890843040000. constexpr int64_t BIAS_292277022000 = 9223371890843040000LL; constexpr int64_t BIAS_2000 = 946684800LL; @@ -86,10 +86,10 @@ namespace time_shield { constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60 - 1; constexpr int TABLE_MONTH_OF_YEAR[] = { - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 31 январь - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 28 февраль - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 31 март - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 30 апрель + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // January (31 days) + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // February (28 days) + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // March (31 days) + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // April (30 days) 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, @@ -100,10 +100,10 @@ namespace time_shield { 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, }; constexpr int TABLE_DAY_OF_YEAR[] = { - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 январь - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // 28 февраль - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 март - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // 30 апрель + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // January (31 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // February (28 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // March (31 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // April (30 days) 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, @@ -219,7 +219,7 @@ namespace time_shield { /// \throws std::invalid_argument if the date-time combination is invalid. /// /// \par Aliases: - /// The following function names are provided as aliases: + /// Following function names are provided as aliases: /// - `ts(...)` /// - `get_ts(...)` /// - `get_timestamp(...)` @@ -262,9 +262,9 @@ namespace time_shield { secs += years * SEC_PER_YEAR; - // 9223372029693630000 - значение на момент 292277024400 от 2000 года - // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS - // Поэтому пришлось снизить до 9223371890843040000 + // 9223372029693630000 reaches year 292277024400 from the 2000 epoch. + // This value overflows the n_400_years * SEC_PER_400_YEARS calculation. + // The supported bound is reduced to 9223371890843040000. constexpr int64_t BIAS_292277022000 = 9223371890843040000LL; constexpr int64_t BIAS_2000 = 946684800LL; @@ -332,9 +332,9 @@ namespace time_shield { secs += years * SEC_PER_YEAR; - // 9223372029693630000 - значение на момент 292277024400 от 2000 года - // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS - // Поэтому пришлось снизить до 9223371890843040000 + // 9223372029693630000 reaches year 292277024400 from the 2000 epoch. + // This value overflows the n_400_years * SEC_PER_400_YEARS calculation. + // The supported bound is reduced to 9223371890843040000. constexpr int64_t BIAS_292277022000 = 9223371890843040000LL; constexpr int64_t BIAS_2000 = 946684800LL; @@ -422,7 +422,7 @@ namespace time_shield { /// \throws std::invalid_argument if the date-time combination is invalid. /// /// \par Aliases: - /// The following function names are provided as aliases: + /// Following function names are provided as aliases: /// - `ts(...)` /// - `get_ts(...)` /// - `get_timestamp(...)` @@ -646,7 +646,7 @@ namespace time_shield { /// \brief Get the start of the day timestamp. /// /// This function returns the timestamp at the start of the day. - /// The function sets the hours, minutes, and seconds to zero. + /// Sets the hours, minutes, and seconds to zero. /// /// \param ts Timestamp. /// \return Start of the day timestamp. @@ -669,7 +669,7 @@ namespace time_shield { /// \brief Get the start of the day timestamp in seconds. /// /// This function returns the timestamp at the start of the day in seconds. - /// The function sets the hours, minutes, and seconds to zero. + /// Sets the hours, minutes, and seconds to zero. /// /// \param ts_ms Timestamp in milliseconds. /// \return Start of the day timestamp in seconds. @@ -680,7 +680,7 @@ namespace time_shield { /// \brief Get the start of the day timestamp in milliseconds. /// /// This function returns the timestamp at the start of the day in milliseconds. - /// The function sets the hours, minutes, seconds, and milliseconds to zero. + /// Sets the hours, minutes, seconds, and milliseconds to zero. /// /// \param ts_ms Timestamp in milliseconds. /// \return Start of the day timestamp in milliseconds. @@ -904,10 +904,10 @@ namespace time_shield { constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60; constexpr int TABLE_MONTH_OF_YEAR[] = { 0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 31 январь - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 28 февраль - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 31 март - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // 30 апрель + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // January (31 days) + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // February (28 days) + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // March (31 days) + 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, // April (30 days) 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, @@ -930,13 +930,13 @@ namespace time_shield { template TIME_SHIELD_CONSTEXPR inline T day_of_month(ts_t ts = time_shield::ts()) { constexpr int JAN_AND_FEB_DAY_LEAP_YEAR = 60; - // таблица для обычного года, не високосного + // Month numbers for a common year. constexpr int TABLE_DAY_OF_YEAR[] = { 0, - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 январь - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // 28 февраль - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // 31 март - 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // 30 апрель + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // January (31 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28, // February (28 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, // March (31 days) + 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, // April (30 days) 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31, diff --git a/include/time_shield/ntp_client.hpp b/include/time_shield/ntp_client.hpp index 398354fd..9f8631aa 100644 --- a/include/time_shield/ntp_client.hpp +++ b/include/time_shield/ntp_client.hpp @@ -6,7 +6,7 @@ /// \file ntp_client.hpp /// \brief Simple NTP client for querying time offset from NTP servers. /// -/// The feature is optional and controlled by `TIME_SHIELD_ENABLE_NTP_CLIENT`. +/// Feature availability is controlled by `TIME_SHIELD_ENABLE_NTP_CLIENT`. /// \ingroup ntp #include "config.hpp" diff --git a/include/time_shield/time_conversion_aliases.hpp b/include/time_shield/time_conversion_aliases.hpp index 367227a7..6891a165 100644 --- a/include/time_shield/time_conversion_aliases.hpp +++ b/include/time_shield/time_conversion_aliases.hpp @@ -4,11 +4,11 @@ #define TIME_SHIELD_HEADER_TIME_SHIELD_TIME_CONVERSION_ALIASES_HPP_INCLUDED /// \file time_conversion_aliases.hpp -/// \brief Doxygen-only stubs for alias functions defined via macros. +/// \brief Convenience aliases for the time-conversion API. /// -/// These declarations are only visible to Doxygen to enable searching and linking -/// to functions like `ts`, `get_ts`, etc., which are defined via macros. -/// This file should be included only at the end of `time_conversion.hpp`. +/// Definitions provide alternative names for commonly used conversion helpers. +/// Doxygen sees the declarations directly and can index each alias independently. +/// Include this header after the canonical conversion declarations. #include diff --git a/include/time_shield/time_formatting.hpp b/include/time_shield/time_formatting.hpp index 86b63f2f..2c1037b1 100644 --- a/include/time_shield/time_formatting.hpp +++ b/include/time_shield/time_formatting.hpp @@ -396,7 +396,7 @@ namespace time_shield { /// This function is similar to the strftime function and supports the majority of its specifiers, /// as well as additional ones: YY, YYYY, YYYYYY, WWW, www, hh, mm, ss, dd, sss. /// - /// The function accepts the following format specifiers as parameters: + /// Accepts the following format specifiers as parameters: /// - %YYYYYY: Year with reduction in the number of millennia. /// - %YYYY: Year represented by 4 digits. /// - %YY: Last two digits of the year. @@ -484,7 +484,7 @@ namespace time_shield { /// This function is similar to the strftime function and supports the majority of its specifiers, /// as well as additional ones: YY, YYYY, YYYYYY, WWW, www, hh, mm, ss, dd, sss. /// - /// The function accepts the following format specifiers as parameters: + /// Accepts the following format specifiers as parameters: /// - %YYYYYY: Year with reduction in the number of millennia. /// - %YYYY: Year represented by 4 digits. /// - %YY: Last two digits of the year. diff --git a/include/time_shield/time_utils.hpp b/include/time_shield/time_utils.hpp index 787c62eb..6ec4fbf9 100644 --- a/include/time_shield/time_utils.hpp +++ b/include/time_shield/time_utils.hpp @@ -41,7 +41,7 @@ namespace time_shield { // https://en.cppreference.com/w/c/chrono/timespec_get struct timespec ts; # if defined(CLOCK_REALTIME) - clock_gettime(CLOCK_REALTIME, &ts); // Версия для POSIX + clock_gettime(CLOCK_REALTIME, &ts); // POSIX implementation # else timespec_get(&ts, TIME_UTC); # endif diff --git a/include/time_shield/unix_time_conversions.hpp b/include/time_shield/unix_time_conversions.hpp index a6251028..f0347ec8 100644 --- a/include/time_shield/unix_time_conversions.hpp +++ b/include/time_shield/unix_time_conversions.hpp @@ -26,9 +26,9 @@ namespace time_shield { /// \return T Year corresponding to the given timestamp. template TIME_SHIELD_CONSTEXPR T years_since_epoch(ts_t ts) noexcept { - // 9223372029693630000 - значение на момент 292277024400 от 2000 года - // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS - // Поэтому пришлось снизить до 9223371890843040000 + // 9223372029693630000 reaches year 292277024400 from the 2000 epoch. + // This value overflows the n_400_years * SEC_PER_400_YEARS calculation. + // The supported bound is reduced to 9223371890843040000. constexpr int64_t BIAS_292277022000 = 9223371890843040000LL; constexpr int64_t BIAS_2000 = 946684800LL; diff --git a/include/time_shield/validation.hpp b/include/time_shield/validation.hpp index bfc060a3..532917b4 100644 --- a/include/time_shield/validation.hpp +++ b/include/time_shield/validation.hpp @@ -82,9 +82,9 @@ namespace time_shield { /// \param ts Timestamp in seconds since the Unix epoch. /// \return Returns true if the year is a leap year. TIME_SHIELD_CONSTEXPR inline bool is_leap_year_ts(ts_t ts) { - // 9223372029693630000 - значение на момент 292277024400 от 2000 года - // Такое значение приводит к неправильному вычислению умножения n_400_years * SEC_PER_400_YEARS - // Поэтому пришлось снизить до 9223371890843040000 + // 9223372029693630000 reaches year 292277024400 from the 2000 epoch. + // This value overflows the n_400_years * SEC_PER_400_YEARS calculation. + // The supported bound is reduced to 9223371890843040000. constexpr int64_t BIAS_292277022000 = 9223371890843040000LL; constexpr int64_t BIAS_2000 = 946684800LL; diff --git a/tests/time_conversions_coverage_test.cpp b/tests/time_conversions_coverage_test.cpp index 28114503..68bb2ce3 100644 --- a/tests/time_conversions_coverage_test.cpp +++ b/tests/time_conversions_coverage_test.cpp @@ -5,6 +5,9 @@ #include #include +static_assert(time_shield::MIN_PER_30_DAY == 30 * time_shield::MIN_PER_DAY, + "MIN_PER_30_DAY must represent thirty days"); + int main() { using namespace time_shield;