1 Star 9 Fork 5

阿彪开源 / 通用万能日历

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
gm_calendar.c 10.94 KB
一键复制 编辑 原始数据 按行查看 历史
/*******************************************************************************
** 文件名称:gm_calendar.c
** 文件作用:通用日历操作
** 创建作者:Tom Free 付瑞彪
** 创建时间:2018-11-10
**
** Copyright (c) 2018-2021 付瑞彪 All Rights Reserved
**
** 1 Tab == 4 Spaces UTF-8 ANSI C Language(C99)
*******************************************************************************/
#include "gm_calendar.h"
#include "stdio.h"
/* 默认时区为北京时区,UTC+8 */
#ifndef GM_CALENDAR_CFG_DEFAULT_TIMEZONE
#define GM_CALENDAR_CFG_DEFAULT_TIMEZONE 8
#elif ((GM_CALENDAR_CFG_DEFAULT_TIMEZONE < -12) || \
(GM_CALENDAR_CFG_DEFAULT_TIMEZONE > 12))
#define GM_CALENDAR_CFG_DEFAULT_TIMEZONE 8
#endif
/* 判断闰年 */
#define LEAP_YEAR(year) ((((year) % 4 == 0) && ((year) % 100 != 0)) || \
((year) % 400 == 0))
/* 月天数分配,未考虑闰年 */
static const uint8_t days_of_month[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/* 当前时区,UTC标识,正标识东时区,负标识西时区,默认北京时间,东八区,UTC+8 */
static int8_t now_time_zone = GM_CALENDAR_CFG_DEFAULT_TIMEZONE;
#ifdef __cplusplus
extern "C" {
#endif
/* 当前年是否是闰年,提供给应用层 */
bool gm_calendar_is_leap_year(uint16_t year)
{
return LEAP_YEAR(year) ? true : false;
}
/* 设置用于转换时间的时区,采用UTC标识,东+西-,入北京时间,东八区,UTC+8,输入8 */
bool gm_calendar_set_time_zone(int8_t timezone)
{
if ((now_time_zone < -12) || (timezone > 12))
{
/* 不能超过24小时时区跨度,最大正负12 */
return false;
}
now_time_zone = timezone;
return true;
}
/* 获得当前月份的总天数 */
uint8_t gm_calendar_get_month_days(uint16_t year, uint8_t month)
{
if ((year == 0) || (month == 0) || (month > 12))
{
/* 年与月份错误 */
return 0;
}
if ((LEAP_YEAR(year)) && (month == 2))
{
/* 闰年二月29天 */
return 29;
}
else
{
/* 其它直接返回表对应值 */
return days_of_month[month - 1];
}
}
/* 根据日期计算星期 */
uint8_t gm_calandar_calc_week_day(uint16_t year, uint8_t month, uint8_t day)
{
uint8_t week_day;
if ((year == 0) ||
(month == 0) ||
(month > 12) ||
(day == 0) ||
(day > gm_calendar_get_month_days(year, month)))
{
/* 年、月份和日期错误 */
return 0;
}
/* 将1/2月转换为上一年的13/14月 */
if ((month == 1) ||
(month == 2))
{
month += 12;
year--;
}
/* 计算星期,采用基姆拉尔森计算公式 */
week_day = (day +
2 * month +
3 * (month + 1) / 5 +
year +
year / 4 -
year / 100 +
year / 400) % 7 + 1;
return week_day;
}
/* 计算某日期是那一年的第几天 */
uint16_t gm_calendar_calc_now_days(uint16_t year, uint8_t month, uint8_t day)
{
uint16_t days = 0;
if ((year == 0) ||
(month == 0) ||
(month > 12) ||
(day == 0) ||
(day > gm_calendar_get_month_days(year, month)))
{
/* 年、月份和日期错误 */
return 0;
}
/* 计算到当前月之前的总天数 */
for (uint8_t i = 1; i < month; i++)
{
/* 按月累计 */
days += days_of_month[i - 1];
}
/* 修正闰年 */
if (LEAP_YEAR(year) && (month > 2))
{
/* 闰年二月多一天,所以之后的月都要加1 */
days++;
}
/* 加入当前月的天数 */
days += day;
return days;
}
/* 计算某日期从1970年1月1日以来的总天数 */
uint32_t gm_calendar_calc_all_days(uint16_t year, uint8_t month, uint8_t day)
{
uint32_t days = 0;
if ((year < 1970) ||
(month == 0) ||
(month > 12) ||
(day == 0) ||
(day > gm_calendar_get_month_days(year, month)))
{
/* 年、月份和日期错误 */
return 0;
}
/* 计算到当前年为止总共天数 */
for (uint16_t i = 1970; i < year; i++)
{
if (LEAP_YEAR(i))
{
days += 366ul;
}
else
{
days += 365ul;
}
}
/* 加上当年的天数 */
days += gm_calendar_calc_now_days(year, month, day);
/* 因为上面加的是当年的第几天,包括了1月1日,所以要减去这一天 */
return (days - 1);
}
/* 通过1970年1月1日以来的总天数计算公历日期 */
void gm_calendar_all_days_to_solar(gm_solar_t *p_solar, uint16_t days)
{
uint16_t now_year_days;
uint8_t now_month_days;
/* 计算年 */
for (p_solar->year = 1970; ; p_solar->year++)
{
now_year_days = gm_calendar_is_leap_year(p_solar->year) ? 366 : 365;
if (days < now_year_days)
{
break;
}
days -= now_year_days;
}
/* 计算月 */
for (p_solar->month = 1; ; p_solar->month++)
{
now_month_days = gm_calendar_get_month_days(p_solar->year, p_solar->month);
if (days < now_month_days)
{
break;
}
days -= now_month_days;
}
/* 计算日,因为计算的时候计算的是差值,所以需要加上1号的偏移 */
p_solar->day = days + 1;
}
/* 判断时间合法性 */
bool gm_calendar_check_time_validity(gm_time_t* p_time)
{
if ( (p_time->year == 0) ||
(p_time->month == 0) || (p_time->month > 12) ||
(p_time->day == 0) ||
(p_time->day > gm_calendar_get_month_days(p_time->year, p_time->month)) ||
(p_time->hour > 23) ||
(p_time->minute > 59)||
(p_time->second > 59))
{
return false;
}
else
{
return true;
}
}
/* 时间转换成时间戳,此函数需要时区参与,请保证时区设置OK */
bool gm_calendar_time_to_stamp(gm_time_t* p_time, gm_stamp_t *p_stamp)
{
uint16_t i;
if ((p_time == NULL) || (p_stamp == NULL))
{
return false;
}
/* 初始化为0 */
*p_stamp = 0;
if ((p_time->year < 1970) ||
(gm_calendar_check_time_validity(p_time) != true))
{
/* 时间不合法 */
return false;
}
/* 计算1970到去年的总的年秒数 */
for (i = 1970; i < p_time->year; i++)
{
if (LEAP_YEAR(i))
{
/* 闰年多一天 */
*p_stamp += 31622400ul;
}
else
{
*p_stamp += 31536000ul;
}
}
/* 计算到上个月的秒数 */
for (i = 1; i < p_time->month; i++)
{
*p_stamp += (gm_stamp_t)(days_of_month[i - 1] * 86400ul);
/* 二月需要多加一天 */
if ((i == 2) && LEAP_YEAR(p_time->year))
{
*p_stamp += 86400ul;
}
}
/* 把前面日期的秒钟数相加 */
*p_stamp += (gm_stamp_t)((p_time ->day - 1) * 86400uL);
/* 把前面小时秒钟数相加 */
*p_stamp += (gm_stamp_t)(p_time->hour * 3600uL);
/* 把前面分钟秒钟数相加 */
*p_stamp += (gm_stamp_t)(p_time->minute * 60uL);
/* 把最后的秒钟加上去 */
*p_stamp += (gm_stamp_t)(p_time->second);
/* 减去误差时间(UTC+X) */
*p_stamp -= (gm_stamp_t)(3600l * now_time_zone);
return true;
}
/* 时间戳转换为时间,此函数需要时区参与,请保证时区设置OK */
bool gm_calendar_stamp_to_time(gm_stamp_t *p_stamp, gm_time_t* p_time)
{
uint32_t total_days;
uint16_t year;
uint8_t month;
gm_stamp_t stamp;
if ((p_time == NULL) || (p_stamp == NULL))
{
return false;
}
stamp = *p_stamp;
/* 先将时间戳调整到当前时区 */
stamp += (gm_stamp_t)(3600l * now_time_zone);
/* 计算出总天数 */
total_days = stamp / 86400ul;
/* 从1970开始计算 */
year = 1970ul;
/* 判断有无超过一年,直到不够一年为止 */
while (total_days >= 365ul)
{
/* 是闰年 */
if (LEAP_YEAR(year))
{
/* 超过了闰年的天数 */
if (total_days >= 366ul)
{
total_days -= 366ul;
}
else
{
break;
}
}
else
{
/* 平年 */
total_days -= 365ul;
}
year++;
}
/* 计算当前年 */
p_time->year = year;
month = 1;
//超过了一个月
while (total_days >= 28)
{
if (LEAP_YEAR(year) && (month == 2))//当年是不是闰年/2月份
{
if (total_days >= 29)
{
total_days -= 29ul;//闰年的秒钟数
}
else
{
break;
}
}
else
{
if (total_days >= days_of_month[month - 1])
{
total_days -= days_of_month[month - 1];//平年
}
else
{
break;
}
}
month++;
}
p_time->month = month;
p_time->day = total_days + 1;
total_days = stamp % 86400; //得到秒钟数
p_time->hour = total_days / 3600; //小时
p_time->minute = (total_days % 3600) / 60; //分钟
p_time->second = (total_days % 3600) % 60; //秒钟
p_time->week = gm_calandar_calc_week_day(p_time->year, p_time->month, p_time->day);
return true;
}
/* 计算当前公历的后一天 */
bool gm_calendar_next_day(gm_solar_t *p_solar)
{
uint8_t cur_month_day;
if ((p_solar->year == 0) ||
(p_solar->month == 0) ||
(p_solar->month > 12) ||
(p_solar->day == 0))
{
return false;
}
cur_month_day = gm_calendar_get_month_days(p_solar->year, p_solar->month);
if (p_solar->day > cur_month_day)
{
return false;
}
if (p_solar->day >= cur_month_day)
{
p_solar->day = 1;
if (p_solar->month >= 12)
{
p_solar->month = 1;
p_solar->year++;
}
else
{
p_solar->month++;
}
}
else
{
p_solar->day++;
}
return true;
}
/* 计算当前公历的前一天 */
bool gm_calendar_prev_day(gm_solar_t *p_solar)
{
uint8_t cur_month_day;
if ((p_solar->year == 0) ||
(p_solar->month == 0) ||
(p_solar->month > 12) ||
(p_solar->day == 0))
{
return false;
}
cur_month_day = gm_calendar_get_month_days(p_solar->year, p_solar->month);
if (p_solar->day > cur_month_day)
{
return false;
}
if (p_solar->day == 1)
{
if (p_solar->month == 1)
{
p_solar->month = 12;
p_solar->year--;
}
else
{
p_solar->month--;
}
p_solar->day = gm_calendar_get_month_days(p_solar->year, p_solar->month);
}
else
{
p_solar->day--;
}
return true;
}
#ifdef __cplusplus
}
#endif
C
1
https://gitee.com/tomfree_opensource/gm_calendar.git
git@gitee.com:tomfree_opensource/gm_calendar.git
tomfree_opensource
gm_calendar
通用万能日历
master

搜索帮助