offtime.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /* Copyright (C) 1991, 1993, 1997, 1998, 2002 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. The GNU C Library is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public
  5. License as published by the Free Software Foundation; either
  6. version 2.1 of the License, or (at your option) any later version.
  7. The GNU C Library is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public
  12. License along with the GNU C Library; if not, write to the Free
  13. Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  14. 02111-1307 USA. */
  15. /******************************************************************************
  16. 版权所有:
  17. 文件名称: offtime.c
  18. 文件版本: 01.01
  19. 创建作者: sunxi
  20. 创建日期: 2010-05-06
  21. 功能说明: 时间格式转化。
  22. 其它说明: 原始文件来自gcc\glibc-2.6\time\offtime.c
  23. 修改记录:
  24. */
  25. /*------------------------------- 头文件 --------------------------------------
  26. */
  27. //#include <linux/time.h>
  28. #include "head.h"
  29. /*------------------------------- 宏定义 --------------------------------------
  30. */
  31. /* Nonzero if YEAR is a leap year (every 4 years,
  32. except every 100th isn't, and every 400th is). */
  33. # define __isleap(year) ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
  34. #define SECS_PER_HOUR (60 * 60)
  35. #define SECS_PER_DAY (SECS_PER_HOUR * 24)
  36. /*------------------------------ 类型结构 -------------------------------------
  37. */
  38. /*------------------------------ 全局变量 -------------------------------------
  39. */
  40. /* How many days come before each month (0-12). */
  41. const unsigned short int __mon_yday[2][13] =
  42. {
  43. /* Normal years. */
  44. { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
  45. /* Leap years. */
  46. { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
  47. };
  48. /*------------------------------ 函数声明 -------------------------------------
  49. */
  50. uint32_t
  51. _mktime(const unsigned int year0, const unsigned int mon0,
  52. const unsigned int day, const unsigned int hour,
  53. const unsigned int min, const unsigned int sec);
  54. /*------------------------------ 外部函数 -------------------------------------
  55. 外部函数供其它实体文件引用,必须仔细检查传入参数的合法性.
  56. */
  57. /******************************************************************************
  58. 函数名称: rtc_to_timespec
  59. 函数版本: v1.00
  60. 创建作者: 杨海涛
  61. 创建日期: 2011-2-22
  62. 函数说明: 将rtc_time_t结构的数据转换为timespec格式
  63. 参数说明:
  64. p_ts: 输出的timespec结构的时间
  65. p_rtc: 输入的rtc_time_t结构的时间
  66. 返回值:
  67. 0: 成功
  68. -1: 失败
  69. 修改记录:
  70. */
  71. int rtc_to_timespec(struct rtc_time_t * p_rtc, struct timespec * p_ts)
  72. {
  73. #if 1
  74. if(check_rtc(p_rtc)!= true)
  75. {
  76. return -1;
  77. }
  78. #else
  79. if(p_rtc->month > 12 || p_rtc->day > 31 || p_rtc->hour > 24 || p_rtc->min > 60 || p_rtc->ms > 60000)
  80. {
  81. return -1;
  82. }
  83. #endif
  84. //将系统时间转换为timespec格式
  85. p_ts->tv_sec = _mktime(p_rtc->year + 2000, p_rtc->month, p_rtc->day, p_rtc->hour, p_rtc->min, (p_rtc->ms)/1000);
  86. p_ts->tv_nsec = p_rtc->ms%1000*1000000;
  87. //RTC和GPS中的时间是北京时间(东8区),我们需要将其调整为UTC时间。
  88. //p_ts->tv_sec -= 8*60*60;
  89. return 0;
  90. }
  91. /******************************************************************************
  92. 函数名称: timespec_to_rtc
  93. 函数版本: 01.01
  94. 创建作者: sunxi
  95. 创建日期: 2008-11-04
  96. 函数说明: 将timespec结构的数据转换为rtc_time_t格式
  97. 参数说明:
  98. ts: 输入的timespec结构的时间
  99. p_rtc: 输出的rtc_time_t结构的时间
  100. is_round: 是否需要四舍五入到ms
  101. 返回值:
  102. 0: 成功
  103. 其它: 失败
  104. 修改记录:
  105. 2015-5-14: sunxi 增加is_round参数。当只需要ms精度时,应该设置为1,使ms的精度更高;
  106. 如果需要此函数的结果和ts中ns组成更高精度的时间记录,应设置为0,且使用ns时,
  107. 也不应该进行四舍五入操作,否则将导致组合出来的时间不正确。(是否难以理解?直接问我好了!)
  108. */
  109. int timespec_to_rtc(struct timespec ts, struct rtc_time_t * p_rtc,int is_round)
  110. {
  111. long int days, rem, y;
  112. const unsigned short int *ip;
  113. if(p_rtc == 0)
  114. {
  115. return -1;
  116. }
  117. if ((uint32_t)ts.tv_nsec >= NSEC_PER_SEC)
  118. {
  119. memset(p_rtc,0,sizeof(*p_rtc));
  120. return -2;
  121. }
  122. // 根据是否需要四舍五入对ms进行处理
  123. if(is_round)
  124. {
  125. ts.tv_nsec += NSEC_PER_MSEC/2;
  126. if(ts.tv_nsec >= NSEC_PER_SEC)
  127. {
  128. ts.tv_nsec -= NSEC_PER_SEC;
  129. ts.tv_sec++;
  130. }
  131. }
  132. //以日期为界,分开算
  133. days = ts.tv_sec/ SECS_PER_DAY;
  134. rem = ts.tv_sec % SECS_PER_DAY;
  135. //得到时分秒
  136. p_rtc->hour = rem / SECS_PER_HOUR;
  137. rem %= SECS_PER_HOUR;
  138. p_rtc->min= rem / 60;
  139. // ms,前面已作四舍五入处理
  140. p_rtc->ms = rem % 60*MSEC_PER_SEC + ts.tv_nsec/NSEC_PER_MSEC;
  141. #define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
  142. #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
  143. //算年
  144. //这个算法有点意思,一下子没有看懂,下次再看
  145. y = 1970; //UTC
  146. while (days < 0 || days >= (__isleap (y) ? 366 : 365))
  147. {
  148. /* Guess a corrected year, assuming 365 days per year. */
  149. long int yg = y + days / 365 - (days % 365 < 0);
  150. /* Adjust DAYS and Y to match the guessed year. */
  151. days -= ((yg - y) * 365
  152. + LEAPS_THRU_END_OF (yg - 1)
  153. - LEAPS_THRU_END_OF (y - 1));
  154. y = yg;
  155. }
  156. //rtc_time_t中的年从2000年起
  157. p_rtc->year = y - 2000;
  158. if (p_rtc->year != y - 2000)
  159. {
  160. /* The year cannot be represented due to overflow. */
  161. memset(p_rtc,0,sizeof(*p_rtc));
  162. return -3;
  163. }
  164. //得到月日
  165. ip = __mon_yday[__isleap(y)];
  166. for (y = 11; days < (long int) ip[y]; --y)
  167. continue;
  168. days -= ip[y];
  169. //rtc_time_t中month是1~12
  170. //p_rtc->month = y;
  171. p_rtc->month = y + 1;
  172. p_rtc->day = days + 1;
  173. return 0;
  174. }
  175. int timespec_to_rtchms(struct timespec ts, struct rtc_time_t * p_rtc,int is_round)
  176. {
  177. long int rem;
  178. if(p_rtc == 0)
  179. {
  180. return -1;
  181. }
  182. if ((uint32_t)ts.tv_nsec >= NSEC_PER_SEC)
  183. {
  184. memset(p_rtc,0,sizeof(*p_rtc));
  185. return -2;
  186. }
  187. // 根据是否需要四舍五入对ms进行处理
  188. if(is_round)
  189. {
  190. ts.tv_nsec += NSEC_PER_MSEC/2;
  191. if(ts.tv_nsec >= NSEC_PER_SEC)
  192. {
  193. ts.tv_nsec -= NSEC_PER_SEC;
  194. ts.tv_sec++;
  195. }
  196. }
  197. //以日期为界,分开算
  198. rem = ts.tv_sec % SECS_PER_DAY;
  199. //得到时分秒
  200. p_rtc->hour = rem / SECS_PER_HOUR;
  201. rem %= SECS_PER_HOUR;
  202. p_rtc->min= rem / 60;
  203. // ms,前面已作四舍五入处理
  204. p_rtc->ms = rem % 60*MSEC_PER_SEC + ts.tv_nsec/NSEC_PER_MSEC;
  205. return 0;
  206. }
  207. uint32_t mktimehms(const unsigned int hour,
  208. const unsigned int min, const unsigned int sec)
  209. {
  210. return (uint32_t)((hour*60 + min)*60 + sec); /* finally seconds */
  211. }
  212. int check_rtc(struct rtc_time_t *pct)
  213. {
  214. //时间有效检查
  215. if(pct->year>99) return false;
  216. if(pct->month>12||pct->month<1) return false;
  217. if(pct->day>31||pct->day<1)return false;
  218. if(pct->hour>23)return false;
  219. if(pct->min>59) return false;
  220. if(pct->ms>=60000) return false;
  221. if(pct->month==2) // 2月特殊处理
  222. {
  223. unsigned short year=pct->year+2000;
  224. if(year%4==0) //闰年
  225. {
  226. if(pct->day>29)return false;
  227. }
  228. else
  229. {
  230. if(pct->day>28)return false;
  231. }
  232. }
  233. if(pct->month==4||pct->month==6||pct->month==9||pct->month==11)
  234. {
  235. if(pct->day>30)
  236. {
  237. return false;
  238. }
  239. }
  240. return true;
  241. }
  242. /*------------------------------ 内部函数 -------------------------------------
  243. 内部函数以下划线‘_’开头,不需要检查参数的合法性.
  244. */
  245. /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
  246. * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
  247. * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
  248. *
  249. * [For the Julian calendar (which was used in Russia before 1917,
  250. * Britain & colonies before 1752, anywhere else before 1582,
  251. * and is still in use by some communities) leave out the
  252. * -year/100+year/400 terms, and add 10.]
  253. *
  254. * This algorithm was first published by Gauss (I think).
  255. *
  256. * WARNING: this function will overflow on 2106-02-07 06:28:16 on
  257. * machines where long is 32-bit! (However, as time_t is signed, we
  258. * will already get problems at other places on 2038-01-19 03:14:08)
  259. */
  260. // 本函数来自Linux内核
  261. uint32_t
  262. _mktime(const unsigned int year0, const unsigned int mon0,
  263. const unsigned int day, const unsigned int hour,
  264. const unsigned int min, const unsigned int sec)
  265. {
  266. unsigned int mon = mon0, year = year0;
  267. /* 1..12 -> 11,12,1..10 */
  268. if (0 >= (int) (mon -= 2)) {
  269. mon += 12; /* Puts Feb last since it has leap day */
  270. year -= 1;
  271. }
  272. return ((((uint32_t)
  273. (year/4 - year/100 + year/400 + 367*mon/12 + day) +
  274. year*365 - 719499
  275. )*24 + hour /* now have hours */
  276. )*60 + min /* now have minutes */
  277. )*60 + sec; /* finally seconds */
  278. }
  279. /*------------------------------ 测试函数 -------------------------------------
  280. 一个实体文件必须带一个本模块的测试函数来进行单元测试,如果的确不方便在本模块中
  281. 进行单元测试,必须在此注明实际的测试位置(例如在哪个实体文件中使用哪个测试函数).
  282. */
  283. /*------------------------------ 文件结束 -------------------------------------
  284. */