├── .gitattributes ├── .github └── workflows │ └── tg-send.yml ├── LICENSE ├── README.md ├── README_EN.md ├── examples ├── dayIndex │ └── index.h ├── demo │ └── demo.ino ├── keeper │ └── keeper.ino └── test │ └── test.ino ├── keywords.txt ├── library.properties └── src ├── Datime.h ├── DaySeconds.h ├── Stamp.h ├── StampBuild.h ├── StampKeeper.h ├── StampSync.h ├── StampTicker.h ├── VirtualRTC.h └── core ├── StampConvert.h ├── StampUtils.cpp ├── StampUtils.h ├── stamp_zone.cpp └── stamp_zone.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/tg-send.yml: -------------------------------------------------------------------------------- 1 | 2 | name: Telegram Message 3 | on: 4 | release: 5 | types: [published] 6 | jobs: 7 | build: 8 | name: Send Message 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: send telegram message on push 12 | uses: appleboy/telegram-action@master 13 | with: 14 | to: ${{ secrets.TELEGRAM_TO }} 15 | token: ${{ secrets.TELEGRAM_TOKEN }} 16 | disable_web_page_preview: true 17 | message: | 18 | ${{ github.event.repository.name }} v${{ github.event.release.tag_name }} 19 | ${{ github.event.release.body }} 20 | https://github.com/${{ github.repository }} 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 AlexGyver 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![latest](https://img.shields.io/github/v/release/GyverLibs/Stamp.svg?color=brightgreen)](https://github.com/GyverLibs/Stamp/releases/latest/download/Stamp.zip) 2 | [![PIO](https://badges.registry.platformio.org/packages/gyverlibs/library/Stamp.svg)](https://registry.platformio.org/libraries/gyverlibs/Stamp) 3 | [![Foo](https://img.shields.io/badge/Website-AlexGyver.ru-blue.svg?style=flat-square)](https://alexgyver.ru/) 4 | [![Foo](https://img.shields.io/badge/%E2%82%BD%24%E2%82%AC%20%D0%9F%D0%BE%D0%B4%D0%B4%D0%B5%D1%80%D0%B6%D0%B0%D1%82%D1%8C-%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D0%B0-orange.svg?style=flat-square)](https://alexgyver.ru/support_alex/) 5 | [![Foo](https://img.shields.io/badge/README-ENGLISH-blueviolet.svg?style=flat-square)](https://github-com.translate.goog/GyverLibs/Stamp?_x_tr_sl=ru&_x_tr_tl=en) 6 | 7 | [![Foo](https://img.shields.io/badge/ПОДПИСАТЬСЯ-НА%20ОБНОВЛЕНИЯ-brightgreen.svg?style=social&logo=telegram&color=blue)](https://t.me/GyverLibs) 8 | 9 | # Stamp 10 | Библиотека для хранения и манипуляции со временем 11 | - Более удобная в использовании, чем встроенная time.h 12 | - Используются более быстрые алгоритмы преобразования, чем в time.h 13 | - Парсинг из строк 14 | - Может считать и поддерживать время на базе millis() 15 | - Работает ~до 2106 года 16 | 17 | ### Совместимость 18 | Совместима со всеми Arduino платформами (используются Arduino-функции) 19 | 20 | ## Содержание 21 | - [Документация](#reference) 22 | - [Пример](#example) 23 | - [Версии](#versions) 24 | - [Установка](#install) 25 | - [Баги и обратная связь](#feedback) 26 | 27 | 28 | 29 | ## Документация 30 | ### Часовой пояс 31 | Настраивается глобально для всех инструментов библиотеки 32 | 33 | ```cpp 34 | void setStampZone(int zone); // установить глобальную часовую зону в часах или минутах 35 | int getStampZone(); // получить глобальную часовую зону в минутах 36 | ``` 37 | 38 | ### Утилиты 39 | Набор функций для работы со временем и датой 40 | 41 | ```cpp 42 | // время в секунды 43 | uint32_t StampUtils::timeToSeconds(uint8_t hours, uint8_t minutes, uint8_t seconds); 44 | 45 | // високосный год 46 | bool StampUtils::isLeap(uint16_t year); 47 | 48 | // дней в месяце без учёта года (февраль 28) 49 | uint8_t StampUtils::daysInMonth(uint8_t month); 50 | 51 | // дней в месяце с учётом високосного года 52 | uint8_t StampUtils::daysInMonth(uint8_t month, uint16_t year); 53 | 54 | // дней года к месяцу (янв 0, фев 31, март 59/60...) 55 | uint16_t StampUtils::daysToMonth(uint8_t month, uint16_t year); 56 | 57 | // дата в день текущего года (начиная с 1) 58 | uint16_t StampUtils::dateToYearDay(uint8_t day, uint8_t month, uint16_t year); 59 | 60 | // дата в день недели (пн 1.. вс 7) 61 | uint8_t StampUtils::dateToWeekDay(uint8_t day, uint8_t month, uint16_t year); 62 | 63 | // дата в количество дней с 01.01.2000 (начиная с 0) 64 | uint16_t StampUtils::dateToDays2000(uint8_t day, uint8_t month, uint16_t year); 65 | 66 | // дата в unix время, zone в минутах 67 | uint32_t StampUtils::dateToUnix(uint8_t day, uint8_t month, uint16_t year, uint8_t hour, uint8_t minute, uint8_t seconds, int16_t zone = 0); 68 | ``` 69 | 70 | ### Макросы 71 | ```cpp 72 | // время и дата компиляции 73 | __TIME_SEC__ 74 | __TIME_MIN__ 75 | __TIME_HOUR__ 76 | __DATE_DAY__ 77 | __DATE_MONTH__ 78 | __DATE_YEAR__ 79 | 80 | // unix с часовой зоной компьютера 81 | __TIME_UNIX__ 82 | ``` 83 | 84 | ### DaySeconds 85 | Хранит время в секундах с начала текущих суток 86 | ```cpp 87 | DaySeconds(uint8_t hour, uint8_t minute, uint8_t second); 88 | 89 | void set(uint8_t hour, uint8_t minute, uint8_t second); 90 | 91 | uint32_t seconds = 0; 92 | ``` 93 | 94 | ### Datime 95 | Хранит локальные дату и время в отдельных переменных: 96 | 97 | ```cpp 98 | uint16_t year; // год 99 | uint8_t month; // месяц (1.. 12) 100 | uint8_t day; // день месяца (1.. 28-31) 101 | uint8_t hour; // час (0.. 23) 102 | uint8_t minute; // минута (0.. 59) 103 | uint8_t second; // секунда (0.. 59) 104 | uint8_t weekDay; // день недели (1 пн.. 7 вс) ISO 8601 105 | uint16_t yearDay; // день года (1.. 365-366) 106 | ``` 107 | 108 | > Указанные диапазоны справедливы для всех остальных функций библиотеки! 109 | 110 | ```cpp 111 | Datime() {} 112 | Datime(const char* str); 113 | Datime(uint32_t unix); 114 | Datime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); 115 | Datime(uint16_t yh, uint16_t mm, uint16_t ds); 116 | ``` 117 | ```cpp 118 | // ============= SET ============= 119 | // установить время (год, месяц, день, час, минута, секунда) 120 | void set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); 121 | 122 | // установить время (год, месяц, день) или (час, минута, секунда) 123 | void set(uint16_t yh, uint16_t mm, uint16_t ds); 124 | 125 | // установить из unix времени и глобального часового пояса setStampZone 126 | void set(uint32_t unix); 127 | 128 | // =========== EXPORT ============ 129 | // вывести в секунды с начала текущих суток 130 | uint32_t daySeconds(); 131 | 132 | // вывести в unix-секунды 133 | uint32_t getUnix(); 134 | 135 | // ========== TO STRING ========== 136 | // вывести дату в формате "dd.mm.yyyy" [11]. Вернёт указатель на конец строки 137 | char* dateToChar(char* buf); 138 | 139 | // вывести дату в формате "dd.mm.yyyy" 140 | String dateToString(); 141 | 142 | // вывести время в формате "hh:mm:ss" [9]. Вернёт указатель на конец строки 143 | char* timeToChar(char* buf); 144 | 145 | // вывести время в формате "hh:mm:ss" 146 | String timeToString(); 147 | 148 | // вывести в формате "dd.mm.yyyy hh:mm:ss" [20]. Вернёт указатель на конец строки 149 | char* toChar(char* buf, char div = ' '); 150 | 151 | // вывести в формате "dd.mm.yyyy hh:mm:ss" 152 | String toString(char div = ' '); 153 | 154 | // ========== PARSE ========== 155 | // yyyy-mm-dd 156 | bool parseDate(const char* s); 157 | 158 | // hh:mm:ss 159 | bool parseTime(const char* s); 160 | 161 | // hh:mm:ss или yyyy-mm-dd или yyyy-mm-ddThh:mm:ss 162 | bool parse(const char* s); 163 | 164 | // , dd yyyy hh:mm:ss 165 | bool parseHTTP(const char* s); 166 | 167 | // =========== COMPARE =========== 168 | // сравнивается с Datime, uint32_t, DaySeconds 169 | 170 | // одинаковое время 171 | bool equals(const Datime& dt); 172 | 173 | // високосный ли год 174 | bool isLeap(); 175 | 176 | // дата и время корректны 177 | bool valid(); 178 | 179 | // дата 01.01.2000 180 | bool isY2K(); 181 | 182 | // день года как индекс массива от 0 до 365 независимо от високосного года. 29 февраля имеет индекс 59 183 | uint16_t dayIndex(); 184 | 185 | // ============= ADD ============= 186 | // добавить секунды 187 | void addSeconds(uint32_t s); 188 | 189 | // добавить минуты 190 | void addMinutes(uint32_t m); 191 | 192 | // добавить часы 193 | void addHours(uint32_t h); 194 | 195 | // добавить дни 196 | void addDays(uint32_t d); 197 | 198 | // ============= NEXT ============= 199 | // следующая секунда 200 | void nextSecond(); 201 | 202 | // следующая минута (xx:xx:00) 203 | void nextMinute(); 204 | 205 | // следующий час (xx:00:00) 206 | void nextHour(); 207 | 208 | // следующий день (00:00:00) 209 | void nextDay(); 210 | 211 | // следующий месяц (1 число 00:00:00) 212 | void nextMonth(); 213 | 214 | // обновить weekDay и yearDay исходя из текущей даты (после ручного изменения) 215 | void updateDays(); 216 | ``` 217 | > Все добавления времени в Datime выполняются напрямую, без конвертации в unix, т.е. довольно быстро 218 | 219 | ```cpp 220 | // ============= АЛГОРИТМ ============= 221 | // Алгоритм преобразования времени задаётся перед подключением библиотеки 222 | // для исследования и просто так чтобы было 223 | #define UNIX_ALG UNIX_ALG_0 // ~402us и ~94B Flash (AVR) 224 | #define UNIX_ALG UNIX_ALG_1 // ~298us и ~138B Flash (AVR) 225 | #define UNIX_ALG UNIX_ALG_2 // ~216us и ~584B Flash (AVR) 226 | #define UNIX_ALG UNIX_ALG_3 // ~297us и ~178B Flash (AVR) 227 | #define UNIX_ALG UNIX_ALG_TIME_T // ~246us и ~842B Flash (AVR) 228 | ``` 229 | 230 | ### StampConvert 231 | Конвертер для других классов 232 | 233 | ```cpp 234 | virtual uint32_t getUnix(); 235 | 236 | // =========== GET TIME =========== 237 | // экспортировать в локальное время Datime 238 | Datime now(); 239 | 240 | operator Datime(); 241 | 242 | // ============ TO STRING ============ 243 | // вывести дату в формате "dd.mm.yyyy" 244 | char* dateToChar(char* buf); 245 | String dateToString(); 246 | 247 | // вывести время в формате "hh:mm:ss" 248 | char* timeToChar(char* buf); 249 | String timeToString(); 250 | 251 | // вывести время и дату в формате "dd.mm.yyyy hh:mm:ss" 252 | char* toChar(char* buf, char div = ' '); 253 | String toString(char div = ' '); 254 | 255 | // ============ EXPORT EPOCH ============ 256 | 257 | // получить секунды с epoch 258 | uint32_t toSeconds(); 259 | 260 | // получить минуты с epoch 261 | uint32_t toMinutes(); 262 | 263 | // получить часы с epoch 264 | uint32_t toHours(); 265 | 266 | // получить сутки с epoch 267 | uint32_t toDays(); 268 | 269 | // ============ DATIME ============ 270 | 271 | // получить секунды с начала текущих суток (локальное время) 272 | uint32_t daySeconds(); 273 | 274 | // получить текущие секунды 275 | uint8_t second(); 276 | 277 | // получить текущие минуты 278 | uint8_t minute(); 279 | 280 | // получить текущие часы 281 | uint8_t hour(); 282 | 283 | // получить текущий день месяца 284 | uint8_t day(); 285 | 286 | // получить текущий месяц 287 | uint8_t month(); 288 | 289 | // получить текущий год 290 | uint16_t year(); 291 | 292 | // получить текущий день недели 293 | uint8_t weekDay(); 294 | 295 | // получить текущий день года 296 | uint8_t yearDay(); 297 | 298 | // сравнивается с Datime, uint32_t, DaySeconds 299 | ``` 300 | 301 | ### Stamp 302 | Хранит дату и время в UNIX, наследует `StampConvert`: 303 | 304 | ```cpp 305 | uint32_t unix = 0; 306 | ``` 307 | ```cpp 308 | Stamp; 309 | Stamp(const char* str); 310 | Stamp(uint32_t unix); 311 | Stamp(const Datime& dt); 312 | Stamp(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); 313 | Stamp(uint16_t yh, uint16_t mm, uint16_t ds); 314 | ``` 315 | ```cpp 316 | // =========== SET TIME ============ 317 | // установить время из Datime 318 | void set(Datime dt); 319 | 320 | // установить время (год, месяц, день, час, минута, секунда) 321 | void set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); 322 | 323 | // установить время (год, месяц, день) или (час, минута, секунда) 324 | void set(uint16_t yh, uint16_t mm, uint16_t ds); 325 | 326 | // =========== ADD ============ 327 | // добавить секунды 328 | void addSeconds(uint32_t s); 329 | 330 | // добавить минуты 331 | void addMinutes(uint32_t m); 332 | 333 | // добавить часы 334 | void addHours(uint32_t h); 335 | 336 | // добавить дни 337 | void addDays(uint32_t d); 338 | 339 | // =========== PARSE ============ 340 | // hh:mm:ss или yyyy-mm-dd или yyyy-mm-ddThh:mm:ss 341 | bool parse(const char* s); 342 | 343 | // , dd yyyy hh:mm:ss 344 | bool parseHTTP(const char* s); 345 | 346 | // =========== OVERLOAD =========== 347 | // получить время в секундах 348 | uint32_t getUnix(); 349 | ``` 350 | 351 | ### StampKeeper 352 | После "синхронизации" сохраняет счёт времени на базе `millis()`. Имеет тикер, нужно вызывать его в `loop()`. Сигналит раз в секунду в 0 миллисекунд новой секунды, имеет **механизм стабильного хода** времени: 353 | 354 | - Не пропускает секунды при задержках в программе - будет вызван несколько раз подряд, чтобы "догнать" время 355 | - Если при синхронизации время отстаёт от реального - тикер будет вызван несколько раз подряд на весь период рассинхронизации 356 | - Если при синхронизации время спешит - не будет вызываться, пока реальное время не догонит внутреннее 357 | 358 | > Если вообще не вызывать тикер в программе - время будет просто считаться с момента синхронизации 359 | 360 | ```cpp 361 | // установить unix и миллисекунды 362 | StampKeeper(uint32_t unix = 0, uint16_t ms = 0); 363 | ``` 364 | ```cpp 365 | // установить unix и миллисекунды 366 | void sync(uint32_t unix, uint16_t ms = 0, bool skipTicks = false); 367 | 368 | // синхронизировать с другим кипером 369 | void sync(StampKeeper& keeper, bool skipTicks = false); 370 | 371 | // синхронизировать с Datime 372 | void sync(Datime& dt, uint16_t ms = 0, bool skipTicks = false); 373 | 374 | // сбросить синхронизацию 375 | void reset(); 376 | 377 | // пропустить отставшие секунды (вызывать после sync) 378 | void skipTicks(); 379 | 380 | // есть рассинхронизация, которую нужно "дотикать" 381 | bool hasDesync(); 382 | 383 | // время синхронизировано 384 | bool synced(); 385 | 386 | // секундный флаг 387 | bool newSecond(); 388 | 389 | // подключить функцию-обработчик новой секунды (вида void f()) 390 | void onSecond(SecondCallback handler); 391 | 392 | // подключить функцию-обработчик синхронизации (вида void f(uint32_t unix)) 393 | void onSync(SyncCallback cb); 394 | 395 | // получить текущий unix 396 | uint32_t getUnix(); 397 | 398 | // получить миллисекунды текущей секунды 399 | uint16_t ms(); 400 | 401 | // получить миллисекунды с epoch 402 | uint64_t getUnixMs(); 403 | 404 | // тикер, вызывать в loop. Вернёт true на новой секунде 405 | bool tick(); 406 | ``` 407 | 408 | ### VirtualRTC 409 | Интерфейс для других библиотек 410 | 411 | ```cpp 412 | virtual void setUnix(uint32_t unix) = 0; 413 | virtual uint32_t getUnix() = 0; 414 | ``` 415 | 416 | 417 | 418 | ## Примеры 419 | ### StampKeeper 420 | Некоторые библиотеки используют `StampKeeper` для поддержки синхронизированного времени (GyverNTP, GyverDS3231, Settings...). Примеры подходят под все эти библиотеки: 421 | 422 | ```cpp 423 | StampKeeper rtc; // GyverNTP, GyverDS3231, Settings.rtc 424 | 425 | void setup() { 426 | Serial.begin(115200); 427 | 428 | // часовой пояс, установить до всех действий с объектами 429 | setStampZone(3); 430 | 431 | // обработчик секунды (вызывается из тикера) 432 | rtc.onSecond([]() { 433 | Serial.println("new second!"); 434 | }); 435 | 436 | // обработчик синхронизации (вызывается из sync) 437 | rtc.onSync([](uint32_t unix) { 438 | Serial.println("sync: "); 439 | Serial.print(unix); 440 | }); 441 | 442 | // синхронизация вручную для примера 443 | // rtc.sync(1738237474); 444 | } 445 | void loop() { 446 | // тикер вернёт true каждую секунду в 0 мс секунды, если время синхронизировано 447 | if (rtc.tick()) { 448 | // вывод даты и времени строкой 449 | Serial.print(rtc.toString()); // rtc.timeToString(), rtc.dateToString() 450 | Serial.print(':'); 451 | Serial.println(rtc.ms()); // + миллисекунды текущей секунды. Внутри tick всегда равно 0 452 | 453 | // вывод в Datime 454 | Datime dt = rtc; // или Datime dt(rtc) 455 | dt.year; 456 | dt.second; 457 | dt.hour; 458 | dt.weekDay; 459 | dt.yearDay; 460 | // ... и прочие методы и переменные Datime 461 | 462 | // чтение напрямую, медленнее чем вывод в Datime 463 | rtc.second(); 464 | rtc.minute(); 465 | rtc.year(); 466 | // ... и прочие методы StampConvert 467 | 468 | // сравнение 469 | rtc == DaySeconds(12, 35, 0); // сравнение с DaySeconds (время равно 12:35:00) 470 | rtc == 1738237474; // сравнение с unix 471 | rtc == Datime(2025, 1, 30, 14, 14, 30); // сравнение с Datime 472 | } 473 | 474 | if (rtc.newSecond()) { 475 | // новую секунду можно поймать и здесь 476 | } 477 | } 478 | ``` 479 | 480 | Если не вызывать тикер - время будет считаться просто с момента синхронизации и всегда будет верным: 481 | 482 | ```cpp 483 | StampKeeper t; 484 | 485 | void setup() { 486 | Serial.begin(115200); 487 | setStampZone(3); // часовой пояс 488 | t.sync(1738237474); 489 | } 490 | void loop() { 491 | Serial.println(t.toString()); 492 | delay(2000); 493 | } 494 | ``` 495 | 496 | 497 | ## Версии 498 | - v1.0 499 | - v1.1 - добавлено много новых инструментов и возможностей 500 | - v1.2.2 - оптимизация, рефакторинг, улучшен StampTicker 501 | - v1.3.9 - исправлен критический баг в выводе toString/dateToString/timeToString 502 | - v1.4.0 - добавлен StampKeeper, объединяет StampTicker и StampSync. Куча мелких улучшений 503 | 504 | 505 | ## Установка 506 | - Библиотеку можно найти по названию **Stamp** и установить через менеджер библиотек в: 507 | - Arduino IDE 508 | - Arduino IDE v2 509 | - PlatformIO 510 | - [Скачать библиотеку](https://github.com/GyverLibs/Stamp/archive/refs/heads/main.zip) .zip архивом для ручной установки: 511 | - Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) 512 | - Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) 513 | - Распаковать и положить в *Документы/Arduino/libraries/* 514 | - (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив 515 | - Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 516 | ### Обновление 517 | - Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи 518 | - Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить" 519 | - Вручную: **удалить папку со старой версией**, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам! 520 | 521 | 522 | ## Баги и обратная связь 523 | При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru) 524 | Библиотека открыта для доработки и ваших **Pull Request**'ов! 525 | 526 | При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать: 527 | - Версия библиотеки 528 | - Какой используется МК 529 | - Версия SDK (для ESP) 530 | - Версия Arduino IDE 531 | - Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде 532 | - Какой код загружался, какая работа от него ожидалась и как он работает в реальности 533 | - В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код 534 | -------------------------------------------------------------------------------- /README_EN.md: -------------------------------------------------------------------------------- 1 | This is an automatic translation, may be incorrect in some places. See sources and examples! 2 | 3 | # Stamp 4 | Library for storage and manipulation over time 5 | - more convenient to use than built -in Time.h 6 | - Faster transformation algorithms are used than in Time.h 7 | - keeps the date and time of 4 bytes of the variable (seconds from 01.01.2000) 8 | - transforms a year, month, day, hours, minutes, seconds, day of the week, day of the year 9 | - can count and maintain time on the basis of Millis () 10 | - Parsing of lines 11 | - works ~ until 2106 12 | 13 | ## compatibility 14 | Compatible with all arduino platforms (used arduino functions) 15 | 16 | ## Content 17 | - [documentation] (#reference) 18 | - [Example] (# Example) 19 | - [versions] (#varsions) 20 | - [installation] (# Install) 21 | - [bugs and feedback] (#fedback) 22 | 23 | 24 | 25 | ## Documentation 26 | ### Timezone 27 | `` `CPP 28 | VOID setstampzone (int Zone);// Install the global time zone in hours or minutes 29 | int Getstampzone ();// Get a global time zone 30 | `` ` 31 | 32 | ### Datime 33 | Saves date and time in separate variables: 34 | `` `CPP 35 | uint16_t year;// year 36 | uint8_t months;// month (1 .. 12) 37 | uint8_t day;// Day of the month (1 .. 28-31) 38 | Uint8_t Hour;// hour (0 .. 23) 39 | uint8_t minute;// minute (0 .. 59) 40 | uint8_t second;// second (0 .. 59) 41 | uint8_t Weekday;// Day of the week (1 Mon .. 7 Sun) ISO 8601 42 | uint16_t soarday;// Day of the year (1 .. 365-366) 43 | 44 | // The indicated ranges are true for all other functions of the library! 45 | `` ` 46 | 47 | `` `CPP 48 | // ============ Design =============== 49 | Datime; 50 | Datime (UNIX);// Unix Time 51 | Datime (year, month, day);// year, month, day 52 | Datime (Hour, Minute, Second);// hour, minute, second 53 | Datime (year, month, day, hor, minute, second); 54 | Datime (Consta Char* str);// Line of the type yyyy-mm-ddthh: mm: ss 55 | 56 | // ============= Installation ===================== 57 | VOID SET (UNIX);// Unix Time 58 | VOID SET (Year, Month, Day);// year, month, day 59 | VOID SET (Hour, Minute, Second);// hour, minute, second 60 | VOID SET (year, Month, Day, Hour, Minute, Second); 61 | 62 | // ============== Parsing ==================== 63 | Bool Parsedate (Consta Char* S);// from the line of the type yyyy-mm-dd 64 | Bool Parsetime (Consta Char* S);// from the line of the species hh: mm: ss 65 | Bool Parse (Const Char* S);// from the line of the type YYYY-MM-DD or hh: mm: ss or yyyy-mm-ddthh: mm: ss 66 | Bool Parsehttp (Consta Char* S);// from the line of species , dd yyyy hh: mm: ss 67 | 68 | // ============== EXPORT ======================== 69 | uint32_t toseconds ();// Bring time per second (excluding the date) 70 | uint32_t getunix ();// Bend into unix seconds 71 | 72 | // ============= In the line ====================== 73 | // Bring the date in the format "DD.mm.yyy" 74 | Char* DATETOChar (Char* BUF); 75 | String Datetostring (); 76 | 77 | // Bring the time in the format "hh: mm: ss" 78 | Char* Timetochar (Char* Buf); 79 | String Timetosting (); 80 | 81 | // Determine in DD.mm.yyyy hh: mm: ss, div - division 82 | Char* toChar (char* buf, char div = ''); 83 | String Tostring (Char Div = ''); 84 | 85 | // ============= add =================== 86 | VOID AddSeconds (Uint32_T S);// Add seconds 87 | VOID Addminutes (Uint32_T M);// Add minutes 88 | VOID Addhours (Uint32_T H);// Add a watch 89 | VOID Adddays (Uint32_T D);// Add days 90 | 91 | VOID NEXTSECOND ();// Next second 92 | VOID NEXTMINUTE ();// The next michicks (XX: XX: 00) 93 | VOID NEXTHOUR ();// Next hour (XX: 00: 00) 94 | VOID NEXTDAY ();// The next day (00:00:00) 95 | VOID NEXTMONTH ();// Next month (1st number 00:00:00) 96 | 97 | VOID updatedys ();// update Weekday and Yearday based on the current date (after manual change) 98 | 99 | // ============== Engorithm ====================== 100 | // The time transformation algorithm is set before connecting the library 101 | // for research and just so that it was 102 | #define unix_alg unix_alg_0 // ~ 402us and ~ 94b flash (avr) 103 | #define unix_alg unix_alg_1 // ~ 298us and ~ 138b flash (avr) 104 | #define unix_alg unix_alg_2 // ~ 216us and ~ 584b flash (avr) 105 | #define unix_alg unix_alg_3 // ~ 297us and ~ 178b flash (avr) 106 | #define unix_alg unix_alg_time_t // ~ 246us and ~ 842b flash (avr) 107 | `` ` 108 | 109 | > All time adds in Datime are performed directly, without converting in UNIX, i.e.Pretty fast. 110 | 111 | ### Stamp 112 | Keeps the date and time in one variable `uint32_t` - unix time 113 | 114 | `` `CPP 115 | // ============ Design =============== 116 | Stamp; 117 | Stamp (uint32_t unix);// from UNIX 118 | Stamp (Datime & DT);// from Datime 119 | Stamp (year, month, day);// year, month, day 120 | Stamp (Hour, Minute, Second);// hour, minute, second 121 | Stamp (const char* str);// from the line of the type YYYY-MM-DD or hh: mm: ss or yyyy-mm-ddthh: mm: ss 122 | Stamp (year, month, day, hor, minute, second); 123 | 124 | // =========== Institute ================= 125 | VOID SET (Datime & DT);// Install from Datime 126 | VOID SET (Year, Month, Day);// year, month, day 127 | VOID SET (Hour, Minute, Second);// hour, minute, second 128 | VOID SET (year, Month, Day, Hour, Minute, Second); 129 | 130 | Bool Parse (Const Char* S);// from the line of the type YYYY-MM-DD or hh: mm: ss or yyyy-mm-ddthh: mm: ss 131 | Bool Parsehttp (Consta Char* S);// from the line of species , dd yyyy hh: mm: ss 132 | 133 | // ============== EXPORT ======================== 134 | Datime Get ();// Export to Datime format 135 | Void Get (Datime & DT);// Export to the Datime type variable 136 | uint32_t toseconds ();// Get seconds 137 | uint32_t Tominutes ();// Get minutes 138 | uint32_t tohours ();// Get a clock 139 | uint32_t Todays ();// Get a day 140 | 141 | // ============= In a line ====================== 142 | // Bring the date in the format "DD.mm.yyy" 143 | Char* DATETOChar (Char* BUF); 144 | String Datetostring (); 145 | 146 | // Bring the time in the format "hh: mm: ss" 147 | Char* Timetochar (Char* Buf); 148 | String Timetosting (); 149 | 150 | // Determine in DD.mm.yyyy hh: mm: ss, div - division 151 | Char* toChar (char* buf, char div = ''); 152 | String Tostring (Char Div = ''); 153 | `` ` 154 | 155 | ### Stampticker 156 | The same `Stamp`, but saves the time on the basis of` millis () `after synchronization.Signaling once per second, you can connect the handler.It has a ticker, you need to call it in `look ()`. 157 | 158 | `` `CPP 159 | // Install the current unix, additionally milliseconds of synchronization 160 | Stampticker (uint32_t unix, uint16_t ms = 0); 161 | 162 | // Install the current unix, additionally milliseconds of synchronization 163 | VOID update (uint32_t unix, uint16_t ms = 0); 164 | 165 | VOID Attach (F);// Connect the function-processor of the operation (type VOID F ()) 166 | VOID Detach ();// Disconnect the function-cutter 167 | 168 | Bool Ready ();// Returns True every second 169 | Bool Synced ();// Time synchronized 170 | uint16_t ms ();// Get milliseconds of the current second 171 | uint32_t calcunix ();// Calculate and get the current unix 172 | 173 | // ticker, call in LOOP.Unix updates once a second.Will return True every second taking into account MS synchronization 174 | Bool Tick (); 175 | `` ` 176 | 177 | ### StampSync 178 | The same `Stamp`, but saves the time on the basis of` millis () `after synchronization.It works without a ticer. 179 | 180 | `` `CPP 181 | // Install the current unix, additionally milliseconds of synchronization 182 | StampSync (uint32_t unix, uint16_t ms = 0); 183 | 184 | // Install the current unix, additionally milliseconds of synchronization 185 | VOID update (uint32_t unix, uint16_t ms = 0); 186 | 187 | Bool Synced ();// Time synchronized 188 | uint32_t getunix ();// Get the current unix 189 | uint16_t ms ();// Get milliseconds of the current second 190 | `` `### utilities 191 | Set of functions for working with time and date 192 | 193 | `` `CPP 194 | // Time per second 195 | uint32_t Stamputils :: Timetoseconds (Uint8_t Hours, Uint8_t Minutes, Uint8_T Seconds); 196 | 197 | // leap year 198 | Bool Stamputils :: isleap (uint16_t year); 199 | 200 | // days in the month without accounting for the year (February 28) 201 | uint8_t Stamputils :: Daysinmonth (Uint8_t Month); 202 | 203 | // days in the month taking into account the leap year 204 | uint8_t Stamputils :: Daysinmonth (Uint8_t Month, Uint16_t Year); 205 | 206 | // Days of the year to the month (Jan 0, Feb 31, March 59/60 ...) 207 | uint16_t Stamputils :: Daystomonth (Uint8_t Month, Uint16_t Year); 208 | 209 | // Date on the day of the current year (starting with 1) 210 | uint16_t Stamputils :: DateToyearday (Uint8_t Day, Uint8_t Month, Uint16_t Year); 211 | 212 | // Date on the day of the week (PN 1 .. Sun 7) 213 | uint8_t Stamputils :: DateTeWeekday (Uint8_t Day, Uint8_t Month, Uint16_T Year); 214 | 215 | // Date in the number of days from 01.01.2000 (starting with 0) 216 | uint16_t Stamputils :: DateTodays2000 (Uint8_t Day, Uint8_t Month, Uint16_T Year); 217 | 218 | // Date in UNIX time, zone in minutes 219 | uint32_t Stamputils :: DateTouNix (Uint8_t Day, Uint8_t Month, Uint16_t Year, Uint8_t Hour, Uint8_t Minute, Uint8_T Seconds, Int16_T Zone = 0); 220 | 221 | `` ` 222 | 223 | 224 | 225 | ## Example 226 | `` `CPP 227 | Stamp S (2023, 5, 8, 16, 26, 0); 228 | Serial.println (S.Getunix ()); 229 | Serial.println (S.Tostring ()); 230 | 231 | Datime D = S.Get (); 232 | Serial.println (D.Year); 233 | Serial.println (D.MONTH); 234 | Serial.println (D.Day); 235 | 236 | D.YEAR = 2022;// changed the year 237 | S.Set (D);// updated Stamp 238 | Serial.println (S.Tostring ()); 239 | `` ` 240 | 241 | 242 | ## versions 243 | - V1.0 244 | - V1.1 - added many new tools and capabilities 245 | 246 | 247 | ## Installation 248 | - The library can be found by the name ** Stamp ** and installed through the library manager in: 249 | - Arduino ide 250 | - Arduino ide v2 251 | - Platformio 252 | - [download library] (https://github.com/gyverlibs/stamp/archive/refs/heads/main.zip). Zip archive for manual installation: 253 | - unpack and put in * C: \ Program Files (X86) \ Arduino \ Libraries * (Windows X64) 254 | - unpack and put in * C: \ Program Files \ Arduino \ Libraries * (Windows X32) 255 | - unpack and put in *documents/arduino/libraries/ * 256 | - (Arduino id) Automatic installation from. Zip: * sketch/connect the library/add .Zip library ... * and specify downloaded archive 257 | - Read more detailed instructions for installing libraries [here] (https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%BD%D0%BE%BE%BE%BED0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) 258 | ### Update 259 | - I recommend always updating the library: errors and bugs are corrected in the new versions, as well as optimization and new features are added 260 | - through the IDE library manager: find the library how to install and click "update" 261 | - Manually: ** remove the folder with the old version **, and then put a new one in its place.“Replacement” cannot be done: sometimes in new versions, files that remain when replacing are deleted and can lead to errors! 262 | 263 | 264 | ## bugs and feedback 265 | Create ** Issue ** when you find the bugs, and better immediately write to the mail [alex@alexgyver.ru] (mailto: alex@alexgyver.ru) 266 | The library is open for refinement and your ** pull Request ** 'ow! 267 | 268 | When reporting about bugs or incorrect work of the library, it is necessary to indicate: 269 | - The version of the library 270 | - What is MK used 271 | - SDK version (for ESP) 272 | - version of Arduino ide 273 | - whether the built -in examples work correctly, in which the functions and designs are used, leading to a bug in your code 274 | - what code has been loaded, what work was expected from it and how it works in reality 275 | - Ideally, attach the minimum code in which the bug is observed.Not a canvas of a thousand lines, but a minimum code -------------------------------------------------------------------------------- /examples/dayIndex/index.h: -------------------------------------------------------------------------------- 1 | int idx[] = { 2 | 0, // 01.01 3 | 1, // 02.01 4 | 2, // 03.01 5 | 3, // 04.01 6 | 4, // 05.01 7 | 5, // 06.01 8 | 6, // 07.01 9 | 7, // 08.01 10 | 8, // 09.01 11 | 9, // 10.01 12 | 10, // 11.01 13 | 11, // 12.01 14 | 12, // 13.01 15 | 13, // 14.01 16 | 14, // 15.01 17 | 15, // 16.01 18 | 16, // 17.01 19 | 17, // 18.01 20 | 18, // 19.01 21 | 19, // 20.01 22 | 20, // 21.01 23 | 21, // 22.01 24 | 22, // 23.01 25 | 23, // 24.01 26 | 24, // 25.01 27 | 25, // 26.01 28 | 26, // 27.01 29 | 27, // 28.01 30 | 28, // 29.01 31 | 29, // 30.01 32 | 30, // 31.01 33 | 31, // 01.02 34 | 32, // 02.02 35 | 33, // 03.02 36 | 34, // 04.02 37 | 35, // 05.02 38 | 36, // 06.02 39 | 37, // 07.02 40 | 38, // 08.02 41 | 39, // 09.02 42 | 40, // 10.02 43 | 41, // 11.02 44 | 42, // 12.02 45 | 43, // 13.02 46 | 44, // 14.02 47 | 45, // 15.02 48 | 46, // 16.02 49 | 47, // 17.02 50 | 48, // 18.02 51 | 49, // 19.02 52 | 50, // 20.02 53 | 51, // 21.02 54 | 52, // 22.02 55 | 53, // 23.02 56 | 54, // 24.02 57 | 55, // 25.02 58 | 56, // 26.02 59 | 57, // 27.02 60 | 58, // 28.02 61 | 59, // 29.02 62 | 60, // 01.03 63 | 61, // 02.03 64 | 62, // 03.03 65 | 63, // 04.03 66 | 64, // 05.03 67 | 65, // 06.03 68 | 66, // 07.03 69 | 67, // 08.03 70 | 68, // 09.03 71 | 69, // 10.03 72 | 70, // 11.03 73 | 71, // 12.03 74 | 72, // 13.03 75 | 73, // 14.03 76 | 74, // 15.03 77 | 75, // 16.03 78 | 76, // 17.03 79 | 77, // 18.03 80 | 78, // 19.03 81 | 79, // 20.03 82 | 80, // 21.03 83 | 81, // 22.03 84 | 82, // 23.03 85 | 83, // 24.03 86 | 84, // 25.03 87 | 85, // 26.03 88 | 86, // 27.03 89 | 87, // 28.03 90 | 88, // 29.03 91 | 89, // 30.03 92 | 90, // 31.03 93 | 91, // 01.04 94 | 92, // 02.04 95 | 93, // 03.04 96 | 94, // 04.04 97 | 95, // 05.04 98 | 96, // 06.04 99 | 97, // 07.04 100 | 98, // 08.04 101 | 99, // 09.04 102 | 100, // 10.04 103 | 101, // 11.04 104 | 102, // 12.04 105 | 103, // 13.04 106 | 104, // 14.04 107 | 105, // 15.04 108 | 106, // 16.04 109 | 107, // 17.04 110 | 108, // 18.04 111 | 109, // 19.04 112 | 110, // 20.04 113 | 111, // 21.04 114 | 112, // 22.04 115 | 113, // 23.04 116 | 114, // 24.04 117 | 115, // 25.04 118 | 116, // 26.04 119 | 117, // 27.04 120 | 118, // 28.04 121 | 119, // 29.04 122 | 120, // 30.04 123 | 121, // 01.05 124 | 122, // 02.05 125 | 123, // 03.05 126 | 124, // 04.05 127 | 125, // 05.05 128 | 126, // 06.05 129 | 127, // 07.05 130 | 128, // 08.05 131 | 129, // 09.05 132 | 130, // 10.05 133 | 131, // 11.05 134 | 132, // 12.05 135 | 133, // 13.05 136 | 134, // 14.05 137 | 135, // 15.05 138 | 136, // 16.05 139 | 137, // 17.05 140 | 138, // 18.05 141 | 139, // 19.05 142 | 140, // 20.05 143 | 141, // 21.05 144 | 142, // 22.05 145 | 143, // 23.05 146 | 144, // 24.05 147 | 145, // 25.05 148 | 146, // 26.05 149 | 147, // 27.05 150 | 148, // 28.05 151 | 149, // 29.05 152 | 150, // 30.05 153 | 151, // 31.05 154 | 152, // 01.06 155 | 153, // 02.06 156 | 154, // 03.06 157 | 155, // 04.06 158 | 156, // 05.06 159 | 157, // 06.06 160 | 158, // 07.06 161 | 159, // 08.06 162 | 160, // 09.06 163 | 161, // 10.06 164 | 162, // 11.06 165 | 163, // 12.06 166 | 164, // 13.06 167 | 165, // 14.06 168 | 166, // 15.06 169 | 167, // 16.06 170 | 168, // 17.06 171 | 169, // 18.06 172 | 170, // 19.06 173 | 171, // 20.06 174 | 172, // 21.06 175 | 173, // 22.06 176 | 174, // 23.06 177 | 175, // 24.06 178 | 176, // 25.06 179 | 177, // 26.06 180 | 178, // 27.06 181 | 179, // 28.06 182 | 180, // 29.06 183 | 181, // 30.06 184 | 182, // 01.07 185 | 183, // 02.07 186 | 184, // 03.07 187 | 185, // 04.07 188 | 186, // 05.07 189 | 187, // 06.07 190 | 188, // 07.07 191 | 189, // 08.07 192 | 190, // 09.07 193 | 191, // 10.07 194 | 192, // 11.07 195 | 193, // 12.07 196 | 194, // 13.07 197 | 195, // 14.07 198 | 196, // 15.07 199 | 197, // 16.07 200 | 198, // 17.07 201 | 199, // 18.07 202 | 200, // 19.07 203 | 201, // 20.07 204 | 202, // 21.07 205 | 203, // 22.07 206 | 204, // 23.07 207 | 205, // 24.07 208 | 206, // 25.07 209 | 207, // 26.07 210 | 208, // 27.07 211 | 209, // 28.07 212 | 210, // 29.07 213 | 211, // 30.07 214 | 212, // 31.07 215 | 213, // 01.08 216 | 214, // 02.08 217 | 215, // 03.08 218 | 216, // 04.08 219 | 217, // 05.08 220 | 218, // 06.08 221 | 219, // 07.08 222 | 220, // 08.08 223 | 221, // 09.08 224 | 222, // 10.08 225 | 223, // 11.08 226 | 224, // 12.08 227 | 225, // 13.08 228 | 226, // 14.08 229 | 227, // 15.08 230 | 228, // 16.08 231 | 229, // 17.08 232 | 230, // 18.08 233 | 231, // 19.08 234 | 232, // 20.08 235 | 233, // 21.08 236 | 234, // 22.08 237 | 235, // 23.08 238 | 236, // 24.08 239 | 237, // 25.08 240 | 238, // 26.08 241 | 239, // 27.08 242 | 240, // 28.08 243 | 241, // 29.08 244 | 242, // 30.08 245 | 243, // 31.08 246 | 244, // 01.09 247 | 245, // 02.09 248 | 246, // 03.09 249 | 247, // 04.09 250 | 248, // 05.09 251 | 249, // 06.09 252 | 250, // 07.09 253 | 251, // 08.09 254 | 252, // 09.09 255 | 253, // 10.09 256 | 254, // 11.09 257 | 255, // 12.09 258 | 256, // 13.09 259 | 257, // 14.09 260 | 258, // 15.09 261 | 259, // 16.09 262 | 260, // 17.09 263 | 261, // 18.09 264 | 262, // 19.09 265 | 263, // 20.09 266 | 264, // 21.09 267 | 265, // 22.09 268 | 266, // 23.09 269 | 267, // 24.09 270 | 268, // 25.09 271 | 269, // 26.09 272 | 270, // 27.09 273 | 271, // 28.09 274 | 272, // 29.09 275 | 273, // 30.09 276 | 274, // 01.10 277 | 275, // 02.10 278 | 276, // 03.10 279 | 277, // 04.10 280 | 278, // 05.10 281 | 279, // 06.10 282 | 280, // 07.10 283 | 281, // 08.10 284 | 282, // 09.10 285 | 283, // 10.10 286 | 284, // 11.10 287 | 285, // 12.10 288 | 286, // 13.10 289 | 287, // 14.10 290 | 288, // 15.10 291 | 289, // 16.10 292 | 290, // 17.10 293 | 291, // 18.10 294 | 292, // 19.10 295 | 293, // 20.10 296 | 294, // 21.10 297 | 295, // 22.10 298 | 296, // 23.10 299 | 297, // 24.10 300 | 298, // 25.10 301 | 299, // 26.10 302 | 300, // 27.10 303 | 301, // 28.10 304 | 302, // 29.10 305 | 303, // 30.10 306 | 304, // 31.10 307 | 305, // 01.11 308 | 306, // 02.11 309 | 307, // 03.11 310 | 308, // 04.11 311 | 309, // 05.11 312 | 310, // 06.11 313 | 311, // 07.11 314 | 312, // 08.11 315 | 313, // 09.11 316 | 314, // 10.11 317 | 315, // 11.11 318 | 316, // 12.11 319 | 317, // 13.11 320 | 318, // 14.11 321 | 319, // 15.11 322 | 320, // 16.11 323 | 321, // 17.11 324 | 322, // 18.11 325 | 323, // 19.11 326 | 324, // 20.11 327 | 325, // 21.11 328 | 326, // 22.11 329 | 327, // 23.11 330 | 328, // 24.11 331 | 329, // 25.11 332 | 330, // 26.11 333 | 331, // 27.11 334 | 332, // 28.11 335 | 333, // 29.11 336 | 334, // 30.11 337 | 335, // 01.12 338 | 336, // 02.12 339 | 337, // 03.12 340 | 338, // 04.12 341 | 339, // 05.12 342 | 340, // 06.12 343 | 341, // 07.12 344 | 342, // 08.12 345 | 343, // 09.12 346 | 344, // 10.12 347 | 345, // 11.12 348 | 346, // 12.12 349 | 347, // 13.12 350 | 348, // 14.12 351 | 349, // 15.12 352 | 350, // 16.12 353 | 351, // 17.12 354 | 352, // 18.12 355 | 353, // 19.12 356 | 354, // 20.12 357 | 355, // 21.12 358 | 356, // 22.12 359 | 357, // 23.12 360 | 358, // 24.12 361 | 359, // 25.12 362 | 360, // 26.12 363 | 361, // 27.12 364 | 362, // 28.12 365 | 363, // 29.12 366 | 364, // 30.12 367 | 365, // 31.12 368 | }; -------------------------------------------------------------------------------- /examples/demo/demo.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void setup() { 5 | Serial.begin(115200); 6 | 7 | Stamp s(2023, 5, 8, 16, 26, 0); 8 | Serial.println(s.toString()); 9 | 10 | Datime d = s.now(); 11 | Serial.println(d.year); 12 | Serial.println(d.month); 13 | Serial.println(d.day); 14 | 15 | d.year = 2022; // изменили год 16 | s.set(d); // обновили Stamp 17 | Serial.println(s.toString()); 18 | } 19 | void loop() { 20 | } -------------------------------------------------------------------------------- /examples/keeper/keeper.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | StampKeeper rtc; // GyverNTP, GyverDS3231, Settings.rtc 5 | 6 | void setup() { 7 | Serial.begin(115200); 8 | 9 | // часовой пояс, установить до всех действий с объектами 10 | setStampZone(3); 11 | 12 | // обработчик секунды (вызывается из тикера) 13 | rtc.onSecond([]() { 14 | Serial.println("new second!"); 15 | }); 16 | 17 | // обработчик синхронизации (вызывается из sync) 18 | rtc.onSync([](uint32_t unix) { 19 | Serial.println("sync: "); 20 | Serial.print(unix); 21 | }); 22 | 23 | // синхронизация вручную для примера 24 | // rtc.sync(1738237474); 25 | } 26 | void loop() { 27 | // тикер вернёт true каждую секунду в 0 мс секунды, если время синхронизировано 28 | if (rtc.tick()) { 29 | // вывод даты и времени строкой 30 | Serial.print(rtc.toString()); // rtc.timeToString(), rtc.dateToString() 31 | Serial.print(':'); 32 | Serial.println(rtc.ms()); // + миллисекунды текущей секунды. Внутри tick всегда равно 0 33 | 34 | // вывод в Datime 35 | Datime dt = rtc; // или Datime dt(rtc) 36 | dt.year; 37 | dt.second; 38 | dt.hour; 39 | dt.weekDay; 40 | dt.yearDay; 41 | // ... и прочие методы и переменные Datime 42 | 43 | // чтение напрямую, медленнее чем вывод в Datime 44 | rtc.second(); 45 | rtc.minute(); 46 | rtc.year(); 47 | // ... и прочие методы StampConvert 48 | 49 | // сравнение 50 | rtc == DaySeconds(12, 35, 0); // сравнение с DaySeconds (время равно 12:35:00) 51 | rtc == 1738237474; // сравнение с unix 52 | rtc == Datime(2025, 1, 30, 14, 14, 30); // сравнение с Datime 53 | } 54 | 55 | if (rtc.newSecond()) { 56 | // новую секунду можно поймать и здесь 57 | } 58 | } -------------------------------------------------------------------------------- /examples/test/test.ino: -------------------------------------------------------------------------------- 1 | #include 2 | // сравнение с time.h 3 | 4 | #include 5 | #include 6 | 7 | void print_t(tm& t) { 8 | Serial.println(String() + (t.tm_year + 1900) + '.' + (t.tm_mon + 1) + '.' + (t.tm_mday) + ' ' + (t.tm_hour) + ':' + (t.tm_min) + ':' + (t.tm_sec)); 9 | } 10 | void print_dt(Datime& t) { 11 | Serial.println(String() + (t.year) + '.' + (t.month) + '.' + (t.day) + ' ' + (t.hour) + ':' + (t.minute) + ':' + (t.second)); 12 | } 13 | 14 | void setup() { 15 | Serial.begin(115200); 16 | // unix to date test 17 | for (uint32_t i = 0; i < 365 * 100ul; i++) { 18 | uint32_t unix = 946684800 + 86400ul * i + random(86400); 19 | time_t t = unix - 946684800; 20 | tm tt; 21 | gmtime_r(&t, &tt); 22 | 23 | Stamp dt(unix); 24 | Datime dt_s = dt.get(); 25 | 26 | if (dt_s.year != (tt.tm_year + 1900) || 27 | dt_s.month != (tt.tm_mon + 1) || 28 | dt_s.day != (tt.tm_mday) || 29 | dt_s.hour != (tt.tm_hour) || 30 | dt_s.minute != (tt.tm_min) || 31 | dt_s.second != (tt.tm_sec)) { 32 | Serial.println(); 33 | Serial.println(dt.toString()); 34 | print_t(tt); 35 | } 36 | } 37 | 38 | // date to unix test 39 | for (uint32_t i = 0; i < 365 * 100ul; i++) { 40 | uint32_t unix = 946684800 + 86400ul * i + random(86400); 41 | time_t t = unix - 946684800; 42 | tm tt; 43 | gmtime_r(&t, &tt); 44 | 45 | Datime dt_s(tt.tm_year + 1900, tt.tm_mon + 1, tt.tm_mday, tt.tm_hour, tt.tm_min, tt.tm_sec); 46 | Stamp dt(dt_s); 47 | 48 | if (dt.unix != unix) { 49 | Serial.println(); 50 | Serial.println(dt.toString()); 51 | print_t(tt); 52 | } 53 | } 54 | 55 | Serial.println("test end"); 56 | } 57 | 58 | void loop() { 59 | } -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Stamp 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | Stamp KEYWORD1 10 | Datime KEYWORD1 11 | StampKeeper KEYWORD1 12 | StampUtils KEYWORD1 13 | DaySeconds KEYWORD1 14 | STAMP_ALG KEYWORD1 15 | 16 | ####################################### 17 | # Methods and Functions (KEYWORD2) 18 | ####################################### 19 | 20 | getStampZone KEYWORD2 21 | setStampZone KEYWORD2 22 | 23 | timeToSeconds KEYWORD2 24 | isLeap KEYWORD2 25 | daysInMonth KEYWORD2 26 | daysToMonth KEYWORD2 27 | dateToYearDay KEYWORD2 28 | dateToWeekDay KEYWORD2 29 | dateToDays2000 KEYWORD2 30 | dateToUnix KEYWORD2 31 | 32 | year KEYWORD2 33 | month KEYWORD2 34 | day KEYWORD2 35 | hour KEYWORD2 36 | minute KEYWORD2 37 | second KEYWORD2 38 | weekDay KEYWORD2 39 | yearDay KEYWORD2 40 | set KEYWORD2 41 | daySeconds KEYWORD2 42 | toSeconds KEYWORD2 43 | getUnix KEYWORD2 44 | dateToChar KEYWORD2 45 | dateToString KEYWORD2 46 | timeToChar KEYWORD2 47 | timeToString KEYWORD2 48 | toChar KEYWORD2 49 | toString KEYWORD2 50 | parseDate KEYWORD2 51 | parseTime KEYWORD2 52 | parse KEYWORD2 53 | parseHTTP KEYWORD2 54 | addSeconds KEYWORD2 55 | addMinutes KEYWORD2 56 | addHours KEYWORD2 57 | addDays KEYWORD2 58 | nextSecond KEYWORD2 59 | nextMinute KEYWORD2 60 | nextHour KEYWORD2 61 | nextDay KEYWORD2 62 | nextMonth KEYWORD2 63 | updateDays KEYWORD2 64 | dayIndex KEYWORD2 65 | 66 | get KEYWORD2 67 | ms KEYWORD2 68 | synced KEYWORD2 69 | update KEYWORD2 70 | attach KEYWORD2 71 | detach KEYWORD2 72 | tick KEYWORD2 73 | ready KEYWORD2 74 | calcUnix KEYWORD2 75 | skipTicks KEYWORD2 76 | onSecond KEYWORD2 77 | onSync KEYWORD2 78 | 79 | ####################################### 80 | # Constants (LITERAL1) 81 | ####################################### 82 | 83 | UNIX_ALG_0 LITERAL1 84 | UNIX_ALG_1 LITERAL1 85 | UNIX_ALG_2 LITERAL1 86 | UNIX_ALG_3 LITERAL1 87 | UNIX_ALG_TIME_T LITERAL1 -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Stamp 2 | version=1.4.2 3 | author=AlexGyver 4 | maintainer=AlexGyver 5 | sentence=Library for time keeping and manipulation 6 | paragraph=Library for time keeping and manipulation 7 | category=Timing 8 | url=https://github.com/GyverLibs/Stamp 9 | architectures=* -------------------------------------------------------------------------------- /src/Datime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "./core/StampUtils.h" 5 | #include "./core/stamp_zone.h" 6 | #include "DaySeconds.h" 7 | 8 | #define UNIX_ALG_0 0 // ~402us / ~94B Flash (AVR) 9 | #define UNIX_ALG_1 1 // ~298us / ~138B Flash (AVR) 10 | #define UNIX_ALG_2 2 // ~216us / ~584B Flash (AVR) 11 | #define UNIX_ALG_3 3 // ~297us / ~178B Flash (AVR) 12 | #define UNIX_ALG_TIME_T 4 // ~246us / ~842B Flash (AVR) 13 | 14 | #ifndef UNIX_ALG 15 | #define _UNIX_ALG UNIX_ALG_3 16 | #endif 17 | 18 | #if _UNIX_ALG == UNIX_ALG_TIME_T 19 | #include 20 | #endif 21 | 22 | class Datime { 23 | public: 24 | // год 25 | uint16_t year = 2000; 26 | 27 | // месяц (1.. 12) 28 | uint8_t month = 1; 29 | 30 | // день месяца (1.. 28-31) 31 | uint8_t day = 1; 32 | 33 | // час (0.. 23) 34 | uint8_t hour = 0; 35 | 36 | // минута (0.. 59) 37 | uint8_t minute = 0; 38 | 39 | // секунда (0.. 59) 40 | uint8_t second = 0; 41 | 42 | // день недели (1 пн.. 7 вс) 43 | uint8_t weekDay = 1; 44 | 45 | // день года (1.. 365-366) 46 | uint16_t yearDay = 1; 47 | 48 | // ========= CONSTRUCTOR ========= 49 | Datime() {} 50 | // Datime(const Datime& dat) = default; 51 | Datime(const char* str) { 52 | parse(str); 53 | } 54 | Datime(uint32_t unix) { 55 | set(unix); 56 | } 57 | Datime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { 58 | set(year, month, day, hour, minute, second); 59 | } 60 | Datime(uint16_t yh, uint16_t mm, uint16_t ds) { 61 | set(yh, mm, ds); 62 | } 63 | 64 | // Datime& operator=(uint32_t unix) { 65 | // set(unix); 66 | // return *this; 67 | // } 68 | 69 | // ============= SET ============= 70 | // установить время (год, месяц, день, час, минута, секунда) 71 | void set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { 72 | Datime::year = year; 73 | Datime::month = month; 74 | Datime::day = day; 75 | Datime::hour = hour; 76 | Datime::minute = minute; 77 | Datime::second = second; 78 | updateDays(); 79 | } 80 | 81 | // установить время (год, месяц, день) или (час, минута, секунда) 82 | void set(uint16_t yh, uint16_t mm, uint16_t ds) { 83 | if (yh >= 24) { 84 | year = yh; 85 | month = mm; 86 | day = ds; 87 | } else { 88 | hour = yh; 89 | minute = mm; 90 | second = ds; 91 | } 92 | updateDays(); 93 | } 94 | 95 | // установить из unix времени и глобального часового пояса setStampZone 96 | void set(uint32_t unix) { 97 | if (!unix) return; 98 | unix += getStampZone() * 60l; 99 | 100 | #if _UNIX_ALG == UNIX_ALG_0 101 | Datime::second = unix % 60ul; 102 | unix /= 60ul; 103 | Datime::minute = unix % 60ul; 104 | unix /= 60ul; 105 | Datime::hour = unix % 24ul; 106 | unix /= 24ul; 107 | Datime::weekDay = (unix + 3) % 7 + 1; 108 | uint32_t z = unix + 719468; 109 | uint8_t era = z / 146097ul; 110 | uint16_t doe = z - era * 146097ul; 111 | uint16_t yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; 112 | uint16_t y = yoe + era * 400; 113 | uint16_t doy = doe - (yoe * 365 + yoe / 4 - yoe / 100); 114 | uint16_t mp = (doy * 5 + 2) / 153; 115 | Datime::day = doy - (mp * 153 + 2) / 5 + 1; 116 | Datime::month = mp + (mp < 10 ? 3 : -9); 117 | y += (Datime::month <= 2); 118 | Datime::year = y; 119 | Datime::yearDay = StampUtils::dateToYearDay(Datime::day, Datime::month, Datime::year); 120 | 121 | #elif _UNIX_ALG == UNIX_ALG_1 122 | int32_t days, rem; 123 | int years400, years100, years4, remainingyears; 124 | 125 | days = unix / 86400ul - 11017; 126 | rem = unix % 86400ul; 127 | if (rem < 0) { 128 | rem += 86400ul; 129 | days--; 130 | } 131 | 132 | Datime::hour = rem / 3600ul; 133 | rem %= 3600ul; 134 | Datime::minute = rem / 60ul; 135 | Datime::second = rem % 60ul; 136 | 137 | if ((Datime::weekDay = ((3 + days) % 7)) < 0) Datime::weekDay += 7; 138 | if (!Datime::weekDay) Datime::weekDay = 7; 139 | 140 | years400 = days / 146097L; 141 | days -= years400 * 146097L; 142 | if (days < 0) { 143 | days += 146097L; 144 | years400--; 145 | } 146 | 147 | years100 = days / 36524L; 148 | if (years100 == 4) years100--; 149 | days -= years100 * 36524L; 150 | years4 = days / 1461L; 151 | days -= years4 * 1461L; 152 | remainingyears = days / 365L; 153 | if (remainingyears == 4) remainingyears--; 154 | days -= remainingyears * 365L; 155 | Datime::year = 2000 + years400 * 400 + years100 * 100 + years4 * 4 + remainingyears; 156 | bool yearleap = remainingyears == 0 && (years4 != 0 || years100 == 0); 157 | 158 | Datime::yearDay = days + 31 + 28 + yearleap; 159 | if (Datime::yearDay >= 365u + yearleap) { 160 | Datime::yearDay -= 365u + yearleap; 161 | Datime::year++; 162 | } 163 | Datime::yearDay++; 164 | 165 | Datime::month = 2; 166 | while (1) { 167 | uint8_t dm = StampUtils::daysInMonth(Datime::month + 1); // from 0. Feb 28 here 168 | if (Datime::month == 1) dm++; // 1 Feb 169 | if (days < dm) break; 170 | days -= dm; 171 | if (++Datime::month >= 12) Datime::month = 0; 172 | } 173 | Datime::month++; 174 | Datime::day = days + 1; 175 | 176 | #elif _UNIX_ALG == UNIX_ALG_2 177 | int32_t fract; 178 | uint16_t days, n, leapyear, years; 179 | ldiv_t lresult; 180 | div_t result; 181 | if (unix < 946684800) unix = 946684800; 182 | 183 | unix -= 946684800; // to 2000-01-01 UTC 184 | days = unix / 86400UL; // 38753+ 185 | fract = unix - days * 86400UL; // 86400 186 | 187 | lresult = ldiv(fract, 60L); // 86400 188 | Datime::second = lresult.rem; 189 | result = div((int)lresult.quot, 60); // 1440 190 | Datime::minute = result.rem; 191 | Datime::hour = result.quot; 192 | 193 | n = days + 6; 194 | n %= 7; 195 | Datime::weekDay = n; 196 | if (!Datime::weekDay) Datime::weekDay = 7; 197 | 198 | lresult = ldiv((long)days, 36525L); // 38753+ 199 | years = 100 * lresult.quot; 200 | lresult = ldiv(lresult.rem, 1461L); // 36525 201 | years += 4 * lresult.quot; 202 | days = lresult.rem; // <- 1461 203 | if (years > 100) days++; 204 | 205 | leapyear = 1; 206 | if (years == 100) leapyear = 0; 207 | n = 364 + leapyear; 208 | 209 | if (days > n) { 210 | days -= leapyear; 211 | leapyear = 0; 212 | result = div(days, 365); // 1461 213 | years += result.quot; 214 | days = result.rem; // <- 365 215 | } 216 | Datime::year = 100 + years + 1900; 217 | Datime::yearDay = days + 1; 218 | 219 | n = 59 + leapyear; 220 | if (days < n) { 221 | result = div(days, 31); // 1461 222 | Datime::month = result.quot; 223 | Datime::day = result.rem; 224 | } else { 225 | days -= n; 226 | result = div(days, 153); // 1461 227 | Datime::month = 2 + result.quot * 5; 228 | result = div(result.rem, 61); // 153 229 | Datime::month += result.quot * 2; 230 | result = div(result.rem, 31); // 61 231 | Datime::month += result.quot; 232 | Datime::day = result.rem; 233 | } 234 | 235 | Datime::day++; 236 | Datime::month++; 237 | 238 | #elif _UNIX_ALG == UNIX_ALG_3 239 | unix -= 946684800; 240 | Datime::second = unix % 60ul; 241 | unix /= 60ul; 242 | Datime::minute = unix % 60ul; 243 | unix /= 60ul; 244 | Datime::hour = unix % 24ul; 245 | 246 | uint16_t days = unix / 24ul; 247 | Datime::weekDay = (days + 5) % 7 + 1; 248 | 249 | bool leap = 0; 250 | for (Datime::year = 0;; Datime::year++) { 251 | leap = !(Datime::year & 3); 252 | if (days < 365u + leap) break; 253 | days -= 365u + leap; 254 | } 255 | Datime::year += 2000; 256 | Datime::yearDay = days + 1; 257 | 258 | for (Datime::month = 1; Datime::month < 12; Datime::month++) { 259 | uint8_t dm = StampUtils::daysInMonth(Datime::month); 260 | if (leap && Datime::month == 2) dm++; 261 | if (days < dm) break; 262 | days -= dm; 263 | } 264 | Datime::day = days + 1; 265 | 266 | #elif _UNIX_ALG == UNIX_ALG_TIME_T 267 | time_t t = unix - 946684800; 268 | tm tt; 269 | gmtime_r(&t, &tt); 270 | Datime::year = tt.tm_year + 1900; 271 | Datime::month = tt.tm_mon + 1; 272 | Datime::day = tt.tm_mday; 273 | Datime::hour = tt.tm_hour; 274 | Datime::minute = tt.tm_min; 275 | Datime::second = tt.tm_sec; 276 | Datime::weekDay = tt.tm_wday; 277 | if (!Datime::weekDay) Datime::weekDay = 7; 278 | Datime::yearDay = tt.tm_yday + 1; 279 | #endif 280 | } 281 | 282 | // =========== EXPORT ============ 283 | // вывести в секунды с начала текущих суток 284 | uint32_t daySeconds() const { 285 | uint32_t sec = second; 286 | if (minute) sec += minute * 60; 287 | if (hour) sec += hour * 3600ul; 288 | return sec; 289 | } 290 | 291 | // вывести в unix-секунды 292 | uint32_t getUnix() const { 293 | return StampUtils::dateToUnix(day, month, year, hour, minute, second, getStampZone()); 294 | } 295 | 296 | // ========== TO STRING ========== 297 | // вывести дату в формате "dd.mm.yyyy" [11]. Вернёт указатель на конец строки 298 | char* dateToChar(char* buf) const { 299 | _btoa(day, buf + 0); 300 | buf[2] = '.'; 301 | _btoa(month, buf + 3); 302 | buf[5] = '.'; 303 | itoa(min(year, (uint16_t)9999), buf + 6, DEC); 304 | return buf + 10; 305 | } 306 | 307 | // вывести дату в формате "dd.mm.yyyy" 308 | String dateToString() const { 309 | char buf[11]; 310 | dateToChar(buf); 311 | return buf; 312 | } 313 | 314 | // вывести время в формате "hh:mm:ss" [9]. Вернёт указатель на конец строки 315 | char* timeToChar(char* buf) const { 316 | _btoa(hour, buf + 0); 317 | buf[2] = ':'; 318 | _btoa(minute, buf + 3); 319 | buf[5] = ':'; 320 | _btoa(second, buf + 6); 321 | buf[8] = 0; 322 | return buf + 8; 323 | } 324 | 325 | // вывести время в формате "hh:mm:ss" 326 | String timeToString() const { 327 | char buf[9]; 328 | timeToChar(buf); 329 | return buf; 330 | } 331 | 332 | // вывести в формате "dd.mm.yyyy hh:mm:ss" [20]. Вернёт указатель на конец строки 333 | char* toChar(char* buf, char div = ' ') const { 334 | dateToChar(buf); 335 | buf[10] = div; 336 | timeToChar(buf + 11); 337 | return buf + 19; 338 | } 339 | 340 | // вывести в формате "dd.mm.yyyy hh:mm:ss" 341 | String toString(char div = ' ') const { 342 | char buf[20]; 343 | toChar(buf, div); 344 | return buf; 345 | } 346 | 347 | // ========== PARSE ========== 348 | // yyyy-mm-dd 349 | bool parseDate(const char* s) { 350 | if (strlen(s) < 10) return 0; 351 | year = atoi(s); 352 | s = strchr(s, '-'); 353 | if (!s) return 0; 354 | month = atoi(++s); 355 | s = strchr(s, '-'); 356 | if (!s) return 0; 357 | day = atoi(++s); 358 | return 1; 359 | } 360 | 361 | // hh:mm:ss 362 | bool parseTime(const char* s) { 363 | if (strlen(s) < 8) return 0; 364 | hour = atoi(s); 365 | s = strchr(s, ':'); 366 | if (!s) return 0; 367 | minute = atoi(++s); 368 | s = strchr(s, ':'); 369 | if (!s) return 0; 370 | second = atoi(++s); 371 | return 1; 372 | } 373 | 374 | // hh:mm:ss или yyyy-mm-dd или yyyy-mm-ddThh:mm:ss 375 | bool parse(const char* s) { 376 | uint16_t len = strlen(s); 377 | if (len == 19 && s[10] == 'T') { // dateTtime 378 | if (!parseDate(s)) return 0; 379 | if (!parseTime(s + 11)) return 0; 380 | } else if (len == 10) { // date 381 | if (!parseDate(s)) return 0; 382 | } else if (len == 8) { // time 383 | if (!parseTime(s)) return 0; 384 | } else { 385 | return 0; 386 | } 387 | return 1; 388 | } 389 | 390 | // , dd yyyy hh:mm:ss 391 | bool parseHTTP(const char* s) { 392 | char* comma = strchr(s, ','); 393 | if (!comma) return 0; 394 | 395 | s = comma + 2; 396 | day = atoi(s); 397 | month = 0; 398 | switch (s[3]) { 399 | case 'J': month = (s[4] == 'a') ? 1 : ((s[5] == 'n') ? 6 : 7); break; 400 | case 'F': month = 2; break; 401 | case 'A': month = (s[5] == 'r') ? 4 : 8; break; 402 | case 'M': month = (s[5] == 'r') ? 3 : 5; break; 403 | case 'S': month = 9; break; 404 | case 'O': month = 10; break; 405 | case 'N': month = 11; break; 406 | case 'D': month = 12; break; 407 | default: return 0; 408 | } 409 | year = atoi(s + 7); 410 | hour = atoi(s + 12); 411 | minute = atoi(s + 15); 412 | second = atoi(s + 18); 413 | return 1; 414 | } 415 | 416 | // =========== COMPARE =========== 417 | bool operator==(const Datime& dt) { 418 | return getUnix() == dt.getUnix(); 419 | } 420 | bool operator!=(const Datime& dt) { 421 | return getUnix() != dt.getUnix(); 422 | } 423 | bool operator>(const Datime& dt) { 424 | return getUnix() > dt.getUnix(); 425 | } 426 | bool operator>=(const Datime& dt) { 427 | return getUnix() >= dt.getUnix(); 428 | } 429 | bool operator<(const Datime& dt) { 430 | return getUnix() < dt.getUnix(); 431 | } 432 | bool operator<=(const Datime& dt) { 433 | return getUnix() <= dt.getUnix(); 434 | } 435 | 436 | bool operator==(uint32_t u) { 437 | return getUnix() == u; 438 | } 439 | bool operator!=(uint32_t u) { 440 | return getUnix() != u; 441 | } 442 | bool operator>(uint32_t u) { 443 | return getUnix() > u; 444 | } 445 | bool operator>=(uint32_t u) { 446 | return getUnix() >= u; 447 | } 448 | bool operator<(uint32_t u) { 449 | return getUnix() < u; 450 | } 451 | bool operator<=(uint32_t u) { 452 | return getUnix() <= u; 453 | } 454 | 455 | bool operator==(const DaySeconds& ds) const { 456 | return daySeconds() == ds.seconds; 457 | } 458 | bool operator!=(const DaySeconds& ds) const { 459 | return daySeconds() != ds.seconds; 460 | } 461 | bool operator>(const DaySeconds& ds) const { 462 | return daySeconds() > ds.seconds; 463 | } 464 | bool operator>=(const DaySeconds& ds) const { 465 | return daySeconds() >= ds.seconds; 466 | } 467 | bool operator<(const DaySeconds& ds) const { 468 | return daySeconds() < ds.seconds; 469 | } 470 | bool operator<=(const DaySeconds& ds) const { 471 | return daySeconds() <= ds.seconds; 472 | } 473 | 474 | // одинаковое время 475 | bool equals(const Datime& dt) const { 476 | return !memcmp(&dt, this, sizeof(Datime)); 477 | } 478 | 479 | // високосный ли год 480 | bool isLeap() const { 481 | return StampUtils::isLeap(year); 482 | } 483 | 484 | // дата и время корректны 485 | bool valid() const { 486 | return (year >= 2000) && (month >= 1 && month <= 12) && (day >= 1 && day <= 31) && (hour <= 23) && (minute <= 59) && (second <= 59); 487 | } 488 | 489 | // дата 01.01.2000 490 | bool isY2K() const { 491 | return year == 2000 && month == 1 && day == 1; 492 | } 493 | 494 | // день года как индекс массива от 0 до 365 независимо от високосного года. 29 февраля имеет индекс 59 495 | uint16_t dayIndex() const { 496 | return ((yearDay >= 60) ? (isLeap() ? yearDay : yearDay + 1) : yearDay) - 1; 497 | } 498 | 499 | // ============= ADD ============= 500 | // добавить секунды 501 | void addSeconds(uint32_t s) { 502 | if (!s) return; 503 | if (s == 1) { 504 | second++; 505 | _update(); 506 | } else { 507 | s += second; 508 | ldiv_t res; 509 | res = ldiv(s, 60L); 510 | second = res.rem; 511 | addMinutes(res.quot); 512 | } 513 | } 514 | 515 | // добавить минуты 516 | void addMinutes(uint32_t m) { 517 | if (!m) return; 518 | if (m == 1) { 519 | minute++; 520 | _update(); 521 | } else { 522 | m += minute; 523 | ldiv_t res; 524 | res = ldiv(m, 60L); 525 | minute = res.rem; 526 | addHours(res.quot); 527 | } 528 | } 529 | 530 | // добавить часы 531 | void addHours(uint32_t h) { 532 | if (!h) return; 533 | if (h == 1) { 534 | hour++; 535 | _update(); 536 | } else { 537 | h += hour; 538 | ldiv_t res; 539 | res = ldiv(h, 24L); 540 | hour = res.rem; 541 | addDays(res.quot); 542 | } 543 | } 544 | 545 | // добавить дни 546 | void addDays(uint32_t d) { 547 | while (d) { 548 | d--; 549 | day++; 550 | weekDay++; 551 | yearDay++; 552 | _update(); 553 | } 554 | } 555 | 556 | // ============= NEXT ============= 557 | // следующая секунда 558 | void nextSecond() { 559 | addSeconds(1); 560 | } 561 | 562 | // следующая минута (xx:xx:00) 563 | void nextMinute() { 564 | addMinutes(1); 565 | second = 0; 566 | } 567 | 568 | // следующий час (xx:00:00) 569 | void nextHour() { 570 | addHours(1); 571 | second = minute = 0; 572 | } 573 | 574 | // следующий день (00:00:00) 575 | void nextDay() { 576 | addDays(1); 577 | second = minute = hour = 0; 578 | } 579 | 580 | // следующий месяц (1 число 00:00:00) 581 | void nextMonth() { 582 | month++; 583 | day = 1; 584 | second = minute = hour = 0; 585 | if (month > 12) { 586 | year++; 587 | month = 1; 588 | } 589 | updateDays(); 590 | } 591 | 592 | // обновить weekDay и yearDay исходя из текущей даты (после ручного изменения) 593 | void updateDays() { 594 | weekDay = StampUtils::dateToWeekDay(day, month, year); 595 | yearDay = StampUtils::dateToYearDay(day, month, year); 596 | } 597 | 598 | private: 599 | void _update() { 600 | if (second > 59) { 601 | second = 0; 602 | minute++; 603 | } 604 | if (minute > 59) { 605 | minute = 0; 606 | hour++; 607 | } 608 | if (hour > 23) { 609 | hour = 0; 610 | weekDay++; 611 | yearDay++; 612 | day++; 613 | } 614 | if (weekDay > 7) weekDay = 1; 615 | if (day > StampUtils::daysInMonth(month, year)) { 616 | month++; 617 | day = 1; 618 | } 619 | if (month > 12) { 620 | year++; 621 | month = 1; 622 | yearDay = 1; 623 | } 624 | } 625 | 626 | void _btoa(uint8_t v, char* str) const { 627 | uint8_t d = v / 10; 628 | str[0] = d + '0'; 629 | str[1] = v - d * 10 + '0'; 630 | } 631 | }; -------------------------------------------------------------------------------- /src/DaySeconds.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class DaySeconds { 5 | public: 6 | DaySeconds() {} 7 | DaySeconds(uint32_t seconds) : seconds(seconds) {} 8 | DaySeconds(uint8_t hour, uint8_t minute, uint8_t second) { 9 | set(hour, minute, second); 10 | } 11 | 12 | void set(uint8_t hour, uint8_t minute, uint8_t second) { 13 | seconds = hour * 3600ul + minute * 60 + second; 14 | } 15 | 16 | bool operator==(uint32_t u) { 17 | return seconds == u; 18 | } 19 | bool operator!=(uint32_t u) { 20 | return seconds != u; 21 | } 22 | bool operator>(uint32_t u) { 23 | return seconds > u; 24 | } 25 | bool operator>=(uint32_t u) { 26 | return seconds >= u; 27 | } 28 | bool operator<(uint32_t u) { 29 | return seconds < u; 30 | } 31 | bool operator<=(uint32_t u) { 32 | return seconds <= u; 33 | } 34 | 35 | uint32_t seconds = 0; 36 | }; -------------------------------------------------------------------------------- /src/Stamp.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "./core/StampConvert.h" 5 | 6 | class Stamp : public StampConvert { 7 | public: 8 | uint32_t unix = 0; 9 | 10 | // ========== CONSTRUCT ========== 11 | Stamp() {} 12 | Stamp(const Stamp& s) = default; 13 | Stamp(const char* str) { 14 | parse(str); 15 | } 16 | Stamp(uint32_t unix) { 17 | Stamp::unix = unix; 18 | } 19 | Stamp(const Datime& dt) { 20 | set(dt); 21 | } 22 | Stamp(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { 23 | set(year, month, day, hour, minute, second); 24 | } 25 | Stamp(uint16_t yh, uint16_t mm, uint16_t ds) { 26 | set(yh, mm, ds); 27 | } 28 | 29 | // =========== SET TIME ============ 30 | // установить время из Datime 31 | void set(const Datime& dt) { 32 | unix = dt.getUnix(); 33 | } 34 | 35 | // установить время (год, месяц, день, час, минута, секунда) 36 | void set(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) { 37 | set(Datime(year, month, day, hour, minute, second)); 38 | } 39 | 40 | // установить время (год, месяц, день) или (час, минута, секунда) 41 | void set(uint16_t yh, uint16_t mm, uint16_t ds) { 42 | set(Datime(yh, mm, ds)); 43 | } 44 | 45 | // =========== ADD ============ 46 | // добавить секунды 47 | void addSeconds(uint32_t s) { 48 | unix += s; 49 | } 50 | 51 | // добавить минуты 52 | void addMinutes(uint32_t m) { 53 | unix += m * 60ul; 54 | } 55 | 56 | // добавить часы 57 | void addHours(uint32_t h) { 58 | unix += h * 3600ul; 59 | } 60 | 61 | // добавить дни 62 | void addDays(uint32_t d) { 63 | unix += d * 86400ul; 64 | } 65 | 66 | // =========== PARSE ============ 67 | // hh:mm:ss или yyyy-mm-dd или yyyy-mm-ddThh:mm:ss 68 | bool parse(const char* s) { 69 | Datime dt; 70 | if (!dt.parse(s)) return 0; 71 | set(dt); 72 | return 1; 73 | } 74 | 75 | // , dd yyyy hh:mm:ss 76 | bool parseHTTP(const char* s) { 77 | Datime dt; 78 | if (!dt.parseHTTP(s)) return 0; 79 | set(dt); 80 | return 1; 81 | } 82 | 83 | // =========== OVERLOAD =========== 84 | // получить время в секундах 85 | uint32_t getUnix() override { 86 | return unix; 87 | } 88 | }; -------------------------------------------------------------------------------- /src/StampBuild.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | // https://stackoverflow.com/a/44271643 4 | 5 | #define _BS_SEC_DAY 86400UL 6 | #define _BS_SEC_YEAR (_BS_SEC_DAY * 365) 7 | #define _BS_FDAY(year) (((year) % 400) == 0UL ? 29UL : (((year) % 100) == 0UL ? 28UL : (((year) % 4) == 0UL ? 29UL : 28UL))) 8 | 9 | #define _BS_DEC(c) (c & 0xf) 10 | #define _BS_DEC_2(str, i) (_BS_DEC(str[i]) * 10 + _BS_DEC(str[i + 1])) 11 | #define _BS_DEC_4(str, i) (_BS_DEC(str[i]) * 1000 + _BS_DEC(str[i + 1]) * 100 + _BS_DEC(str[i + 2]) * 10 + _BS_DEC(str[i + 3])) 12 | 13 | #define _BS_MONTH(str, i) ( \ 14 | str[i] == 'J' && str[i + 1] == 'a' ? 1 \ 15 | : str[i] == 'F' ? 2 \ 16 | : str[i] == 'M' && str[i + 2] == 'r' ? 3 \ 17 | : str[i] == 'A' && str[i + 1] == 'p' ? 4 \ 18 | : str[i] == 'M' ? 5 \ 19 | : str[i] == 'J' && str[i + 2] == 'n' ? 6 \ 20 | : str[i] == 'J' ? 7 \ 21 | : str[i] == 'A' ? 8 \ 22 | : str[i] == 'S' ? 9 \ 23 | : str[i] == 'O' ? 10 \ 24 | : str[i] == 'N' ? 11 \ 25 | : str[i] == 'D' ? 12 \ 26 | : 0) 27 | 28 | #define _BS_YDAY(year, month, day) ( \ 29 | day + \ 30 | (month >= 2 ? 31UL : 0UL) + \ 31 | (month >= 3 ? _BS_FDAY(year) : 0UL) + \ 32 | (month >= 4 ? 31UL : 0UL) + \ 33 | (month >= 5 ? 30UL : 0UL) + \ 34 | (month >= 6 ? 31UL : 0UL) + \ 35 | (month >= 7 ? 30UL : 0UL) + \ 36 | (month >= 8 ? 31UL : 0UL) + \ 37 | (month >= 9 ? 31UL : 0UL) + \ 38 | (month >= 10 ? 30UL : 0UL) + \ 39 | (month >= 11 ? 31UL : 0UL) + \ 40 | (month >= 12 ? 30UL : 0UL)) 41 | 42 | #define _BS_STAMP(year, month, day, hour, minute, second) \ 43 | (second + \ 44 | minute * 60UL + \ 45 | hour * 60UL * 60UL + \ 46 | (_BS_YDAY(year, month, day) - 1) * _BS_SEC_DAY + \ 47 | (year - 1970UL) * _BS_SEC_YEAR + \ 48 | ((year - 1969UL) / 4UL) * _BS_SEC_DAY - \ 49 | ((year - 1901UL) / 100UL) * _BS_SEC_DAY + \ 50 | ((year - 1601UL) / 400UL) * _BS_SEC_DAY) 51 | 52 | // public 53 | #define __TIME_SEC__ _BS_DEC_2(__TIME__, 6) 54 | #define __TIME_MIN__ _BS_DEC_2(__TIME__, 3) 55 | #define __TIME_HOUR__ _BS_DEC_2(__TIME__, 0) 56 | #define __DATE_DAY__ _BS_DEC_2(__DATE__, 4) 57 | #define __DATE_MONTH__ _BS_MONTH(__DATE__, 0) 58 | #define __DATE_YEAR__ _BS_DEC_4(__DATE__, 7) 59 | #define __TIME_UNIX__ (_BS_STAMP(__DATE_YEAR__, __DATE_MONTH__, __DATE_DAY__, __TIME_HOUR__, __TIME_MIN__, __TIME_SEC__)) 60 | 61 | // 62 | #define BUILD_STAMP_LOCAL __TIME_UNIX__ -------------------------------------------------------------------------------- /src/StampKeeper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifndef __AVR__ 5 | #include 6 | #endif 7 | 8 | #include "./core/StampConvert.h" 9 | 10 | #define ST_SKIP_THRESHOLD 30 // макс. порог ушедших секунд 11 | 12 | class StampKeeper : public StampConvert { 13 | #ifdef __AVR__ 14 | typedef void (*SecondCallback)(); 15 | typedef void (*SyncCallback)(uint32_t unix); 16 | #else 17 | typedef std::function SecondCallback; 18 | typedef std::function SyncCallback; 19 | #endif 20 | 21 | public: 22 | // установить unix и миллисекунды 23 | StampKeeper(uint32_t unix = 0, uint16_t ms = 0) { 24 | sync(unix, ms, true); 25 | } 26 | 27 | // установить unix и миллисекунды 28 | void sync(uint32_t unix, uint16_t ms = 0, bool skipTicks = false) { 29 | if (!unix) return; 30 | 31 | _syncTmr = millis() - ms; 32 | if (_unix > unix && _unix - unix > ST_SKIP_THRESHOLD) skipTicks = true; 33 | else if (unix > _unix && unix - _unix > ST_SKIP_THRESHOLD) skipTicks = true; 34 | 35 | if (!_unix || skipTicks) { 36 | _unix = unix; 37 | _diff = 0; 38 | } else { 39 | _diff = unix - _unix; 40 | } 41 | if (_sync_cb) _sync_cb(unix); 42 | } 43 | 44 | // синхронизировать с другим кипером 45 | void sync(StampKeeper& keeper, bool skipTicks = false) { 46 | sync(keeper.getUnix(), keeper.ms(), skipTicks); 47 | } 48 | 49 | // синхронизировать с Datime 50 | void sync(const Datime& dt, uint16_t ms = 0, bool skipTicks = false) { 51 | sync(dt.getUnix(), ms, skipTicks); 52 | } 53 | 54 | // сбросить синхронизацию 55 | void reset() { 56 | _unix = 0; 57 | _tickFlag = false; 58 | _ready = false; 59 | } 60 | 61 | // пропустить отставшие секунды (вызывать после sync) 62 | void skipTicks() { 63 | if (_diff) { 64 | _unix += _diff; 65 | _diff = 0; 66 | } 67 | } 68 | 69 | // есть рассинхронизация, которую нужно "дотикать" 70 | bool hasDesync() { 71 | return _tickFlag && (millis() - _syncTmr >= 1000 || _diff > 0); 72 | } 73 | 74 | // время синхронизировано 75 | inline bool synced() { 76 | return _unix; 77 | } 78 | 79 | // секундный флаг 80 | inline bool newSecond() { 81 | return _ready; 82 | } 83 | 84 | // подключить функцию-обработчик новой секунды (вида void f()) 85 | void onSecond(SecondCallback handler) { 86 | _sec_cb = handler; 87 | } 88 | 89 | // подключить функцию-обработчик синхронизации (вида void f(uint32_t unix)) 90 | void onSync(SyncCallback cb) { 91 | _sync_cb = cb; 92 | } 93 | 94 | // получить текущий unix 95 | uint32_t getUnix() override { 96 | return synced() ? (_tickFlag ? _unix : (_unix + _diff + (millis() - _syncTmr) / 1000ul)) : 0; 97 | } 98 | 99 | // получить миллисекунды текущей секунды 100 | uint16_t ms() { 101 | return synced() ? ((millis() - _syncTmr) % 1000ul) : 0; 102 | } 103 | 104 | // получить миллисекунды с epoch 105 | uint64_t getUnixMs() { 106 | return synced() ? (getUnix() * 1000ull + ms()) : 0; 107 | } 108 | 109 | // тикер, вызывать в loop. Вернёт true на новой секунде 110 | bool tick() { 111 | if (_ready) _ready = false; 112 | if (synced() && (millis() - _syncTmr >= 1000 || _diff > 0)) { 113 | if (!_tickFlag) { 114 | _tickFlag = true; 115 | skipTicks(); 116 | uint32_t dt = (millis() - _syncTmr) / 1000ul; 117 | if (dt) --dt; 118 | _unix += dt; 119 | _syncTmr += dt * 1000ul; 120 | } 121 | if (_diff) { 122 | if (_diff > 0) { 123 | ++_unix; 124 | --_diff; 125 | } else { 126 | _syncTmr += 1000; 127 | ++_diff; 128 | return false; 129 | } 130 | } else { 131 | ++_unix; 132 | _syncTmr += 1000; 133 | } 134 | if (_sec_cb) _sec_cb(); 135 | _ready = true; 136 | return true; 137 | } 138 | return false; 139 | } 140 | 141 | private: 142 | uint32_t _unix = 0; 143 | uint32_t _syncTmr = 0; 144 | int16_t _diff = 0; 145 | SecondCallback _sec_cb = nullptr; 146 | SyncCallback _sync_cb = nullptr; 147 | bool _tickFlag = false; 148 | bool _ready = false; 149 | }; -------------------------------------------------------------------------------- /src/StampSync.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // Синхронизатор Unix, getUnix() выдаёт актуальное время на базе установленного 5 | // в update + millis() с момента обновления 6 | 7 | #include "./core/StampConvert.h" 8 | 9 | #define STAMP_SYNC_LOOP_PRD (7ul * 24 * 60 * 60 * 1000) 10 | 11 | class StampSync : public StampConvert { 12 | public: 13 | // установить unix и миллисекунды 14 | StampSync(uint32_t unix = 0, uint16_t ms = 0) { 15 | update(unix, ms); 16 | } 17 | 18 | // установить unix и миллисекунды 19 | void update(uint32_t unix, uint16_t ms = 0) { 20 | _unix = unix; 21 | _syncTime = millis() - ms; 22 | } 23 | 24 | // время синхронизировано 25 | inline bool synced() { 26 | return _unix; 27 | } 28 | 29 | // время синхронизировано 30 | explicit operator bool() { 31 | return synced(); 32 | } 33 | 34 | // получить текущий unix 35 | uint32_t getUnix() { 36 | if (!synced()) return 0; 37 | uint32_t diff = millis() - _syncTime; 38 | if (diff > STAMP_SYNC_LOOP_PRD) { 39 | _unix += diff / 1000ul; 40 | _syncTime += diff - diff % 1000ul; 41 | return _unix; 42 | } 43 | return _unix + diff / 1000ul; 44 | } 45 | 46 | // получить миллисекунды текущей секунды 47 | uint16_t ms() { 48 | return synced() ? ((millis() - _syncTime) % 1000ul) : 0; 49 | } 50 | 51 | // получить миллисекунды с epoch 52 | uint64_t unixMs() { 53 | return synced() ? (getUnix() * 1000ull + ms()) : 0; 54 | } 55 | 56 | private: 57 | uint32_t _unix = 0; 58 | uint32_t _syncTime = 0; 59 | }; -------------------------------------------------------------------------------- /src/StampTicker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // тикающий unix - встроенный таймер на 1 секунду 5 | 6 | #include "./core/StampConvert.h" 7 | 8 | class StampTicker : public StampConvert { 9 | #ifdef __AVR__ 10 | typedef void (*SecondHandler)(); 11 | #else 12 | typedef std::function SecondHandler; 13 | #endif 14 | 15 | public: 16 | // установить unix и миллисекунды 17 | StampTicker(uint32_t unix = 0, uint16_t ms = 0) { 18 | update(unix, ms); 19 | } 20 | StampTicker(StampTicker& ticker) { 21 | update(ticker); 22 | } 23 | 24 | // установить unix и миллисекунды 25 | void update(uint32_t unix, uint16_t ms = 0, bool skipTicks = false) { 26 | if (unix) { 27 | if (!_unix || skipTicks) { 28 | _unix = unix; 29 | _diff = 0; 30 | } else { 31 | _diff = unix - _unix; 32 | } 33 | _tmr = millis() - ms; 34 | } 35 | } 36 | 37 | // синхронизировать с другим тикером 38 | void update(StampTicker& ticker, bool skipTicks = false) { 39 | update(ticker.getUnix(), ticker.ms(), skipTicks); 40 | } 41 | 42 | // пропустить отставшие секунды (вызывать после update) 43 | void skipTicks() { 44 | if (_diff) { 45 | _unix += _diff; 46 | _diff = 0; 47 | } 48 | } 49 | 50 | // время синхронизировано 51 | inline bool synced() { 52 | return _unix; 53 | } 54 | 55 | // время синхронизировано 56 | explicit operator bool() { 57 | return synced(); 58 | } 59 | 60 | // секундный флаг 61 | inline bool newSecond() { 62 | return _ready; 63 | } 64 | 65 | // тикер, вызывать в loop. Вернёт true на новой секунде 66 | bool tick() { 67 | if (_ready) _ready = 0; 68 | if (_unix && (millis() - _tmr >= 1000 || _diff > 0)) { 69 | if (_diff) { 70 | if (_diff > 0) { 71 | _unix++; 72 | _diff--; 73 | } else { 74 | _tmr += 1000; 75 | _diff++; 76 | return 0; 77 | } 78 | } else { 79 | _unix++; 80 | _tmr += 1000; 81 | } 82 | _ready = 1; 83 | if (_cb) _cb(); 84 | return 1; 85 | } 86 | return 0; 87 | } 88 | 89 | // подключить функцию-обработчик новой секунды (вида void f()) 90 | void attachSecond(SecondHandler handler) { 91 | _cb = handler; 92 | } 93 | 94 | // отключить функцию-обработчик новой секунды 95 | void detachSecond() { 96 | _cb = nullptr; 97 | } 98 | 99 | // получить текущий unix 100 | uint32_t getUnix() { 101 | return _unix; 102 | } 103 | 104 | // получить миллисекунды текущей секунды 105 | uint16_t ms() { 106 | return synced() ? ((millis() - _tmr) % 1000ul) : 0; 107 | } 108 | 109 | // получить миллисекунды с epoch 110 | uint64_t unixMs() { 111 | return synced() ? (getUnix() * 1000ull + ms()) : 0; 112 | } 113 | 114 | inline bool ready() __attribute__((deprecated)) { 115 | return _ready; 116 | } 117 | 118 | private: 119 | uint32_t _unix = 0; 120 | uint32_t _tmr = 0; 121 | int16_t _diff = 0; 122 | bool _ready = 0; 123 | SecondHandler _cb = nullptr; 124 | }; -------------------------------------------------------------------------------- /src/VirtualRTC.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | class VirtualRTC { 5 | public: 6 | virtual void setUnix(uint32_t unix) = 0; 7 | virtual uint32_t getUnix() = 0; 8 | }; -------------------------------------------------------------------------------- /src/core/StampConvert.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "../Datime.h" 5 | #include "../DaySeconds.h" 6 | 7 | class StampConvert { 8 | public: 9 | virtual uint32_t getUnix() = 0; 10 | 11 | // =========== GET TIME =========== 12 | // экспортировать в локальное время Datime 13 | Datime now() { 14 | return getUnix(); 15 | } 16 | 17 | operator Datime() { 18 | return getUnix(); 19 | } 20 | 21 | // ============ TO STRING ============ 22 | // вывести дату в формате "dd.mm.yyyy" 23 | char* dateToChar(char* buf) { 24 | return now().dateToChar(buf); 25 | } 26 | String dateToString() { 27 | return now().dateToString(); 28 | } 29 | 30 | // вывести время в формате "hh:mm:ss" 31 | char* timeToChar(char* buf) { 32 | return now().timeToChar(buf); 33 | } 34 | String timeToString() { 35 | return now().timeToString(); 36 | } 37 | 38 | // вывести время и дату в формате "dd.mm.yyyy hh:mm:ss" 39 | char* toChar(char* buf, char div = ' ') { 40 | return now().toChar(buf, div); 41 | } 42 | String toString(char div = ' ') { 43 | return now().toString(); 44 | } 45 | 46 | // ============ EXPORT EPOCH ============ 47 | 48 | // получить секунды с epoch 49 | uint32_t toSeconds() { 50 | return getUnix(); 51 | } 52 | 53 | // получить минуты с epoch 54 | uint32_t toMinutes() { 55 | return getUnix() / 60ul; 56 | } 57 | 58 | // получить часы с epoch 59 | uint32_t toHours() { 60 | return getUnix() / 3600ul; 61 | } 62 | 63 | // получить сутки с epoch 64 | uint32_t toDays() { 65 | return getUnix() / 86400ul; 66 | } 67 | 68 | // ============ DATIME ============ 69 | 70 | // получить секунды с начала текущих суток (локальное время) 71 | uint32_t daySeconds() { 72 | return _localUnix() % 86400; 73 | } 74 | 75 | // получить текущие секунды 76 | uint8_t second() { 77 | return _localUnix() % 60ul; 78 | } 79 | 80 | // получить текущие минуты 81 | uint8_t minute() { 82 | return (_localUnix() / 60ul) % 60ul; 83 | } 84 | 85 | // получить текущие часы 86 | uint8_t hour() { 87 | return (_localUnix() / 3600ul) % 24ul; 88 | } 89 | 90 | // получить текущий день месяца 91 | uint8_t day() { 92 | return now().day; 93 | } 94 | 95 | // получить текущий месяц 96 | uint8_t month() { 97 | return now().month; 98 | } 99 | 100 | // получить текущий год 101 | uint16_t year() { 102 | return now().year; 103 | } 104 | 105 | // получить текущий день недели 106 | uint8_t weekDay() { 107 | return now().weekDay; 108 | } 109 | 110 | // получить текущий день года 111 | uint8_t yearDay() { 112 | return now().yearDay; 113 | } 114 | 115 | // =========== OVERLOAD =========== 116 | bool operator==(const Datime& dt) { 117 | return getUnix() == dt.getUnix(); 118 | } 119 | bool operator!=(const Datime& dt) { 120 | return getUnix() != dt.getUnix(); 121 | } 122 | bool operator>(const Datime& dt) { 123 | return getUnix() > dt.getUnix(); 124 | } 125 | bool operator>=(const Datime& dt) { 126 | return getUnix() >= dt.getUnix(); 127 | } 128 | bool operator<(const Datime& dt) { 129 | return getUnix() < dt.getUnix(); 130 | } 131 | bool operator<=(const Datime& dt) { 132 | return getUnix() <= dt.getUnix(); 133 | } 134 | 135 | bool operator==(StampConvert& s) { 136 | return getUnix() == s.getUnix(); 137 | } 138 | bool operator!=(StampConvert& s) { 139 | return getUnix() != s.getUnix(); 140 | } 141 | bool operator>(StampConvert& s) { 142 | return getUnix() > s.getUnix(); 143 | } 144 | bool operator>=(StampConvert& s) { 145 | return getUnix() >= s.getUnix(); 146 | } 147 | bool operator<(StampConvert& s) { 148 | return getUnix() < s.getUnix(); 149 | } 150 | bool operator<=(StampConvert& s) { 151 | return getUnix() <= s.getUnix(); 152 | } 153 | 154 | bool operator==(uint32_t u) { 155 | return getUnix() == u; 156 | } 157 | bool operator!=(uint32_t u) { 158 | return getUnix() != u; 159 | } 160 | bool operator>(uint32_t u) { 161 | return getUnix() > u; 162 | } 163 | bool operator>=(uint32_t u) { 164 | return getUnix() >= u; 165 | } 166 | bool operator<(uint32_t u) { 167 | return getUnix() < u; 168 | } 169 | bool operator<=(uint32_t u) { 170 | return getUnix() <= u; 171 | } 172 | 173 | bool operator==(const DaySeconds& ds) { 174 | return daySeconds() == ds.seconds; 175 | } 176 | bool operator!=(const DaySeconds& ds) { 177 | return daySeconds() != ds.seconds; 178 | } 179 | bool operator>(const DaySeconds& ds) { 180 | return daySeconds() > ds.seconds; 181 | } 182 | bool operator>=(const DaySeconds& ds) { 183 | return daySeconds() >= ds.seconds; 184 | } 185 | bool operator<(const DaySeconds& ds) { 186 | return daySeconds() < ds.seconds; 187 | } 188 | bool operator<=(const DaySeconds& ds) { 189 | return daySeconds() <= ds.seconds; 190 | } 191 | 192 | // экспортировать в локальное время Datime 193 | Datime get() { 194 | return getUnix(); 195 | } 196 | 197 | // экспортировать в переменную типа Datime 198 | void get(Datime& dt) { 199 | dt = getUnix(); 200 | } 201 | 202 | private: 203 | uint32_t _localUnix() { 204 | return getUnix() + getStampZone() * 60l; 205 | } 206 | }; -------------------------------------------------------------------------------- /src/core/StampUtils.cpp: -------------------------------------------------------------------------------- 1 | #include "StampUtils.h" 2 | 3 | namespace StampUtils { 4 | 5 | static const uint8_t dim_table[] PROGMEM = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 6 | 7 | uint32_t timeToSeconds(uint8_t hours, uint8_t minutes, uint8_t seconds) { 8 | return (hours * 60 + minutes) * 60ul + seconds; 9 | } 10 | 11 | bool isLeap(uint16_t year) { 12 | return !(year & 3) && (!(year % 400) || (year % 100)); 13 | } 14 | 15 | uint8_t daysInMonth(uint8_t month) { 16 | return pgm_read_byte(&dim_table[month - 1]); 17 | } 18 | 19 | uint8_t daysInMonth(uint8_t month, uint16_t year) { 20 | return (month == 2 && isLeap(year)) ? (daysInMonth(month) + 1) : daysInMonth(month); 21 | } 22 | 23 | uint16_t daysToMonth(uint8_t month, uint16_t year) { 24 | uint16_t days = 0; 25 | for (uint8_t i = 1; i < month; i++) days += daysInMonth(i, year); 26 | return days; 27 | } 28 | 29 | uint16_t dateToYearDay(uint8_t day, uint8_t month, uint16_t year) { 30 | return day + daysToMonth(month, year); 31 | } 32 | 33 | uint16_t dateToDays2000(uint8_t day, uint8_t month, uint16_t year) { 34 | uint16_t yday = dateToYearDay(day, month, year); 35 | if (year >= 2000) year -= 2000; 36 | return yday + 365 * year + (year + 3) / 4 - 1; 37 | } 38 | 39 | uint8_t dateToWeekDay(uint8_t day, uint8_t month, uint16_t year) { 40 | return (dateToDays2000(day, month, year) + 5) % 7 + 1; 41 | } 42 | 43 | uint32_t dateToUnix(uint8_t day, uint8_t month, uint16_t year, uint8_t hour, uint8_t minute, uint8_t second, int16_t zone) { 44 | return 946684800ul + (dateToDays2000(day, month, year)) * 86400ul + timeToSeconds(hour, minute, second) - zone * 60; 45 | } 46 | 47 | } // namespace StampUtils -------------------------------------------------------------------------------- /src/core/StampUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace StampUtils { 5 | 6 | // время в секунды 7 | uint32_t timeToSeconds(uint8_t hours, uint8_t minutes, uint8_t seconds); 8 | 9 | // високосный год 10 | bool isLeap(uint16_t year); 11 | 12 | // дней в месяце без учёта года (февраль 28) 13 | uint8_t daysInMonth(uint8_t month); 14 | 15 | // дней в месяце с учётом високосного года 16 | uint8_t daysInMonth(uint8_t month, uint16_t year); 17 | 18 | // дней года к месяцу (янв 0, фев 31, март 59/60...) 19 | uint16_t daysToMonth(uint8_t month, uint16_t year); 20 | 21 | // дата в день текущего года (начиная с 1) 22 | uint16_t dateToYearDay(uint8_t day, uint8_t month, uint16_t year); 23 | 24 | // дата в день недели (пн 1.. вс 7) 25 | uint8_t dateToWeekDay(uint8_t day, uint8_t month, uint16_t year); 26 | 27 | // дата в количество дней с 01.01.2000 (начиная с 0) 28 | uint16_t dateToDays2000(uint8_t day, uint8_t month, uint16_t year); 29 | 30 | // дата в unix время, zone в минутах 31 | uint32_t dateToUnix(uint8_t day, uint8_t month, uint16_t year, uint8_t hour, uint8_t minute, uint8_t seconds, int16_t zone = 0); 32 | 33 | } // namespace StampUtils -------------------------------------------------------------------------------- /src/core/stamp_zone.cpp: -------------------------------------------------------------------------------- 1 | #include "stamp_zone.h" 2 | 3 | static int16_t _dt_zone = 0; 4 | 5 | void setStampZone(int16_t zone) { 6 | if (zone >= -12 && zone <= 14) zone *= 60; 7 | _dt_zone = zone; 8 | } 9 | 10 | int16_t getStampZone() { 11 | return _dt_zone; 12 | } -------------------------------------------------------------------------------- /src/core/stamp_zone.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | // установить часовую зону в часах или минутах 5 | void setStampZone(int16_t zone); 6 | 7 | // получить часовую зону в минутах 8 | int16_t getStampZone(); --------------------------------------------------------------------------------