#include #include #include #include #include SDate::SDate(void) { initArray(); getTodaysDate(); } SDate::SDate(const CompatibleDate &someDate) { initArray(); CompatibleDate::Month=someDate.Month; CompatibleDate::Day=someDate.Day; CompatibleDate::Year=someDate.Year; } SDate::SDate(long someLongDate) { initArray(); *this=someLongDate; } SDate::SDate(unsigned char month,unsigned char day,unsigned year) { initArray(); CompatibleDate::Month=month; CompatibleDate::Day=day; CompatibleDate::Year=year; } SDate::SDate(const SDate &someDate) { initArray(); CompatibleDate::Month=someDate.CompatibleDate::Month; CompatibleDate::Day=someDate.CompatibleDate::Day; CompatibleDate::Year=someDate.CompatibleDate::Year; } SDate::SDate(Options dateOptions) { initArray(); switch(dateOptions) { case TodaysDate : getTodaysDate(); break; default : break; } } SDate::~SDate() { } void SDate::getTodaysDate(void) { struct tm *lpTime; time_t currTime; ::time(&currTime); lpTime=::localtime(&currTime); CompatibleDate::Month=lpTime->tm_mon+1; CompatibleDate::Day=lpTime->tm_mday; CompatibleDate::Year=lpTime->tm_year+1900; } SDate &SDate::operator=(const CompatibleDate &someDate) { CompatibleDate::Month=(unsigned)someDate.Month; CompatibleDate::Day=(unsigned)someDate.Day; CompatibleDate::Year=(unsigned)someDate.Year; return *this; } SDate &SDate::operator=(long someLongDate) { CompatibleDate::Year=(unsigned)(someLongDate/10000L); CompatibleDate::Month=(unsigned)((someLongDate/100L)-((long)CompatibleDate::Year*100L)); CompatibleDate::Day=(unsigned)(someLongDate-(((long)CompatibleDate::Year*10000L)+((long)CompatibleDate::Month*100L))); return *this; } int SDate::operator<(const CompatibleDate &someDate)const { if (CompatibleDate::YearsomeDate.Year) return FALSE; if (CompatibleDate::MonthsomeDate.Month) return FALSE; return(CompatibleDate::Day(const CompatibleDate &someDate)const { if (CompatibleDate::Year>someDate.Year) return TRUE; if (CompatibleDate::YearsomeDate.Month) return TRUE; if (CompatibleDate::MonthsomeDate.Day); } int SDate::operator==(const CompatibleDate &someDate)const { return (CompatibleDate::Month==someDate.Month && CompatibleDate::Day==someDate.Day && CompatibleDate::Year==someDate.Year ); } int SDate::operator<=(const CompatibleDate &someDate)const { if(!(operator<(someDate)))return operator==(someDate); return TRUE; } int SDate::month(void)const { return CompatibleDate::Month; } void SDate::month(int newMonth) { CompatibleDate::Month=newMonth; } int SDate::day(void)const { return CompatibleDate::Day; } void SDate::day(int newDay) { CompatibleDate::Day=newDay; } int SDate::year(void)const { return CompatibleDate::Year; } void SDate::year(int newYear) { CompatibleDate::Year=newYear; } long SDate::makeLong(void)const { return 10000L*CompatibleDate::Year + 100L*CompatibleDate::Month + CompatibleDate::Day; } String SDate::makeString(void)const { String tempString; tempString.reserve(String::MaxString); ::sprintf((LPSTR)tempString,"%02d/%02d/%04d", CompatibleDate::Month, CompatibleDate::Day, CompatibleDate::Year); return tempString; } SDate SDate::monthYearStringToDate(char *str,short default_day) { SDate null_date; SDate return_date; SDate cur_date; short n_items; short first_num; short second_num; short third_num; short first_two_digits; short second_two_digits; short last_two_digits; short first_four_digits; short last_four_digits; char s[256]; char s2[80]; char first[32]; char second[32]; char third[32]; char *ps; char *ps2; unsigned short ndays[sizeof(mDayArray)/sizeof(WORD)]; ::memcpy(ndays,mDayArray,sizeof ndays); cur_date=SDate(SDate::TodaysDate); ::memset(&null_date,0,sizeof(null_date)); ::memset(first,0,sizeof(first)); ::memset(second,0,sizeof(second)); ::memset(third,0,sizeof(third)); if(!str)return null_date; if(::strlen(str)>255)::strncpy(s,str,255); else ::strcpy(s,str); ::strupr(s); for(ps=s,ps2=s2;*ps!='\0';++ps) { if(!isalnum(*ps)) { *ps=' '; if(ps2==s2)continue; } if(ps2>s2) { if(isdigit(*(ps2-1))&&isalpha(*ps)||isalpha(*(ps2-1)) && isdigit(*ps)) { *ps2=' '; ++ps2; } else if(*(ps2-1)==' '&&*ps==' ')continue; } *ps2=*ps; ++ps2; } *ps2='\0'; /* Terminating null */ strcpy(s,s2); n_items=::sscanf(s," %s %s %s",first,second,third); if(n_items<=0)return null_date; if(1==n_items) { long single_num; if(isalpha(first[0])) /* Not a numeric value */ { return_date.Month=stringToMonth(first); if(0==return_date.Month)return null_date; return_date.Year=cur_date.Year; if(0==default_day) { if(2==return_date.Month&&((short)return_date.Year%4))ndays[2]=28; default_day=ndays[return_date.Month]; } else if(default_day<1||default_day>ndays[return_date.Month])return null_date; return_date.Day=default_day; return return_date; } single_num=::atol(first); if(single_num>1000||(first[0]=='0'&&single_num>=100)) { if (single_num>100000) { first_two_digits=(first[0]-'0')*10+(first[1]-'0'); second_two_digits=(first[2]-'0')*10+(first[3]-'0'); last_two_digits=single_num%100; } else if(single_num>10000) { first_four_digits=single_num/10; last_four_digits=single_num%10000; if(last_four_digits>=1960&&last_four_digits<=2060) { return_date.Year=last_four_digits; return_date.Month=single_num/10000; if(0==default_day) { if(2==return_date.Month&&((short)return_date.Year%4))ndays[2]=28; default_day=ndays[return_date.Month]; } return_date.Day=default_day; n_items=0; } else if(first_four_digits>=1960&&first_four_digits<=2060&&(single_num%10)!=0) { return_date.Year=first_four_digits; return_date.Month=single_num%10; if(0==default_day) { if(return_date.Month==2&&((short)return_date.Year%4))ndays[2]=28; default_day=ndays[return_date.Month]; } return_date.Day=default_day; n_items=0; } else { first_two_digits=(first[0]-'0')*10+(first[1]-'0'); last_two_digits=single_num%100; second_num=single_num/100; if((second_num % 100) <= 31 && (second_num / 100) != 0) { sprintf(second, "%d", second_num / 100); /* Month or day string */ sprintf(third, "%d", second_num % 100); /* Day or month string */ return_date=stringToMonthDay(second,third); return_date.Year = last_two_digits; n_items = 0; } else if ((second_num % 10) > 0 || (second_num / 10) <= 31) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); return_date = stringToMonthDay(second, third); return_date.Year = last_two_digits; n_items = 0; } else /* Assume first 2 digits are the year */ { second_num = single_num % 1000; /* Assume first 2 digits are yr */ if ((second_num % 100) <= 31 && (second_num / 100) != 0) { sprintf(second, "%d", second_num / 100); /* Month or day string */ sprintf(third, "%d", second_num % 100); /* Day or month string */ return_date = stringToMonthDay(second, third); return_date.Year = first_two_digits; n_items = 0; } else if ((second_num % 10) > 0 || (second_num / 10) <= 31) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); return_date = stringToMonthDay(second, third); return_date.Year = first_two_digits; n_items = 0; } else /* Nothing works */ { sprintf(second, "%d", second_num / 100); /* Month or day string */ sprintf(third, "%d", second_num % 100); /* Day or month string */ return_date = stringToMonthDay(second, third); return_date.Year = last_two_digits; n_items = 0; } } } } else /* Only 4 digits */ { first_two_digits = (first[0] - '0') * 10 + (first[1] - '0'); last_two_digits = single_num % 100; if ((last_two_digits < 1 || last_two_digits > 12) && first_two_digits >= 1 && first_two_digits <= 12) { /* Definitely MMYY */ return_date.Year = last_two_digits; return_date.Month = first_two_digits; if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ default_day = ndays[return_date.Month]; } return_date.Day = default_day; n_items = 0; } else if ((first_two_digits < 1 || first_two_digits > 12) && last_two_digits >= 1 && last_two_digits <= 12) { /* Definitely YYMM */ return_date.Year = last_two_digits; return_date.Month = last_two_digits; if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ default_day = ndays[return_date.Month]; } return_date.Day = default_day; n_items = 0; } else if (first_two_digits >= 1 && first_two_digits <= 12) { /* Qualifies as MMYY */ return_date.Year = last_two_digits; return_date.Month = first_two_digits; if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ default_day = ndays[return_date.Month]; } return_date.Day = default_day; n_items = 0; } else /* Might be month/day/year combination */ { if (first[0] == '0' || first[1] == '0') { /* First two digits are most likely the year */ second_two_digits = first[2] - '0'; last_two_digits = first[3] - '0'; } else if (first[2] == '0' || first[3] == '0') { /* Last two digits are most likely the year */ first_two_digits = first[0] - '0'; second_two_digits = first[1] - '0'; } else if ((last_two_digits < 30 || last_two_digits > 80) && first_two_digits >= 30 && first_two_digits <= 80) { /* Last two digits are most likely the year */ first_two_digits = first[0] - '0'; second_two_digits = first[1] - '0'; } else if ((first_two_digits < 30 || first_two_digits > 80) && last_two_digits >= 30 && last_two_digits <= 80) { /* First two digits are most likely the year */ second_two_digits = first[2] - '0'; last_two_digits = first[3] - '0'; } else /* Really don't know; assume last two digits are year */ { /* Last two digits are most likely the year */ first_two_digits = first[0] - '0'; second_two_digits = first[1] - '0'; } } } if (n_items == 1) if (last_two_digits == 0 || last_two_digits > 31) { /* Last two digits are definitely the year */ if (single_num > 1000000) /* It is a 4-digit year */ second_num = single_num / 10000; else /* It is a 2-digit year */ second_num = single_num / 100; sprintf(second, "%d", second_num / 100); /* Month or day string */ sprintf(third, "%d", second_num % 100); /* Day or month string */ if ((second_num % 100) > 31 || (second_num / 100) == 0) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); } return_date = stringToMonthDay(second, third); return_date.Year = last_two_digits; n_items = 0; } else if (first_two_digits == 0 || first_two_digits > 31) { /* First 2 digits are the year */ second_num = atoi(&first[2]); sprintf(second, "%d", second_num / 100); sprintf(third, "%d", second_num % 100); if ((second_num % 100) > 31 || (second_num / 100) == 0) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); } return_date = stringToMonthDay(second, third); return_date.Year = first_two_digits; n_items = 0; } else if (second_two_digits == 0 || second_two_digits > 31) { /* Second 2 digits are the year, assume 4-digit year was given */ second_num = atoi(&first[4]); sprintf(second, "%d", second_num / 100); sprintf(third, "%d", second_num % 100); if ((second_num % 100) > 31 || (second_num / 100) == 0) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); } return_date = stringToMonthDay(second, third); return_date.Year = first_two_digits * 100 + second_two_digits; n_items = 0; } else /* Can't tell from looking for 2-digit years; try 4-digit yrs */ { short first_four_digits, last_four_digits; strncpy(second, first, 4); second[4] = '\0'; first_four_digits = atoi(second); last_four_digits = single_num % 10000; if (last_four_digits >= 1960 && last_four_digits <= 2060) { /* Last 4 digits are definitely the year */ second_num = single_num / 10000; sprintf(second, "%d", second_num / 100); sprintf(third, "%d", second_num % 100); if ((second_num % 100) > 31 || (second_num / 100) == 0) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); } return_date = stringToMonthDay(second, third); return_date.Year = last_four_digits; n_items = 0; } else /* Give up; assume YYMMDD format */ if (first_four_digits >= 1960 && first_four_digits <= 2060) { /* First 4 digits are definitely the year */ second_num = atoi(&first[4]); sprintf(second, "%d", second_num / 100); sprintf(third, "%d", second_num % 100); if ((second_num % 100) > 31 || (second_num / 100) == 0) { /* Split it differently */ sprintf(second, "%d", second_num / 10); sprintf(third, "%d", second_num % 10); } return_date = stringToMonthDay(second, third); return_date.Year = first_four_digits; n_items = 0; } else { sprintf(first, "%d", first_two_digits); sprintf(second, "%d", second_two_digits); sprintf(third, "%d", last_two_digits); n_items = 3; } } } else /* 3 or fewer digits */ { return null_date; /* Does not qualify as month/year */ } } switch (n_items) { case 0: /* This means we already parsed the date */ break; case 1: /* Only 1 item scanned, assume it is a month */ return_date.Month = atoi(first); if (return_date.Month >= 1 && return_date.Month <= 12) { return_date.Year = cur_date.Year; if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ default_day = ndays[return_date.Month]; } return_date.Day = default_day; } else /* Not a valid month number; an error */ return null_date; break; case 2: /* 2 items scanned, assume month and year */ { short n_days; return_date=stringToMonthYear(first, second); if (*(long *)&return_date) /* It was month/year */ { if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ if (return_date.Month >= 1 && return_date.Month <= 12) default_day = ndays[return_date.Month]; } return_date.Day = default_day; } else /* Not month/year */ { return_date = stringToMonthDay(first, second); return_date.Year = cur_date.Year; n_days = daysBetweenActual(cur_date, return_date); if (n_days < -182) /* More than 6 months back */ ++return_date.Year; /* Assume it's next year */ else if (n_days > 182) /* More than 6 months in the future */ --return_date.Year; /* Assume it's last year */ } break; } case 3: /* 3 items scanned, assume month, day, and year */ first_num = atoi(first); second_num = atoi(second); third_num = atoi(third); if (first_num > 31) /* First item is a year */ { return_date = stringToMonthDay(second, third); return_date.Year = first_num; } else if (third_num > 31) /* Third item is a year */ { return_date = stringToMonthDay(first, second); return_date.Year = third_num; } else if (second_num > 31) /* Second item might be a year? */ { return_date = stringToMonthDay(first, third); return_date.Year = second_num; } else if (isalpha(first[0])) /* First item is a month */ { /* Assume second is day, third is year */ return_date = stringToMonthDay(first, second); return_date.Year = third_num; } else if (isalpha(second[0])) /* Second item is a month */ { /* Assume first is day, third is year */ return_date = stringToMonthDay(first, second); return_date.Year = third_num; } else if (isalpha(third[0])) /* Third item might be a month? */ { /* Assume first is year, second is day */ return_date = stringToMonthDay(second, third); return_date.Year = first_num; } else /* Assume month, day, year */ { return_date = stringToMonthDay(first, second); return_date.Year = third_num; } break; } /* End of switch */ if (return_date.Month < 1 || return_date.Month > 12) return null_date; /* Month is out of range */ if (return_date.Day < 1 || return_date.Day > ndays[return_date.Month]) { /* Day of month is out of range */ if (default_day == 0) { if (return_date.Month == 2 && ((short)return_date.Year % 4)) ndays[2] = 28; /* Not a leap year */ default_day = ndays[return_date.Month]; } return_date.Day = default_day; } if (((short)return_date.Year % 4) != 0) /* Not a leap year */ ndays[2] = 28; if (return_date.Year > 1900) return return_date; /* A valid date */ if (return_date.Year >= 100) /* Lotus format date for 21st century */ { return_date.Year = 2000 + ((short)return_date.Year % 100); return return_date; } if (return_date.Year > 60) return_date.Year += 1900; else return_date.Year += 2000; return return_date; } short SDate::stringToMonth(char *szMonth)const /* Converts string to month number */ { String strMonth(szMonth); char *str; if(strMonth.isNull())return FALSE; strMonth.upper(); str=(char*)strMonth; switch (str[0]) /* Look at first character to determine month */ { case 'F': /* February */ return 2; case 'S': /* September */ return 9; case 'O': /* October */ return 10; case 'N': /* November */ return 11; case 'D': /* December */ return 12; case 'J': /* January, June, or July */ switch (str[1]) /* Look at second character */ { case 'A': /* January */ return 1; case 'U': /* June or July */ switch (str[2]) /* Look at third character */ { case 'N': /* June */ return 6; case 'L': /* July */ return 7; } /* End of switch (str[2]) */ break; case 'E': /* June */ return 6; case 'L': /* July */ return 7; } /* End of switch (str[1]) */ return 0; /* Cannot determine what month this is */ case 'M': /* March or May */ switch (str[1]) /* Look at second character */ { case 'A': /* March or May */ switch (str[2]) /* Look at third character */ { case 'R': /* March */ return 3; case 'Y': /* May */ return 5; } /* End of switch (str[2]) */ return 0; /* Cannot determine the month */ case 'R': /* March */ return 3; case 'Y': return 5; } /* End of switch (str[1]) */ return 0; /* Cannot determine what month this is */ case 'A': /* April or August */ switch (str[1]) /* Look at second character */ { case 'P': /* April */ case 'R': return 4; case 'U': /* August */ case 'G': return 8; } /* End of switch (str[1]) */ return 0; /* Cannot determine what month this is */ default: return 0; /* Cannot determine what month this is */ } } SDate SDate::stringToMonthDay(char *first, char *second) { SDate return_date; short first_num; short second_num; ::memset(&return_date,0,sizeof(return_date)); if(isalpha(first[0])) { return_date.month(stringToMonth(first)); return_date.day(::atoi(second)); return return_date; } if (isalpha(second[0])) /* Second item is a month */ { return_date.month(stringToMonth(second)); return_date.day(::atoi(first)); return return_date; } first_num=::atoi(first); second_num=::atoi(second); if(first_num>12) { return_date.day(first_num); return_date.month(second_num); return return_date; } if(second_num>12) { return_date.day(second_num); return_date.month(first_num); return return_date; } return_date.month(first_num); return_date.day(second_num); return return_date; } SDate SDate::stringToMonthYear(char *first, char *second) { SDate return_date; short first_num, second_num; ::memset(&return_date, 0, sizeof return_date); if(isalpha(first[0])) /* First item is a month */ { return_date.month(stringToMonth(first)); return_date.year(::atoi(second)); return return_date; } if(isalpha(second[0])) /* Second item is a month */ { return_date.month(stringToMonth(second)); return_date.year(::atoi(first)); return return_date; } first_num=::atoi(first); second_num=::atoi(second); if((second_num<1||second_num>12)&&first_num>=1&&first_num<=12) { return_date.year(second_num); return_date.month(first_num); return return_date; } else if((first_num<1||first_num>12)&&second_num>=1&&second_num<=12) { return_date.year(first_num); return_date.month(second_num); return return_date; } else if(first_num>=1&&first_num<=12) { return_date.year(second_num); return_date.month(first_num); return return_date; } return_date.year(first_num); return_date.month(second_num); return return_date; } short SDate::daysBetweenActual(SDate toDate)const { return daysBetweenActual(*this,toDate); } short SDate::daysBetweenActual(SDate fromDate,SDate toDate)const { short fromCount; short fromDay; short fromMonth; short fromYear; short fromQuad; short toCount; short toDay; short toMonth; short toYear; short toQuad; short daysTo[13]; daysTo[0]=0; daysTo[1]=0; daysTo[2]=31; daysTo[3]=59; daysTo[4]=90; daysTo[5]=120; daysTo[6]=151; daysTo[7]=181; daysTo[8]=212; daysTo[9]=243; daysTo[10]=273; daysTo[11]=304; daysTo[12]=334; if(fromDate.makeLong()<19010101|| fromDate.makeLong()>20991231|| toDate.makeLong()<19010101|| toDate.makeLong()>20991231)return FALSE; fromDay=fromDate.day(); fromMonth=fromDate.month(); fromYear=((short)fromDate.year()-1)%4; fromQuad=((short)fromDate.year()-1)/4; fromCount=fromDay+daysTo[fromMonth]+fromYear*365+fromQuad*((4*365)+1); if(3==fromYear&&fromMonth>2)++fromCount; toDay=toDate.day(); toMonth=toDate.month(); toYear=((short)toDate.year()-1)%4; toQuad=((short)toDate.year()-1)/4; toCount=toDay+daysTo[toMonth]+toYear*365+toQuad*((4*365)+1); if(3==toYear&&toMonth>2)++toCount; return toCount-fromCount; } SDate SDate::daysAdd360(short dayCount) { long days; WORD thirtyOne; SDate toDate; if(!year()&&!day()&&!month())return *this; if(!dayCount)return *this; thirtyOne=(31==day()); if(thirtyOne)day(30); if(2==month()&&day()>27) { int daysInMonth=!(year%4)&&(year%100)||!(year%400)?28:29; if(day()>=daysInMonth)day(30); } days=360*(long)year()+30*(long)month()+(long)day()+dayCount-391; toDate.day((short)(days%30)+1); toDate.month((short)(days/30)%12+1); toDate.year((short)(days/360)+1); if(!(dayCount%30)&&thirtyOne) { switch(toDate.month()) { case 1 : case 3 : case 5 : case 7 : case 8 : case 10 : case 12 : toDate.day(toDate.day()+1); break; } } return toDate; } SDate SDate::daysAddActual(short actualDays)const { return daysAddActual(*this,actualDays); } SDate SDate::daysAddActual(SDate fromDate,short actualDays)const { short day; short month; short year; short daysInMonth; short days360; short dayCount; SDate date360; SDate returnDate; if(!fromDate.day()&&!fromDate.month()&&!fromDate.year())return fromDate; days360=((float)actualDays*360.00/365.24)+.5; // date360=fromDate.daysAdd360(days360); date360=SDate(fromDate).daysAdd360(days360); dayCount=actualDays-daysBetweenActual(fromDate,date360); day=date360.day(); month=date360.month(); year=date360.year(); if(dayCount>=0) { while(dayCount>0) { switch(month) { case 2 : if(!(year%4)&&(year%100)||!(year%400))daysInMonth=29; else daysInMonth=28; break; case 4 : case 6 : case 9 : case 11 : daysInMonth=30; break; case 1: case 3: case 5: case 7: case 8: case 10: case 12: daysInMonth=31; break; } if(dayCount<=(daysInMonth-day)){day+=dayCount;dayCount=0;} else { dayCount-=daysInMonth-day+1; month=(month%12)+1; day=1; if(1==month)++year; } } } else { while(dayCount<0) { if(abs(dayCount)=30) { if(toDate.day()>=30)return (short)(360*((long)toDate.year()-(long)fromDate.year())+30*((long)toDate.month()-(long)fromDate.month())); fromDate.day(30); } return (short)(360*((long)toDate.year()-(long)fromDate.year())+30*((long)toDate.month()-(long)fromDate.month())+(long)toDate.day()-(long)fromDate.day()); }