Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
3 : : * This file is part of the GNU C Library.
4 : : * Contributed by Paul Eggert (eggert@twinsun.com).
5 : : *
6 : : * The GNU C Library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Library General Public License as
8 : : * published by the Free Software Foundation; either version 2 of the
9 : : * License, or (at your option) any later version.
10 : : *
11 : : * The GNU C Library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Library General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Library General Public
17 : : * License along with the GNU C Library; see the file COPYING.LIB. If not,
18 : : * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 : : * Boston, MA 02111-1307, USA.
20 : : */
21 : :
22 : : /*
23 : : * Converts the calendar time to broken-down time representation
24 : : * Based on code from glibc-2.6
25 : : *
26 : : * 2009-7-14:
27 : : * Moved from glibc-2.6 to kernel by Zhaolei<zhaolei@cn.fujitsu.com>
28 : : */
29 : :
30 : : #include <linux/time.h>
31 : : #include <linux/module.h>
32 : :
33 : : /*
34 : : * Nonzero if YEAR is a leap year (every 4 years,
35 : : * except every 100th isn't, and every 400th is).
36 : : */
37 : : static int __isleap(long year)
38 : : {
39 [ # # ][ # # ]: 0 : return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0);
[ # # ][ # # ]
[ # # ][ # # ]
40 : : }
41 : :
42 : : /* do a mathdiv for long type */
43 : : static long math_div(long a, long b)
44 : : {
45 : 0 : return a / b - (a % b < 0);
46 : : }
47 : :
48 : : /* How many leap years between y1 and y2, y1 must less or equal to y2 */
49 : 0 : static long leaps_between(long y1, long y2)
50 : : {
51 : 0 : long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100)
52 : : + math_div(y1 - 1, 400);
53 : 0 : long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100)
54 : : + math_div(y2 - 1, 400);
55 : 0 : return leaps2 - leaps1;
56 : : }
57 : :
58 : : /* How many days come before each month (0-12). */
59 : : static const unsigned short __mon_yday[2][13] = {
60 : : /* Normal years. */
61 : : {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
62 : : /* Leap years. */
63 : : {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
64 : : };
65 : :
66 : : #define SECS_PER_HOUR (60 * 60)
67 : : #define SECS_PER_DAY (SECS_PER_HOUR * 24)
68 : :
69 : : /**
70 : : * time_to_tm - converts the calendar time to local broken-down time
71 : : *
72 : : * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970,
73 : : * Coordinated Universal Time (UTC).
74 : : * @offset offset seconds adding to totalsecs.
75 : : * @result pointer to struct tm variable to receive broken-down time
76 : : */
77 : 0 : void time_to_tm(time_t totalsecs, int offset, struct tm *result)
78 : : {
79 : : long days, rem, y;
80 : : const unsigned short *ip;
81 : :
82 : 0 : days = totalsecs / SECS_PER_DAY;
83 : 0 : rem = totalsecs % SECS_PER_DAY;
84 : 0 : rem += offset;
85 [ # # ]: 0 : while (rem < 0) {
86 : 0 : rem += SECS_PER_DAY;
87 : 0 : --days;
88 : : }
89 [ # # ]: 0 : while (rem >= SECS_PER_DAY) {
90 : 0 : rem -= SECS_PER_DAY;
91 : 0 : ++days;
92 : : }
93 : :
94 : 0 : result->tm_hour = rem / SECS_PER_HOUR;
95 : 0 : rem %= SECS_PER_HOUR;
96 : 0 : result->tm_min = rem / 60;
97 : 0 : result->tm_sec = rem % 60;
98 : :
99 : : /* January 1, 1970 was a Thursday. */
100 : 0 : result->tm_wday = (4 + days) % 7;
101 [ # # ]: 0 : if (result->tm_wday < 0)
102 : 0 : result->tm_wday += 7;
103 : :
104 : : y = 1970;
105 : :
106 [ # # ][ # # ]: 0 : while (days < 0 || days >= (__isleap(y) ? 366 : 365)) {
[ # # ]
107 : : /* Guess a corrected year, assuming 365 days per year. */
108 : 0 : long yg = y + math_div(days, 365);
109 : :
110 : : /* Adjust DAYS and Y to match the guessed year. */
111 : 0 : days -= (yg - y) * 365 + leaps_between(y, yg);
112 : : y = yg;
113 : : }
114 : :
115 : 0 : result->tm_year = y - 1900;
116 : :
117 : 0 : result->tm_yday = days;
118 : :
119 : 0 : ip = __mon_yday[__isleap(y)];
120 [ # # ]: 0 : for (y = 11; days < ip[y]; y--)
121 : 0 : continue;
122 : 0 : days -= ip[y];
123 : :
124 : 0 : result->tm_mon = y;
125 : 0 : result->tm_mday = days + 1;
126 : 0 : }
127 : : EXPORT_SYMBOL(time_to_tm);
|