From 7ff1228ff7e5b4e15780934f5c16262c58e18740 Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Thu, 16 Jul 2020 18:34:41 +0200 Subject: rewrite using own date routines using julian dates --- wcal.c | 151 +++++++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 90 insertions(+), 61 deletions(-) diff --git a/wcal.c b/wcal.c index 294002b..8ee635d 100644 --- a/wcal.c +++ b/wcal.c @@ -15,7 +15,6 @@ * -d YYYY-MM-DD different value for today */ -#define _XOPEN_SOURCE 700 #include #include #include @@ -24,33 +23,82 @@ int flag1, flag3, flagc, flagC, flagi, flagy; +const char monthname[13][4] = { + " ", + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +/* all args are 1-indexed */ +long +ymd2jd(int year, int month, int day) +{ + month--; + if (month >= 12 || month < 0) { + int adj = month / 12; + month %= 12; + if (month < 0) { + adj--; + month += 12; + } + year += adj; + } + month++; + + if (month < 3) { + year--; + month += 12; + } + year += 4800; + return day + (153*(month-3)+2)/5 + + 365*year + year/4 - year/100 + year/400 - 32045; +} + +/* Mon = 1, Sun = 7 */ +void +jd2ymdwi(long jd, int *year, int *month, int *day, int *wday, int *isoweek) +{ + int _; + long e = 4*(jd+1401+(4*jd+274277)/146097*3/4-38) + 3; + long h = e%1461/4*5 + 2; + + *day = h%153/5 + 1; + int m = *month = (h/153+2)%12 + 1; + int y = *year = e/1461 - 4716 + (14-m)/12; + int w = *wday = jd%7 + 1; + + int yday = jd - ymd2jd(y, 1, 1) + 1; + *isoweek = (yday - w + 10) / 7; + if (*isoweek < 1) + jd2ymdwi(ymd2jd(y - 1, 12, 31), &_, &_, &_, &_, isoweek); + else if (*isoweek == 53 && + ymd2jd(y+1, 1, 1) + (7 - (y+y/4-y/100+y/400+3)%7 - 4) <= jd) + *isoweek = 1; +} + void -parse_isodate(char *optarg, struct tm *tm) +parse_isodate(char *optarg, int *y, int *m, int *d) { - tm->tm_hour = tm->tm_min = tm->tm_sec = 0; - tm->tm_mday = 1; - tm->tm_mon = 0; + *m = *d = 1; if (isdigit(optarg[0]) && isdigit(optarg[1]) && isdigit(optarg[2]) && isdigit(optarg[3]) && (!optarg[4] || optarg[4] == '-')) { - tm->tm_year = atoi(optarg) - 1900; + *y = atoi(optarg); if (!optarg[4]) { flagy = 1; } else if (isdigit(optarg[5]) && isdigit(optarg[6]) && (!optarg[7] || optarg[7] == '-')) { - tm->tm_mon = atoi(optarg+5) - 1; + *m = atoi(optarg+5); if (isdigit(optarg[8]) && isdigit(optarg[9]) && (!optarg[10] || optarg[10] == '-')) - tm->tm_mday = atoi(optarg+8); + *d = atoi(optarg+8); } } - - mktime(tm); } int @@ -58,17 +106,12 @@ main(int argc, char *argv[]) { time_t now = time(0); struct tm *tm = localtime(&now); - struct tm tm2 = { - .tm_year = tm->tm_year, - .tm_mon = tm->tm_mon, - .tm_mday = tm->tm_mday - }; - setenv("TZ", "", 1); - tzset(); - - now = mktime(&tm2); - tm = gmtime(&now); + int y = tm->tm_year + 1900; + int m = tm->tm_mon + 1; + int d = tm->tm_mday; + int w; + int i; int c; while ((c = getopt(argc, argv, "13cCid:y")) != -1) @@ -79,14 +122,10 @@ main(int argc, char *argv[]) case 'C': flagC = 1; break; case 'y': flagy = 1; break; case 'i': flagi = 1; break; - case 'd': parse_isodate(optarg, tm); break; + case 'd': parse_isodate(optarg, &y, &m, &d); break; } - tm->tm_hour = tm->tm_min = tm->tm_sec = 0; - - int today_mday = tm->tm_mday; - int today_mon = tm->tm_mon; - int today_year = tm->tm_year; + long today = ymd2jd(y, m, d); int max_weeks = 1; int max_months = 0; @@ -94,21 +133,20 @@ main(int argc, char *argv[]) if (flagc) { max_weeks = 1; } else if (flag3) { - tm->tm_mday = 1; tm->tm_mon--; max_weeks = 14; + d = 1; m--; max_weeks = 14; } else if (flagy) { - tm->tm_mday = 1; tm->tm_mon = 0; max_months = 12; max_weeks = 53; - } else if (flagi) { - tm->tm_mday = 1; + d = 1; m = 1; max_months = 12; max_weeks = 53; + } else if (flagi) { + d = 1; } else { /* flag1 is default */ - tm->tm_mday = 1; max_months = 1; max_weeks = 6; + d = 1; max_months = 1; max_weeks = 6; } - mktime(tm); + long jd = ymd2jd(y, m, d); - while (tm->tm_wday != 1) { - tm->tm_mday--; - mktime(tm); - } + jd2ymdwi(jd, &y, &m, &d, &w, &i); + jd -= (w - 1); // skip back to last monday. + jd2ymdwi(jd, &y, &m, &d, &w, &i); int color = isatty(1) || flagC; @@ -119,38 +157,29 @@ main(int argc, char *argv[]) for (int weeks = 0, months = 0; flagi || (max_months && months < max_months) || (weeks < max_weeks); weeks++) { - char buf[8]; - strftime(buf, sizeof buf, "%V", tm); - printf("%s ", buf); - - tm->tm_mday += 6; - mktime(tm); - if (tm->tm_mday <= 7 || weeks == 0) { - strftime(buf, sizeof buf, "%b", tm); - printf("%s ", buf); + printf("%02d ", i); + + int ey, em, ed, ew, ei; + jd2ymdwi(jd + 6, &ey, &em, &ed, &ew, &ei); /* end of week */ + + if (ed <= 7 || weeks == 0) { + printf("%s ", monthname[em]); months++; - } else if ((tm->tm_mon == 0 && tm->tm_yday < 14) || weeks == 1) { - printf("%04d", tm->tm_year + 1900); + } else if ((em == 1 && ed <= 14) || weeks == 1) { + printf("%04d", ey); } else { printf(" "); } - tm->tm_mday -= 6; - mktime(tm); - - for (int i = 0; i < 7; i++) { - int today = - tm->tm_mday == today_mday && - tm->tm_mon == today_mon && - tm->tm_year == today_year; + do { printf(" %s%2d%s", - color && today ? "\e[7m" : "", - tm->tm_mday, - color && today ? "\e[0m" : ""); + color && (jd == today) ? "\e[7m" : "", + d, + color && (jd == today) ? "\e[0m" : ""); - tm->tm_mday++; - mktime(tm); - } + jd++; + jd2ymdwi(jd, &y, &m, &d, &w, &i); + } while (w != 1); printf("\n"); } -- cgit 1.4.1