Date parse_date(char *str) { int y, m, d, y2, m2, d2, delta; Date ret; if (sscanf(str, "%d-%d-%d", &y, &m, &d) == 3) { if (d < 1 || d > 31 || m < 1 || m > 12 || y < 1900) return INVALID_DATE; ret = ymd_to_date(y, m, d); /* * Double-check the user hasn't entered anything stupid such as * 30th Feb. */ date_to_ymd(ret, &y2, &m2, &d2); if (y2 != y || m2 != m || d2 != d) return INVALID_DATE; } else if (sscanf(str, "+%d", &delta) == 1) { return today() + delta; } else if (sscanf(str, "-%d", &delta) == 1) { return today() - delta; } else { return INVALID_DATE; } return ret; }
char *format_date_core(Date d, int full) { char *s, *t; int yy, mm, dd; date_to_ymd(d, &yy, &mm, &dd); s = smalloc(32); if (d == INVALID_DATE) sprintf(s, full ? "*INVALID DATE*" : "*INVALID!*"); else if (d == NO_DATE) sprintf(s, "%*s", full ? 14 : 10, ""); else { if (full) { t = s + sprintf(s, "%3s ", weekdays[weekday(d)]); } else t = s; sprintf(t, "%4d-%02d-%02d", yy, mm, dd); } return s; }
int main(void) { Date sd, ed, d; struct { int y, m, d, ymd; } curr, prev; sd = ymd_to_date(1995, 1, 1); ed = ymd_to_date(2005, 1, 1); assert(ed - sd > 365 * 8); for (d = sd; d <= ed; d++) { date_to_ymd(d, &curr.y, &curr.m, &curr.d); curr.ymd = 10000 * curr.y + 100 * curr.m + curr.d; if (d == sd) { prev = curr; continue; } printf("prev: %4d-%02d-%02d curr: %4d-%02d-%02d d:%8d\n", prev.y, prev.m, prev.d, curr.y, curr.m, curr.d, d); /* Monotonicity. */ assert(prev.ymd < curr.ymd); /* Other obvious date properties. */ if (curr.d != 1) { /* Date increases by 1 except at start of new month. */ assert(prev.y == curr.y); assert(prev.m == curr.m); assert(prev.d == curr.d - 1); } else if (curr.m != 1) { /* Month increases by 1 except at start of new year. */ assert(prev.y == curr.y); assert(prev.m == curr.m - 1); switch (prev.m) { case 9: case 4: case 6: case 11: /* 30 days hath September, April, June and November ... */ assert(prev.d == 30); break; default: /* All the rest have 31 ... */ assert(prev.d == 31); break; case 2: /* except for February. */ if (prev.y % 4) assert(prev.d == 28); else assert(prev.d == 29); break; } } else { /* Year increases by 1. */ assert(prev.y == curr.y - 1); } /* Round-trip conversion. */ assert(ymd_to_date(curr.y, curr.m, curr.d) == d); /* And round to the next one. */ prev = curr; } printf("tests passed ok\n"); return 0; }
void test_date_time_implementation() { ULL timestamp = 20090618001732ULL; int dt; int tm; int Y,M,D,h,m,s; split_timestamp(timestamp, dt, tm); date_to_ymd(dt, Y, M, D); time_to_hms(tm, h, m, s); cout << "Timestamp: " << timestamp << endl; cout << "Date: " << dt << " -> " << Y << "/" << M << "/" << D << endl; cout << "Time: " << tm << " -> " << h << ":" << m << ":" << s << endl << endl; UL seconds = 31834133; Interval i = Interval(0,0,0,0,0,seconds); cout << "20080101 + 31834133 seconds = " << join_timestamp(20080101, 0) + i << endl; cout << "20080101 - -31834133 seconds = " << join_timestamp(20080101, 0) - -i << endl; cout << "20080101 - 31834133 seconds = " << join_timestamp(20080101, 0) - i << endl; cout << "20080101 + -31834133 seconds = " << join_timestamp(20080101, 0) + -i << endl; cout << endl; i = Interval(1, 3, 3, 25, 7, 38); cout << "20090601 + (1 year 3 months 3 days 25 hours 7 minutes 38 seconds) = " << join_timestamp(20090601, 0) + i << endl; cout << "20090601 - -(1 year 3 months 3 days 25 hours 7 minutes 38 seconds) = " << join_timestamp(20090601, 0) - (-i) << endl; cout << "20090601 - (1 year 3 months 3 days 25 hours 7 minutes 38 seconds) = " << join_timestamp(20090601, 0) - i << endl; cout << "20090601 + -(1 year 3 months 3 days 25 hours 7 minutes 38 seconds) = " << join_timestamp(20090601, 0) + (-i) << endl; cout << endl; Interval l = Interval(2, 3, 32, 25, 7, 112); Interval r = Interval(1, 15, 33, 1, 8, 52); cout << "(2 years 3 months 32 days 25 hours 7 minutes 112 seconds) <=> (1 year 15 months 33 days 1 hour 8 minutes 52 seconds) = " << leg(l,r) << endl; cout << endl; l = Interval(0,0,0,0,0,31834133); r = Interval(0, 0, 368, 10, 48, 52); cout << "(31834133 seconds) <=> (368 days 10 hours 48 minutes 52 seconds) = " << leg(l,r) << endl; cout << "(31834133 seconds) > (368 days 10 hours 48 minutes 52 seconds) = " << ((l > r) ? "true" : "false") << endl; r = Interval(0, 0, 368, 10, 48, 53); cout << "(31834133 seconds) <=> (368 days 10 hours 48 minutes 53 seconds) = " << leg(l,r) << endl; cout << "(31834133 seconds) == (368 days 10 hours 48 minutes 53 seconds) = " << ((l == r) ? "true" : "false") << endl; r = Interval(0, 0, 368, 10, 48, 54); cout << "(31834133 seconds) <=> (368 days 10 hours 48 minutes 54 seconds) = " << leg(l,r) << endl; cout << "(31834133 seconds) < (368 days 10 hours 48 minutes 54 seconds) = " << ((l < r) ? "true" : "false") << endl; cout << endl; ULL t1 = 19831129031500ULL; // my birth date (time?) ULL t2 = 20090626005206ULL; // now i = Interval::between(t1, t2); l = Interval(25, 6, 27, 21, 37, 6); r = Interval(0, 0, 9340, 21, 37, 6); cout << "Interval between 1983-11-29 03:15:00 and 2009-06-26 00:52:06 = " << i.to_s() << endl; cout << i.to_s() << " <=> " << l.to_s() << " = " << leg(i, l) << endl; cout << i.to_s() << " <=> " << r.to_s() << " = " << leg(i, r) << endl; cout << l.to_s() << " <=> " << r.to_s() << " = " << leg(l, r) << endl; cout << endl; l = Interval(0, 1, -29, 4, -29, 0); r = Interval(0, 0, 2, 3, 31, 0); cout << l.to_s() << " <=> " << r.to_s() << " = " << leg(l, r) << endl; cout << l.to_s() << " < " << r.to_s() << " -> " << ((l < r) ? "true" : "false") << endl; cout << l.to_s() << " == " << r.to_s() << " -> " << ((l == r) ? "true" : "false") << endl; cout << l.to_s() << " > " << r.to_s() << " -> " << ((l > r) ? "true" : "false") << endl; cout << endl; i = Interval(390, -1354, -3395, -6671, -5719, 0); // ~9.7556 days long divisor = 10000; cout << i.to_s() << " / " << divisor << " = " << (i / divisor).to_s() << endl; cout << endl; cout << "Day of week of 20090623 is a " << getDayOfWeek(6, 23, 2009, 1); }
int getDayOfWeek(ULL timestamp, int CalendarSystem) { int year, month, day; year = month = day = 0; date_to_ymd(timestamp_date(timestamp), year, month, day); return getDayOfWeek(month, day, year, CalendarSystem); }
void split_timestamp(ULL timestamp, int& out_year, int& out_month, int& out_day, int& out_hour, int& out_minute, int& out_second) { date_to_ymd(timestamp_date(timestamp), out_year, out_month, out_day); time_to_hms(timestamp_time(timestamp), out_hour, out_minute, out_second); }
/* * Normalization of hours, minutes, and seconds is different than normalization of years, months, and day. * A specific time is a number of hours, minutes, and seconds that has already elapsed (e.g. 3:00 PM means * that 15 hours of the day have elapsed). A specific date is not a number of years, months, and days that * have elapsed, they indicate the current year, month, and day -- they indicate which year, month, and day * that we are in (e.g. 12/3/2009 at 8:00 AM means that 2008 years, 11 months, 2 days, 8 hours have elapsed). */ ULL operator+(const ULL& ts, const Interval& i) { // ULL t = 0; // int year,month,day,hours,minutes,seconds; // year = month = day = hours = minutes = seconds = 0; ULL t = 0; int year,month,day,hours,minutes,seconds; long inc = 0; long multiple; year = month = day = hours = minutes = seconds = 0; date_to_ymd(timestamp_date(ts), year, month, day); time_to_hms(timestamp_time(ts), hours, minutes, seconds); // add the interval's seconds, minutes, hours, and years to the values extracted from the timestamp (ts); // we'll add the months and days later seconds += i.seconds; minutes += i.minutes; hours += i.hours; year += i.years; // Since adding a number of months might affect the day, we want to normalize the months before // we go into normalizing the days. // For example: 1/29/2009 + 1 month = 1/28/2009 // but: 1/29/2008 + 1 month = 1/29/2009 // Also: 1/30/2009 + 1 month = 1/28/2009 // and: 1/31/2009 + 2 months = 3/31/2009 // ** I am assuming the the day we fall on depends on how many days the target month has in it -- If ** // ** the target month has fewer days in it than the origin month, and the origin day is a day that ** // ** the target month doesn't have, then the target day will be the last day of the target month. ** // normalize month count //int origin_month_length = days_in_month(year, month); month += i.months; // figure out how many years worth of months we can increment our year count by, // and determine which month we will be in after we remove that number of years worth of months from the month count. /* if(month > 12) { year += (month - 1) / 12; month = ((month - 1) % 12) + 1; } */ // see http://tinyurl.com/nu97yg for a demonstration of why this math works multiple = 12; inc = floor((double)(month - 1) / multiple); year += inc; month = ((month - 1) - multiple*inc) + 1; int target_month_length = days_in_month(year, month); if(/* target_month_length < origin_month_length && */ day > target_month_length) { // adjust the day of the month if we need to day = target_month_length; // set the day to the last day in the (shorter) target month } /* // normalize seconds, minutes, and hours. minutes += seconds / 60; seconds %= 60; hours += minutes / 60; minutes %= 60; // we've already normalized the month count so adding to the day count is ok here (we'll normalize the day count afterward). day += hours / 24; hours %= 24; */ // normalize seconds, minutes, and hours. multiple = 60; inc = floor((double)seconds / multiple); minutes += inc; seconds = seconds - multiple*inc; inc = floor((double)minutes / multiple); hours += inc; minutes = minutes - multiple*inc; // we've already normalized the month count so adding to the day count is ok here (we'll normalize the day count afterward). multiple = 24; inc = floor((double)hours / multiple); day += inc; hours = hours - multiple*inc; // normalize day count multiple = 12; day += i.days; int dpm = days_in_month(year, month); //cout << day << " " << dpm << endl; while(day > dpm) { day -= dpm; month++; // re-normalize month if needed inc = floor((double)(month - 1) / multiple); year += inc; month = ((month - 1) - multiple*inc) + 1; dpm = days_in_month(year, month); } while(day < 1) { month--; dpm = days_in_month(year, month); day += dpm; // re-normalize month if needed inc = floor((double)(month - 1) / multiple); year += inc; month = ((month - 1) - multiple*inc) + 1; //dpm = days_in_month(year, month); } t = join_timestamp(year, month, day, hours, minutes, seconds); return t; }