//%TITLE Days and Date Date Implementation // See IDIDATE.HPP for documentation #include "global.hpp" #include "Date.hpp" #include // Days implementation // ------------------- char* Days::unit = "day"; ostream& Days::put(ostream& ls) const {ls << value << ' ' << Days::unit; if (abs(value) != 1) ls << 's'; // Append English plural return ls; } istream& Days::get(istream& ls) {ls >> value; return ls; } // (mainly for debugging) //%SPACE 5 // Date implementation // ------------------- // Constant initialization // ----------------------- LONG Date::BIAS // Internal representation = - CalendarInfo::DAYS_PER_400_YEARS * 5 // Origin date is December 30, + CalendarInfo::DAYS_PER_100_YEARS // 1899, for compatibility + CalendarInfo::DAYS_PER_YEAR + 2; // with Lotus 1-2-3 //%SPACE 2 SHORT Date::BIAS_WEEKDAY = 6; // Origin date is a Saturday //%SPACE 2 short Date::century_break = 20; // 2-digit year is 20yy if yy less // 19yy otherwise // (user may override this one) Date::Date (LONG yyyy, UINT ddd) // Year and day number : value(BIAS) // (no error check on ddd) {LONG years = yyyy - 1; // Number of elapsed years value += years // Convert years * CalendarInfo::DAYS_PER_YEAR// to days + years / 4 // Apply - years / 100 // leap-year + years / 400 // adjustment + ddd; // Add day number within year } Date::Date (LONG yyyy, SHORT mm, SHORT dd) // Year-month-day : value(0) // (with full error checking) {bool leap_year = CalendarInfo::isLeapYear(yyyy); if (mm < 1 || mm > 12 || dd < 1 || (dd > CalendarInfo::DAYS_IN_MONTH [mm] && !(dd == 29 && mm == 2 && leap_year))) {clog << endl << "DATE01 -- Illegal value (" << yyyy << '-' << mm << '-' << dd << "). ";} {int ddd = CalendarInfo::DAYS_BEFORE_MONTH [mm] + dd; ddd += (leap_year && (mm > 2)); // First convert mm-dd to ddd value = Date(yyyy,ddd).value;} // Now use previous constructor } Date::Date (CHAR yymmdd[6]) // ANSI 6-character string {if (strlen(yymmdd) != 6) return; // (check only on length) char charVal[6]; for (int i = 0; i < 6; i++) // Convert characters charVal[i] = yymmdd[i] - '0'; // to their values int yy = charVal[0] * 10 + charVal[1]; // Extract year short mm = charVal[2] * 10 + charVal[3]; // Extract month short dd = charVal[4] * 10 + charVal[5]; // Extract day yy += (yy < century_break) ? 2000 : 1900; // Choose 20th or 21st century value = Date(yy,mm,dd).value; // Now use previous constructor } //%SPACE 2 ostream& Date::put(ostream& rs) const {return rs << year() << '-' << month() << '-' << day();} istream& Date::get(istream& rs) {int y, m, d; rs >> y >> m >> d; value = Date(y,m,d).value; return rs; } //%EJECT long Date::yyyy = 0; // Meaningless short Date::mm = 0; // initializations short Date::dd = 0; // required by the short Date::ddd = 0; // linking loader long Date::cur_value = 0; void Date::set_ymd() const // Extract date subfields {if (value == cur_value) return; // To avoid redundant calculation we cur_value = value; // save the results, but this won't // won't work with multi-tasking. long ndays = value - BIAS; // Strip off origin date int ngrps; ngrps = ndays / CalendarInfo::DAYS_PER_400_YEARS; yyyy = ngrps * 400; ndays -= ngrps * CalendarInfo::DAYS_PER_400_YEARS; ngrps = ndays / CalendarInfo::DAYS_PER_100_YEARS; yyyy += ngrps * 100; ndays -= ngrps * CalendarInfo::DAYS_PER_100_YEARS; ngrps = ndays / CalendarInfo::DAYS_PER_4_YEARS; yyyy += ngrps * 4; ndays -= ngrps * CalendarInfo::DAYS_PER_4_YEARS; if (ndays == 0) ndays = ddd = CalendarInfo::isLeapYear? 366 : 365; else {ndays += CalendarInfo::DAYS_PER_YEAR - 1; yyyy += ndays / CalendarInfo::DAYS_PER_YEAR; ndays %= CalendarInfo::DAYS_PER_YEAR; ++ddd; } // At this point, ndays is the day number within yyyy ddd = ndays; if (CalendarInfo::isLeapYear(yyyy)) if (ndays > 60) --ddd; else if (ndays=60) {mm = 2; dd = 29; return;} mm = (ddd + 28) / 29; if (dd < CalendarInfo::DAYS_BEFORE_MONTH[mm]) --mm; dd = dd - CalendarInfo::DAYS_BEFORE_MONTH[mm]; if (mm==13) {mm=1; ++yyyy;} return;}