0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/export.h>
0014 #include <linux/rtc.h>
0015
0016 static const unsigned char rtc_days_in_month[] = {
0017 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
0018 };
0019
0020 static const unsigned short rtc_ydays[2][13] = {
0021
0022 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
0023
0024 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
0025 };
0026
0027
0028
0029
0030 int rtc_month_days(unsigned int month, unsigned int year)
0031 {
0032 return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
0033 }
0034 EXPORT_SYMBOL(rtc_month_days);
0035
0036
0037
0038
0039 int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
0040 {
0041 return rtc_ydays[is_leap_year(year)][month] + day - 1;
0042 }
0043 EXPORT_SYMBOL(rtc_year_days);
0044
0045
0046
0047
0048
0049
0050
0051
0052 void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
0053 {
0054 unsigned int secs;
0055 int days;
0056
0057 u64 u64tmp;
0058 u32 u32tmp, udays, century, day_of_century, year_of_century, year,
0059 day_of_year, month, day;
0060 bool is_Jan_or_Feb, is_leap_year;
0061
0062
0063 days = div_s64_rem(time, 86400, &secs);
0064
0065
0066 tm->tm_wday = (days + 4) % 7;
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096 udays = ((u32) days) + 719468;
0097
0098 u32tmp = 4 * udays + 3;
0099 century = u32tmp / 146097;
0100 day_of_century = u32tmp % 146097 / 4;
0101
0102 u32tmp = 4 * day_of_century + 3;
0103 u64tmp = 2939745ULL * u32tmp;
0104 year_of_century = upper_32_bits(u64tmp);
0105 day_of_year = lower_32_bits(u64tmp) / 2939745 / 4;
0106
0107 year = 100 * century + year_of_century;
0108 is_leap_year = year_of_century != 0 ?
0109 year_of_century % 4 == 0 : century % 4 == 0;
0110
0111 u32tmp = 2141 * day_of_year + 132377;
0112 month = u32tmp >> 16;
0113 day = ((u16) u32tmp) / 2141;
0114
0115
0116
0117
0118
0119 is_Jan_or_Feb = day_of_year >= 306;
0120
0121
0122 year = year + is_Jan_or_Feb;
0123 month = is_Jan_or_Feb ? month - 12 : month;
0124 day = day + 1;
0125
0126 day_of_year = is_Jan_or_Feb ?
0127 day_of_year - 306 : day_of_year + 31 + 28 + is_leap_year;
0128
0129
0130 tm->tm_year = (int) (year - 1900);
0131 tm->tm_mon = (int) month;
0132 tm->tm_mday = (int) day;
0133 tm->tm_yday = (int) day_of_year + 1;
0134
0135 tm->tm_hour = secs / 3600;
0136 secs -= tm->tm_hour * 3600;
0137 tm->tm_min = secs / 60;
0138 tm->tm_sec = secs - tm->tm_min * 60;
0139
0140 tm->tm_isdst = 0;
0141 }
0142 EXPORT_SYMBOL(rtc_time64_to_tm);
0143
0144
0145
0146
0147 int rtc_valid_tm(struct rtc_time *tm)
0148 {
0149 if (tm->tm_year < 70 ||
0150 tm->tm_year > (INT_MAX - 1900) ||
0151 ((unsigned int)tm->tm_mon) >= 12 ||
0152 tm->tm_mday < 1 ||
0153 tm->tm_mday > rtc_month_days(tm->tm_mon,
0154 ((unsigned int)tm->tm_year + 1900)) ||
0155 ((unsigned int)tm->tm_hour) >= 24 ||
0156 ((unsigned int)tm->tm_min) >= 60 ||
0157 ((unsigned int)tm->tm_sec) >= 60)
0158 return -EINVAL;
0159
0160 return 0;
0161 }
0162 EXPORT_SYMBOL(rtc_valid_tm);
0163
0164
0165
0166
0167
0168 time64_t rtc_tm_to_time64(struct rtc_time *tm)
0169 {
0170 return mktime64(((unsigned int)tm->tm_year + 1900), tm->tm_mon + 1,
0171 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
0172 }
0173 EXPORT_SYMBOL(rtc_tm_to_time64);
0174
0175
0176
0177
0178 ktime_t rtc_tm_to_ktime(struct rtc_time tm)
0179 {
0180 return ktime_set(rtc_tm_to_time64(&tm), 0);
0181 }
0182 EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
0183
0184
0185
0186
0187 struct rtc_time rtc_ktime_to_tm(ktime_t kt)
0188 {
0189 struct timespec64 ts;
0190 struct rtc_time ret;
0191
0192 ts = ktime_to_timespec64(kt);
0193
0194 if (ts.tv_nsec)
0195 ts.tv_sec++;
0196 rtc_time64_to_tm(ts.tv_sec, &ret);
0197 return ret;
0198 }
0199 EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);