Skip to content
Open
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
23 changes: 18 additions & 5 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
branches:
- main
tags:
- "v*"
workflow_dispatch:

jobs:
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,19 @@ Header guard rules:
`TIME_SHIELD_MQL5_HEADER_<PATH>_<FILE>_<EXT>_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.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -18,9 +21,6 @@ target_include_directories(
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)

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})

Expand Down
7 changes: 5 additions & 2 deletions MQL5/Include/time_shield/constants.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down
11 changes: 9 additions & 2 deletions MQL5/Scripts/time_shield/tests/test_eet_to_gmt.mq5
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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");
}

15 changes: 12 additions & 3 deletions MQL5/Scripts/time_shield/tests/test_time_zone_matrix.mq5
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
2 changes: 1 addition & 1 deletion docs/groups.dox
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
2 changes: 1 addition & 1 deletion docs/groups_mql5.dox
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

Expand Down
2 changes: 1 addition & 1 deletion include/time_shield.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.)
Expand Down
6 changes: 3 additions & 3 deletions include/time_shield/TimerScheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand All @@ -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<class Rep, class Period>
static void single_shot(TimerScheduler& scheduler,
std::chrono::duration<Rep, Period> interval,
Expand Down
2 changes: 1 addition & 1 deletion include/time_shield/ZonedClock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion include/time_shield/constants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Loading
Loading