Applied patch by Julun: time computations based on an algorithm by Fliegel,

and van Flandern (1968), instead of those inefficient loops we had before.
Thanks!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22557 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-10-14 17:27:44 +00:00
parent d5fb5794c6
commit 6a0f39da22
3 changed files with 44 additions and 112 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2006-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved. * Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved.
* *
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
@ -13,7 +13,7 @@
#include <time.h> #include <time.h>
#define RTC_EPOCHE_BASE_YEAR 1970 #define RTC_EPOCH_BASE_YEAR 1970
typedef struct rtc_info { typedef struct rtc_info {
uint32 time; uint32 time;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2005, Axel Dörfler, axeld@pinc-software.de * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de
* Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved. * Copyright 2003, Jeff Ward, jeff@r2d2.stcloudstate.edu. All rights reserved.
* *
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
@ -141,7 +141,7 @@ cmos_to_secs(const cmos_time *cmos)
{ {
struct tm t; struct tm t;
t.tm_year = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year) t.tm_year = bcd_to_int(cmos->century) * 100 + bcd_to_int(cmos->year)
- RTC_EPOCHE_BASE_YEAR; - RTC_EPOCH_BASE_YEAR;
t.tm_mon = bcd_to_int(cmos->month) - 1; t.tm_mon = bcd_to_int(cmos->month) - 1;
t.tm_mday = bcd_to_int(cmos->day); t.tm_mday = bcd_to_int(cmos->day);
t.tm_hour = bcd_to_int(cmos->hour); t.tm_hour = bcd_to_int(cmos->hour);
@ -160,7 +160,7 @@ secs_to_cmos(uint32 seconds, cmos_time *cmos)
struct tm t; struct tm t;
rtc_secs_to_tm(seconds, &t); rtc_secs_to_tm(seconds, &t);
wholeYear = t.tm_year + RTC_EPOCHE_BASE_YEAR; wholeYear = t.tm_year + RTC_EPOCH_BASE_YEAR;
cmos->century = int_to_bcd(wholeYear / 100); cmos->century = int_to_bcd(wholeYear / 100);
cmos->year = int_to_bcd(wholeYear % 100); cmos->year = int_to_bcd(wholeYear % 100);

View File

@ -23,6 +23,10 @@
#endif #endif
#define RTC_SECONDS_DAY 86400
#define RTC_EPOCH_JULIAN_DAY 2440588
// January 1st, 1970
static struct real_time_data *sRealTimeData; static struct real_time_data *sRealTimeData;
static bool sIsGMT = false; static bool sIsGMT = false;
static char sTimezoneFilename[B_PATH_NAME_LENGTH] = ""; static char sTimezoneFilename[B_PATH_NAME_LENGTH] = "";
@ -161,130 +165,58 @@ get_rtc_info(rtc_info *info)
// #pragma mark - // #pragma mark -
#define SECONDS_31 2678400 /*! Converts the \a tm data to seconds. Note that the base year is not
#define SECONDS_30 2592000 1900 as in POSIX, but 1970.
#define SECONDS_28 2419200 */
#define SECONDS_DAY 86400
static uint32 sSecsPerMonth[12] = {SECONDS_31, SECONDS_28, SECONDS_31, SECONDS_30,
SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_31, SECONDS_30, SECONDS_31, SECONDS_30,
SECONDS_31};
static bool
leap_year(uint32 year)
{
if (year % 400 == 0)
return true;
if (year % 100 == 0)
return false;
if (year % 4 == 0)
return true;
return false;
}
static inline uint32
secs_this_year(uint32 year)
{
if (leap_year(year))
return 31622400;
return 31536000;
}
uint32 uint32
rtc_tm_to_secs(const struct tm *t) rtc_tm_to_secs(const struct tm *tm)
{ {
uint32 wholeYear; uint32 days;
uint32 time = 0; int year, month;
uint32 i;
wholeYear = RTC_EPOCHE_BASE_YEAR + t->tm_year; month = tm->tm_mon + 1;
year = tm->tm_year + RTC_EPOCH_BASE_YEAR;
// ToDo: get rid of these loops and compute the correct value // Reference: Fliegel, H. F. and van Flandern, T. C. (1968).
// i.e. days = (long)(year > 0) + year*365 + --year/4 - year/100 + year/400; // Communications of the ACM, Vol. 11, No. 10 (October, 1968).
// let sSecsPerMonth[] have the values already added up days = tm->tm_mday - 32075 - RTC_EPOCH_JULIAN_DAY
+ 1461 * (year + 4800 + (month - 14) / 12) / 4
+ 367 * (month - 2 - 12 * ((month - 14) / 12)) / 12
- 3 * ((year + 4900 + (month - 14) / 12) / 100) / 4;
// Add up the seconds from all years since 1970 that have elapsed. return days * RTC_SECONDS_DAY + tm->tm_hour * 3600 + tm->tm_min * 60
for (i = RTC_EPOCHE_BASE_YEAR; i < wholeYear; ++i) { + tm->tm_sec;
time += secs_this_year(i);
}
// Add up the seconds from all months passed this year.
for (i = 0; i < t->tm_mon && i < 12; ++i)
time += sSecsPerMonth[i];
// Add up the seconds from all days passed this month.
if (leap_year(wholeYear) && t->tm_mon >= 2)
time += SECONDS_DAY;
time += (t->tm_mday - 1) * SECONDS_DAY;
time += t->tm_hour * 3600;
time += t->tm_min * 60;
time += t->tm_sec;
return time;
} }
void void
rtc_secs_to_tm(uint32 seconds, struct tm *t) rtc_secs_to_tm(uint32 seconds, struct tm *t)
{ {
uint32 wholeYear = RTC_EPOCHE_BASE_YEAR; uint32 year, month, day, l, n;
uint32 secsThisYear;
bool keepLooping;
bool isLeapYear;
int temp;
int month;
keepLooping = 1; // Reference: Fliegel, H. F. and van Flandern, T. C. (1968).
// Communications of the ACM, Vol. 11, No. 10 (October, 1968).
l = seconds / 86400 + 68569 + RTC_EPOCH_JULIAN_DAY;
n = 4 * l / 146097;
l = l - (146097 * n + 3) / 4;
year = 4000 * (l + 1) / 1461001;
l = l - 1461 * year / 4 + 31;
month = 80 * l / 2447;
day = l - 2447 * month / 80;
l = month / 11;
month = month + 2 - 12 * l;
year = 100 * (n - 49) + year + l;
// Determine the current year by starting at 1970 and incrementing whole_year as long as t->tm_mday = day;
// we can keep subtracting secs_this_year from seconds. t->tm_mon = month - 1;
while (keepLooping) { t->tm_year = year - RTC_EPOCH_BASE_YEAR;
secsThisYear = secs_this_year(wholeYear);
if (seconds >= secsThisYear) {
seconds -= secsThisYear;
++wholeYear;
} else
keepLooping = false;
}
t->tm_year = wholeYear - RTC_EPOCHE_BASE_YEAR;
// Determine the current month
month = 0;
isLeapYear = leap_year(wholeYear);
do {
temp = seconds - sSecsPerMonth[month];
if (isLeapYear && month == 1)
temp -= SECONDS_DAY;
if (temp >= 0) {
seconds = temp;
++month;
}
} while (temp >= 0 && month < 12);
t->tm_mon = month;
t->tm_mday = seconds / SECONDS_DAY + 1;
seconds = seconds % SECONDS_DAY;
seconds = seconds % RTC_SECONDS_DAY;
t->tm_hour = seconds / 3600; t->tm_hour = seconds / 3600;
seconds = seconds % 3600; seconds = seconds % 3600;
t->tm_min = seconds / 60; t->tm_min = seconds / 60;
seconds = seconds % 60; t->tm_sec = seconds % 60;
t->tm_sec = seconds;
} }