/*
 * @Description: 工具模块-时间转换子模块
 * @Author: yangsw
 * @Date: 2021-05-20 17:39:02
 * @LastEditTime: 2022-07-04 13:53:47
 * @LastEditors: yangsw
 * @Reference:
 */

#include "util_time.h"

/**
 * @brief: 判断是否为润年
 * @return {gw_u8} 1：润年，0：不是润年
 * @note:
 * @see:
 * @param {gw_u16} year 年份
 */
static gw_u8 Time_Year_Is_Leap(gw_u16 year)
{
    if ((year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0))
    {
        return 1;
    }
    else
    {
        return 0;
    }
}

/**
 * @brief: 计算当年已过多少天
 * @return {gw_u32} 当年已过天数
 * @note:
 * @see:
 * @param {gw_u16} year 年
 * @param {gw_u16} month 月
 * @param {gw_u16} mday 日
 */
gw_u32 Util_Time_Sum(gw_u16 year, gw_u16 month, gw_u16 mday)
{
    gw_u8 days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    gw_u8 leap_days[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    gw_u8 i;
    gw_u8 leap = 0;
    leap = Time_Year_Is_Leap(year);
    for (i = 1; i < month; i++)
    {
        if (leap == 1)
        {
            mday += leap_days[i];
        }
        else
        {
            mday += days[i];
        }
    }
    return mday;
}

/**
 * @brief: 日期转换为时间戳
 * @return {gw_u32} 时间戳
 * @note: 2000-1-1开始计算
 * @see:
 * @param {gw_u8} date[6] 年、月、日、时、分、秒
 */
gw_u32 Util_Time_Date_To_Timestamp(gw_u8 date[6])
{
    gw_u8 base_date[3] = {0, 1, 1};
    gw_u8 src_date[3];
    gw_s32 diff_day;
    gw_u32 u32Temp;
    src_date[0] = date[0];
    src_date[1] = date[1];
    src_date[2] = date[2];
    diff_day = Util_Time_Diff_Day(src_date, base_date);
    u32Temp = (gw_u32)diff_day * 86400;
    u32Temp = u32Temp + ((gw_u32)date[3] * 3600);
    u32Temp = u32Temp + ((gw_u32)date[4] * 60) + date[5];
    //((diff_day*86400)+(date[3]*3600)+(date[4]*60)+date[5]);
    return u32Temp;
}

/**
 * @brief: 时间戳转日期
 * @return {void}
 * @note: 2000-1-1开始计算
 * @see:
 * @param {gw_u32} in_timestamp 时间戳
 * @param {gw_u8} *out_time 日期，年、月、日、时、分、秒
 */
void Util_Time_Timestamp_To_Time(gw_u32 in_timestamp, gw_u8 *out_time)
{
    gw_u8 base_date[3] = {0, 1, 1};
    gw_s16 diff_day;
    gw_u32 remain_second;
    diff_day = in_timestamp / 86400;
    Util_Time_Cal_Date(base_date, diff_day, out_time);
    remain_second = in_timestamp % 86400;
    out_time[3] = remain_second / 3600;
    remain_second = remain_second % 3600;
    out_time[4] = remain_second / 60;
    out_time[5] = remain_second % 60;
}

/**
 * @brief: 经过多少天后的日期
 * @return {gw_s8} 执行结果 0：正常
 * @note:
 * @see:
 * @param {gw_u8} in_date[3] 当前日期，年、月、日
 * @param {gw_s32} days 经过的天数，负数表示往前，正数表示往后
 * @param {gw_u8} *out_date 结果日期，年、月、日
 */
gw_s8 Util_Time_Cal_Date(gw_u8 in_date[3], gw_s32 days, gw_u8 *out_date)
{
    gw_u16 year, month, day;
    gw_u8 leapyear = 0; // 闰年时使用
    gw_s32 sum;
    gw_u8 month_date[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    year = in_date[0] + 2000;
    month = in_date[1];
    day = in_date[2];
    if (month > 12 || month < 1) // 判断输入是否正确
    {
        return -1;
    }
    if (day > 31)
    {
        return -1;
    }
    leapyear = Time_Year_Is_Leap(year);
    if (days < 0)
    { // 往前推算时间
        sum = days;
        while ((sum + day) <= 0)
        {
            month--;
            if (month == 0)
            {
                year--;
                leapyear = Time_Year_Is_Leap(year);
                month = 12;
            }
            if (month == 2) // 判断当月是不是二月份
                month_date[month - 1] = 28 + leapyear;
            sum += month_date[month - 1];
        }
        day += sum;
    }
    else if (days > 0)
    {                     // 往后推算时间
        sum = days + day; // 当前日期与N天相加
        do
        {
            if (month == 2) // 判断当月是不是二月份
                month_date[month - 1] = 28 + leapyear;
            if (sum > month_date[month - 1])
            {
                sum -= month_date[month - 1];
                month++;         // 超过当月天数，加一个月
                if (month == 13) // 当月份超过12月时，重新返到1月
                {
                    year++; // 加一年
                    leapyear = Time_Year_Is_Leap(year);
                    month = 1; // 因为12月的下一个月是1月
                }
            }
        } while (sum > month_date[month - 1]); // 当加起来的天数少于当月的天数就停止循环
        day = sum;
    }
    out_date[0] = year - 2000;
    out_date[1] = month;
    out_date[2] = day;
    return 0;
}

/**
 * @brief: 经过多少个月后的日期
 * @return {gw_u8} 执行结果 0：正常
 * @note:
 * @see:
 * @param {gw_u8} in_date[2] 当前日期，年、月
 * @param {gw_s16} month_num 经过的月数，负数表示往前，正数表示往后
 * @param {gw_u8} *out_date 结果日期，年、月
 */
gw_u8 Util_Time_Cal_Month(gw_u8 in_date[2], gw_s16 month_num, gw_u8 *out_date)
{
    int months;
    months = in_date[1] + month_num;
    out_date[0] = in_date[0] + months / 12;
    if (month_num >= 0)
    {
        out_date[1] = months % 12;
    }
    else
    {
        out_date[1] = months % 12 + 12;
        out_date[0] = out_date[0] - 1;
    }
    return 0;
}

/**
 * @brief: 计算两个日期相差多少天
 * @return {gw_s32} 相差天数
 * @note: date1-date2
 * @see:
 * @param {gw_u8} date1 日期1，年、月、日
 * @param {gw_u8} date2 日期2，年、月、日
 */
gw_s32 Util_Time_Diff_Day(gw_u8 date1[3], gw_u8 date2[3])
{
    gw_u16 year1, year2;
    gw_u32 day_sum1, day_sum2;
    gw_s32 diff_day;
    year1 = date1[0] + 2000;
    year2 = date2[0] + 2000;
    day_sum1 = Util_Time_Sum(year1, date1[1], date1[2]);
    day_sum2 = Util_Time_Sum(year2, date2[1], date2[2]);
    diff_day = day_sum1 - day_sum2;
    if (year1 > year2)
    {
        while (year1 > year2)
        {
            if (Time_Year_Is_Leap(year2) == 1)
            {
                diff_day += 366;
            }
            else
            {
                diff_day += 365;
            }
            year2++;
        }
    }
    else if (year1 < year2)
    {
        while (year1 < year2)
        {
            if (Time_Year_Is_Leap(year1) == 1)
            {
                diff_day = diff_day - 366;
                year1++;
            }
            else
            {
                diff_day = diff_day - 365;
            }
            year1++;
        }
    }
    else
    {
    }
    return diff_day;
}

/**
 * @brief: 计算两个日期相差多少月
 * @return {gw_s16} 相差月数
 * @note: date1-date2
 * @see:
 * @param {gw_u8} date1 日期1，年、月
 * @param {gw_u8} date2 日期2，年、月
 */
gw_s16 Util_Time_Diff_Month(gw_u8 date1[2], gw_u8 date2[2])
{
    gw_s16 diff_month;
    diff_month = (gw_s16)(date1[0] - date2[0]) * 12 + (gw_s16)(date1[1] - date2[1]);
    return diff_month;
}

/**
 * @brief: 计算两个时间相差多少秒
 * @return {gw_s32} 相差秒数
 * @note: time1-time2
 * @see:
 * @param {gw_u8} time1 时间1，时、分、秒
 * @param {gw_u8} time2 时间2，时、分、秒
 */
gw_s32 Util_Time_Diff_Second(gw_u8 time1[3], gw_u8 time2[3])
{
    gw_s32 diff_second;
    diff_second = (gw_s32)(time1[0] - time2[0]) * 3600 + (gw_s32)(time1[1] - time2[1]) * 60 + (gw_s32)(time1[2] - time2[2]);
    return diff_second;
}

/**
 * @brief: 经过多少小时后的日期
 * @return {gw_u8} 执行结果 0：正常
 * @note:
 * @see:
 * @param {gw_u8} in_time[6] 当前日期，年、月、日、时、分、秒
 * @param {gw_u32} hour 经过的小时数
 * @param {gw_u8} *out_time 结果日期，年、月、日、时、分、秒
 */
gw_u8 Util_Time_Add_Hour(gw_u8 in_time[6], gw_u32 hour, gw_u8 *out_time)
{
    gw_u32 timestamp;
    timestamp = Util_Time_Date_To_Timestamp(in_time);
    timestamp = timestamp + hour * 3600;
    Util_Time_Timestamp_To_Time(timestamp, out_time);
    return 0;
}

// 获取某个月的最大天数
gw_u8 Util_Time_GetMaxDaysInMonth(gw_u8 month, gw_u16 year)
{
    switch (month)
    {
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
        return 31;
    case 4:
    case 6:
    case 9:
    case 11:
        return 30;
    case 2:
        return Time_Year_Is_Leap(year) ? 29 : 28;
    default:
        return 0;
    }
}

// 验证时间数组的正确性
gw_u8 Util_Time_ValidateTime(gw_u8 u8time[6])
{
    gw_u8 year = u8time[0];
    gw_u8 month = u8time[1];
    gw_u8 day = u8time[2];
    gw_u8 hour = u8time[3];
    gw_u8 minute = u8time[4];
    gw_u8 second = u8time[5];
    // 检查月份是否在1到12之间
    if (month < 1 || month > 12)
    {
        return 0;
    }
    // 检查日期是否在1到最大天数之间
    gw_u8 maxDays = Util_Time_GetMaxDaysInMonth(month, year);
    if (day < 1 || day > maxDays)
    {
        return 0;
    }
    // 检查小时是否在0到23之间
    if (hour > 23)
    {
        return 0;
    }
    // 检查分钟是否在0到59之间
    if (minute > 59)
    {
        return 0;
    }
    // 检查秒钟是否在0到59之间
    if (second > 59)
    {
        return 0;
    }
    // 如果所有检查都通过，返回1表示时间格式正确
    return 1;
}
