打印
[Cortex-M0技术交流]

分享我的RTC应用中的秒和时间的转换函数

[复制链接]
2955|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gdmgb520|  楼主 | 2012-6-18 18:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
主要是秒和年月日时分秒之间的相互转换。开始在网上找了写资料,包括野火的和正点原子的例程。都有一些小问题或者不是十分满足我的要求。最后修改的结果如下。已经做了些测试,也希望大家不要拿来直接用,确认没有问题再用。


time.c文件:
#define FEBRUARY                2
#define        STARTOFTIME                1970
#define SECDAY                        86400L
#define SECYR                        (SECDAY * 365)
#define        leapyear(year)                ((year) % 4 == 0)
#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
#define        days_in_month(a)         (month_days[(a) - 1])


extern _strTime g_SysTime;

static const u8 MonthDay[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},   //非闰年
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}    //闰年
};

/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
/*计算公历*/   //gb 计算星期 2012-04-27 星期五 13:56:10
static void GregorianDay(_strTime* tm)
{
        int leapsToDate;
        int lastYear;
        int day;
        int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };

        lastYear=tm->tm_year-1;

        /*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/
        leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      

     /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
        if((tm->tm_year%4==0) &&
           ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
           (tm->tm_mon>2)) {
                /*
                 * We are past Feb. 29 in a leap year
                 */
                day=1;
        } else {
                day=0;
        }

        day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_day; /*计算从公元元年元旦到计数日期一共有多少天*/

        tm->tm_wday=day%7;
}

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* [For the **n calendar (which was used in Russia before 1917,
* Britain & colonies before 1752, anywhere else before 1582,
* and is still in use by some communities) leave out the
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
*
* WARNING: this function will overflow on 2106-02-07 06:28:16 on
* machines were long is 32-bit! (However, as time_t is signed, we
* will already get problems at other places on 2038-01-19 03:14:08)
*/
//        u32 mktimev(_strTime *tm)
uint32_t ap_time_date2sec(_strTime *Time)
{
//          char Temp = 0;
  _strTime tmp = {0,0,0,0,0,0,0};
//          u32 lTime = 0;

//   tmp = g_SysTime;
  tmp.tm_sec = Time->tm_sec;
  tmp.tm_min = Time->tm_min;
  tmp.tm_hour = Time->tm_hour;
  tmp.tm_day = Time->tm_day;
  tmp.tm_mon = Time->tm_mon;
  tmp.tm_year = Time->tm_year;

//                if (0 >= (int) (tm.tm_mon -= 2)) {        /* 1..12 -> 11,12,1..10 */
  if (0 >= (s8) (tmp.tm_mon -= 2)) {  /* 1..12 -> 11,12,1..10 */
                tmp.tm_mon += 12;                /* Puts Feb last since it has leap day */
                tmp.tm_year -= 1;
        }

        return (((
                (u32) (tmp.tm_year/4 - tmp.tm_year/100 + tmp.tm_year/400 + 367*tmp.tm_mon/12 + tmp.tm_day) +
                        tmp.tm_year*365 - 719499
            )*24 + tmp.tm_hour /* now have hours */
          )*60 + tmp.tm_min /* now have minutes */
        )*60 + tmp.tm_sec; /* finally seconds */
}

/******************************************************************************
*Function        : ap_sec2date
*CreatDate: 2012-04-27 星期五 14:11:31
*Author                :
*
*Descrip        : 将秒转换为日期
*Input                : tim - 秒,tm - 日期结构体指针,用于保存转换结果
*Output                :
*
*Note                :
******************************************************************************/
void ap_time_sec2date(u32 tim, _strTime * tm)
{
        register u32    i;
        register long   hms, day;

        day = tim / SECDAY;
        hms = tim % SECDAY;

        /* Hours, minutes, seconds are easy */
        tm->tm_hour = hms / 3600;
        tm->tm_min = (hms % 3600) / 60;
        tm->tm_sec = (hms % 3600) % 60;

        /* Number of years in days */ /*算出当前年份,起始的计数年份为1970年*/
        for (i = STARTOFTIME; day >= days_in_year(i); i++) {
                day -= days_in_year(i);
        }
        tm->tm_year = i;

        /* Number of months in days left */ /*计算当前的月份*/
//                if (leapyear(tm->tm_year)) {
//                        days_in_month(FEBRUARY) = 29;
//                }
        for(i = 1; day >= MonthDay[leapyear(tm->tm_year)][i-1]; i++)
        {
                day -= MonthDay[leapyear(tm->tm_year)][i-1];
        }
//                days_in_month(FEBRUARY) = 28;
        tm->tm_mon = i;

        /* Days are what is left over (+1) from all that. *//*计算当前日期*/
        tm->tm_day = day + 1;

        /* Determine the day of week*/
        GregorianDay(tm);
}

/*===================================================================
名    称:Is_Leap_Year
功    能:
入口参数:uint16 year
出口参数:uint8 TRUE or FALSE
作    者:
  WebSite:www.elecbench.com
创建日期:2011-3-30 17:14:05
修改日期:
说    明:
===================================================================*/
BOOL Is_Leap_Year(u16 nyear)
{

    if ((nyear % 4 == 0 && nyear % 100 != 0 )|| (nyear % 400 == 0))
        return TRUE;
    return FALSE;
}

/*===================================================================
名    称:Caculate_Weekday
功    能:根据年月日获得星期
入口参数:系统日期结构体变量地址 &_system_date
出口参数:
作    者:
  WebSite:www.elecbench.com
创建日期:2011-3-30 17:14:01
修改日期:
说    明:
===================================================================*/
//        void Caculate_Weekday(DATE *p_date)
//        {
//            uint16 y;
//            uint8 m,d,c;
//                uint16 w;
//            y = p_date->year;
//            m = p_date->month;
//            d = p_date->day;
//                if(m==1) {m=13;y -= 1;}
//                if(m==2) {m=14;y -= 1;}
//                c = y / 100;
//                y %= 100;
//       
//                w = (y + y/4 + c/4 -2*c + (26*(m+1)/10) + d - 1)%7;
//                p_date->_weekday = (WEEKDAY)w;
//        }

/*===================================================================
名    称:Time_Add_Secd
功    能:系统日期时间刷新
入口参数:日期变量和时间变量地址
出口参数:
作    者:
  WebSite:www.elecbench.com
创建日期:2011-3-30 17:13:55
修改日期:
说    明:
===================================================================*/
void ap_time_add_sec(_strTime* pTime)
{
  if (++(*pTime).tm_sec > 59)
  {
    (*pTime).tm_sec = 0;        //此时(*p_time).secd已经等于60,可能导致显示60,可以考虑在这里关中断
    RefreshTime标志寄存器 = TRUE;  //置刷新待机界面标志
    if (++(*pTime).tm_min > 59)
    {
      (*pTime).tm_min = 0;
      if (++(*pTime).tm_hour > 23)
      {
        (*pTime).tm_hour = 0;
        if (++pTime->tm_day > MonthDay[leapyear(pTime->tm_year)][pTime->tm_mon-1])
        {
          pTime->tm_day = 1;
          if (++pTime->tm_mon > 12)
          {
            pTime->tm_mon = 1;
            pTime->tm_year++;
          }
        }
//                                        if (++pTime->_weekday > sat)
//                                        {
//                                                pTime->_weekday = sun;
//                                        }
      }
    }
  }
}


tiem.h文件:
#include "config.h"
#include "include.h"

typedef struct
{
        u16 tm_year;    //年
        u8  tm_mon;     //月
        u8  tm_day;   //日
        u8  tm_hour;     //小时
        u8  tm_min;      //分钟
        u8  tm_sec;      //秒
        u8  tm_wday;   //星期
}_strTime;
   
u32 ap_time_date2sec(_strTime *tm);
void ap_time_sec2date(u32 tim, _strTime * tm);
void ap_time_add_sec(_strTime* pTime);

相关帖子

沙发
xyz549040622| | 2012-6-19 08:17 | 只看该作者
顶,有空测试下

使用特权

评论回复
板凳
gdmgb520|  楼主 | 2012-6-19 09:27 | 只看该作者
呵呵,要找这么个可靠的程序真的是不容易。
哇哦在网上找了好几个版本,首先要自己看明白,觉得没有逻辑问题,然后还要实际测试能通过。
发现一些错误,我已经做了修改。大家有空也试试。
这个可以收藏,呵呵,以备不时之需;P

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:了解新东西才知道自己的不足。 www.elecbench.com

67

主题

452

帖子

1

粉丝