Commit 57f1f0874f426a9bdfc5cd3f886113dd5cd17834
Committed by
Linus Torvalds
1 parent
ef1ff6b8c0
Exists in
master
and in
4 other branches
time: add function to convert between calendar time and broken-down time for universal use
There are many similar code in kernel for one object: convert time between calendar time and broken-down time. Here is some source I found: fs/ncpfs/dir.c fs/smbfs/proc.c fs/fat/misc.c fs/udf/udftime.c fs/cifs/netmisc.c net/netfilter/xt_time.c drivers/scsi/ips.c drivers/input/misc/hp_sdc_rtc.c drivers/rtc/rtc-lib.c arch/ia64/hp/sim/boot/fw-emu.c arch/m68k/mac/misc.c arch/powerpc/kernel/time.c arch/parisc/include/asm/rtc.h ... We can make a common function for this type of conversion, At least we can get following benefit: 1: Make kernel simple and unify 2: Easy to fix bug in converting code 3: Reduce clone of code in future For example, I'm trying to make ftrace display walltime, this patch will make me easy. This code is based on code from glibc-2.6 Signed-off-by: Zhao Lei <zhaolei@cn.fujitsu.com> Cc: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@elte.hu> Cc: Pavel Machek <pavel@ucw.cz> Cc: Andi Kleen <andi@firstfloor.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 3 changed files with 156 additions and 1 deletions Side-by-side Diff
include/linux/time.h
... | ... | @@ -155,6 +155,34 @@ |
155 | 155 | struct tms; |
156 | 156 | extern void do_sys_times(struct tms *); |
157 | 157 | |
158 | +/* | |
159 | + * Similar to the struct tm in userspace <time.h>, but it needs to be here so | |
160 | + * that the kernel source is self contained. | |
161 | + */ | |
162 | +struct tm { | |
163 | + /* | |
164 | + * the number of seconds after the minute, normally in the range | |
165 | + * 0 to 59, but can be up to 60 to allow for leap seconds | |
166 | + */ | |
167 | + int tm_sec; | |
168 | + /* the number of minutes after the hour, in the range 0 to 59*/ | |
169 | + int tm_min; | |
170 | + /* the number of hours past midnight, in the range 0 to 23 */ | |
171 | + int tm_hour; | |
172 | + /* the day of the month, in the range 1 to 31 */ | |
173 | + int tm_mday; | |
174 | + /* the number of months since January, in the range 0 to 11 */ | |
175 | + int tm_mon; | |
176 | + /* the number of years since 1900 */ | |
177 | + long tm_year; | |
178 | + /* the number of days since Sunday, in the range 0 to 6 */ | |
179 | + int tm_wday; | |
180 | + /* the number of days since January 1, in the range 0 to 365 */ | |
181 | + int tm_yday; | |
182 | +}; | |
183 | + | |
184 | +void time_to_tm(time_t totalsecs, int offset, struct tm *result); | |
185 | + | |
158 | 186 | /** |
159 | 187 | * timespec_to_ns - Convert timespec to nanoseconds |
160 | 188 | * @ts: pointer to the timespec variable to be converted |
kernel/time/Makefile
kernel/time/timeconv.c
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 | + 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 | + 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 | +static long leaps_between(long y1, long y2) | |
50 | +{ | |
51 | + long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) | |
52 | + + math_div(y1 - 1, 400); | |
53 | + long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) | |
54 | + + math_div(y2 - 1, 400); | |
55 | + 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 | +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 | + days = totalsecs / SECS_PER_DAY; | |
83 | + rem = totalsecs % SECS_PER_DAY; | |
84 | + rem += offset; | |
85 | + while (rem < 0) { | |
86 | + rem += SECS_PER_DAY; | |
87 | + --days; | |
88 | + } | |
89 | + while (rem >= SECS_PER_DAY) { | |
90 | + rem -= SECS_PER_DAY; | |
91 | + ++days; | |
92 | + } | |
93 | + | |
94 | + result->tm_hour = rem / SECS_PER_HOUR; | |
95 | + rem %= SECS_PER_HOUR; | |
96 | + result->tm_min = rem / 60; | |
97 | + result->tm_sec = rem % 60; | |
98 | + | |
99 | + /* January 1, 1970 was a Thursday. */ | |
100 | + result->tm_wday = (4 + days) % 7; | |
101 | + if (result->tm_wday < 0) | |
102 | + result->tm_wday += 7; | |
103 | + | |
104 | + y = 1970; | |
105 | + | |
106 | + while (days < 0 || days >= (__isleap(y) ? 366 : 365)) { | |
107 | + /* Guess a corrected year, assuming 365 days per year. */ | |
108 | + long yg = y + math_div(days, 365); | |
109 | + | |
110 | + /* Adjust DAYS and Y to match the guessed year. */ | |
111 | + days -= (yg - y) * 365 + leaps_between(y, yg); | |
112 | + y = yg; | |
113 | + } | |
114 | + | |
115 | + result->tm_year = y - 1900; | |
116 | + | |
117 | + result->tm_yday = days; | |
118 | + | |
119 | + ip = __mon_yday[__isleap(y)]; | |
120 | + for (y = 11; days < ip[y]; y--) | |
121 | + continue; | |
122 | + days -= ip[y]; | |
123 | + | |
124 | + result->tm_mon = y; | |
125 | + result->tm_mday = days + 1; | |
126 | +} | |
127 | +EXPORT_SYMBOL(time_to_tm); |