rtc-lib.c revision 73442daf2ea85e2a779396b76b1a39b10188ecb5
1c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
2c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * rtc and date/time utility functions
3c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
4c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Copyright (C) 2005-06 Tower Technologies
5c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it>
6c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
7c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * based on arch/arm/common/rtctime.c and other bits
8c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
9c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * This program is free software; you can redistribute it and/or modify
10c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * it under the terms of the GNU General Public License version 2 as
11c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * published by the Free Software Foundation.
12c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo*/
13c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
14c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#include <linux/module.h>
15c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#include <linux/rtc.h>
16c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
17c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummostatic const unsigned char rtc_days_in_month[] = {
18c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
19c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo};
20c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
218232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victorstatic const unsigned short rtc_ydays[2][13] = {
228232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	/* Normal years */
238232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
248232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	/* Leap years */
258232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
268232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor};
278232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor
28c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
29c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
30c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
318232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor/*
328232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor * The number of days in the month.
338232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor */
34c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_month_days(unsigned int month, unsigned int year)
35c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
36c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
37c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
38c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_month_days);
39c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
40c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
418232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor * The number of days since January 1. (0 to 365)
428232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor */
438232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victorint rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
448232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor{
458232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
468232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor}
478232212e0b4ee4eb3e407f5a9b098f6377820164Andrew VictorEXPORT_SYMBOL(rtc_year_days);
488232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor
498232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor/*
50c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
51c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
52c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummovoid rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
53c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
5473442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	unsigned int month, year;
5573442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	int days;
56c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
57c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	days = time / 86400;
5873442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	time -= (unsigned int) days * 86400;
59c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
60c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	/* day of the week, 1970-01-01 was a Thursday */
61c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_wday = (days + 4) % 7;
62c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
63c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	year = 1970 + days / 365;
64c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	days -= (year - 1970) * 365
65c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		+ LEAPS_THRU_END_OF(year - 1)
66c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		- LEAPS_THRU_END_OF(1970 - 1);
67c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	if (days < 0) {
68c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		year -= 1;
69c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		days += 365 + LEAP_YEAR(year);
70c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	}
71c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_year = year - 1900;
72c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_yday = days + 1;
73c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
74c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	for (month = 0; month < 11; month++) {
75c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		int newdays;
76c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
77c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		newdays = days - rtc_month_days(month, year);
78c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		if (newdays < 0)
79c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo			break;
80c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		days = newdays;
81c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	}
82c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_mon = month;
83c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_mday = days + 1;
84c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
85c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_hour = time / 3600;
86c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	time -= tm->tm_hour * 3600;
87c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_min = time / 60;
88c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_sec = time - tm->tm_min * 60;
89c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
90c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_time_to_tm);
91c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
92c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
93c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Does the rtc_time represent a valid date/time?
94c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
95c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_valid_tm(struct rtc_time *tm)
96c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
97c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	if (tm->tm_year < 70
98db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_mon) >= 12
99c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		|| tm->tm_mday < 1
100c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
101db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_hour) >= 24
102db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_min) >= 60
103db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_sec) >= 60)
104c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		return -EINVAL;
105c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
106c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	return 0;
107c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
108c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_valid_tm);
109c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
110c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
111c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
112c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
113c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
114c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
115c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
116c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo			tm->tm_hour, tm->tm_min, tm->tm_sec);
117c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	return 0;
118c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
119c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_tm_to_time);
120c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
121c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoMODULE_LICENSE("GPL");
122