aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2020-07-16 18:34:41 +0200
committerLeah Neukirchen <leah@vuxu.org>2020-07-16 18:34:41 +0200
commit7ff1228ff7e5b4e15780934f5c16262c58e18740 (patch)
tree0fa85091182ba2f1d7b03e0047d250553f5b23ef
parent21121a8ab2692c2976f1be8c4779bef064b7df1c (diff)
downloadwcal-7ff1228ff7e5b4e15780934f5c16262c58e18740.tar.gz
wcal-7ff1228ff7e5b4e15780934f5c16262c58e18740.tar.xz
wcal-7ff1228ff7e5b4e15780934f5c16262c58e18740.zip
rewrite using own date routines using julian dates
-rw-r--r--wcal.c151
1 files 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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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");
}