Time Shield — это header-only C++-библиотека для работы со временем. Она включает функции для конвертации временных значений, форматирования дат и множество утилит для задач с таймстампами.
Названа в честь «временного щита» Хомуры Акэми.
#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);Используйте #include <time_shield.hpp> для полного API или подключайте
отдельные заголовки для минимальной сборки.
Публичные заголовки сгруппированы по доменам. Для целевого подключения рекомендуются следующие umbrella-заголовки:
time_shield/core.hpp— базовые типы, структуры, проверки и утилиты;time_shield/conversions.hpp— преобразования временных и календарных значений;time_shield/text.hpp— разбор и форматирование;time_shield/date_time.hpp— типDateTime;time_shield/timezone.hpp— именованные зоны и фиксированные смещения;time_shield/astronomy.hpp— Julian- и лунные helper-ы;time_shield/timers.hpp— таймеры и планировщик;time_shield/ntp.hpp— необязательные NTP-клиент и сервис времени.
Доменные пути являются единственными поддерживаемыми публичными путями к заголовкам. Подключайте umbrella или leaf-header домена, которому принадлежит нужный API.
Time Shield создавался как практичный инструмент для работы с временем в C++, ориентированный на прикладные и инженерные задачи. В отличие от стандартной std::chrono или более академичных решений вроде HowardHinnant/date, библиотека:
- использует простые типы (
int64_t,double) для представления времени (ts_t,fts_t) — их легко логировать, сериализовать и передавать через JSON, RPC и базы данных; без перегруженных классовstd::chrono; - поддерживает разные временные представления — Unix‑время, дробные секунды, милли- и микросекунды, OLE Automation (Excel), джулианские даты;
- включает утилиты для округления, форматирования, парсинга ISO 8601, работы с частями времени и вычисления границ периодов;
- имеет расширяемую архитектуру — новые форматы (Julian, OLE, UTC-offset) добавляются как отдельные типы и модули;
- есть адаптированные заголовки для MQL5/MetaTrader в каталоге
MQL5, покрывающие ключевые части API; - поставляется как header-only — подключается одной строкой, без сборки и внешних зависимостей;
- использует только стандартные заголовки STL и системные API; платформенные модули (например, сокетный
NtpClient) изолированы и не мешают кроссплатформенной сборке.
- Календарные и датовые хелперы — валидация, будни/выходные/рабочие дни (включая строки ISO 8601).
- Форматирование времени — преобразование таймстампов в строки по стандартным и пользовательским шаблонам.
- Конвертации — перевод между секундными, миллисекундными и плавающими представлениями времени, структуры
DateTimeStruct, OLE Automation (Excel) и временные зоны. - Быстрые конвертации дат — часть функций
timestamp -> календарьиспользует ускоренный алгоритм, вдохновлённый https://www.benjoffe.com/fast-date-64 и реализованный с нуля. - Тип
DateTime— обёртка, хранящая UTC миллисекунды и фиксированное смещение, поддерживает ISO 8601, локальные/UTC компоненты и арифметику. - ISO week date — конвертация, форматирование и парсинг ISO 8601 для недельного счёта.
- Астрономические утилиты — расчёт Julian Date/MJD/JDN и оценка лунной фазы/возраста по Unix‑времени.
- Утилиты — получение текущих меток времени, вычисления начала/конца периодов, работа с частями секунды.
- Преобразование часовых поясов — функции для европейских, американских и популярных Asia/EMEA trading-зон, а также универсальная zone-to-zone конвертация.
- NTP‑клиент и пул — одиночные запросы и конфигурируемый пул/раннер/сервис с возможностью офлайн‑тестов (Windows и Unix).
- Поддержка MQL5 — адаптированные заголовки в каталоге
MQL5позволяют использовать библиотеку в MetaTrader. - Совместимость с
C++11–C++17.
Компиляционные флаги в time_shield/core/config.hpp позволяют адаптировать библиотеку под платформу и отключать необязательные модули:
TIME_SHIELD_PLATFORM_WINDOWS/TIME_SHIELD_PLATFORM_UNIX— определение целевой платформы.TIME_SHIELD_HAS_WINSOCK— наличие WinSock API.TIME_SHIELD_ENABLE_NTP_CLIENT— включает модульNtpClient(по умолчанию1на поддерживаемых платформах).TIME_SHIELD_ENABLE_LEGACY_ALIASES— включает алиасы для подтверждённо переименованных функций преобразования. Макрос определяется до включения заголовков Time Shield и по умолчанию выключен.
Все заголовки библиотеки используют пространство имён time_shield. Для доступа к API можно писать time_shield:: или подключать using namespace time_shield;.
Часть функций зависит от системных API и может быть ограничена платформой (например, получение realtime через
QueryPerformanceCounterпод Windows).
ts_t— Unix-время в секундах (signed 64-bit). Представляет целые секунды.ts_ms_t/ts_us_t— Unix-время в милли/микросекундах (signed 64-bit).monotonic_sec()/monotonic_ms()/monotonic_us()— монотонные process-local счётчики для интервалов и дедлайнов, а не UTC timestamps.fts_t— Unix-время в секундах какdouble. Точность дробной части зависит от величины значения; около современной эпохи обычно сохраняет микросекунды, на очень больших |ts| младшие разряды могут теряться.year_t— signed 64-bit год.dse_t/unix_day_t/unixday_t— число суток с 1970-01-01 (signed 64-bit), подходит для дат до эпохи.dse,dse_ms,dse_to_tsиdse_to_ts_ms— краткие convenience-имена для конверсий числа суток с эпохи.- ISO 8601 утилиты используют пролептический григорианский календарь и не учитывают високосные секунды.
- Базовые конверсии и “горячие” функции ориентированы на
noexceptи отсутствие динамических аллокаций; строковые/парсинговые и часть высокоуровневых хелперов могут выделять память и/или бросать исключения (это указано в документации конкретных функций).
Time Shield использует семантический стиль номеров версий и разделяет API на три уровня стабильности:
- Canonical API — основные документированные типы и функции. Ломающие изменения требуют отдельного решения по совместимости и версии.
- Convenience API — поддерживаемые альтернативные имена и короткие алиасы для частых операций. Наличие канонического эквивалента само по себе не делает алиас устаревшим.
- Legacy compatibility API — исторически переименованные или вытесненные
имена с установленной заменой. Такие имена могут быть отключены по умолчанию,
если доступен явный opt-in, например
TIME_SHIELD_ENABLE_LEGACY_ALIASES.
Patch-релизы могут содержать исправления, внутренний рефакторинг, изменения документации, небольшие дополнительные возможности и очистку compatibility API. Minor-релизы предназначены для более крупных возможностей и развития API. Major-релизы зарезервированы для намеренных существенных изменений канонического API.
Символ не считается legacy только потому, что он короткий, длинный, избыточный или стилистически отличается. Статус legacy подтверждается историей репозитория, документацией, явным переименованием или установленной заменой.
Библиотека поставляется в виде заголовков. Для подключения достаточно добавить путь include/time_shield в проект и подключить основной файл:
#include <time_shield.hpp>Примеры можно собрать скриптом build-examples.bat. Для установки файлов MQL5 предусмотрен install_mql5.bat.
time_shield::time_shieldявляется header-only target и может одновременно использоваться из нескольких статических библиотек в одной программе.NtpTimeServiceявляется header-only и поддерживает стандартыC++11/C++14/C++17.- На Windows при
TIME_SHIELD_ENABLE_NTP_CLIENT=ONэкспортируемый CMake target транзитивно подтягивает требуемую socket library. - При ручной интеграции без CMake target платформенную socket library нужно добавить самостоятельно.
Подробности см. в docs/library-integration-guidelines-RU.md.
Ниже приведены небольшие примеры из разделов библиотеки.
#include <time_shield.hpp>
using namespace time_shield;
ts_t now = ts(); // секунды с эпохи
fts_t now_f = fts(); // время в секундах с дробной частью
int ms_part = ms_of_sec(now_f); // миллисекундная часть
ts_t mono_sec = monotonic_sec(); // монотонные process-local секунды
ts_ms_t mono = monotonic_ms(); // монотонные process-local миллисекундыИспользуйте now() / ts_ms() / ts_us() для wall-clock меток времени.
Используйте monotonic_sec() / monotonic_ms() / monotonic_us() для
измерения интервалов, дедлайнов и timeout-логики.
#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);См. examples/time_formatting_example.cpp для компактного cross-platform
примера с ISO8601, custom formatting, offset-aware rendering и
filename-safe строками.
См. examples/time_formatting_showcase_example.cpp для более широкого
formatter showcase с UTC/local вариантами, millisecond helpers, MQL5,
human-readable и filename-oriented выводом.
#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);
}Парсер использует быстрый ручной path без std::regex. Если в строке есть
timezone offset, локальное время из строки переводится в канонический 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* понимает ту же custom grammar, что и to_string() /
to_string_ms(), остаётся non-throwing и не использует regex-парсинг. %z
в formatter выдаёт compact offsets вида +0530, а parser принимает и +HHMM,
и ISO-вид +HH:MM.
См. examples/time_parser_example.cpp для ISO8601 parsing, seconds/ms/floating
timestamp parsing, formatter round-trip и простого failure case.
#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 принимает canonical формы (YYYY-Www-D, YYYYWwwD) и
совместимые mixed separator варианты (YYYY-WwwD, YYYYWww-D). Поддерживаются
uppercase и lowercase W, а при отсутствии ISO weekday используется Monday.
В custom formatting и parsing %G / %g / %V / %u обозначают ISO
week-based tokens. В custom parse format нельзя смешивать ISO week-based
year/week tokens с Gregorian %Y / %m / %d.
DateTime хранит UTC миллисекунды и фиксированный offset, что позволяет
сохранять смещение при форматировании и получать локальные компоненты.
#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(); // сохраняет +02:30
std::string utc = dt.to_iso8601_utc(); // выводит Z
DateTime tomorrow = dt.add_days(1).start_of_day();
int hour_local = dt.hour(); // локальный час с учётом offset
int hour_utc = dt.utc_hour(); // час в UTCZonedClock хранит переиспользуемый контекст локального времени для
именованной зоны или фиксированного UTC offset. Именованные зоны
пересчитывают effective offset для заданного UTC-момента, а числовой offset
остаётся фиксированным.
#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(...) проверяет синтаксис и принимает числовые смещения вплоть до 23:59. Семантическая проверка поддерживаемых UTC offset для DateTime, ZonedClock и связанных helper-ов использует is_valid_tz_offset(...) и диапазон [-12:00, +14:00].
Преобразования OA совместимы с Excel/COM (базовая дата 1899-12-30), выполняются в UTC и корректно обрабатывают специальную семантику отрицательных дробных OA serials до базовой даты.
#include <time_shield/conversions/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); // преобразование обратно в Unix-время
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:00ZХелперы Julian Date используют пролептический григорианский календарь и ориентированы на аналитические значения (JD, MJD, JDN), а не на высокоточные эфемериды. Лунные helper-ы по-прежнему доступны через astronomy entry header.
#include <time_shield/astronomy/julian_conversions.hpp>
#include <time_shield/astronomy/astronomy_conversions.hpp>
using namespace time_shield;
jd_t jd = gregorian_ymd_to_jd(2024, 5, 2, 12, 0); // Julian Date для календарного момента
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()); // фаза Луны [0..1)
double age_days = moon_age_days(fts()); // примерный возраст Луны в днях
MoonPhaseSineCosine signal = moon_phase_sincos(fts()); // sin/cos фазового угла без скачка в 0/1
MoonQuarterInstants quarters = moon_quarters(fts()); // ближайшие четверти (Unix секунды в double)
bool is_near_new = is_new_moon_window(fts()); // попадание в окно новолуния +/-12чMoonPhaseCalculator (time_shield::astronomy::MoonPhase) выдаёт расширенный набор показателей (освещённость, угловые диаметры, расстояние, фазовый угол), sin/cos для непрерывного фазового сигнала, моменты четвертей и проверки «окон» вокруг фаз. Текущая математика геоцентрическая: положения Солнца/Луны рассчитываются без топоцентрических поправок. Поэтому освещённость и фазовый угол — «глобальные» в данный момент времени, а локально отличается:
- дата/время из-за часового пояса,
- ориентация освещённой части (в южном полушарии картинка отражена),
- наблюдаемость (первый серп, высота над горизонтом, атмосфера).
Текущая математика — геоцентрическая (относительно центра Земли), без топоцентрических поправок/параллакса. Освещённость/фазовый угол глобальны для Земли как целого. По месту реально меняются:
- локальная дата/время (часовой пояс),
- ориентация освещённой части (в северном/южном полушарии «картинка» перевёрнута),
- видимость (первый серп/наблюдаемость) — уже про атмосферу/высоту над горизонтом и т.п.
#include <time_shield/astronomy/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 секунды (double)
MoonQuarterInstants around = moon_quarters(ts);
MoonPhaseSineCosine signal = moon_phase_sincos(ts);
bool is_new = calculator.is_new_moon_window(ts); // по умолчанию окно +/-12ч#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);Поддерживаются фиксированные зоны IST, MYT, WIB, WITA, WIT, KZT,
TRT, BYT, SGT, ICT, PHT, GST, HKT, JST и KST. Для
универсального API в секундах используйте zone_to_gmt() / gmt_to_zone() /
convert_time_zone(), а для миллисекундных таймстампов —
zone_to_gmt_ms() / gmt_to_zone_ms() / convert_time_zone_ms().
#include <time_shield/ntp/ntp_client_pool.hpp>
#include <time_shield/ntp/ntp_time_service.hpp>
using namespace time_shield;
NtpClientPool pool;
pool.set_default_servers();
pool.measure();
int64_t pool_offset = pool.offset_us();
// Фоновый runner + ленивый сервис через функции-обёртки:
ntp::init(30000); // 30 сек.
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 является header-only и поддерживает стандарты
C++11/C++14/C++17. Сервис использует immortal singleton, чтобы избежать
проблем порядка разрушения статических объектов. Во время обычной работы
геттеры сохраняют ленивый старт. Во время завершения процесса сервис не
перезапускает background runner и переходит на fallback через realtime и
последний закешированный offset. В общем случае C++17+ позволяет
использовать более простой singleton-storage паттерн через inline
variables. Для NtpTimeService публичный способ подключения и вызова
одинаков в C++11/C++14/C++17.
Полное описание API и дополнительные примеры доступны по адресу: https://liminode.github.io/time-shield-cpp/
HTML-документация Doxygen публикуется через GitHub Pages.
Проект распространяется по лицензии MIT.
