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
9 changes: 5 additions & 4 deletions .github/doxygen-custom/header.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!-- HTML header for doxygen 1.11.0-->
<!-- HTML header for doxygen 1.12.0 -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
<head>
Expand All @@ -8,9 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
<!--BEGIN PROJECT_ICON-->
<link rel="icon" href="$relpath^$projecticon" type="image/x-icon" />
<!--END PROJECT_ICON-->
<link rel="icon" href="$relpath^icon-64x64.png" type="image/png" />
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
<!--BEGIN DISABLE_INDEX-->
<!--BEGIN FULL_SIDEBAR-->
Expand All @@ -24,13 +22,15 @@
<!--END COPY_CLIPBOARD-->
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
<script type="text/javascript" src="$relpath^theme-toggle.js"></script>
<script type="text/javascript">
DoxygenAwesomeDarkModeToggle.init()
DoxygenAwesomeParagraphLink.init()
</script>
$treeview
$search
$mathjax
$darkmode
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
$extrastylesheet
</head>
Expand Down Expand Up @@ -80,6 +80,7 @@
<!--END SEARCHENGINE-->
</tbody>
</table>
<div id="time-shield-theme-toggle" aria-label="Color theme"></div>
</div>
<!--END TITLEAREA-->
<!-- end header part -->
30 changes: 28 additions & 2 deletions .github/doxygen-custom/overrides.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
html {
--top-nav-height: 150px
--top-nav-height: 150px;
--side-nav-fixed-width: 460px;
}

#titlearea {
position: relative;
}

#time-shield-theme-toggle {
position: absolute;
top: var(--spacing-medium);
right: var(--spacing-medium);
z-index: 2;
width: var(--searchbar-height);
height: var(--searchbar-height);
}

#time-shield-theme-toggle > doxygen-awesome-dark-mode-toggle {
margin: 0;
}

@media screen and (min-width: 768px) {
html {
--top-height: 140px;
}

#time-shield-theme-toggle {
top: calc(100% + var(--spacing-small) + 1.5px);
}

#top {
height: var(--top-nav-height);
}
Expand All @@ -14,4 +40,4 @@ html {
#side-nav {
top: var(--top-nav-height);
}
}
}
24 changes: 24 additions & 0 deletions .github/doxygen-custom/theme-toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
(function () {
function moveThemeToggle() {
var target = document.getElementById("time-shield-theme-toggle");
var toggles = document.querySelectorAll("doxygen-awesome-dark-mode-toggle");
if (!target || toggles.length === 0) {
return;
}

if (toggles[0].parentNode !== target) {
target.appendChild(toggles[0]);
}
for (var i = 1; i < toggles.length; ++i) {
toggles[i].remove();
}
}

document.addEventListener("DOMContentLoaded", function () {
moveThemeToggle();
window.addEventListener("resize", moveThemeToggle);
var observer = new MutationObserver(moveThemeToggle);
observer.observe(document.body, { childList: true, subtree: true });
window.setInterval(moveThemeToggle, 100);
});
})();
43 changes: 42 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ jobs:
run: cmake -S tests/install_consumer -B build-consumer -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install -DCMAKE_CXX_STANDARD=${{ matrix.std }}
- name: Build consumer project
run: cmake --build build-consumer
- name: Configure pkg-config consumer
run: |
PKG_CONFIG_PATH="${{ github.workspace }}/install/lib/pkgconfig" \
cmake -S tests/pkg_config_consumer -B build-pkg-config -DCMAKE_CXX_STANDARD=${{ matrix.std }}
- name: Build pkg-config consumer
run: cmake --build build-pkg-config

windows:
runs-on: windows-latest
Expand Down Expand Up @@ -122,14 +128,24 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pin overlay port to the checked-out revision
env:
TIME_SHIELD_REF: ${{ github.event.pull_request.head.sha || github.sha }}
run: |
set -euo pipefail
test -n "$TIME_SHIELD_REF"
archive_url="https://github.com/LimiNode/time-shield-cpp/archive/${TIME_SHIELD_REF}.tar.gz"
sha512=$(curl -fsSL "$archive_url" | sha512sum | awk '{print $1}')
sed -i -E "s/^ REF .*/ REF ${TIME_SHIELD_REF}/" vcpkg-overlay/ports/time-shield-cpp/portfile.cmake
sed -i -E "s/^ SHA512 .*/ SHA512 ${sha512}/" vcpkg-overlay/ports/time-shield-cpp/portfile.cmake
- name: Install vcpkg
run: |
git clone https://github.com/microsoft/vcpkg.git
./vcpkg/bootstrap-vcpkg.sh -disableMetrics
- name: Validate port
run: ./vcpkg/vcpkg install time-shield-cpp --overlay-ports=vcpkg-overlay/ports
- name: Configure consumer project
run: cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=./vcpkg/scripts/buildsystems/vcpkg.cmake
run: cmake -B build -S tests/vcpkg_consumer -DCMAKE_TOOLCHAIN_FILE=${{ github.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake
- name: Build consumer project
run: cmake --build build

Expand All @@ -149,3 +165,28 @@ jobs:
run: cmake -S tests/install_consumer -B build-consumer -DCMAKE_PREFIX_PATH=${{ github.workspace }}/install -DCMAKE_CXX_STANDARD=11
- name: Build installed consumer
run: cmake --build build-consumer
- name: Configure pkg-config consumer without NTP
run: |
PKG_CONFIG_PATH="${{ github.workspace }}/install/lib/pkgconfig" \
cmake -S tests/pkg_config_consumer -B build-pkg-config -DCMAKE_CXX_STANDARD=11
- name: Build pkg-config consumer without NTP
run: cmake --build build-pkg-config

pkg-config-multiarch:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure with multiarch library directory
run: cmake -S . -B build -DTIME_SHIELD_CPP_BUILD_TESTS=OFF -DCMAKE_INSTALL_LIBDIR=lib/x86_64-linux-gnu
- name: Build and install
run: cmake --build build && cmake --install build --prefix install
- name: Verify relocatable pkg-config prefix
run: |
export PKG_CONFIG_PATH="${{ github.workspace }}/install/lib/x86_64-linux-gnu/pkgconfig"
test "$(realpath "$(pkg-config --variable=prefix time-shield)")" = "$(realpath install)"
- name: Configure pkg-config consumer
run: |
PKG_CONFIG_PATH="${{ github.workspace }}/install/lib/x86_64-linux-gnu/pkgconfig" \
cmake -S tests/pkg_config_consumer -B build-pkg-config -DCMAKE_CXX_STANDARD=11
- name: Build pkg-config consumer
run: cmake --build build-pkg-config
89 changes: 80 additions & 9 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,17 @@ on:
- main
tags:
- "v*"
pull_request:
branches:
- main
workflow_dispatch:

jobs:
deploy:
if: github.event_name != 'pull_request'
runs-on: ubuntu-22.04
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -19,19 +25,21 @@ jobs:
fetch-depth: 0
- name: Inject documentation version
run: |
CMAKE_VERSION=$(sed -nE 's/^project\(TimeShield VERSION ([^ ]+) .*/\1/p' CMakeLists.txt)
CMAKE_VERSION=$(sed -nE 's/^project\(TimeShield VERSION ([^ ]+) .*/\1/p' CMakeLists.txt | head -n 1)
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
DOC_VERSION="$VERSION"
else
VERSION="$CMAKE_VERSION"
DOC_VERSION="${CMAKE_VERSION}-dev"
fi
test -n "$VERSION" || { echo "Unable to determine project version"; exit 1; }
echo "Documentation version: $VERSION"
test -n "$DOC_VERSION" || { echo "Unable to determine documentation version"; exit 1; }
echo "Documentation version: $DOC_VERSION"
echo "DOC_VERSION=$DOC_VERSION" >> "$GITHUB_ENV"
test -f docs/mainpage.md || { echo "mainpage.md not found!"; exit 1; }
test -f Doxyfile || { echo "Doxyfile not found!"; exit 1; }
grep -Fq "VERSION_PLACEHOLDER" docs/mainpage.md || {
Expand All @@ -42,21 +50,84 @@ jobs:
echo "Version-neutral PROJECT_NUMBER not found in Doxyfile"
exit 1
}
sed -i "s/VERSION_PLACEHOLDER/$VERSION/g" docs/mainpage.md
sed -i -E "s/^PROJECT_NUMBER[[:space:]]*=.*/PROJECT_NUMBER = $VERSION/" Doxyfile
sed -i "0,/VERSION_PLACEHOLDER/s//${DOC_VERSION}/" docs/mainpage.md
sed -i -E "s/^PROJECT_NUMBER[[:space:]]*=.*/PROJECT_NUMBER = $DOC_VERSION/" Doxyfile
if grep -Fq "VERSION_PLACEHOLDER" docs/mainpage.md; then
echo "Version placeholder was not replaced"
exit 1
fi
grep -Fxq "PROJECT_NUMBER = $VERSION" Doxyfile || {
grep -Fxq "PROJECT_NUMBER = $DOC_VERSION" Doxyfile || {
echo "Doxygen PROJECT_NUMBER was not updated"
exit 1
}
- name: Generate Documentation
uses: mattnotmitt/doxygen-action@edge
uses: mattnotmitt/[email protected]
- name: Validate generated documentation
run: |
test -s docs/html/index.html
grep -q "$DOC_VERSION" docs/html/index.html
grep -q "Time Shield Library" docs/html/index.html
! grep -R -q "Archived Demo Assets" docs/html
- name: Publish generated content to GitHub Pages
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.ACCESS_TOKEN }}
github_token: ${{ github.token }}
publish_dir: docs/html
publish_branch: gh-pages

validate-docs:
if: github.event_name == 'pull_request'
runs-on: ubuntu-22.04
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: "true"
fetch-depth: 0
- name: Inject development version
run: |
CMAKE_VERSION=$(sed -nE 's/^project\(TimeShield VERSION ([^ ]+) .*/\1/p' CMakeLists.txt | head -n 1)
test -n "$CMAKE_VERSION" || { echo "Unable to determine CMake project version"; exit 1; }
DOC_VERSION="${CMAKE_VERSION}-dev"
echo "Documentation version: $DOC_VERSION"
echo "DOC_VERSION=$DOC_VERSION" >> "$GITHUB_ENV"
test -f docs/mainpage.md || { echo "mainpage.md not found!"; exit 1; }
test -f Doxyfile || { echo "Doxyfile not found!"; exit 1; }
grep -Fq "VERSION_PLACEHOLDER" docs/mainpage.md || {
echo "Version placeholder not found in mainpage.md"
exit 1
}
grep -Eq '^PROJECT_NUMBER[[:space:]]*=[[:space:]]*$' Doxyfile || {
echo "Version-neutral PROJECT_NUMBER not found in Doxyfile"
exit 1
}
sed -i "0,/VERSION_PLACEHOLDER/s//${DOC_VERSION}/" docs/mainpage.md
sed -i -E "s/^PROJECT_NUMBER[[:space:]]*=.*/PROJECT_NUMBER = $DOC_VERSION/" Doxyfile
grep -Fq "VERSION_PLACEHOLDER" docs/mainpage.md && {
echo "Version placeholder was not replaced"
exit 1
}
grep -Fxq "PROJECT_NUMBER = $DOC_VERSION" Doxyfile || {
echo "Doxygen PROJECT_NUMBER was not updated"
exit 1
}
- name: Generate Documentation
uses: mattnotmitt/[email protected]
- name: Validate generated documentation
run: |
test -s docs/html/index.html
grep -q "$DOC_VERSION" docs/html/index.html
grep -q "Time Shield Library" docs/html/index.html
! grep -R -q "Archived Demo Assets" docs/html
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Playwright browser
run: |
npm install --no-save --no-package-lock @playwright/[email protected]
npx playwright install --with-deps chromium
- name: Run documentation layout smoke tests
run: npx playwright test --config=tests/docs_smoke/playwright.config.mjs
8 changes: 4 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,11 @@ Global rules:
Additional policy:

- Public C++ headers are organized by domain under `include/time_shield`.
Prefer domain umbrellas (`core.hpp`, `conversions.hpp`, `text.hpp`,
Use domain umbrellas (`core.hpp`, `conversions.hpp`, `text.hpp`,
`date_time.hpp`, `timezone.hpp`, `astronomy.hpp`, `timers.hpp`, and
optional `ntp.hpp`) for cross-domain includes. Same-domain leaf includes may
use local paths. Do not use `../` includes or include another domain's leaf
header directly. Root-level compatibility headers and documented legacy
paths are forwarding shells and are exempt from the domain dependency rule.
header directly. Do not add root-level compatibility forwarding headers.
- Keep domain dependencies acyclic: lower-level domains must not include
higher-level domain headers. Detail headers belong to their owning domain
and are not public cross-domain dependencies.
Expand Down Expand Up @@ -75,5 +74,6 @@ Use the following order for repository changes and reviews:
7. Preserve convenient public aliases. Short or alternative names are not legacy merely because a canonical equivalent exists. Classify an API as legacy only when it has been historically renamed or superseded, or when a deliberate replacement is introduced. When replacing a useful short alias, provide an equally practical preferred alias. Move a confirmed legacy alias to `legacy_aliases.hpp` and make it available only through `TIME_SHIELD_ENABLE_LEGACY_ALIASES`.
8. Keep documentation source templates version-neutral. Do not commit generated
documentation version substitutions; publish.yaml injects the effective version
during publication.
during publication. Main-branch documentation uses the CMake version with a
`-dev` suffix; release-tag documentation uses the matching tag version.
9. Finish with `git diff --check`, a status review, and a concise summary of remaining risks or unverified platform-specific checks.
26 changes: 23 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

All notable changes to this project will be documented in this file.

## [v1.0.6] - Unreleased
## [v2.0.0] - Unreleased
- Added `dse`, `dse_ms`, `dse_to_ts`, and `dse_to_ts_ms` convenience aliases for days-since-epoch conversions.
- Corrected the default return type of `unix_day_to_ts_ms` to the millisecond timestamp type.
- Added `ZonedClock` with reusable named-zone and fixed-offset local-time helpers, including explicit resolution of ambiguous and nonexistent local times.
- Added an MQL4 `TimeShield` facade and aligned MQL4/MQL5 umbrella-header compatibility.
- 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.
- Split Julian conversions into a dedicated header while preserving the public include surface.
- Split Julian conversions into the astronomy domain and added dedicated canonical headers.
- Extended parser and formatting examples and refreshed README coverage for newer APIs.
- Accepted ISO-style offsets in `%z` custom-format parsing.
- Restored C++11 `constexpr` compatibility in affected header-owned APIs.
Expand All @@ -20,6 +20,26 @@ All notable changes to this project will be documented in this file.
- Moved confirmed legacy day-first Julian overloads and historical next-day aliases behind the same opt-in compatibility layer.
- Corrected the default return type of `start_of_next_day_from_unix_day` to the seconds timestamp type.
- Expanded timezone and NTP coverage and finalized recent timezone conversion support and NTP-facing documentation for consumers.
- Organized public C++ headers into domain directories with domain umbrellas and removed obsolete root-level forwarding headers.

### Breaking header-layout change

Public C++ headers use canonical domain paths. The full-library include remains
unchanged:

```cpp
#include <time_shield.hpp>
```

Old root-level selective include paths are removed. Use domain umbrellas or
domain-owned leaf headers instead. For example:

```text
time_shield/validation.hpp -> time_shield/core/validation.hpp
time_shield/time_conversions.hpp -> time_shield/conversions.hpp
time_shield/DateTime.hpp -> time_shield/date_time.hpp
time_shield/ntp_client.hpp -> time_shield/ntp/ntp_client.hpp
```

## [v1.0.5] - 2025-12-22
- Added fast date conversion paths for timestamp-to-calendar helpers, along with unchecked timestamp math to reduce validation overhead in hot paths (legacy fallbacks remain for comparison).
Expand All @@ -30,7 +50,7 @@ All notable changes to this project will be documented in this file.
- Added ISO week-date conversions, formatting, and parsing utilities.
- Added geocentric MoonPhase calculator with quarter timings, documentation, and tests.
- Added continuous lunar phase sin/cos helpers, structured quarter instants with event windows, documentation, and tests.
- Split `time_conversions.hpp` into modular headers while keeping the umbrella include, preserving APIs with compatibility aliases and refreshed docs.
- Split the former time-conversions aggregate into modular domain headers with compatibility aliases and refreshed docs.
- Added short-form weekday and timestamp conversion aliases alongside new constexpr timezone offset helpers.
- Expanded conversion coverage tests to exercise the renamed helpers and new wrappers across C++11/14/17 builds.
- Documented first/last workday boundary helpers and their UTC semantics in README and Doxygen mainpage.
Expand Down
Loading
Loading