#include "date.h" #include static int DaysInMonth(int,int); // # of days in month in year string dayNames [] = {"Sunday", "Monday", "Tuesday","Wednesday", "Thursday","Friday", "Saturday"}; string monthNames [] = {"January","February","March","April", "May","June","July","August", "September","October","November","December"}; Date::Date() // postcondition: date initialized to default date (today) { static struct tm timeHolder; static struct tm *date = &timeHolder; time_t tloc; time(&tloc); date = localtime(&tloc); myMonth = date->tm_mon+1; myDay = date->tm_mday; myYear = date->tm_year+1900; // struct tm based on 1900 } Date::Date(int m, int d, int y) // postcondition: date properly initialized for date m/d/y (american style) // exception: if m isn't between 1 and 12, converted to 1 // if d out of range for month, converted to 1 { CheckDate(m,d,y); } Date::Date(long int days) // postcondition: date initialized corresponding to absolute days // after 1 A.D. { // this code is taken from "Calendrical Calculations, II" // Reingold and Dershowitz and Clamen // Software Practice and Experience, V. 23(4) 383-404 (april 1993) int prior = days - 1; // prior days int years400 = prior / 146097; // # of 400 year cycles int days400 = prior % 146097; // days NOT in years400 int years100 = days400 / 36524; // # 100 yr. cycles not checked int days100 = days400 % 36524; // days NOT already included int years4 = days100 / 1461; // # 4 yr cycles not checked int days4 = days100 % 1461; // days NOT already included int year1 = days4 / 365; // # years not already checked int day1 = days4 % 365; // days NOT already included // use "magic formula" from SP&E article int finalDay; int finalYear = 400*years400 + 100*years100 + 4*years4 + year1; if (years100 == 4 || year1 == 4){ // December 31 of leap year finalDay = 366; } else{ finalDay = day1 + 1; finalYear += 1; } // now have year and day #, find month and day in month myMonth = 1; while (myMonth <= 12 && 0 < finalDay){ finalDay -= DaysInMonth(myMonth,finalYear); myMonth += 1; } myMonth -= 1; // went one to far finalDay += DaysInMonth(myMonth,finalYear); myDay = finalDay; myYear = finalYear; } void Date::SetDate(int m, int d, int y) // postcondition: date properly initialized for date m/d/y (american style) { CheckDate(m,d,y); } int Date::Month() const // postcondition: returns month of Date { return myMonth; } int Date::Day() const // postcondition: returns day of Date { return myDay; } int Date::Year() const // postcondition: returns year of Date { return myYear; } string Date::Ascii() const // postcondition: returns string (ascii) for date: day, month, year { const int BUFSIZE = 50; char buf[BUFSIZE]; struct tm timeHolder; struct tm *date = &timeHolder; // set parameters for use of strftime date->tm_mday = myDay; date->tm_mon = myMonth-1; date->tm_year = myYear-1900; strftime(buf,BUFSIZE,"%B %d %Y",date); return buf; } string Date::DateAscii() const // postcondition: returns string (ascii) for date: day, month, year { return Ascii(); } static bool IsLeap(int year) // postcondition: returns 1 if year is a leap year, else returns 0 { int leapValue = 0; // default is NOT leap year if (year % 400 == 0){ leapValue = 1; } else if (year % 100 == 0){ leapValue = 0; } else if (year % 4 == 0){ leapValue = 1; } return leapValue; } static int DaysInMonth(int month,int year) // postcondition: returns # of days in month in year { int days = 30; // 30 days hath september, april, june, and november // other months have 31 as below (except February) if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12){ days = 31; } else if (month == 2){ // treat February differently days = 28; if (IsLeap(year) == 1){ // add 1 for leap years days += 1; } } return days; } int Date::DaysIn() const { return DaysInMonth(myMonth,myYear); } long int Date::Absolute() const // postcondition: returns absolute # days corresponding to Date // assuming January 1, 1 B.C is day 1 { int m = 1; // start in January; int daysBefore = 0; // count # days before month while (m < myMonth){ // tally # of days in preceding months daysBefore += DaysInMonth(m,myYear); m += 1; } long int dayYears = 365 * (myYear - 1); // days before this year // add 1 extra day for each leap year int leapYears = (myYear - 1) / 4; // initial # of leap years leapYears -= (myYear - 1) / 100; // subtract years divisible by 100 leapYears += (myYear - 1) / 400; // add back years divisibly by 400 return myDay + daysBefore + dayYears + leapYears; } string Date::DayName() const { return dayNames[Absolute() % 7]; } string Date::MonthName() const { return monthNames[myMonth-1]; } Date& Date::operator +=(int dx) { *this = Date(Absolute()+dx); return *this; } Date& Date::operator -=(int dx) { *this = Date(Absolute()-dx); return *this; } Date Date::operator ++(int) { Date hold = *this; *this += 1; return hold; } Date Date::operator --(int) { Date hold = *this; *this -= 1; return hold; } Date operator + (const Date & d, int dx) { Date copy(d); copy += dx; return copy; } Date operator + (int dx, const Date & d) { return d+dx; } Date operator - (const Date & d, int dx) { Date copy(d); copy -= dx; return copy; } void Date::CheckDate(int m, int d, int y) { if (m < 1 || 12 < m) // month out of range? { m = 1; } myMonth = m; if (d < 1 || DaysInMonth(m,y) < d) // day out of range? { d = 1; } myDay = d; myYear = y; }