1*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 2*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * (C) Copyright 2001 3*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 5*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * See file CREDITS for list of people who contributed to this 6*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * project. 7*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 8*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * This program is free software; you can redistribute it and/or 9*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * modify it under the terms of the GNU General Public License as 10*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * published by the Free Software Foundation; either version 2 of 11*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * the License, or (at your option) any later version. 12*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 13*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * This program is distributed in the hope that it will be useful, 14*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * but WITHOUT ANY WARRANTY; without even the implied warranty of 15*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * GNU General Public License for more details. 17*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 18*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * You should have received a copy of the GNU General Public License 19*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * along with this program; if not, write to the Free Software 20*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 21*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * MA 02111-1307 USA 22*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 23*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 24*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 25*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Date & Time support for Philips PCF8563 RTC 26*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 27*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 28*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <common.h> 29*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <command.h> 30*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <rtc.h> 31*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 32*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP) 33*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 34*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define FEBRUARY 2 35*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define STARTOFTIME 1970 36*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define SECDAY 86400L 37*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define SECYR (SECDAY * 365) 38*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define leapyear(year) ((year) % 4 == 0) 39*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define days_in_year(a) (leapyear(a) ? 366 : 365) 40*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #define days_in_month(a) (month_days[(a) - 1]) 41*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 42*0c698dcaSJean-Christophe PLAGNIOL-VILLARD static int month_days[12] = { 43*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 44*0c698dcaSJean-Christophe PLAGNIOL-VILLARD }; 45*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 46*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 47*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) 48*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 49*0c698dcaSJean-Christophe PLAGNIOL-VILLARD void GregorianDay(struct rtc_time * tm) 50*0c698dcaSJean-Christophe PLAGNIOL-VILLARD { 51*0c698dcaSJean-Christophe PLAGNIOL-VILLARD int leapsToDate; 52*0c698dcaSJean-Christophe PLAGNIOL-VILLARD int lastYear; 53*0c698dcaSJean-Christophe PLAGNIOL-VILLARD int day; 54*0c698dcaSJean-Christophe PLAGNIOL-VILLARD int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 }; 55*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 56*0c698dcaSJean-Christophe PLAGNIOL-VILLARD lastYear=tm->tm_year-1; 57*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 58*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 59*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Number of leap corrections to apply up to end of last year 60*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 61*0c698dcaSJean-Christophe PLAGNIOL-VILLARD leapsToDate = lastYear/4 - lastYear/100 + lastYear/400; 62*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 63*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 64*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * This year is a leap year if it is divisible by 4 except when it is 65*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * divisible by 100 unless it is divisible by 400 66*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 67*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be 68*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 69*0c698dcaSJean-Christophe PLAGNIOL-VILLARD if((tm->tm_year%4==0) && 70*0c698dcaSJean-Christophe PLAGNIOL-VILLARD ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && 71*0c698dcaSJean-Christophe PLAGNIOL-VILLARD (tm->tm_mon>2)) { 72*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 73*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * We are past Feb. 29 in a leap year 74*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 75*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day=1; 76*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } else { 77*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day=0; 78*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 79*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 80*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; 81*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 82*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_wday=day%7; 83*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 84*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 85*0c698dcaSJean-Christophe PLAGNIOL-VILLARD void to_tm(int tim, struct rtc_time * tm) 86*0c698dcaSJean-Christophe PLAGNIOL-VILLARD { 87*0c698dcaSJean-Christophe PLAGNIOL-VILLARD register int i; 88*0c698dcaSJean-Christophe PLAGNIOL-VILLARD register long hms, day; 89*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 90*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day = tim / SECDAY; 91*0c698dcaSJean-Christophe PLAGNIOL-VILLARD hms = tim % SECDAY; 92*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 93*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Hours, minutes, seconds are easy */ 94*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_hour = hms / 3600; 95*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_min = (hms % 3600) / 60; 96*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_sec = (hms % 3600) % 60; 97*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 98*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Number of years in days */ 99*0c698dcaSJean-Christophe PLAGNIOL-VILLARD for (i = STARTOFTIME; day >= days_in_year(i); i++) { 100*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day -= days_in_year(i); 101*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 102*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_year = i; 103*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 104*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Number of months in days left */ 105*0c698dcaSJean-Christophe PLAGNIOL-VILLARD if (leapyear(tm->tm_year)) { 106*0c698dcaSJean-Christophe PLAGNIOL-VILLARD days_in_month(FEBRUARY) = 29; 107*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 108*0c698dcaSJean-Christophe PLAGNIOL-VILLARD for (i = 1; day >= days_in_month(i); i++) { 109*0c698dcaSJean-Christophe PLAGNIOL-VILLARD day -= days_in_month(i); 110*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 111*0c698dcaSJean-Christophe PLAGNIOL-VILLARD days_in_month(FEBRUARY) = 28; 112*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_mon = i; 113*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 114*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Days are what is left over (+1) from all that. */ 115*0c698dcaSJean-Christophe PLAGNIOL-VILLARD tm->tm_mday = day + 1; 116*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 117*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* 118*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Determine the day of week 119*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 120*0c698dcaSJean-Christophe PLAGNIOL-VILLARD GregorianDay(tm); 121*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 122*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 123*0c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Converts Gregorian date to seconds since 1970-01-01 00:00:00. 124*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 125*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. 126*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 127*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * [For the Julian calendar (which was used in Russia before 1917, 128*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * Britain & colonies before 1752, anywhere else before 1582, 129*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * and is still in use by some communities) leave out the 130*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * -year/100+year/400 terms, and add 10.] 131*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 132*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * This algorithm was first published by Gauss (I think). 133*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * 134*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * WARNING: this function will overflow on 2106-02-07 06:28:16 on 135*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * machines were long is 32-bit! (However, as time_t is signed, we 136*0c698dcaSJean-Christophe PLAGNIOL-VILLARD * will already get problems at other places on 2038-01-19 03:14:08) 137*0c698dcaSJean-Christophe PLAGNIOL-VILLARD */ 138*0c698dcaSJean-Christophe PLAGNIOL-VILLARD unsigned long 139*0c698dcaSJean-Christophe PLAGNIOL-VILLARD mktime (unsigned int year, unsigned int mon, 140*0c698dcaSJean-Christophe PLAGNIOL-VILLARD unsigned int day, unsigned int hour, 141*0c698dcaSJean-Christophe PLAGNIOL-VILLARD unsigned int min, unsigned int sec) 142*0c698dcaSJean-Christophe PLAGNIOL-VILLARD { 143*0c698dcaSJean-Christophe PLAGNIOL-VILLARD if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ 144*0c698dcaSJean-Christophe PLAGNIOL-VILLARD mon += 12; /* Puts Feb last since it has leap day */ 145*0c698dcaSJean-Christophe PLAGNIOL-VILLARD year -= 1; 146*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 147*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 148*0c698dcaSJean-Christophe PLAGNIOL-VILLARD return ((( 149*0c698dcaSJean-Christophe PLAGNIOL-VILLARD (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + 150*0c698dcaSJean-Christophe PLAGNIOL-VILLARD year*365 - 719499 151*0c698dcaSJean-Christophe PLAGNIOL-VILLARD )*24 + hour /* now have hours */ 152*0c698dcaSJean-Christophe PLAGNIOL-VILLARD )*60 + min /* now have minutes */ 153*0c698dcaSJean-Christophe PLAGNIOL-VILLARD )*60 + sec; /* finally seconds */ 154*0c698dcaSJean-Christophe PLAGNIOL-VILLARD } 155*0c698dcaSJean-Christophe PLAGNIOL-VILLARD 156*0c698dcaSJean-Christophe PLAGNIOL-VILLARD #endif 157