├── .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 | [](https://github.com/GyverLibs/Stamp/releases/latest/download/Stamp.zip)
2 | [](https://registry.platformio.org/libraries/gyverlibs/Stamp)
3 | [](https://alexgyver.ru/)
4 | [](https://alexgyver.ru/support_alex/)
5 | [](https://github-com.translate.goog/GyverLibs/Stamp?_x_tr_sl=ru&_x_tr_tl=en)
6 |
7 | [](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();
--------------------------------------------------------------------------------