Этот код автора Michael Duane, взят на GitHub [5]. Предназначен для 8-битной платформы AVR, но может работать и на 32-битных системах, если предоставлена поддержка стандартных библиотек C.
/*
* (C)2012 Michael Duane Rice All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer. Redistributions in binary
* form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials
* provided with the distribution. Neither the name of the copyright holders
* nor the names of contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. */
/* $Id: time.h 2427 2014-05-01 14:06:03Z amylaar $ */
/** \file */
/** \defgroup avr_time < time.h>: Time
\code #include < time.h> \endcode
< h3>Введение в функции времени< /h3>
Этот файл декларирует функции времени, реализованные в \c avr-libc.
Эта реализация стремится соответствовать ISO/IEC 9899 (C90). Однако из-за
ограничений целевого процессора и рабочего окружения среды разработки
практическое поведение функций может отличаться от этого стандарта.
Section 7.23.2.1 clock()
Тип clock_t, макрос CLOCKS_PER_SEC и функция clock() не реализованы.
Подразумевается, что они принадлежат коду операционной системы или коду
приложения, если операционной системы нет.
Section 7.23.2.3 mktime()
Стандарт указывает, что mktime() должна возвратить (time_t) -1, если время
не отслеживается. Эта реализация всегда вернет представление времени по
принципу 'best effort' (сделано все, что было возможно).
Section 7.23.2.4 time()
Стандарт указывает, что time() должна возвратить (time_t) -1, если время
не отслеживается. Поскольку за инициализацию времени в системе отвечает
приложение, эта функциональность не реализована.
Section 7.23.2.2, difftime()
Из-за отсутствия 64-битных чисел double функция function difftime()
возвратит long integer. В большинстве случаев это будет незаметно для
пользователя, и автоматически обработается компилятором.
Section 7.23.1.4 struct tm
В соответствии со стандартом при переходе на летнее время (Daylight
Saving time) значение struct tm->tm_isdst больше нуля. Эта реализация
дополнительно функционирует так, что при положительном значении
tm_isdst указывает, насколько увеличилось время при переходе на летнее
время.
Section 7.23.3.5 strftime()
Поддерживается только локаль 'C'. Таким образом, модификаторы 'E' и 'O'
игнорируются. Преобразование 'Z' также игнорируется из-за отсутствия
поддержки имен временной зоны.
В дополнение к вышеперечисленным отклонениям от стандарта существуют
некоторые варианты поведения отличающиеся от ожидаемого по стандарту,
хотя это допускается стандартом.
При работе в AVR-окружении отсутствует 'platform standard' метод
получения текущего времени, временной зоны или правил перехода на летнее
время. Таким образом, приложение само должно инициализировать этой
информацией систему отслеживания времени. Функции set_zone(), set_dst()
и set_system_time() предоставлены для инициализации. Будучи
инициализированным, системное время поддерживается актуальным путем
вызова функции system_tick() с секундными интервалами.
Хотя в стандарте это не указано, часто ожидается, что time_t это целое
число со знаком, выражающее смещение в секундах относительно полуночи
1 января 1970 года, т. е. используется время Unix. Эта реализация
использует беззнаковое 32-битное целое смещение от полуночи 1 января
2000 года. Применение этой модифицированной "эпохи" помогает упростить
функции преобразования, хотя 32-битное значение позволяет правильно
представить время до четверга 7 февраля 06:28:15 2136 UTC. Определены
макросы UNIX_OFFSET и NTP_OFFSET, чтобы помочь преобразовать метки
времени из форматов Unix и NTP.
В отличие от десктопных аналогов, внедрять и поддерживать информацию
о временной зоне нецелесообразно. Поэтому никаких попыток учета часового
пояса, перехода на летнее время или високосных секунд в прошлые даты
не предпринимается. Все вычисления делаются в соответствии с текущей
сконфигурированной зоной времени и правилам перехода на летнее время.
В дополнение к стандартным функциям C предоставлены реэнтрантные версии
ctime(), asctime(), gmtime() и localtime(). В дополнение к реэнтрантности
они менее требовательны к расходам RAM. Дополнительное преобразование
времени isotime() и её реэнтрантная версия используют намного меньше
памяти, чем ctime() или asctime().
Наряду с обычными предоставляющими сервис функциями, такими как
is_leap_year(), эта библиотека включает в себя набор функций, связанных
с Солнцем и Луной, а также функции сидерического времени.
*/
#ifndef TIME_H
#define TIME_H
#ifdef __cplusplus
extern "C" {
#endif
#include < inttypes.h>
#include < stdlib.h>
/** \ingroup avr_time */
/* @{ */
/** time_t представляет количество секунд, прошедших от полуночи
1 января 2000 UTC ("эпоха" Y2K). Такой диапазон позволяет этой
реализации представить время до четверга 7 февраля 06:28:15 2136 UTC.
*/
typedef uint32_t time_t;
/**
Функция time возвратит текущую метку времени системы (time stamp).
Если timer не нулевой указатель, возвращаемое значение будет также
назначено ячейке, на которую он указывает.
*/
time_t time(time_t *timer);
/**
Функция difftime вернет разницу между двумя двоичными метками времени,
time1 - time0.
*/
int32_t difftime(time_t time1, time_t time0);
/**
Структура tm содержит "разбитое" представление времени на компоненты
из Грегорианского календаря.
Нормальные диапазоны элементов следующие.
\code
tm_sec количество секунд после минуты - [ 0 .. 59 ]
tm_min количество минут после часа - [ 0 .. 59 ]
tm_hour часов от полуночи - [ 0 .. 23 ]
tm_mday день месяца - [ 1 .. 31 ]
tm_wday дней от понедельника - [ 0 .. 6 ]
tm_mon месяцев от января - [ 0 .. 11 ]
tm_year годов от 1900
tm_yday дней от 1 января - [ 0 .. 365 ]
tm_isdst флаг перехода на летнее время (Daylight Saving Time) *
\endcode
* Значение tm_isdst будет 0, если летнее время не активно,
и отрицательное, если эта информация недоступна.
Когда произошел переход на летнее время, значение представляет
количество секунд, на которое летнее время переводят вперед.
См. функцию set_dst() для дополнительной информации по Daylight Saving.
*/
struct tm {
int8_t tm_sec;
int8_t tm_min;
int8_t tm_hour;
int8_t tm_mday;
int8_t tm_wday;
int8_t tm_mon;
int16_t tm_year;
int16_t tm_yday;
int16_t tm_isdst;
};
/* Мы должны предоставить clock_t / CLOCKS_PER_SEC, чтобы можно было собрать
libstdc++-v3. Мы определили CLOCKS_PER_SEC символом _CLOCKS_PER_SEC_,
так что пользователь может предоставить значение на этапе линковки,
что должно привести к незначительным или отсутствующим накладным расходам
времени выполнения по сравнению с константой #define. */
typedef unsigned long clock_t;
extern char *_CLOCKS_PER_SEC_;
#define CLOCKS_PER_SEC ((clock_t) _CLOCKS_PER_SEC_)
extern clock_t clock(void);
/**
Эта функция составляет элементы из структуры времени timeptr, возвращая
двоичную метку времени. Элементы timeptr интерпретируются как представляющие
локальное время.
Оригинальные значения элементов tm_wday и tm_yday структуры игнорируются,
и оригинальные значения других элементов не ограничены диапазонами,
установленными для структуры tm.
При успешном завершении значения всех элементов timeptr устанавливаются
в соответствующий диапазон.
*/
time_t mktime(struct tm * timeptr);
/**
Эта функция составляет элементы из структуры времени timeptr, возвращая
двоичную метку времени. Элементы timeptr интерпретируются как представляющие
время UTC.
Оригинальные значения элементов tm_wday и tm_yday структуры игнорируются,
и оригинальные значения других элементов не ограничены диапазонами,
установленными для структуры tm.
В отличие от mktime(), функция mk_gmtime НЕ МОДИФИЦИРУЕТ элементы timeptr.
*/
time_t mk_gmtime(const struct tm * timeptr);
/**
Функция gmtime преобразует метку времени, на которую указывает timer,
в "разбитое" на отдельные компоненты времени, выраженные в UTC.
*/
struct tm *gmtime(const time_t * timer);
/**
Реэнтрантная версия gmtime().
*/
void gmtime_r(const time_t * timer, struct tm * timeptr);
/**
Функция localtime преобразует метку времени, на которую указывает timer,
в компонентное время, выраженное как локальное время.
*/
struct tm *localtime(const time_t * timer);
/**
Реэнтрантная версия localtime().
*/
void localtime_r(const time_t * timer, struct tm * timeptr);
/**
Функция asctime преобразует "разбитое" время timeptr в строку ascii.
Sun Mar 23 01:03:52 2013
*/
char *asctime(const struct tm * timeptr);
/**
Реэнтрантная версия asctime().
*/
void asctime_r(const struct tm * timeptr, char *buf);
/**
Функция ctime эквивалентна asctime(localtime(timer)).
*/
char *ctime(const time_t * timer);
/**
Реэнтрантная версия ctime().
*/
void ctime_r(const time_t * timer, char *buf);
/**
Функция isotime конструирует строку ascii в форме
\code2013-03-23 01:03:52\endcode
*/
char *isotime(const struct tm * tmptr);
/**
Реэнтрантная версия isotime()
*/
void isotime_r(const struct tm *, char *);
/**
Полное описание strftime() не входит в рамки рассмотрения этого
документа. Подробности см. в документе ISO/IEC 9899.
Все преобразования делаются с использованием локали C, с игнорированием
модификаторов E или O. Из-за отсутствия имени временной зоны (time
zone 'name'), преобразование 'Z' также игнорируется.
*/
size_t strftime(char *s,
size_t maxsize,
const char *format,
const struct tm * timeptr);
/**
Указывает функцию перехода на летнее время (Daylight Saving).
Функция Daylight Saving должна проанализировать параметры, чтобы
определить, действует ли Daylight Saving, и вернет значение,
подходящее для tm_isdst.
Доступны рабочие примеры для USA и EU.
\code #include < util/eu_dst.h>\endcode
Для Европы, и
\code #include < util/usa_dst.h>\endcode
для США.
Если функция Daylight Saving не указана, то система будет
игнорировать переход на летнее время (Daylight Saving).
*/
void set_dst(int (*) (const time_t *, int32_t *));
/**
Устанавливает временную зону. Параметр задается в секундах к востоку
от первичного меридиана (Prime Meridian). Пример для Нью-Йорка:
\code set_zone(-5 * ONE_HOUR);\endcode
Если зона времени не установлена, то система времени будет работать
только в UTC.
*/
void set_zone(int32_t);
/**
Инициализация системного времени. Примеры:
Из Clock / Calendar типа RTC:
\code
struct tm rtc_time;
read_rtc(&rtc_time);
rtc_time.tm_isdst = 0;
set_system_time( mktime(&rtc_time) );
\endcode
Для метки времени NTP (Network Time Protocol):
\code
set_system_time(ntp_timestamp - NTP_OFFSET);
\endcode
Для метки времени UNIX:
\code
set_system_time(unix_timestamp - UNIX_OFFSET);
\endcode
*/
void set_system_time(time_t timestamp);
/**
Вызовом этой функции с частотой 1 Гц поддерживается актуальность
системного времени.
Предполагается, что эта функция обычно вызывается из ISR (хотя это
не требуется). Поэтому она включает в себя код, который упрощает
использование из голого ISR, избегая затрат на сохранение
и восстановление регистров MCU.
Такой ISR может напоминать следующий пример:
\code
ISR(RTC_OVF_vect, ISR_NAKED)
{
system_tick();
reti();
}
\endcode
*/
void system_tick(void);
/**
Перечисление меток для дней недели.
*/
enum _WEEK_DAYS_ {
SUNDAY,
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY
};
/**
Перечисление меток для месяцев.
*/
enum _MONTHS_ {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER
};
/**
Возвращает 1, если год високосный (leap year), 0 если не високосный.
*/
uint8_t is_leap_year(int16_t year);
/**
Возвращает длину месяца, определяемую годом и месяцем, где месяц
находится в диапазоне от 1 до 12.
*/
uint8_t month_length(int16_t year, uint8_t month);
/**
Возвращает календарную неделю года, где 1 считается началом дня недели,
заданным параметром start. Возвращаемое значение может быть от 0 до 52.
*/
uint8_t week_of_year(const struct tm * timeptr, uint8_t start);
/**
Возвращает календарную неделю месяца, где первая неделя считается
начинающейся в день недели, указанный в параметре start. Возвращаемое
значение может быть в диапазоне от 0 до 5.
*/
uint8_t week_of_month(const struct tm * timeptr, uint8_t start);
/**
Структура, которая представляет дату как год, номер недели этого года
и день недели. См. < a href="http://en.wikipedia.org/wiki/ISO_week_date"
title="http://en.wikipedia.org/wiki/ISO_week_date" rel="nofollow">
http://en.wikipedia.org/wiki/ISO_week_date< /a> для дополнительной
информации.
*/
struct week_date{
int year;
int week;
int day;
};
/**
Возвратит структуру week_date с неделей ISO_8601 на основе даты,
соответствующей указанным году и дню года.
См. < a href="http://en.wikipedia.org/wiki/ISO_week_date"
title="http://en.wikipedia.org/wiki/ISO_week_date" rel="nofollow">
http://en.wikipedia.org/wiki/ISO_week_date< /a> для дополнительной
информации.
*/
struct week_date * iso_week_date( int year, int yday);
/**
Реэнтрантная версия iso-week_date.
*/
void iso_week_date_r( int year, int yday, struct week_date *);
/**
Преобразует метку времени Y2K в метку времени файловой системы FAT.
*/
uint32_t fatfs_time(const struct tm * timeptr);
/** Час, выраженный в секундах */
#define ONE_HOUR 3600
/** Угловая степень, выраженная в секундах дуги */
#define ONE_DEGREE 3600
/** День, выраженный в секундах */
#define ONE_DAY 86400
/** Разница между эпохами Y2K и UNIX, выраженная в секундах. Для
преобразования метки времени Y2K в метку времени UNIX:
\code
long unix;
time_t y2k;
y2k = time(NULL);
unix = y2k + UNIX_OFFSET;
\endcode
*/
#define UNIX_OFFSET 946684800
/** Разница между эпохами Y2K и NTP, выраженная в секундах. Для
преобразования метки времени Y2K в метку времени NTP:
\code
unsigned long ntp;
time_t y2k;
y2k = time(NULL);
ntp = y2k + NTP_OFFSET;
\endcode
*/
#define NTP_OFFSET 3155673600
/*
* ===================================================================
* Ephemera
*/
/**
Устанавливает географические координаты 'наблюдателя' для использования
с некоторыми следующими функциями. Параметры передаются как секунды
северной широты (North Latitude) и секунды восточной долготы (East
Longitude).
Для Нью-Иорка:
\code set_position( 40.7142 * ONE_DEGREE, -74.0064 * ONE_DEGREE);\endcode
*/
void set_position(int32_t latitude, int32_t longitude);
/**
Вычисляет разницу между видимым солнечным временем и средним солнечным
временем. Возвращает значение в секундах.
*/
int16_t equation_of_time(const time_t * timer);
/**
Вычисляет время нахождения солнца над горизонтом в месте нахождения
наблюдателя.
Примечание: в местах нахождения наблюдателя внутри полярного круга это
значение может быть равно 0 во время зимы, и может превышать ONE_DAY
летом.
Возвращает значение в секундах.
*/
int32_t daylight_seconds(const time_t * timer);
/**
Вычисляет время солнечного полудня в месте нахождения наблюдателя.
*/
time_t solar_noon(const time_t * timer);
/**
Возвращает время восхода солнца в месте нахождения наблюдателя.
См. описание daylight_seconds().
*/
time_t sun_rise(const time_t * timer);
/**
Возвращает время захода солнца в месте нахождения наблюдателя.
См. описание daylight_seconds().
*/
time_t sun_set(const time_t * timer);
/** Возвращает склонение солнца в радианах. */
double solar_declination(const time_t * timer);
/**
Возвращает приближение к фазе Луны. Знак возвращенного значения
показывает фазу убывания или нарастания. Абсолютное значение
величины возврата показывает процентное освещение.
*/
int8_t moon_phase(const time_t * timer);
/**
Возвращает Greenwich Mean Sidereal Time в секундах sidereal-дня.
Возвращаемое значение будет в диапазоне от 0 до 86399 секунд.
*/
unsigned long gm_sidereal(const time_t * timer);
/**
Возвращает Local Mean Sidereal Time в секундах sidereal-дня.
Возвращаемое значение будет в диапазоне от 0 до 86399 секунд.
*/
unsigned long lm_sidereal(const time_t * timer);
/* @} */
#ifdef __cplusplus
}
#endif
#endif /* TIME_H */