| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Time Shield is a header-only C++ library for working with time. It provides functions for converting time values, formatting dates and many utilities for working with timestamps.
Named after Homura Akemi's "time shield".
See the Russian version for documentation in Russian.
#include <time_shield.hpp>
using namespace time_shield;
ts_t now = ts();
std::string iso = to_iso8601(now);
ts_t gmt = cet_to_gmt(now);
bool monday = is_workday(now);Use #include <time_shield.hpp> for the full API, or include specific headers for a minimal build.
Time Shield was created as a practical tool for handling time in C++ with a focus on application and engineering tasks. Unlike the standard std::chrono or more academic solutions like HowardHinnant/date, the library:
Compile-time flags in time_shield/config.hpp control optional parts of the library and report platform capabilities:
C++ and MQL5 public headers place their declarations inside the time_shield namespace. Use time_shield:: or using namespace time_shield; to access that API. MQL4 uses the TimeShield class for static methods and TSHIELD_ constants because the MQL4 language does not provide namespaces.
Some functions depend on platform APIs and may be limited (for example, obtaining realtime via QueryPerformanceCounter on Windows).
Time Shield follows Semantic Versioning. Patch releases contain only backward-compatible fixes. Minor versions add backward-compatible features. Major versions may include breaking changes. The public API comprises headers under include/time_shield.
After installing the library (e.g., with cmake --install), consume it in a project with CMake:
cmake_minimum_required(VERSION 3.15)
project(app LANGUAGES CXX)
find_package(TimeShield CONFIG REQUIRED)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE time_shield::time_shield)Vendor the library as a submodule:
git submodule add https://github.com/NewYaroslav/time-shield-cpp external/time-shield-cppThen include it:
add_subdirectory(external/time-shield-cpp)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE time_shield::time_shield)Install via a local overlay port:
vcpkg install time-shield-cpp --overlay-ports=./vcpkg-overlay/portsUse the vcpkg toolchain when configuring CMake:
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmakeThe port is intended to be upstreamed to microsoft/vcpkg.
Examples can be built with the provided scripts:
Use install_mql5.bat to install the MQL5 files. For MQL4, copy MQL4/Include into the terminal Include directory and include the header:
#include <TimeShield.mqh>
long now_ms = TimeShield::now();
int second_day = TimeShield::sec_of_day(TimeCurrent());
int one_day = TSHIELD_SEC_PER_DAY;
See docs/library-integration-guidelines.md for the full integration contract.
| Platform | Compilers | C++ Standards |
|---|---|---|
| Windows | MSVC, ClangCL | 11, 14, 17 |
| Linux | GCC, Clang | 11, 14, 17 |
| macOS | Apple Clang | 11, 14, 17 |
Below are small examples from different sections of the library.
#include <time_shield.hpp>
using namespace time_shield;
ts_t now = ts(); // seconds since epoch
fts_t now_f = fts(); // time in seconds with fraction
int ms_part = ms_of_sec(now_f); // millisecond part
ts_t mono_sec = monotonic_sec(); // monotonic process-local seconds
ts_ms_t mono = monotonic_ms(); // monotonic process-local millisecondsUse now() / ts_ms() / ts_us() for wall-clock timestamps. Use monotonic_sec() / monotonic_ms() / monotonic_us() for elapsed-time measurement, intervals, and timeout logic.
#include <time_shield.hpp>
std::string iso = to_iso8601(now); // 2024-06-21T12:00:00
std::string local = to_iso8601(now, 2 * SEC_PER_HOUR + 30 * SEC_PER_MIN);
std::string custom = to_string("%Y-%m-%d %H:%M:%S", now);
std::string custom_local = to_string("%Y-%m-%d %H:%M:%S %z", now, 2 * SEC_PER_HOUR);
std::string filename = to_windows_filename(now);See examples/time_formatting_example.cpp for a compact cross-platform example covering ISO8601, custom formatting, offset-aware rendering, and filename-safe output. See examples/time_formatting_showcase_example.cpp for a broader formatter showcase with UTC/local variants, millisecond helpers, MQL5, human-readable, and filename-oriented output.
#include <time_shield.hpp>
DateTimeStruct dt;
TimeZoneStruct tz;
if (parse_iso8601("2024-11-25T14:30:00-05:30", dt, tz)) {
ts_t ts_val = to_timestamp(dt) - to_offset(tz);
}The parser uses a manual fast path without std::regex. Strings with an explicit offset are interpreted canonically: the wall-clock time in the string is converted to the corresponding UTC instant.
#include <time_shield.hpp>
ts_t ts_val = 0;
bool ok = try_parse_format_ts(
"2024-11-25 14:30:00 -0530",
"%Y-%m-%d %H:%M:%S %z",
ts_val);try_parse_format* mirrors the custom formatter grammar used by to_string() and to_string_ms(), stays non-throwing, and avoids regex-based parsing. %z emits compact offsets like +0530 in the formatter and accepts both +HHMM and ISO-style +HH:MM during parsing. See examples/time_parser_example.cpp for ISO8601 parsing, seconds/ms/floating timestamp parsing, formatter round-trips, and a simple failure case.
#include <time_shield.hpp>
using namespace time_shield;
ts_t m15_sec = timeframe_sec("M15"); // 900
ts_ms_t h1_ms = timeframe_ms("hour"); // 3600000
ts_t two_weeks = timeframe_sec("2 weeks"); // 1209600
ts_t quarter = 0;
bool ok = str_to_timeframe_sec("Q1", quarter); // 90 fixed daysstr_to_timeframe_sec(...) and str_to_timeframe_ms(...) parse compact trading tokens such as M1, M15, H1, H4, D1, W1, MN1, Q1, and Y1, plus English word forms such as minute, hour, 2 weeks, and month. Calendar-sized units use fixed conversions: month = 30 days, quarter = 90 days, and year = 365 days.
#include <time_shield.hpp>
using namespace time_shield;
IsoWeekDateStruct iso{};
bool ok_iso = parse_iso_week_date("2025-W512", iso); // permissive mixed form
bool ok_dt = DateTime::try_parse_iso_week_date("2025w51", iso); // lowercase 'w', Monday default
DateTime monday = DateTime::from_iso_week_date(iso, 9, 30);
std::string custom_iso = to_string_ms("%G-%V-%u", monday.unix_ms(), monday.utc_offset());ISO week-date parsing accepts canonical forms (YYYY-Www-D, YYYYWwwD) and compatible mixed separator variants (YYYY-WwwD, YYYYWww-D). The parser also accepts uppercase or lowercase W, and missing ISO weekday defaults to Monday. Custom formatting and parsing support %G / %g / %V / %u as ISO week-based tokens. Custom parse formats reject mixes of ISO week-based year/week tokens with Gregorian %Y / %m / %d date tokens.
DateTime stores UTC milliseconds plus an optional fixed offset for local component access and round-trip formatting.
#include <time_shield.hpp>
using namespace time_shield;
DateTime dt = DateTime::parse_iso8601("2025-12-16T10:20:30.123+02:30");
std::string local = dt.to_iso8601(); // preserves +02:30
std::string utc = dt.to_iso8601_utc(); // prints Z
DateTime tomorrow = dt.add_days(1).start_of_day();
int hour_local = dt.hour(); // local hour (offset applied)
int hour_utc = dt.utc_hour(); // UTC hourZonedClock stores a reusable local-time context for either a named zone or a fixed UTC offset. Named zones recompute DST-sensitive offsets for the requested UTC instant, while numeric offsets stay fixed.
#include <time_shield.hpp>
using namespace time_shield;
ZonedClock clock(CET);
DateTime berlin_now = clock.now();
TimeZone zone = UNKNOWN;
bool has_zone = parse_time_zone_name("CET", zone);
TimeZoneStruct tz_struct{};
bool has_offset = parse_time_zone("+05:30", tz_struct);
ZonedClock fixed_clock;
bool created_fixed = ZonedClock::try_from_offset(2 * SEC_PER_HOUR, fixed_clock);
clock.try_set_zone("+05:30");
std::string local_iso = clock.to_iso8601();
ZonedClock ntp_tokyo(JST, true);
ts_ms_t tokyo_local_ms = ntp_tokyo.local_time_ms();parse_time_zone(...) validates timezone syntax and accepts numeric offsets up to 23:59. Semantic support checks for reusable offsets in DateTime, ZonedClock, and related helpers use is_valid_tz_offset(...) with the supported range [-12:00, +14:00].
#include <time_shield/validation.hpp>
#include <time_shield/time_parser.hpp>
using namespace time_shield;
bool monday = is_workday(1710720000); // seconds timestamp
bool monday_ms = is_workday_ms("2024-03-18T09:00:00.500Z"); // ISO 8601 with milliseconds
bool from_date = is_workday(2024, 3, 18); // year, month, day components
bool from_str = is_workday("2024-03-18T09:00:00Z"); // ISO 8601 stringThe string helpers accept the same ISO 8601 formats as str_to_ts / str_to_ts_ms and evaluate to false when parsing fails or the date falls on a weekend.
#include <time_shield/time_conversions.hpp>
using namespace time_shield;
ts_t first_open = start_of_first_workday_month(2024, 6); // 2024-06-03T00:00:00Z
ts_t first_close = end_of_first_workday_month(2024, Month::JUN);
ts_t last_open = start_of_last_workday_month(2024, 3); // 2024-03-29T00:00:00Z
ts_ms_t last_close_ms = end_of_last_workday_month_ms(2024, Month::MAR);The helpers reuse the start_of_day / end_of_day semantics and therefore return UTC timestamps. Invalid months or months without workdays produce ERROR_TIMESTAMP to simplify downstream validation.
OA conversions are Excel/COM compatible (base date 1899-12-30), operate in UTC, and preserve the special negative-fraction semantics used by OA serials before the base date.
#include <time_shield/ole_automation_conversions.hpp>
using namespace time_shield;
oadate_t oa = ts_to_oadate(1714608000); // 2024-05-02 00:00:00Z
ts_t ts_from_oa = oadate_to_ts(oa); // round toward zero
oadate_t pre_base = to_oadate(1899, Month::DEC, 29, 6, 0); // -1.25
oadate_t from_parts = to_oadate(2024, Month::MAY, 2, 12, 0); // 2024-05-02 12:00:00ZThe Julian helpers use the proleptic Gregorian calendar and provide lightweight analytics-oriented values (JD, MJD, JDN) rather than high-precision ephemerides. The lunar helpers remain analytics-oriented and are exposed through the astronomy entry header.
#include <time_shield/julian_conversions.hpp>
#include <time_shield/astronomy_conversions.hpp>
using namespace time_shield;
jd_t jd = gregorian_ymd_to_jd(2024, 5, 2, 12, 0); // Julian Date for a calendar instant
mjd_t mjd = ts_to_mjd(1714608000); // Modified Julian Date
jdn_t jdn = gregorian_ymd_to_jdn(2024, 5, 2); // Julian Day Number
double phase = moon_phase(fts()); // lunar phase fraction [0..1)
double age_days = moon_age_days(fts()); // approximate lunar age
MoonPhaseSineCosine signal = moon_phase_sincos(fts()); // sin/cos of the phase angle (continuous)
MoonQuarterInstants quarters = moon_quarters(fts()); // nearest quarter instants (Unix seconds, double)
bool is_near_new = is_new_moon_window(fts()); // inside +/-12h new moon windowMoonPhaseCalculator (time_shield::astronomy::MoonPhase) exposes richer geocentric outputs (illumination, angular diameters, distance, phase angle), sin/cos for a continuous phase signal, quarter instants, and phase event windows. The current math is geocentric (Earth-centered) without topocentric corrections, so phase and illumination are “global” for a given moment. What varies locally:
Current math is geocentric (Sun/Moon positions relative to Earth’s center, without topocentric parallax). This means illumination and the phase angle are primarily “global” at a given instant for the Earth as a whole. Locally, what actually differs is:
- calendar date/time via timezone shifts,
- apparent orientation of the illuminated side (flipped between northern/southern hemispheres),
- visibility (e.g., first crescent) driven by atmosphere/horizon/altitude rather than the geocentric phase itself.
#include <time_shield/MoonPhase.hpp>
using namespace time_shield;
MoonPhaseCalculator calculator{};
const double ts = 1704067200.0; // 2024-01-01T00:00:00Z
MoonPhaseResult res = calculator.compute(ts);
MoonPhase::quarters_unix_s_t quarters = calculator.quarter_times_unix(ts); // Unix seconds (double)
MoonQuarterInstants around = moon_quarters(ts);
MoonPhaseSineCosine signal = moon_phase_sincos(ts);
bool is_new = calculator.is_new_moon_window(ts); // +/-12h window by default#include <time_shield.hpp>
ts_t gmt = to_ts(2024, Month::JUN, 21, 12, 0, 0);
ts_t ist = gmt_to_ist(gmt);
ts_t kyiv = gmt_to_kyiv(gmt);
ts_t myt = convert_time_zone(ist, TimeZone::IST, TimeZone::MYT);Supported fixed-offset additions include IST, MYT, WIB, WITA, WIT, KZT, TRT, BYT, SGT, ICT, PHT, GST, HKT, JST, and KST. Use zone_to_gmt() / gmt_to_zone() / convert_time_zone() for the generic seconds-based API and zone_to_gmt_ms() / gmt_to_zone_ms() / convert_time_zone_ms() for millisecond timestamps.
The legacy two-argument zone_to_gmt*() functions keep their best-effort behavior for compatibility. For calendar scheduling and other cases that need explicit DST handling, use resolve_local_time_ms() first or call the policy overloads:
ts_ms_t local = to_timestamp_ms(2024, OCT, 27, 2, 30, 0);
auto resolved = resolve_local_time_ms(local, CET);
if (resolved.status == LocalTimeStatus::ambiguous) {
ts_ms_t first = resolved.first_utc_ms;
ts_ms_t second = resolved.second_utc_ms;
}
ts_ms_t utc = zone_to_gmt_ms(
local,
CET,
AmbiguousTimePolicy::first_occurrence,
NonexistentTimePolicy::error);LocalTimeStatus::nonexistent marks a local timestamp inside a DST spring gap; LocalTimeStatus::ambiguous marks a local timestamp repeated during a DST fall fold. gmt_to_zone*() maps UTC to local time and is always a single instant, but repeated local times need zone_offset_at_utc*() if you must preserve which occurrence/offset was used.
#include <time_shield/ntp_client_pool.hpp>
#include <time_shield/ntp_time_service.hpp>
using namespace time_shield;
NtpClientPool pool;
pool.set_default_servers();
pool.measure();
int64_t pool_offset = pool.offset_us();
// Background runner + lazy singleton service via wrapper functions:
ntp::init(30000); // 30 sec
int64_t utc_ms = ntp::utc_time_ms();
int64_t offset_us = ntp::offset_us();
int64_t utc_sec = ntp::utc_time_sec();
bool ok = ntp::last_measure_ok();
uint64_t attempts = ntp::measure_count();
ntp::shutdown();NtpTimeService is header-only and supports C++11/C++14/C++17. The service uses an immortal singleton to avoid static destruction order issues. During normal runtime the singleton getters keep their lazy-start behavior. During process teardown the service does not restart the background runner and falls back to realtime plus the last cached offset. In general, C++17+ allows a simpler singleton-storage pattern with inline variables. For NtpTimeService, the public usage contract is the same in C++11/C++14/C++17.
Full API description and additional examples are available at https://newyaroslav.github.io/time-shield-cpp/
Doxygen HTML is published via GitHub Pages.
The project is distributed under the MIT license.
| Back | FazBrowse Home | New Git URL |