--- tai_cal.c 2003/03/23 18:00:29 1.2
+++ tai_cal.c 2005/01/24 11:04:07 1.3
@@ -30,60 +30,7 @@
#include "tai.h"
#include "tai_p.h"
-
-#if 0
-struct leap {
- tai_ui64_t leapsec;
-} tai_tab_leapsec[] = {
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1972 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1972 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1973 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1974 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1975 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1976 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1977 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1978 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1979 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1981 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1982 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1983 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1985 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1987 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1989 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1990 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1992 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1993 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1994 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1995 Dec 31 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* 1997 Jun 30 23:59:60 + */
- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* 1998 Dec 31 23:59:60 + */
-};
-#endif
-
-#define TAI_CAL_SUNDAY 0
-#define TAI_CAL_MONDAY 1
-#define TAI_CAL_TUESDAY 2
-#define TAI_CAL_WEDNESDAY 3
-#define TAI_CAL_THURSDAY 4
-#define TAI_CAL_FRIDAY 5
-#define TAI_CAL_SATURDAY 6
-
-#define TAI_CAL_JANUARY 0
-#define TAI_CAL_FEBRUARY 1
-#define TAI_CAL_MARCH 2
-#define TAI_CAL_APRIL 3
-#define TAI_CAL_MAY 4
-#define TAI_CAL_JUNE 5
-#define TAI_CAL_JULY 6
-#define TAI_CAL_AUGUST 7
-#define TAI_CAL_SEPTEMBER 8
-#define TAI_CAL_OCTOBER 9
-#define TAI_CAL_NOVEMBER 10
-#define TAI_CAL_DECEMBER 11
-
-#define TAI_EPOCH "9223372036854775808" /* 2^62 / 2 (=2^63) meaning 1972-01-01 00:00:00 UTC was 1972-01-01 00:00:10 TAI */
-#define TAI_EPOCH_YEAR 1970
-#define TAI_EPOCH_WDAY TAI_CAL_THURSDAY
+#include "tai_cal.h"
/* the Gregorian calendar */
#define TAI_CAL_SECS_PER_MIN 60
@@ -96,59 +43,181 @@
#define TAI_CAL_SECS_PER_DAY (TAI_CAL_SECS_PER_HOUR * TAI_CAL_HOURS_PER_DAY)
#define TAI_CAL_MONS_PER_YEAR 12
-#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+/* 2^64/2 (=2^63) meaning Thu 1972-01-01 00:00:00 UTC was Thu 1972-01-01 00:00:10 TAI */
+#define TAI_EPOCH_BASE "8000000000000000"
+#define TAI_EPOCH_YEAR 1970
+#define TAI_EPOCH_WDAY TAI_CAL_THURSDAY
+
+/* A year that has 366 days instead of 365 days, is a leap year,
+ February has 29 days instead of 28 in a leap year. Leap years fall on
+ any year that either can be evenly divisible by 4 and is not evenly
+ divisible by 100, or is evenly divisible by 400. For example, the
+ year 2000 is a leap year, but 1900 is not. */
+#define tai_cal_is_leap_year(y) \
+ (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
+#define tai_leapdays_between_years(y1,y2) \
+ ( ((y1) / 4 - (y1) / 100 + (y1) / 400) \
+ - ((y2) / 4 - (y2) / 100 + (y2) / 400))
+
+static const int tai_cal_mon_len[2][TAI_CAL_MONS_PER_YEAR] = {
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+};
-tai_rc_t tai_tai2cal(tai_t *tai, int offset)
+static const int tai_cal_year_len[2] = {
+ TAI_CAL_DAYS_PER_NYEAR,
+ TAI_CAL_DAYS_PER_LYEAR
+};
+
+struct tai_leapsec_st {
+ ui64_t trans;
+ int corr;
+} tai_tab_leapsec[] = {
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1972 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1972 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1973 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1974 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1975 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1976 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1977 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1978 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1979 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1981 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1982 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1983 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1985 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1987 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1989 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1990 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1992 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1993 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1994 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1995 Dec 31 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 }, /* 1997 Jun 30 23:59:60 */
+ { ui64_cons(00,00,00,00,00,00,00,00), 1 } /* 1998 Dec 31 23:59:60 */
+};
+
+tai_rc_t tai_tai2cal(const tai_t *tai, tai_cal_t *cal, long offset, int isdst)
{
- tai_ui64_t secs;
- tai_ui64_t days;
- tai_ui64_t rem;
- tai_ui64_t tmp;
- tai_ui64_t tmp2;
- int lshit;
+ ui64_t secs;
+ ui64_t days;
+ ui64_t rem;
+ ui64_t tmp;
+ ui64_t tmp2;
+ int ls_corr;
+ int ls_hit;
+ int cmp;
+ int yleap;
+ int year;
+ int dyear;
+ int ddays;
+ int i;
+ /* calculate (rounded) number of total seconds */
secs = tai->sec;
+ if (ui64_cmp(tai->asec, tai_half_sec_in_asec) > 0)
+ ui64_addn(secs, 1, NULL);
- /* perform leap second correction */
- lshit = 0; /* FIXME */
+ /* calculate involved leap seconds */
+ ls_corr = 0;
+ ls_hit = 0;
+ for (i = 0; i < (sizeof(tai_tab_leapsec)/sizeof(tai_tab_leapsec[0])); i++) {
+ cmp = ui64_cmp(secs, tai_tab_leapsec[i].trans);
+ if (cmp > 0)
+ break;
+ if (cmp == 0)
+ ls_hit = tai_tab_leapsec[i].corr;
+ ls_corr += tai_tab_leapsec[i].corr;
+ }
+ if (ls_corr > 0)
+ secs = ui64_addn(secs, ls_corr, NULL);
+ else
+ secs = ui64_subn(secs, -ls_corr, NULL);
/* perform timezone offset correction */
- secs = tai_ui64_addn(secs, offset, NULL);
+ if (offset > 0)
+ secs = ui64_addn(secs, offset, NULL);
+ else
+ secs = ui64_subn(secs, -offset, NULL);
+ cal->offs = offset;
+
+ /* perform Daylight Saving Time (DST) offset correction */
+ if (isdst)
+ secs = ui64_addn(secs, 1, NULL); /* FIXME */
+ cal->isdst = isdst;
/* days = secs / TAI_CAL_SECS_PER_DAY
rem = secs % TAI_CAL_SECS_PER_DAY */
- tmp = tai_ui64_n2i(TAI_CAL_SECS_PER_DAY);
- days = tai_ui64_div(secs, tmp, &rem);
+ tmp = ui64_n2i(TAI_CAL_SECS_PER_DAY);
+ days = ui64_div(secs, tmp, &rem);
/* hour = rem / TAI_CAL_SECS_PER_HOUR
rem = rem % TAI_CAL_SECS_PER_HOUR */
- tmp = tai_ui64_n2i(TAI_CAL_SECS_PER_HOUR);
- tmp = tai_ui64_div(rem, tmp, &rem);
- tai->tai_hour = (int)tai_ui64_i2n(tmp);
+ tmp = ui64_n2i(TAI_CAL_SECS_PER_HOUR);
+ tmp = ui64_div(rem, tmp, &rem);
+ cal->hour = (int)ui64_i2n(tmp);
/* min = rem / TAI_CAL_SECS_PER_MIN
rem = rem % TAI_CAL_SECS_PER_MIN */
- tmp = tai_ui64_n2i(TAI_CAL_SECS_PER_MIN);
- tmp = tai_ui64_div(rem, tmp, &rem);
- tai->tai_min = (int)tai_ui64_i2n(tmp);
+ tmp = ui64_n2i(TAI_CAL_SECS_PER_MIN);
+ tmp = ui64_div(rem, tmp, &rem);
+ cal->min = (int)ui64_i2n(tmp);
- /* sec = rem + lshit */
- tai->tai_sec = (int)tai_ui64_i2n(rem) + lshit;
+ /* sec = rem + ls_hit */
+ cal->sec = (int)ui64_i2n(rem) + ls_hit;
/* wday = (TAI_EPOCH_WDAY + days) % TAI_CAL_DAYS_PER_WEEK */
/* FIXME: TAI is not 0 on EPOCH */
- tmp = tai_ui64_addn(days, TAI_EPOCH_WDAY, NULL);
- tmp2 = tai_ui64_n2i(TAI_CAL_DAYS_PER_WEEK);
- tai_ui64_div(tmp, tmp2, &tmp);
- tai->tai_wday = (int)tai_ui64_i2n(tmp);
+ tmp = ui64_addn(days, TAI_EPOCH_WDAY, NULL);
+ tmp2 = ui64_n2i(TAI_CAL_DAYS_PER_WEEK);
+ ui64_div(tmp, tmp2, &tmp);
+ cal->wday = (int)ui64_i2n(tmp);
+
+ /* What about the -10 offset in 1972 (epoch)? */
+
+ /* calculate year */
+ epoch = ui64_s2i(TAI_EPOCH_BASE, NULL, 16);
+ epoch = ui64_divn(epoch, TAI_CAL_SECS_PER_DAY, NULL);
+ year = TAI_EPOCH_YEAR;
+ if (ui64_cmp(days, epoch) > 0) {
+ /* date after the epoch */
+ ui64_sub(days, epoch, &days);
+ dyear = ui64_i2n(ui64_div(days, ui64_n2i(TAI_CAL_DAYS_PER_NYEAR), NULL));
+ ddays = ui64_muln(ui64_n2i(dyear), TAI_CAL_DAYS_PER_NYEAR);
+ ddays = ui64_addn(ddays, tai_leapdays_between_years(year+dyear-1, year-1));
+ days = ui64_sub(days, ddays, NULL);
+ years += dyear;
+ }
+ else {
+ /* date before the epoch */
+ ui64_sub(epoch, days, &days);
+ dyear = ui64_i2n(ui64_div(days, ui64_n2i(TAI_CAL_DAYS_PER_NYEAR), NULL));
+ ddays = ui64_muln(ui64_n2i(dyear), TAI_CAL_DAYS_PER_NYEAR);
+ ddays = ui64_addn(ddays, tai_leapdays_between_years(year+dyear-1, year-1));
+ days = ui64_sub(days, ddays, NULL);
+ years -= dyear;
+ }
+ cal->year = year;
+
+ /* calculate day of the year */
+ cal->yday = ui64_i2n(days);
+
+ /* calculate month of the year */
+ cal->mon = 0;
+ while (days >= tai_cal_mon_len[yleap][cal->mon]) {
+ days = ui64_subn(days, tai_cal_mon_len[yleap][cal->mon], NULL);
+ cal->mon++;
+ }
+
+ /* calculate day of the month */
+ cal->mday = ui64_i2n(days) + 1;
- tai->tai_gmtoff = (long)offset;
-
return TAI_OK;
}
-tai_rc_t tai_cal2tai(tai_t *tai)
+tai_rc_t tai_cal2tai(tai_t *tai, const tai_cal_t *cal, long *offset, int *isdst)
{
+ /* FIXME: binary search with tai_tai2cal!! See mktime implementations!! */
return TAI_OK;
}
|