Click here to Skip to main content
15,895,142 members
Articles / Desktop Programming / MFC

MS Outlook style date edit control/date picker

Rate me:
Please Sign up or sign in to vote.
4.92/5 (13 votes)
26 Jan 2002CPOL11 min read 270.4K   4.4K   78  
Simulates the MS Outlook date edit/picker control.
// COleDateTimeEx
// Author:	Matt Gullett
//			gullettm@yahoo.com
// Copyright (c) 2001
//
// This is a utility class used to enhance the date/time parsing abilities of
// the MFC provided class COleDateTime
//
// You may freely use this source code in personal, freeware, shareware
// or commercial applications provided that 1) my name is recognized in the
// code and if this code represents a substantial portion of the application
// that my name be included in the credits for the application (about box, etc)
//
// Use this code at your own risk.  This code is provided AS-IS.  No warranty
// is granted as to the correctness, usefulness or value of this code.
//
// Special thanks to Oskar Wieland for his Easter calculation formula posted
// on CodeProject.
// http://www.codeproject.com/datetime/easter.asp
//
//
// *******************************************************************
// TECHNICAL NOTES:
// 
// This code is suitable for US and english speaking users only.  There
// is a need to enahance this algorithm to deal with multiple languages.  
// This enhancement is beyond the scope of the current projects requirements.
//
// Also, the methodology used here is quite simple and is basically a
// hard-coded set of common date/time entry situations.  There are no
// doubt numerous situations which are not covered.  The functions
// "EvaluateInputTextDate" and "EvaluateInputTextTime" are responsbile for
// the "parsing".  I belive it would be possible to come up with a rules
// based engine for dealing with this stuff, but I did not have time to
// create this engine.
//
// Also, this code makes heavy use of CString and as a result (in addition
// to the code being unoptimized), this code is not a high performance 
// algorithm.  This was perfectly OK for my uses since the parses are only
// used on rare occasions and even on slow PCs one hit is faster than the
// user would notice.  However, if this were used in an inner-loop situation
// where it was being called repeatedly, this algorithm would slow down
// the overall loop.
//
// Finally, at the time I released this code on CodeProject, the product
// which uses this class was in "late alpha" testing.  So far no problems
// have been identified in this class, but if some are, I will post them
// as soon as I can.
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "OleDateTimeEx.h"

#include "math.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

COleDateTimeEx::COleDateTimeEx()
{
	if (!m_bDefaultShortcutsLoaded)
	{
		LoadDefaultShortcuts();
		m_bDefaultShortcutsLoaded = TRUE;
	}

	m_lHourOptions = 0;
	m_lHourCutoff = OLEDATEEX_DEFAULT_HOUR_CUTOFF;
}

COleDateTimeEx::COleDateTimeEx(COleDateTimeEx& CopyFrom)
	: COleDateTime(CopyFrom)
{
	if (!m_bDefaultShortcutsLoaded)
	{
		LoadDefaultShortcuts();
		m_bDefaultShortcutsLoaded = TRUE;
	}

	m_lHourOptions = 0;
	m_lHourCutoff = OLEDATEEX_DEFAULT_HOUR_CUTOFF;
}

COleDateTimeEx::COleDateTimeEx(COleDateTime& CopyFrom)
	: COleDateTime(CopyFrom)
{
	if (!m_bDefaultShortcutsLoaded)
	{
		LoadDefaultShortcuts();
		m_bDefaultShortcutsLoaded = TRUE;
	}

	m_lHourOptions = 0;
	m_lHourCutoff = OLEDATEEX_DEFAULT_HOUR_CUTOFF;
}

COleDateTimeEx::~COleDateTimeEx()
{

}

void COleDateTimeEx::operator=(COleDateTimeEx& CopyFrom)
{
	m_dt = CopyFrom.m_dt;
	m_status = CopyFrom.m_status;
	m_lHourCutoff = CopyFrom.m_lHourCutoff;
	m_lHourOptions = CopyFrom.m_lHourOptions;
}

void COleDateTimeEx::operator=(COleDateTime& CopyFrom)
{
	m_dt = CopyFrom.m_dt;
	m_status = CopyFrom.m_status;
}


CMapStringToString		COleDateTimeEx::m_mapShortcuts;
BOOL					COleDateTimeEx::m_bDefaultShortcutsLoaded = FALSE;

// overide of the ParseDateTime function found in COleDateTime.  I call the base
// class first to see if it is a "normal" date situation.  If it is not, I then call
// EvaluateInputText which in-turn calls the EvaluateInputTextDate and 
// EvaluateInputTextTime functions attempting to parse the text.
BOOL COleDateTimeEx::ParseDateTime(LPCTSTR lpszDate, DWORD dwFlags, LCID lcid)
{
	BOOL bReturn = TRUE;

	COleDateTime dtTemp;
	CString strDate = lpszDate;

	// if we are performing time parsing, check for A.M. and P.M. situations
	if (dwFlags == VAR_TIMEVALUEONLY || dwFlags == 0)
		strDate = DealWithAMPMIssues(strDate);

	dtTemp.ParseDateTime(strDate, dwFlags, lcid);

	// try the default parser and check for success
	if (dtTemp.GetStatus() != COleDateTime::valid || (dwFlags == VAR_DATEVALUEONLY && IsOleDefaultDate(dtTemp)))
	{
		bReturn = FALSE; 

		// remove extra white space characters from input text.  This should improve
		// the parsing process to some (unknown) degree 
		CString strDateText = ExpandShortcuts(RemoveExtraWhiteSpace(FPSTrim(strDate, TRUE)));

		// perform only the requested parser operation
		if (dwFlags == VAR_DATEVALUEONLY)
		{
			if (EvaluateInputTextDate(strDateText, dtTemp))
				bReturn = TRUE;
		} 
		else if (dwFlags == VAR_TIMEVALUEONLY)
		{
			if (EvaluateInputTextTime(strDateText, dtTemp))
				bReturn = TRUE;
		}
		else 
		{
			if (EvaluateInputText(strDateText, dtTemp))
				bReturn = TRUE;
		}
	}

	if (bReturn)
	{
		m_dt = dtTemp.m_dt;
		m_status = dtTemp.m_status;
	}
	else
	{
		SetStatus(COleDateTime::invalid);
	}

	return bReturn;
}

// base implemnentation just calls date and time specific functions
BOOL COleDateTimeEx::EvaluateInputText(LPCTSTR lpszInput, COleDateTime &dt)
{
	if (EvaluateInputTextDate(lpszInput, dt))
		return TRUE;

	if (EvaluateInputTextTime(lpszInput, dt))
		return TRUE;

	return FALSE;
}

// This function determines when easter will occur for a specified year
// Special thanks to Oskar Wieland for his Easter calculation formula posted
// on CodeProject.
void COleDateTimeEx::CalcEasterSunday(WORD wYear, WORD &wMonth, WORD &wDay)
{
    // calculate easter sunday
    // [in]  wYear  - 4-digit year to calculate (but not before 1583)
    // [out] wMonth - month of easter sunday
    // [out] wDay   - day of easter sunday

    WORD wCorrection = 0;   
    
    if( wYear < 1700 )      wCorrection = 4;
    else if( wYear < 1800 ) wCorrection = 5;
    else if( wYear < 1900 ) wCorrection = 6;
    else if( wYear < 2100 ) wCorrection = 0;
    else if( wYear < 2200 ) wCorrection = 1;
    else if( wYear < 2300 ) wCorrection = 2;
    else if( wYear < 2500 ) wCorrection = 3;

    wDay = (WORD)((19 * (wYear % 19) + 24) % 30);        
    wDay = (WORD)(22 + wDay + ((2 * (wYear % 4) + 4 * (wYear % 7) + 6 * wDay + 5 + wCorrection) % 7));
    
    // jump to next month
    if( wDay > 31 )
    {
        wMonth = 4;
        wDay -= 31;
    }
    else
    {
        wMonth = 3;
    }
}

// see if strTest begins with a specified test string
BOOL COleDateTimeEx::BeginsWith(CString &strTest, LPCTSTR lpszTestFor)
{
	int iLen = lstrlen(lpszTestFor);

	return FPSCompareString(strTest.Left(iLen), lpszTestFor);
}

// see if strTest ends with a specified test string
BOOL COleDateTimeEx::EndsWith(CString &strTest, LPCTSTR lpszTestFor)
{
	int iLen = lstrlen(lpszTestFor);

	return FPSCompareString(strTest.Right(iLen), lpszTestFor);
}

// determine a month number from a string representation of the month
// This is soooo bad, but I don't have time to do this right at this time
int COleDateTimeEx::GetMonthNumFromName(LPCTSTR lpszInput)
{
	if (FPSCompareString(lpszInput, "JANUARY") || FPSCompareString(lpszInput, "JAN"))
		return 1;
	if (FPSCompareString(lpszInput, "FEBRUARY") || FPSCompareString(lpszInput, "FEB"))
		return 2;
	if (FPSCompareString(lpszInput, "MARCH") || FPSCompareString(lpszInput, "MAR"))
		return 3;
	if (FPSCompareString(lpszInput, "APRIL") || FPSCompareString(lpszInput, "APR"))
		return 4;
	if (FPSCompareString(lpszInput, "MAY"))
		return 5;
	if (FPSCompareString(lpszInput, "JUNE") || FPSCompareString(lpszInput, "JUN"))
		return 6;
	if (FPSCompareString(lpszInput, "JULY") || FPSCompareString(lpszInput, "JUL"))
		return 7;
	if (FPSCompareString(lpszInput, "AUGUST") || FPSCompareString(lpszInput, "AUG"))
		return 8;
	if (FPSCompareString(lpszInput, "SEPTEMBER") || FPSCompareString(lpszInput, "SEP"))
		return 9;
	if (FPSCompareString(lpszInput, "OCTOBER") || FPSCompareString(lpszInput, "OCT"))
		return 10;
	if (FPSCompareString(lpszInput, "NOVEMBER") || FPSCompareString(lpszInput, "NOV"))
		return 11;
	if (FPSCompareString(lpszInput, "DECEMBER") || FPSCompareString(lpszInput, "DEC"))
		return 12;

	return 0;
}

// computes the X weekday of a given month (ie. 2nd sunday in December)
COleDateTime COleDateTimeEx::ComputeDayInMonth(int iCount, int iDayOfWeek, int iMonth)
{
	COleDateTime dtNow = COleDateTime::GetCurrentTime();
	COleDateTime dtReturn;
	int iTries = 0;
	int iFoundTimes = 0;
	CString strStartDate;
	
	strStartDate = CStr(iMonth);
	strStartDate += "/01/";
	strStartDate += CStr(COleDateTime::GetCurrentTime().GetYear());

	dtReturn.SetDate(COleDateTime::GetCurrentTime().GetYear(), iMonth, 1);

	if (dtReturn.m_status == COleDateTime::valid)
	{
		CString strTemp = dtReturn.Format("%m/%d/%Y");

		while (iFoundTimes != iCount && iTries < 32)
		{
			if (dtReturn.GetDayOfWeek() == iDayOfWeek)
				iFoundTimes++;

			if (iFoundTimes < iCount)
				dtReturn += 1;

			iTries++;
		}

		if (iFoundTimes != iCount)
			dtReturn.m_status = COleDateTime::invalid;
	}

	// return should be in the future (or today)
	if (dtReturn.m_status == COleDateTime::valid && dtNow > dtReturn)
	{
		iTries = 0;
		iFoundTimes = 0;

		strStartDate = CStr(iMonth);
		strStartDate += "/01/";
		strStartDate += CStr(COleDateTime::GetCurrentTime().GetYear()+1);

		dtReturn.SetDate(COleDateTime::GetCurrentTime().GetYear()+1, iMonth, 1);

		if (dtReturn.m_status == COleDateTime::valid)
		{
			while (iFoundTimes != iCount && iTries < 32)
			{
				if (dtReturn.GetDayOfWeek() == iDayOfWeek)
					iFoundTimes++;

				if (iFoundTimes < iCount)
					dtReturn += 1;

				iTries++;
			}

			if (iFoundTimes != iCount)
				dtReturn.m_status = COleDateTime::invalid;
		}
	}

	return dtReturn;
}

// determines if the first tag in an input string is a numeric value
BOOL COleDateTimeEx::IsFirstTagNumeric(CString &strInput)
{
	BOOL bReturn = FALSE;
	int iPos = strInput.Find(" ");

	if (iPos != -1)
	{
		CString strTemp = FPSTrim(strInput.Left(iPos));
		if (IsInteger(strTemp))
			bReturn = TRUE;
	}

	return bReturn;
}

BOOL COleDateTimeEx::IsLastTagNumeric(CString &strInput)
{
	BOOL bReturn = FALSE;
	int iPos = strInput.ReverseFind(' ');

	if (iPos != -1)
	{
		CString strTemp = FPSTrim(strInput.Mid(iPos+1));
		if (IsInteger(strTemp))
			bReturn = TRUE;
	}

	return bReturn;
}

// calculates X # of weekday in the past (ie. 2 sundays ago)
BOOL COleDateTimeEx::CalcXDaysOfWeekAgo(int iDesiredCount, int iDayOfWeek, COleDateTime& dt)
{
	BOOL bReturn = FALSE;
	COleDateTime dtTemp = COleDateTime::GetCurrentTime();
	dtTemp -= 1;

	int iCount = 0;
	int iTries = 0;

	while (iCount != iDesiredCount && iTries < 200)
	{
		if (dtTemp.GetDayOfWeek() == iDayOfWeek)
			iCount++;				

		if (iCount != iDesiredCount)
			dtTemp -= 1;

		iTries++;
	}

	if (iCount == iDesiredCount)
	{
		dt = dtTemp;
		bReturn = TRUE;
	}

	return bReturn;
}

// calculates X # of weekday in the future (ie. 2 sundays from now)
BOOL COleDateTimeEx::CalcXDaysOfWeekFromNow(int iDesiredCount, int iDayOfWeek, COleDateTime& dt)
{
	BOOL bReturn = FALSE;
	COleDateTime dtTemp = COleDateTime::GetCurrentTime();
	dtTemp += 1;

	int iCount = 0;
	int iTries = 0;

	while (iCount != iDesiredCount && iTries < 200)
	{
		if (dtTemp.GetDayOfWeek() == iDayOfWeek)
			iCount++;				

		if (iCount != iDesiredCount)
			dtTemp += 1;

		iTries++;
	}

	if (iCount == iDesiredCount)
	{
		dt = dtTemp;
		bReturn = TRUE;
	}

	return bReturn;
}

// used to compute the "X months ago" situation and the "X months before easter"
// situations
COleDateTime COleDateTimeEx::ComputeMonthsAgo(int iMonths, COleDateTime& dtStart)
{
	COleDateTime dtReturn = dtStart;
	
	int iDay = dtReturn.GetDay();
	int iMonth = dtReturn.GetMonth();
	int iYear = dtReturn.GetYear();

	for (int iX = 0; iX < iMonths; iX++)
	{
		iMonth--;
		if (iMonth < 1)
		{
			iMonth = 12;
			iYear--;
		}

		// if the day of month from last iteration is not in the new month,
		// reverse the calculation
		int iDaysInMonth = GetMaxDaysInMonth(iMonth, iYear);
		if (iDay > iDaysInMonth)
		{
			iMonth--;
			if (iMonth < 1)
			{
				iMonth = 12;
				iYear--;
			}

			iDaysInMonth = GetMaxDaysInMonth(iMonth, iYear);
			iDay = iDaysInMonth - (iDaysInMonth - iDay);
		}
	}

	CString strDate = CStr(iMonth);
	strDate += "/";
	strDate += CStr(iDay);
	strDate += "/";
	strDate += CStr(iYear);

	dtReturn.SetDate(iYear, iMonth, iDay);

	return dtReturn;
}

// used to compute the "X months from now" situation and the "X months after easter"
// situations
COleDateTime COleDateTimeEx::ComputeMonthsFrom(int iMonths, COleDateTime& dtStart)
{
	COleDateTime dtReturn = dtStart;
	
	int iDay = dtReturn.GetDay();
	int iMonth = dtReturn.GetMonth();
	int iYear = dtReturn.GetYear();

	for (int iX = 0; iX < iMonths; iX++)
	{
		iMonth++;
		if (iMonth > 12)
		{
			iMonth = 1;
			iYear++;
		}

		// if the day of month from last iteration is not in the new month,
		// reverse the calculation
		int iDaysInMonth = GetMaxDaysInMonth(iMonth, iYear);
		if (iDay > iDaysInMonth)
		{
			iMonth++;
			if (iMonth > 12)
			{
				iMonth = 1;
				iYear++;
			}

			iDaysInMonth = GetMaxDaysInMonth(iMonth, iYear);
			iDay = (iDaysInMonth - iDay);
		}
	}

	CString strDate = CStr(iMonth);
	strDate += "/";
	strDate += CStr(iDay);
	strDate += "/";
	strDate += CStr(iYear);

	dtReturn.SetDate(iYear, iMonth, iDay);

	return dtReturn;
}

// determines the # of days in the month.  Only thing special
// about this function is the february situation and leap years
int COleDateTimeEx::GetMaxDaysInMonth(int iMonth, int iYear)
{
	int iReturn = 0;

	switch (iMonth)
	{
	case 1: {iReturn = 31; break;}
	case 2:
		{
			if (IsLeapYear(iYear))
				iReturn = 29;
			else
				iReturn = 28;
			break;
		}
	case 3: {iReturn = 31; break;}
	case 4: {iReturn = 30; break;}
	case 5: {iReturn = 31; break;}
	case 6: {iReturn = 30; break;}
	case 7: {iReturn = 31; break;}
	case 8: {iReturn = 31; break;}
	case 9: {iReturn = 30; break;}
	case 10: {iReturn = 31; break;}
	case 11: {iReturn = 30; break;}
	case 12: {iReturn = 31; break;}
	}

	return iReturn;
}

// this function checks a text input for various date-specific data entry
// situations such as today, tomorrow, yesterday, 2 weeks from now, etc
BOOL COleDateTimeEx::EvaluateInputTextDate(LPCTSTR lpszInput, COleDateTime &dt)
{
	// setup for various parsers
	BOOL bReturn = FALSE;
	CString strInput = FPSTrim(lpszInput, TRUE);

	// try various known formats of user input
	// these are basic entry methods commonly entered by my users
	if (IsInteger(strInput) && strInput.GetLength() == 6)		// MMDDYY or YYMMDD
	{
		CString strPart1 = strInput.Left(2);
		CString strPart2 = strInput.Mid(2,2);
		CString strPart3 = strInput.Right(2);
		CString strTemp;

		strTemp = strPart1;
		strTemp += "/";
		strTemp += strPart2;
		strTemp += "/";
		strTemp += strPart3;

		dt.ParseDateTime(strTemp, VAR_DATEVALUEONLY);

		if (dt.m_status == COleDateTime::valid && !IsOleDefaultDate(dt))
			return TRUE;
	}
	else if (IsInteger(strInput) && strInput.GetLength() == 8)		// MMDDYYYY
	{
		CString strPart1 = strInput.Left(2);
		CString strPart2 = strInput.Mid(2,2);
		CString strPart3 = strInput.Right(4);
		CString strTemp;

		strTemp = strPart1;
		strTemp += "/";
		strTemp += strPart2;
		strTemp += "/";
		strTemp += strPart3;

		dt.ParseDateTime(strTemp, VAR_DATEVALUEONLY);

		if (dt.m_status == COleDateTime::valid && !IsOleDefaultDate(dt))
			return TRUE;
	}

	// now, run the text through our little parser
	// most of the routines here are based on the current date
	dt = COleDateTime::GetCurrentTime();

	if (stricmp(strInput, "today") == 0 || stricmp(strInput, "now") == 0)
	{
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "yesterday") == 0)
	{
		dt -= 1;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "day before yesterday") == 0)
	{
		dt -= 2;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "tomorrow") == 0)
	{
		dt += 1;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "day after tomorrow") == 0)
	{
		dt += 2;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next week") == 0)
	{
		dt += 7;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last week") == 0)
	{
		dt -= 7;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "christmas") == 0 || stricmp(strInput, "xmas") == 0 || stricmp(strInput, "x-mas") == 0 || stricmp(strInput, "x-mass") == 0 || stricmp(strInput, "xmass") == 0 || stricmp(strInput, "x mass") == 0)
	{
		dt.SetDate(dt.GetYear(), 12, 25);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "christmas eve") == 0 || stricmp(strInput, "xmas eve") == 0 || stricmp(strInput, "x-mas eve") == 0 || stricmp(strInput, "x-mass eve") == 0 || stricmp(strInput, "xmass eve") == 0 || stricmp(strInput, "x mass eve") == 0)
	{
		dt.SetDate(dt.GetYear(), 12, 24);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "new years") == 0 || stricmp(strInput, "new years day") == 0)
	{
		dt.SetDate(dt.GetYear()+1, 1, 1);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "new years eve") == 0 || stricmp(strInput, "new years eve day") == 0)
	{
		dt.SetDate(dt.GetYear(), 12, 31);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "halloween") == 0)
	{
		dt.SetDate(dt.GetYear(), 10, 31);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "July 4th") == 0 || stricmp(strInput, "July fourth") == 0 || stricmp(strInput, "July forth") == 0 || stricmp(strInput, "4th of July") == 0 || stricmp(strInput, "fourth of July") == 0 || stricmp(strInput, "forth of July") == 0 || stricmp(strInput, "independence day") == 0)
	{
		// set to 7/4 this year
		dt.SetDate(dt.GetYear(), 7, 4);

		// if 4th of july is already past, set to next year
		if (dt < COleDateTime::GetCurrentTime())
			dt.SetDate(dt.GetYear()+1, 7, 4);
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "easter") == 0 || stricmp(strInput, "easter sunday") == 0)
	{
		WORD wMonth = 0;
		WORD wDay = 0;

		CalcEasterSunday((WORD)dt.GetYear(), wMonth, wDay);

		dt.SetDate(dt.GetYear(), wMonth, wDay);

		// if easter has alreaddy occured, move to next year
		if (dt < COleDateTime::GetCurrentTime())
		{
			CalcEasterSunday((WORD)(dt.GetYear()+1), wMonth, wDay);

			dt.SetDate(dt.GetYear()+1, wMonth, wDay);
		}

		bReturn = TRUE;
	}
	else if (stricmp(strInput, "good friday") == 0)
	{
		WORD wMonth = 0;
		WORD wDay = 0;

		CalcEasterSunday((WORD)dt.GetYear(), wMonth, wDay);

		dt.SetDate(dt.GetYear(), wMonth, wDay);

		// if easter has alreaddy occured, move to next year
		if (dt < COleDateTime::GetCurrentTime())
		{
			CalcEasterSunday((WORD)(dt.GetYear()+1), wMonth, wDay);

			dt.SetDate(dt.GetYear()+1, wMonth, wDay);
		}
		
		// good friday occurs 2 days before easter sunday
		dt -= 2;

		bReturn = TRUE;
	}
	else if (stricmp(strInput, "ash wednesday") == 0)
	{
		WORD wMonth = 0;
		WORD wDay = 0;

		CalcEasterSunday((WORD)dt.GetYear(), wMonth, wDay);

		dt.SetDate(dt.GetYear(), wMonth, wDay);

		// if easter has alreaddy occured, move to next year
		if (dt < COleDateTime::GetCurrentTime())
		{
			CalcEasterSunday((WORD)(dt.GetYear()+1), wMonth, wDay);

			dt.SetDate(dt.GetYear()+1, wMonth, wDay);
		}
		
		// ash wednesday occurs 46 days before easte
		dt -= 46;

		bReturn = TRUE;
	}
	else if (stricmp(strInput, "veterans day") == 0 || stricmp(strInput, "veteran day") == 0)
	{
		dt.SetDate(dt.GetYear(), 11, 11);

		if (dt < COleDateTime::GetCurrentTime())
			dt.SetDate(dt.GetYear()+1, 11, 11);

		bReturn = TRUE;
	}
	else if (stricmp(strInput, "memorial day") == 0)
	{
		// last monday in may

		// try the 6th, 5th, 4th and 3rd mondays
		dt = ComputeDayInMonth(6, 2, 5);
		if (dt.m_status != COleDateTime::valid)
			dt = ComputeDayInMonth(5, 2, 5);
		if (dt.m_status != COleDateTime::valid)
			dt = ComputeDayInMonth(4, 2, 5);
		if (dt.m_status != COleDateTime::valid)
			dt = ComputeDayInMonth(3, 2, 5);

		if (dt.m_status == COleDateTime::valid)
			bReturn = TRUE;
	}
	else if (stricmp(strInput, "labor day") == 0)
	{
		// first monday in in september
		dt = ComputeDayInMonth(1, 2, 9);

		if (dt.m_status == COleDateTime::valid)
			bReturn = TRUE;
	}
	else if (stricmp(strInput, "columbus day") == 0)
	{
		// second monday in october
		dt = ComputeDayInMonth(2, 2, 10);

		if (dt.m_status == COleDateTime::valid)
			bReturn = TRUE;
	}
	else if (stricmp(strInput, "thanksgiving") == 0 || stricmp(strInput, "thanksgiving day") == 0)
	{
		// 4th thursday in november
		dt = ComputeDayInMonth(4, 5, 11);

		if (dt.m_status == COleDateTime::valid)
			bReturn = TRUE;
	}
	else if (stricmp(strInput, "Washington's Birthday") == 0 || stricmp(strInput, "Washingtons Birthday") == 0 || stricmp(strInput, "Washington Birthday") == 0 || stricmp(strInput, "presidents day") == 0 || stricmp(strInput, "president's day") == 0 || stricmp(strInput, "president day") == 0)
	{
		// third monday in february
		dt = ComputeDayInMonth(3, 2, 2);

		if (dt.m_status == COleDateTime::valid)
			bReturn = TRUE;
	}
	else if (stricmp(strInput, "NEXT YEAR") == 0 || stricmp(strInput, "THIS NEXT YEAR") == 0)
	{
		dt = COleDateTime::GetCurrentTime();

		dt.SetDate(dt.GetYear()+1, dt.GetMonth(), dt.GetDay());
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "PAST YEAR") == 0 || stricmp(strInput, "THIS PAST YEAR") == 0 || stricmp(strInput, "LAST YEAR") == 0 || stricmp(strInput, "THIS LAST YEAR") == 0)
	{
		dt = COleDateTime::GetCurrentTime();

		dt.SetDate(dt.GetYear()-1, dt.GetMonth(), dt.GetDay());
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last sunday") == 0 || stricmp(strInput, "this past sunday") == 0 || stricmp(strInput, "past sunday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 7; break;}		// sunday
		case 2: {iSubDays = 1; break;}		// monday
		case 3: {iSubDays = 2; break;}		// tuesday
		case 4: {iSubDays = 3; break;}		// wednesday
		case 5: {iSubDays = 4; break;}		// thursday
		case 6: {iSubDays = 5; break;}		// friday
		case 7: {iSubDays = 6; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last monday") == 0 || stricmp(strInput, "this past monday") == 0 || stricmp(strInput, "past monday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 6; break;}		// sunday
		case 2: {iSubDays = 7; break;}		// monday
		case 3: {iSubDays = 1; break;}		// tuesday
		case 4: {iSubDays = 2; break;}		// wednesday
		case 5: {iSubDays = 3; break;}		// thursday
		case 6: {iSubDays = 4; break;}		// friday
		case 7: {iSubDays = 5; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last tuesday") == 0 || stricmp(strInput, "this past tuesday") == 0 || stricmp(strInput, "past tuesday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 5; break;}		// sunday
		case 2: {iSubDays = 6; break;}		// monday
		case 3: {iSubDays = 7; break;}		// tuesday
		case 4: {iSubDays = 1; break;}		// wednesday
		case 5: {iSubDays = 2; break;}		// thursday
		case 6: {iSubDays = 3; break;}		// friday
		case 7: {iSubDays = 4; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last wednesday") == 0 || stricmp(strInput, "this past wednesday") == 0 || stricmp(strInput, "past wednesday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 4; break;}		// sunday
		case 2: {iSubDays = 5; break;}		// monday
		case 3: {iSubDays = 6; break;}		// tuesday
		case 4: {iSubDays = 7; break;}		// wednesday
		case 5: {iSubDays = 1; break;}		// thursday
		case 6: {iSubDays = 2; break;}		// friday
		case 7: {iSubDays = 3; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last thursday") == 0 || stricmp(strInput, "this past thursday") == 0 || stricmp(strInput, "past thursday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 3; break;}		// sunday
		case 2: {iSubDays = 4; break;}		// monday
		case 3: {iSubDays = 5; break;}		// tuesday
		case 4: {iSubDays = 6; break;}		// wednesday
		case 5: {iSubDays = 7; break;}		// thursday
		case 6: {iSubDays = 1; break;}		// friday
		case 7: {iSubDays = 2; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last friday") == 0 || stricmp(strInput, "this past friday") == 0 || stricmp(strInput, "past friday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 2; break;}		// sunday
		case 2: {iSubDays = 3; break;}		// monday
		case 3: {iSubDays = 4; break;}		// tuesday
		case 4: {iSubDays = 5; break;}		// wednesday
		case 5: {iSubDays = 6; break;}		// thursday
		case 6: {iSubDays = 7; break;}		// friday
		case 7: {iSubDays = 1; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "last saturday") == 0 || stricmp(strInput, "this past saturday") == 0 || stricmp(strInput, "past saturday") == 0)
	{
		int iSubDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iSubDays = 1; break;}		// sunday
		case 2: {iSubDays = 2; break;}		// monday
		case 3: {iSubDays = 3; break;}		// tuesday
		case 4: {iSubDays = 4; break;}		// wednesday
		case 5: {iSubDays = 5; break;}		// thursday
		case 6: {iSubDays = 6; break;}		// friday
		case 7: {iSubDays = 7; break;}		// saturday
		}

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next sunday") == 0 || stricmp(strInput, "sunday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 7; break;}		// sunday
		case 2: {iAddDays = 6; break;}		// monday
		case 3: {iAddDays = 5; break;}		// tuesday
		case 4: {iAddDays = 4; break;}		// wednesday
		case 5: {iAddDays = 3; break;}		// thursday
		case 6: {iAddDays = 2; break;}		// friday
		case 7: {iAddDays = 1; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next monday") == 0 || stricmp(strInput, "monday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 1; break;}		// sunday
		case 2: {iAddDays = 7; break;}		// monday
		case 3: {iAddDays = 6; break;}		// tuesday
		case 4: {iAddDays = 5; break;}		// wednesday
		case 5: {iAddDays = 4; break;}		// thursday
		case 6: {iAddDays = 3; break;}		// friday
		case 7: {iAddDays = 2; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next tuesday") == 0 || stricmp(strInput, "tuesday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 2; break;}		// sunday
		case 2: {iAddDays = 1; break;}		// monday
		case 3: {iAddDays = 7; break;}		// tuesday
		case 4: {iAddDays = 6; break;}		// wednesday
		case 5: {iAddDays = 5; break;}		// thursday
		case 6: {iAddDays = 4; break;}		// friday
		case 7: {iAddDays = 3; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next wednesday") == 0 || stricmp(strInput, "wednesday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 3; break;}		// sunday
		case 2: {iAddDays = 2; break;}		// monday
		case 3: {iAddDays = 1; break;}		// tuesday
		case 4: {iAddDays = 7; break;}		// wednesday
		case 5: {iAddDays = 6; break;}		// thursday
		case 6: {iAddDays = 5; break;}		// friday
		case 7: {iAddDays = 4; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next thursday") == 0 || stricmp(strInput, "thursday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 4; break;}		// sunday
		case 2: {iAddDays = 3; break;}		// monday
		case 3: {iAddDays = 2; break;}		// tuesday
		case 4: {iAddDays = 1; break;}		// wednesday
		case 5: {iAddDays = 7; break;}		// thursday
		case 6: {iAddDays = 6; break;}		// friday
		case 7: {iAddDays = 5; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next friday") == 0 || stricmp(strInput, "friday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 5; break;}		// sunday
		case 2: {iAddDays = 4; break;}		// monday
		case 3: {iAddDays = 3; break;}		// tuesday
		case 4: {iAddDays = 2; break;}		// wednesday
		case 5: {iAddDays = 1; break;}		// thursday
		case 6: {iAddDays = 7; break;}		// friday
		case 7: {iAddDays = 6; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "next saturday") == 0 || stricmp(strInput, "saturday") == 0)
	{
		int iAddDays = 0;

		switch (dt.GetDayOfWeek())
		{
		case 1: {iAddDays = 6; break;}		// sunday
		case 2: {iAddDays = 5; break;}		// monday
		case 3: {iAddDays = 4; break;}		// tuesday
		case 4: {iAddDays = 3; break;}		// wednesday
		case 5: {iAddDays = 2; break;}		// thursday
		case 6: {iAddDays = 1; break;}		// friday
		case 7: {iAddDays = 7; break;}		// saturday
		}

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE DAY AGO") == 0 || stricmp(strInput, "1 DAY AGO") == 0 || stricmp(strInput, "A DAY AGO") == 0 || stricmp(strInput, "DAY AGO") == 0) ||
			(stricmp(strInput, "ONE DAYS AGO") == 0 || stricmp(strInput, "1 DAYS AGO") == 0 || stricmp(strInput, "A DAYS AGO") == 0 || stricmp(strInput, "DAYS AGO") == 0))
	{
		dt -= 1;
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE DAY FROM NOW") == 0 || stricmp(strInput, "1 DAY FROM NOW") == 0 || stricmp(strInput, "A DAY FROM NOW") == 0 || stricmp(strInput, "DAY FROM NOW") == 0) ||
		(stricmp(strInput, "ONE DAYS FROM NOW") == 0 || stricmp(strInput, "1 DAYS FROM NOW") == 0 || stricmp(strInput, "A DAYS FROM NOW") == 0 || stricmp(strInput, "DAYS FROM NOW") == 0))
	{
		dt += 1;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput, " DAYS AGO") || EndsWith(strInput, " DAY AGO"))
	{
		int iPos = strInput.Find(" ");
		int iSubDays = CInt(strInput.Left(iPos));

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput, " DAYS FROM NOW") || EndsWith(strInput, " DAY FROM NOW"))
	{
		int iPos = strInput.Find(" ");
		int iAddDays = CInt(strInput.Left(iPos));

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput, "WEEKS AGO") || EndsWith(strInput, "WEEK AGO"))
	{
		int iPos = strInput.Find(" ");
		int iSubDays = CInt(strInput.Left(iPos)) * 7;

		dt -= iSubDays;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput, "WEEKS FROM NOW") || EndsWith(strInput, "WEEK FROM NOW"))
	{
		int iPos = strInput.Find(" ");
		int iAddDays = CInt(strInput.Left(iPos)) * 7;

		dt += iAddDays;
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE MONTH AGO") == 0 || stricmp(strInput, "1 MONTH AGO") == 0 || stricmp(strInput, "A MONTH AGO") == 0 || stricmp(strInput, "MONTH AGO") == 0) ||
			(stricmp(strInput, "ONE MONTHS AGO") == 0 || stricmp(strInput, "1 MONTHS AGO") == 0 || stricmp(strInput, "A MONTHS AGO") == 0 || stricmp(strInput, "MONTHS AGO") == 0))
	{
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();
		dt = ComputeMonthsAgo(1, dtNowTemp);
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE MONTH FROM NOW") == 0 || stricmp(strInput, "1 MONTH FROM NOW") == 0 || stricmp(strInput, "A MONTH FROM NOW") == 0 || stricmp(strInput, "MONTH FROM NOW") == 0) ||
		(stricmp(strInput, "ONE MONTHS FROM NOW") == 0 || stricmp(strInput, "1 MONTHS FROM NOW") == 0 || stricmp(strInput, "A MONTHS FROM NOW") == 0 || stricmp(strInput, "MONTHS FROM NOW") == 0))
	{
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();
		dt = ComputeMonthsFrom(1, dtNowTemp);
		bReturn = TRUE;
	}
	else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, " MONTHS AGO") || EndsWith(strInput, " MONTHS AGO")))
	{
		int iPos = strInput.Find(" ");
		int iSubMonths = CInt(strInput.Left(iPos));
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

		dt = ComputeMonthsAgo(iSubMonths, dtNowTemp);
		bReturn = TRUE;
	}
	else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, " MONTHS FROM NOW") || EndsWith(strInput, " MONTHS FROM NOW")))
	{
		int iPos = strInput.Find(" ");
		int iAddMonths = CInt(strInput.Left(iPos));
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

		dt = ComputeMonthsFrom(iAddMonths, dtNowTemp);
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE YEAR AGO") == 0 || stricmp(strInput, "1 YEAR AGO") == 0 || stricmp(strInput, "A YEAR AGO") == 0 || stricmp(strInput, "YEAR AGO") == 0) ||
			(stricmp(strInput, "ONE YEARS AGO") == 0 || stricmp(strInput, "1 YEARS AGO") == 0 || stricmp(strInput, "A YEARS AGO") == 0 || stricmp(strInput, "YEARS AGO") == 0))
	{
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();
		dt = ComputeMonthsAgo(12, dtNowTemp);
		bReturn = TRUE;
	}
	else if ((stricmp(strInput, "ONE YEAR FROM NOW") == 0 || stricmp(strInput, "1 YEAR FROM NOW") == 0 || stricmp(strInput, "A YEAR FROM NOW") == 0 || stricmp(strInput, "YEAR FROM NOW") == 0) ||
		(stricmp(strInput, "ONE YEARS FROM NOW") == 0 || stricmp(strInput, "1 YEARS FROM NOW") == 0 || stricmp(strInput, "A YEARS FROM NOW") == 0 || stricmp(strInput, "YEARS FROM NOW") == 0))
	{
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();
		dt = ComputeMonthsFrom(12, dtNowTemp);
		bReturn = TRUE;
	}
	else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, " YEARS AGO") || EndsWith(strInput, " YEARS AGO")))
	{
		int iPos = strInput.Find(" ");
		int iSubMonths = CInt(strInput.Left(iPos));
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

		dt = ComputeMonthsAgo(iSubMonths*12, dtNowTemp);
		bReturn = TRUE;
	}
	else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, " YEARS FROM NOW") || EndsWith(strInput, " YEARS FROM NOW")))
	{
		int iPos = strInput.Find(" ");
		int iAddMonths = CInt(strInput.Left(iPos));
		COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

		dt = ComputeMonthsFrom(iAddMonths*12, dtNowTemp);
		bReturn = TRUE;
	}
	else if (BeginsWith(strInput, "1ST SUNDAY IN ") || BeginsWith(strInput, "1 SUNDAY IN ") || BeginsWith(strInput, "FIRST SUNDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 1, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND SUNDAY IN ") || BeginsWith(strInput, "2 SUNDAY IN ") || BeginsWith(strInput, "SECOND SUNDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 1, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD SUNDAY IN ") || BeginsWith(strInput, "3 SUNDAY IN ") || BeginsWith(strInput, "THIRD SUNDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 1, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH SUNDAY IN ") || BeginsWith(strInput, "4 SUNDAY IN ") || BeginsWith(strInput, "FOURTH SUNDAY IN ") || BeginsWith(strInput, "FORTH SUNDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 1, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH SUNDAY IN ") || BeginsWith(strInput, "5 SUNDAY IN ") || BeginsWith(strInput, "FIFTH SUNDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 1, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST MONDAY IN ") || BeginsWith(strInput, "1 MONDAY IN ") || BeginsWith(strInput, "FIRST MONDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 2, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND MONDAY IN ") || BeginsWith(strInput, "2 MONDAY IN ") || BeginsWith(strInput, "SECOND MONDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2,2, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD MONDAY IN ") || BeginsWith(strInput, "3 MONDAY IN ") || BeginsWith(strInput, "THIRD MONDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 2, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH MONDAY IN ") || BeginsWith(strInput, "4 MONDAY IN ") || BeginsWith(strInput, "FOURTH MONDAY IN ") || BeginsWith(strInput, "FORTH MONDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 2, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH MONDAY IN ") || BeginsWith(strInput, "5 MONDAY IN ") || BeginsWith(strInput, "FIFTH MONDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 2, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST TUESDAY IN ") || BeginsWith(strInput, "1 TUESDAY IN ") || BeginsWith(strInput, "FIRST TUESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 3, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND TUESDAY IN ") || BeginsWith(strInput, "2 TUESDAY IN ") || BeginsWith(strInput, "SECOND TUESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 3, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD TUESDAY IN ") || BeginsWith(strInput, "3 TUESDAY IN ") || BeginsWith(strInput, "THIRD TUESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 3, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH TUESDAY IN ") || BeginsWith(strInput, "4 TUESDAY IN ") || BeginsWith(strInput, "FOURTH TUESDAY IN ") || BeginsWith(strInput, "FORTH TUESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 3, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH TUESDAY IN ") || BeginsWith(strInput, "5 TUESDAY IN ") || BeginsWith(strInput, "FIFTH TUESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 3, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST WEDNESDAY IN ") || BeginsWith(strInput, "1 WEDNESDAY IN ") || BeginsWith(strInput, "FIRST WEDNESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 4, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND WEDNESDAY IN ") || BeginsWith(strInput, "2 WEDNESDAY IN ") || BeginsWith(strInput, "SECOND WEDNESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 4, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD WEDNESDAY IN ") || BeginsWith(strInput, "3 WEDNESDAY IN ") || BeginsWith(strInput, "THIRD WEDNESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 4, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH WEDNESDAY IN ") || BeginsWith(strInput, "4 WEDNESDAY IN ") || BeginsWith(strInput, "FOURTH WEDNESDAY IN ") || BeginsWith(strInput, "FORTH WEDNESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 4, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH WEDNESDAY IN ") || BeginsWith(strInput, "5 WEDNESDAY IN ") || BeginsWith(strInput, "FIFTH WEDNESDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 4, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST THURSDAY IN ") || BeginsWith(strInput, "1 THURSDAY IN ") || BeginsWith(strInput, "FIRST THURSDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 5, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND THURSDAY IN ") || BeginsWith(strInput, "2 THURSDAY IN ") || BeginsWith(strInput, "SECOND THURSDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 5, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD THURSDAY IN ") || BeginsWith(strInput, "3 THURSDAY IN ") || BeginsWith(strInput, "THIRD THURSDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 5, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH THURSDAY IN ") || BeginsWith(strInput, "4 THURSDAY IN ") || BeginsWith(strInput, "FOURTH THURSDAY IN ") || BeginsWith(strInput, "FORTH THURSDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 5, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH THURSDAY IN ") || BeginsWith(strInput, "5 THURSDAY IN ") || BeginsWith(strInput, "FIFTH THURSDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 5, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST FRIDAY IN ") || BeginsWith(strInput, "1 FRIDAY IN ") || BeginsWith(strInput, "FIRST FRIDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 6, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND FRIDAY IN ") || BeginsWith(strInput, "2 FRIDAY IN ") || BeginsWith(strInput, "SECOND FRIDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 6, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD FRIDAY IN ") || BeginsWith(strInput, "3 FRIDAY IN ") || BeginsWith(strInput, "THIRD FRIDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 6, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH FRIDAY IN ") || BeginsWith(strInput, "4 FRIDAY IN ") || BeginsWith(strInput, "FOURTH FRIDAY IN ") || BeginsWith(strInput, "FORTH FRIDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 6, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH FRIDAY IN ") || BeginsWith(strInput, "5 FRIDAY IN ") || BeginsWith(strInput, "FIFTH FRIDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 6, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "1ST SATURDAY IN ") || BeginsWith(strInput, "1 SATURDAY IN ") || BeginsWith(strInput, "FIRST SATURDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(1, 7, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "2ND SATURDAY IN ") || BeginsWith(strInput, "2 SATURDAY IN ") || BeginsWith(strInput, "SECOND SATURDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(2, 7, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "3RD SATURDAY IN ") || BeginsWith(strInput, "3 SATURDAY IN ") || BeginsWith(strInput, "THIRD SATURDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(3, 7, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "4TH SATURDAY IN ") || BeginsWith(strInput, "4 SATURDAY IN ") || BeginsWith(strInput, "FOURTH SATURDAY IN ") || BeginsWith(strInput, "FORTH SATURDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(4, 7, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}
	else if (BeginsWith(strInput, "5TH SATURDAY IN ") || BeginsWith(strInput, "5 SATURDAY IN ") || BeginsWith(strInput, "FIFTH SATURDAY IN "))
	{
		int iPos = strInput.ReverseFind(' ');
		CString strMonth = FPSTrim(strInput.Mid(iPos));
		int iMonth = GetMonthNumFromName(strMonth);

		if (iMonth > 0)
		{
			dt = ComputeDayInMonth(5, 7, iMonth);
			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}

	// check for the scenarious like (X days from XXXXXX or X weeks from XXXXX)
	if (!bReturn && IsFirstTagNumeric(strInput))
	{	
		COleDateTime dtTemp;
		int iPos = strInput.Find(" ");
		int iNumber = CInt(strInput.Left(iPos));
		CString strTemp = FPSTrim(strInput.Mid(iPos+1));

		if (BeginsWith(strTemp, "DAYS FROM "))
		{
			if (EvaluateInputText(strTemp.Mid(10), dtTemp))
			{
				dt = dtTemp;
				dt += iNumber;
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "DAYS AFTER "))
		{
			if (EvaluateInputText(strTemp.Mid(11), dtTemp))
			{
				dt = dtTemp;
				dt += iNumber;
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "DAYS BEFORE "))
		{
			if (EvaluateInputText(strTemp.Mid(12), dtTemp))
			{
				dt = dtTemp;
				dt -= iNumber;
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "WEEKS FROM "))
		{
			if (EvaluateInputText(strTemp.Mid(11), dtTemp))
			{
				dt = dtTemp;
				dt += (iNumber * 7);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "WEEKS AFTER "))
		{
			if (EvaluateInputText(strTemp.Mid(12), dtTemp))
			{
				dt = dtTemp;
				dt += (iNumber * 7);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "DAYS BEFORE "))
		{
			if (EvaluateInputText(strTemp.Mid(11), dtTemp))
			{
				dt = dtTemp;
				dt -= (iNumber * 7);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "MONTHS BEFORE "))
		{
			if (EvaluateInputText(strTemp.Mid(13), dtTemp))
			{
				dt = ComputeMonthsAgo(iNumber, dtTemp);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "MONTHS FROM "))
		{
			if (EvaluateInputText(strTemp.Mid(11), dtTemp))
			{
				dt = ComputeMonthsFrom(iNumber, dtTemp);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "MONTHS AFTER "))
		{
			if (EvaluateInputText(strTemp.Mid(12), dtTemp))
			{
				dt = ComputeMonthsFrom(iNumber, dtTemp);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "YEARS BEFORE "))
		{
			if (EvaluateInputText(strTemp.Mid(12), dtTemp))
			{
				dt = ComputeMonthsAgo(iNumber*12, dtTemp);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "YEARS FROM "))
		{
			if (EvaluateInputText(strTemp.Mid(10), dtTemp))
			{
				dt = ComputeMonthsFrom(iNumber*12, dtTemp);
				bReturn = TRUE;
			}
		}
		else if (BeginsWith(strTemp, "YEARS AFTER "))
		{
			if (EvaluateInputText(strTemp.Mid(11), dtTemp))
			{
				dt = ComputeMonthsFrom(iNumber*12, dtTemp);
				bReturn = TRUE;
			}
		}
	}

	// if still no match, look for the siutations like ("christmas - 2 days" or "christmas + 2 days")
	if (!bReturn)
	{
		BOOL bOK = TRUE;
		BOOL bAdd = TRUE;
		CString strPart1;
		CString strPart2;

		// find the first addition/subtration operator
		if (strInput.Find(" + ") != -1)
		{
			int iPos = strInput.Find(" + ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+3);
		}
		if (strInput.Find(" +") != -1)
		{
			int iPos = strInput.Find(" +");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+2);
		}
		if (strInput.Find("+ ") != -1)
		{
			int iPos = strInput.Find("+ ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+2);
		}
		if (strInput.Find("+") != -1)
		{
			int iPos = strInput.Find("+");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+1);
		}
		else if (strInput.Find(" PLUS ") != -1)
		{
			int iPos = strInput.Find(" PLUS ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+6);
		}
		else if (strInput.Find(" - ") != -1)
		{
			bAdd = FALSE;
			int iPos = strInput.Find(" - ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+3);
		}
		else if (strInput.Find("- ") != -1)
		{
			bAdd = FALSE;
			int iPos = strInput.Find("- ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+2);
		}
		else if (strInput.Find(" -") != -1)
		{
			bAdd = FALSE;
			int iPos = strInput.Find(" -");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+2);
		}
		else if (strInput.Find("-") != -1)
		{
			bAdd = FALSE;
			int iPos = strInput.Find("-");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+1);
		}
		else if (strInput.Find(" MINUS ") != -1)
		{
			bAdd = FALSE;
			int iPos = strInput.Find(" MINUS ");
			strPart1 = strInput.Left(iPos);
			strPart2 = strInput.Mid(iPos+7);
		}
		else
		{
			bOK = FALSE;
		}

		// only proceed if we found an operator indicator
		if (bOK)
		{
			bOK = FALSE;
			COleDateTime dtTemp;
			int iAddDays = 0;

			// look for various situations (ie. part1 = number, part 2= number)
			if (IsInteger(strPart1))
			{
				iAddDays = CInt(strPart1);

				if (EvaluateInputText(strPart2, dtTemp))
					bOK = TRUE;
			}
			else if (IsInteger(strPart2))
			{
				iAddDays = CInt(strPart2);

				if (EvaluateInputText(strPart1, dtTemp))
					bOK = TRUE;
			}
			else if (IsFirstTagNumeric(strPart1) && FPSCompareString(strPart1.Mid(strPart1.Find(" ")+1), "DAYS"))
			{
				iAddDays = CInt(strPart1.Left(strPart1.Find(" ")));

				if (EvaluateInputText(strPart2, dtTemp))
					bOK = TRUE;
			}
			else if (IsFirstTagNumeric(strPart1) && FPSCompareString(strPart1.Mid(strPart1.Find(" ")+1), "WEEKS"))
			{
				iAddDays = CInt(strPart1.Left(strPart1.Find(" "))) * 7;

				if (EvaluateInputText(strPart2, dtTemp))
					bOK = TRUE;
			}
			else if (IsFirstTagNumeric(strPart2) && FPSCompareString(strPart2.Mid(strPart2.Find(" ")+1), "DAYS"))
			{
				iAddDays = CInt(strPart2.Left(strPart2.Find(" ")));

				if (EvaluateInputText(strPart1, dtTemp))
					bOK = TRUE;
			}
			else if (IsFirstTagNumeric(strPart2) && FPSCompareString(strPart2.Mid(strPart2.Find(" ")+1), "WEEKS"))
			{
				iAddDays = CInt(strPart2.Left(strPart2.Find(" "))) * 7;

				if (EvaluateInputText(strPart1, dtTemp))
					bOK = TRUE;
			}

			// only continue if part 1 and part 2 could be evaluated
			if (bOK && bAdd)
			{
				dt = dtTemp;
				dt += iAddDays;
				bReturn = TRUE;
			}
			else if (bOK && !bAdd)
			{
				dt = dtTemp;
				dt -= iAddDays;
				bReturn = TRUE;
			}
		}
	}

	// if still no computed date, look for the "X SUNDAYS AGO" scenarios
	if (!bReturn)
	{
		if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "SUNDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 1, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "MONDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 2, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "TUESDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 3, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "WEDNESDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 4, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "THURSDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 5, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "FRIDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 6, dt);
		}
		else if (IsFirstTagNumeric(strInput) && EndsWith(strInput, "SATURDAYS AGO"))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekAgo(iDesiredCount, 7, dt);
		}
	}

	// if still no computed date, look for the "X SUNDAYS FROM NOW" scenarios
	if (!bReturn)
	{
		if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "SUNDAYS FROM NOW") || EndsWith(strInput, "SUNDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 1, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "MONDAYS FROM NOW") || EndsWith(strInput, "MONDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 2, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "TUESDAYS FROM NOW") || EndsWith(strInput, "TUESDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 3, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "WEDNESDAYS FROM NOW") || EndsWith(strInput, "WEDNESDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 4, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "THURSDAYS FROM NOW") || EndsWith(strInput, "THURSDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 5, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "FRIDAYS FROM NOW") || EndsWith(strInput, "FRIDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 6, dt);
		}
		else if (IsFirstTagNumeric(strInput) && (EndsWith(strInput, "SATURDAYS FROM NOW") || EndsWith(strInput, "SATURDAYS FROM TODAY")))
		{
			int iDesiredCount = CInt(strInput.Left(strInput.Find(" ")));
			bReturn = CalcXDaysOfWeekFromNow(iDesiredCount, 7, dt);
		}
	}

	// if still no success, check for the NEXT EASTER, LAST NEW YEAR type 
	// siturations as generics
	if (!bReturn)
	{
		CString strTest;
		BOOL bOK = FALSE;
		BOOL bNext = FALSE;
		COleDateTimeEx dtCompute;
		COleDateTime dtNow;
		
		dtNow = COleDateTime::GetCurrentTime();

		if (BeginsWith(strInput, "NEXT "))
		{
			strTest = FPSTrim(strInput.Mid(5));
			bOK = TRUE;
			bNext = TRUE;
		}
		else if (BeginsWith(strInput, "THIS NEXT "))
		{
			strTest = FPSTrim(strInput.Mid(10));
			bOK = TRUE;
			bNext = TRUE;
		}
		else if (BeginsWith(strInput, "LAST ") || BeginsWith(strInput, "PAST "))
		{
			strTest = FPSTrim(strInput.Mid(5));
			bOK = TRUE;
			bNext = FALSE;
		}
		else if (BeginsWith(strInput, "THIS LAST ") || BeginsWith(strInput, "THIS PAST "))
		{
			strTest = FPSTrim(strInput.Mid(10));
			bOK = TRUE;
			bNext = FALSE;
		}

		// if condition is TRUE, try and parse the input text into a date
		if (bOK)
		{
			// compute a date from the words().  This is used for the Easter, Christmas, situations
			if (ComputeDateFromWord(dtCompute, strTest, dtNow.GetYear()))
			{
				if (bNext)
				{
					if (dtCompute <= dtNow)
						ComputeDateFromWord(dtCompute, strTest, dtNow.GetYear()+1);

					dt = dtCompute;
					bReturn = TRUE;
				}
				else
				{
					if (dtCompute >= dtNow)
						ComputeDateFromWord(dtCompute, strTest, dtNow.GetYear()-1);

					dt = dtCompute;
					bReturn = TRUE;
				}
			}
		}
	}

	// if still no parsable conditions, check for the 'Easter 2005' like situations
	if (!bReturn && IsLastTagNumeric(strInput))
	{
		int iPos = strInput.ReverseFind(' ');
		int iYear = CInt(strInput.Mid(iPos+1));
		CString strTest = FPSTrim(strInput.Left(iPos));
		COleDateTimeEx dtCompute;

		if (ComputeDateFromWord(dtCompute, strTest, iYear))
		{
			dt = dtCompute;
			bReturn = TRUE;
		}
	}

	// if still no computed date, look for the "IN X DAYS", "IN X WEEKS" scenarios
	if (!bReturn)
	{
		if (strInput.Right(5) == " DAYS")
		{
			if (strInput.Left(3) == "IN ")
				strInput = strInput.Mid(3);

			int iPos = strInput.Find(" ");
			int iAddDays = CInt(strInput.Left(iPos));

			dt += iAddDays;
			bReturn = TRUE;
		}
		else if (strInput.Right(6) == " WEEKS")
		{
			if (strInput.Left(3) == "IN ")
				strInput = strInput.Mid(3);

			int iPos = strInput.Find(" ");
			int iAddDays = CInt(strInput.Left(iPos)) * 7;

			dt += iAddDays;
			bReturn = TRUE;
		}
		else if (strInput.Right(7) == " MONTHS")
		{
			if (strInput.Left(3) == "IN ")
				strInput = strInput.Mid(3);

			int iPos = strInput.Find(" ");
			int iAddMonths = CInt(strInput.Left(iPos));
			COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

			dt = ComputeMonthsFrom(iAddMonths, dtNowTemp);
			bReturn = TRUE;
		}
		else if (strInput.Right(6) == " YEARS")
		{
			if (strInput.Left(3) == "IN ")
				strInput = strInput.Mid(3);

			int iPos = strInput.Find(" ");
			int iAddMonths = CInt(strInput.Left(iPos));
			COleDateTime dtNowTemp = COleDateTime::GetCurrentTime();

			dt = ComputeMonthsFrom(iAddMonths*12, dtNowTemp);
			bReturn = TRUE;
		}
	}

	return bReturn;
}

BOOL COleDateTimeEx::EvaluateInputTextTime(LPCTSTR lpszInput, COleDateTime &dt)
{
	BOOL bReturn = FALSE;
	CString strInput = FPSTrim(lpszInput, TRUE);

	// most of the routines here are based on the current date
	dt = COleDateTime::GetCurrentTime();

	if (stricmp(strInput, "now") == 0)
	{
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "noon") == 0)
	{
		dt.ParseDateTime("12:00 PM");
		bReturn = TRUE;
	}
	else if (stricmp(strInput, "midnight") == 0)
	{
		dt.ParseDateTime("12:00 AM");
		bReturn = TRUE;
	}
	else if (IsInteger(strInput) && strInput.GetLength() == 3)
	{
		// ie: 430
		CString strTemp;
		CString strHour;
		CString strMinute;
		int iMinute = CInt(strInput.Right(2));
		int iHour = CInt(strInput.Left(1));

		switch(m_lHourOptions)
		{
		case OLEDATEEX_HOUR_DETECT_CURRENT_HOUR:
			{
				if (iHour < dt.GetHour())
					iHour += 12;
				break;
			}
		case OLEDATEEX_HOUR_DETECT_USE_CUTOFF:
			{
				if (iHour < m_lHourCutoff)
					iHour += 12;
				break;
			}
		case OLEDATEEX_HOUR_DETECT_LEAVE:
			{
				// don't be clever, just do what you are told!
				break;
			} 
		default:		 //default behavior, before 7 is PM, after is AM
			{
				if (iHour < 7)
					iHour += 12;
				break;
			}
		}

		if (iHour > 23)
			iHour = 23;

		strHour = "00"; strHour += CStr(iHour); strHour = strHour.Right(2);
		strMinute = "00"; strMinute += CStr(iMinute); strMinute = strMinute.Right(2);

		strTemp = strHour;
		strTemp += ":";
		strTemp += strMinute;

		dt.ParseDateTime(strTemp, VAR_TIMEVALUEONLY);
		bReturn = TRUE;
	}
	else if (IsInteger(strInput) && strInput.GetLength() == 4)
	{
		// ie: 1230
		CString strTemp;
		CString strHour;
		CString strMinute;
		int iMinute = CInt(strInput.Right(2));
		int iHour = CInt(strInput.Left(2));

		switch(m_lHourOptions)
		{
		case OLEDATEEX_HOUR_DETECT_CURRENT_HOUR:
			{
				if (iHour < 12 && iHour < dt.GetHour())
					iHour += 12;
				break;
			}
		case OLEDATEEX_HOUR_DETECT_USE_CUTOFF:
			{
				//two digit hour, but less than 10, must be military, leave as is
				break;
			}
		case OLEDATEEX_HOUR_DETECT_LEAVE:
			{
				//don't be clever, just do what you are told!
				break;
			}
		default:
			{
				if (iHour < 7)
					iHour += 12;
			}
			break;
		}

		if (iHour > 23)
			iHour = 23;

		strHour = "00"; strHour += CStr(iHour); strHour = strHour.Right(2);
		strMinute = "00"; strMinute += CStr(iMinute); strMinute = strMinute.Right(2);

		strTemp = strHour;
		strTemp += ":";
		strTemp += strMinute;

		dt.ParseDateTime(strTemp, VAR_TIMEVALUEONLY);
		bReturn = TRUE;
	}
	else if (IsInteger(strInput))
	{
		// this is used for the situation when the user just enters a number
		CString strTemp;
		CString strHour = strInput;
		CString strMinute;
		int iMinute = 0;
		int iHour = CInt(strInput);

		strHour.TrimLeft();
		strHour.TrimRight();

		switch(m_lHourOptions)
		{
		case OLEDATEEX_HOUR_DETECT_CURRENT_HOUR:
			{
				if (iHour < 12 && iHour < dt.GetHour())
					iHour += 12;
				break;
			}
		case OLEDATEEX_HOUR_DETECT_USE_CUTOFF:
			{
				if (iHour < 12 && iHour < m_lHourCutoff)
					iHour += 12;
				break;
			}
		case OLEDATEEX_HOUR_DETECT_LEAVE:
			{
				//don't be clever, just do what you are told!
				break;
			}
		default:
			{
				if (iHour < 7)
					iHour += 12;
				break;
			}
		}

		if (iHour > 23)
			iHour = 23;

		strHour = "00"; strHour += CStr(iHour); strHour = strHour.Right(2);
		strMinute = "00";

		strTemp = strHour;
		strTemp += ":";
		strTemp += strMinute;

		dt.ParseDateTime(strTemp, VAR_TIMEVALUEONLY);
		bReturn = TRUE;
	}
	else if (strInput.Find("OCLOCK") > 1 || strInput.Find("O'CLOCK") > 1 || strInput.Find("O CLOCK") > 1)
	{
		CString strTemp;
		CString strHour;
		CString strMinute;
		int iPos = strInput.Find(" ");
		int iHour = CInt(strInput.Left(iPos));

		if (iHour < 7)
			iHour += 12;
		if (iHour > 23)
			iHour = 23;

		strHour = "00"; strHour += CStr(iHour); strHour = strHour.Right(2);
		strMinute = "00";

		strTemp = strHour;
		strTemp += ":";
		strTemp += strMinute;

		dt.ParseDateTime(strTemp, VAR_TIMEVALUEONLY);
		bReturn = TRUE;
	}
	else if (EndsWith(strInput, "MINUTES FROM NOW"))
	{
		int iPos = strInput.Find(" ");
		int iMinutes = CInt(strInput.Left(iPos));
		COleDateTimeSpan span(0,0,iMinutes,0);

		dt += span;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput,"HOURS FROM NOW"))
	{
		int iPos = strInput.Find(" ");
		int iHours = CInt(strInput.Left(iPos));
		COleDateTimeSpan span(0,iHours,0,0);

		dt += span;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput,"MINUTES AGO"))
	{
		int iPos = strInput.Find(" ");
		int iMinutes = CInt(strInput.Left(iPos));
		COleDateTimeSpan span(0,0,iMinutes,0);

		dt -= span;
		bReturn = TRUE;
	}
	else if (EndsWith(strInput,"HOURS AGO"))
	{
		int iPos = strInput.Find(" ");
		int iHours = CInt(strInput.Left(iPos));
		COleDateTimeSpan span(0,iHours,0,0);

		dt -= span;
		bReturn = TRUE;
	}
	else if (IsFirstTagNumeric(strInput))		// situations like (15 till 6) or (15 after 6)
	{
		int iPos = strInput.Find(" ");
		int iNumber = CInt(strInput.Left(iPos));
		strInput = FPSTrim(strInput.Mid(iPos+1));

		if (iNumber < 59 && iNumber > 0)
		{
			if (BeginsWith(strInput, "MINUTES TILL "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(12);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt -= span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "TILL "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(4);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt -= span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "TIL "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(3);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt -= span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "MINUTES UNTIL "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(13);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt -= span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "UNTIL "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(5);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt -= span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "MINUTES PAST "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(12);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt += span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "PAST "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(4);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt += span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "MINUTES AFTER "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(13);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt += span;
					bReturn = TRUE;
				}
			}
			else if (BeginsWith(strInput, "AFTER "))
			{
				COleDateTime dtTemp = COleDateTime::GetCurrentTime();
				CString strTemp = strInput.Mid(5);
				int iMinutes = iNumber;
				COleDateTimeSpan span(0,0,iMinutes,0);

				if (EvaluateInputTextTime(strTemp, dtTemp))
				{
					dt = dtTemp;
					dt += span;
					bReturn = TRUE;
				}
			}
		}
	}
	else if (BeginsWith(strInput, "HALF PAST "))
	{
		CString strTemp = strInput.Mid(10);
		COleDateTime dtTemp;
		COleDateTimeSpan span(0,0,30,0);

		if (EvaluateInputTextTime(strTemp, dtTemp))
		{
			dt = dtTemp;
			dt += span;
			bReturn = TRUE;
		}
	}

	return bReturn;
}


// ***************************************************************************
// Begin String Support functions
// ***************************************************************************
BOOL COleDateTimeEx::FPSCompareString(LPCSTR lpszTest1, LPCSTR lpszTest2)
{
	CString strComp1 = lpszTest1;
	CString strComp2 = lpszTest2;

	strComp1.TrimRight();
	strComp2.TrimRight();

	if (stricmp(strComp1, strComp2) == 0)
		return TRUE;

	return FALSE;
}

CString COleDateTimeEx::CStr(long lValue)
{
	char szValue[20];

	_ltoa(lValue, szValue, 10);

	return szValue;
}

CString COleDateTimeEx::FPSTrim(LPCSTR lpszInput, BOOL bForceUpper)
{
	CString strReturn;

	strReturn = lpszInput;
	strReturn.TrimRight();
	strReturn.TrimLeft();

	if (bForceUpper)
		strReturn.MakeUpper();

	return strReturn;
}

BOOL COleDateTimeEx::IsInteger(LPCSTR lpszVL)
{
	BOOL bReturn = TRUE;
	int iNumCount = 0;
	int iLen = lstrlen(lpszVL);
	int iPos = 0;

	while (iPos < iLen && bReturn)
	{
		if (::isdigit(lpszVL[iPos]) || lpszVL[iPos] == '-')
		{
			iNumCount++;
		}
		else
		{
			bReturn = FALSE;
		}

		iPos++;
	}

	if (iNumCount == 0)
		bReturn = FALSE;

	return bReturn;
}

int COleDateTimeEx::CInt(LPCSTR lpszValue)
{
	return atoi(lpszValue);
}
// ***************************************************************************
// END String Support functions
// ***************************************************************************

BOOL COleDateTimeEx::IsLeapYear(int iYear)
{
	if (fmod(iYear, 4) == 0 && (fmod(iYear, 100) != 0 || fmod(iYear, 400) == 0))
		return TRUE;

	return FALSE;
}

BOOL COleDateTimeEx::IsOleDefaultDate(COleDateTime &dt)
{
	// if a ParseDateTime function is called and it cannot properly
	// convert the input text, sometimes (see MSDN article below) it
	// sets the date/time to December 30, 1899.  This is a problem which
	// we need to deal with
	// MSDN Article:
	// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcemfc/htm/coledati_15.asp
	if (dt.GetYear() == 1899 && dt.GetMonth() == 12 && dt.GetDay() == 30)
		return TRUE;
	return FALSE;
}

CString COleDateTimeEx::RemoveExtraWhiteSpace(LPCTSTR lpszInput)
{
	CString strReturn;
	LPCTSTR pszData = lpszInput;
	TCHAR cLastChar = 0;
	TCHAR cChar = 0;

	while (*pszData)
	{
		cChar = *pszData;

		if (cChar != ' ')
			strReturn += cChar;
		else if (cLastChar != ' ')
			strReturn += cChar;

		// record last character processed
		cLastChar = cChar;

		pszData++;
	}

	return strReturn;
}

CString COleDateTimeEx::ExpandShortcuts(LPCTSTR lpszInput)
{
	CString strReturn;
	LPCTSTR pszData = lpszInput;
	TCHAR cLastChar = 0;
	TCHAR cChar = 0;
	CString strTag;

	while (*pszData)
	{
		cChar = *pszData;

		if (!::isalnum(cChar))
		{
			strReturn += ExpandShortCut(strTag);
			strReturn += cChar;
			strTag = "";
		}
		else
		{
			strTag += cChar;
		}

		pszData++;
	}

	if (strTag != "")
		strReturn += ExpandShortCut(strTag);

	return strReturn;

}

CString COleDateTimeEx::ExpandShortCut(LPCTSTR lpszInput)
{
	CString strReturn;
	CString strExpanded;

	if (m_mapShortcuts.Lookup(lpszInput, strExpanded))
		strReturn = strExpanded;
	else
		strReturn = lpszInput;

	return strReturn;
}

// here I am hard-coding some very basic shortcuts.  Methods exist for
// clearing this list and creating a new one.  In the future I will provide
// a way (through UI) to customize these shortcuts
void COleDateTimeEx::LoadDefaultShortcuts()
{
	m_mapShortcuts.SetAt("T", "TODAY");
	m_mapShortcuts.SetAt("N", "NOW");
	m_mapShortcuts.SetAt("Y", "YESTERDAY");
	m_mapShortcuts.SetAt("TM", "TOMORROW");

	m_mapShortcuts.SetAt("NW", "NEXT WEEK");
	m_mapShortcuts.SetAt("NM", "NEXT MONTH");
	m_mapShortcuts.SetAt("N1", "NEXT SUNDAY");
	m_mapShortcuts.SetAt("N2", "NEXT MONDAY");
	m_mapShortcuts.SetAt("N3", "NEXT TUESDAY");
	m_mapShortcuts.SetAt("N4", "NEXT WEDNESDAY");
	m_mapShortcuts.SetAt("N5", "NEXT THURSDAY");
	m_mapShortcuts.SetAt("N6", "NEXT FRIDAY");
	m_mapShortcuts.SetAt("N7", "NEXT SATURDAY");

	m_mapShortcuts.SetAt("LW", "LAST WEEK");
	m_mapShortcuts.SetAt("LM", "LAST MONTH");
	m_mapShortcuts.SetAt("L1", "LAST SUNDAY");
	m_mapShortcuts.SetAt("L2", "LAST MONDAY");
	m_mapShortcuts.SetAt("L3", "LAST TUESDAY");
	m_mapShortcuts.SetAt("L4", "LAST WEDNESDAY");
	m_mapShortcuts.SetAt("L5", "LAST THURSDAY");
	m_mapShortcuts.SetAt("L6", "LAST FRIDAY");
	m_mapShortcuts.SetAt("L7", "LAST SATURDAY");

	m_mapShortcuts.SetAt("DY", "DAY BEFORE YESTERDAY");
	m_mapShortcuts.SetAt("DT", "DAY AFTER TOMORROW");

	m_mapShortcuts.SetAt("X", "CHRISTMAS");
	m_mapShortcuts.SetAt("XE", "CHRISTMAS EVE");
	m_mapShortcuts.SetAt("E", "EASTER");
	m_mapShortcuts.SetAt("GF", "GOOD FRIDAY");
	m_mapShortcuts.SetAt("AW", "ASH WEDNESDAY");
	m_mapShortcuts.SetAt("H", "HALLOWEEN");
	m_mapShortcuts.SetAt("NY", "NEW YEARS");
	m_mapShortcuts.SetAt("NYE", "NEW YEARS EVE");
	m_mapShortcuts.SetAt("J4", "JULY 4TH");
	m_mapShortcuts.SetAt("MD", "MEMORIAL DAY");
	m_mapShortcuts.SetAt("LD", "LABOR DAY");
	m_mapShortcuts.SetAt("VD", "VETERANS DAY");
	m_mapShortcuts.SetAt("CD", "COLUMBUS DAY");
	m_mapShortcuts.SetAt("TH", "THANKSGIVING");
	m_mapShortcuts.SetAt("PD", "PRESIDENTS DAY");
}

BOOL COleDateTimeEx::ComputeDateFromWord(COleDateTimeEx &dt, CString &strInput, int iYear)
{
	BOOL bReturn = FALSE;
	COleDateTime dtTemp;

	// deal with year windowing
	dtTemp.SetDate(iYear, 1, 1);

	if (dtTemp.m_status == COleDateTime::valid)
	{
		// reset year from dtTemp (this takes care of windowing situations like 96 = 1996
		iYear = dtTemp.GetYear();

		// we always start with the current date/time
		COleDateTime dtNow = COleDateTime::GetCurrentTime();
		dt.m_dt = dtNow.m_dt;
		dt.m_status = dtNow.m_status;

		if (stricmp(strInput, "christmas") == 0 || stricmp(strInput, "xmas") == 0 || stricmp(strInput, "x-mas") == 0 || stricmp(strInput, "x-mass") == 0 || stricmp(strInput, "xmass") == 0 || stricmp(strInput, "x mass") == 0)
		{
			dt.SetDate(iYear, 12, 25);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "christmas eve") == 0 || stricmp(strInput, "xmas eve") == 0 || stricmp(strInput, "x-mas eve") == 0 || stricmp(strInput, "x-mass eve") == 0 || stricmp(strInput, "xmass eve") == 0 || stricmp(strInput, "x mass eve") == 0)
		{
			dt.SetDate(iYear, 12, 24);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "new years") == 0 || stricmp(strInput, "new years day") == 0)
		{
			dt.SetDate(iYear, 1, 1);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "new years eve") == 0 || stricmp(strInput, "new years eve day") == 0)
		{
			dt.SetDate(iYear, 12, 31);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "halloween") == 0)
		{
			dt.SetDate(iYear, 10, 31);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "July 4th") == 0 || stricmp(strInput, "July fourth") == 0 || stricmp(strInput, "July forth") == 0 || stricmp(strInput, "4th of July") == 0 || stricmp(strInput, "fourth of July") == 0 || stricmp(strInput, "forth of July") == 0 || stricmp(strInput, "independence day") == 0)
		{
			// set to 7/4 this year
			dt.SetDate(iYear, 7, 4);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "easter") == 0 || stricmp(strInput, "easter sunday") == 0)
		{
			WORD wMonth = 0;
			WORD wDay = 0;

			CalcEasterSunday((WORD)iYear, wMonth, wDay);
			dt.SetDate(iYear, wMonth, wDay);
			bReturn = TRUE;
		}
		else if (stricmp(strInput, "good friday") == 0)
		{
			WORD wMonth = 0;
			WORD wDay = 0;

			CalcEasterSunday((WORD)iYear, wMonth, wDay);
			dt.SetDate(dt.GetYear(), wMonth, wDay);

			// good friday occurs 2 days before easter sunday
			dt -= 2;

			bReturn = TRUE;
		}
		else if (stricmp(strInput, "ash wednesday") == 0)
		{
			WORD wMonth = 0;
			WORD wDay = 0;

			CalcEasterSunday((WORD)iYear, wMonth, wDay);
			dt.SetDate(iYear, wMonth, wDay);
		
			// ash wednesday occurs 46 days before easte
			dt -= 46;

			bReturn = TRUE;
		}
		else if (stricmp(strInput, "veterans day") == 0 || stricmp(strInput, "veteran day") == 0)
		{
			dt.SetDate(iYear, 11, 11);

			bReturn = TRUE;
		}
		else if (stricmp(strInput, "memorial day") == 0)
		{
			// last monday in may
			// try the 6th, 5th, 4th and 3rd mondays
			dt.SetStatus(COleDateTime::invalid);
			dt.ComputeDayInMonth(6, 2, 5, iYear);
			if (dt.m_status != COleDateTime::valid)
				dt.ComputeDayInMonth(5, 2, 5, iYear);
			if (dt.m_status != COleDateTime::valid)
				dt.ComputeDayInMonth(4, 2, 5, iYear);
			if (dt.m_status != COleDateTime::valid)
				dt.ComputeDayInMonth(3, 2, 5, iYear);

			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
		else if (stricmp(strInput, "labor day") == 0)
		{
			// first monday in in september
			dt.ComputeDayInMonth(1, 2, 9, iYear);

			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
		else if (stricmp(strInput, "columbus day") == 0)
		{
			// second monday in october
			dt.ComputeDayInMonth(2, 2, 10, iYear);

			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
		else if (stricmp(strInput, "thanksgiving") == 0 || stricmp(strInput, "thanksgiving day") == 0)
		{
			// 4th thursday in november
			dt.ComputeDayInMonth(4, 5, 11, iYear);

			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
		else if (stricmp(strInput, "Washington's Birthday") == 0 || stricmp(strInput, "Washingtons Birthday") == 0 || stricmp(strInput, "Washington Birthday") == 0 || stricmp(strInput, "presidents day") == 0 || stricmp(strInput, "president's day") == 0 || stricmp(strInput, "president day") == 0)
		{
			// third monday in february
			dt.ComputeDayInMonth(3, 2, 2, iYear);

			if (dt.m_status == COleDateTime::valid)
				bReturn = TRUE;
		}
	}

	return bReturn;
}

BOOL COleDateTimeEx::ComputeDayInMonth(int iCount, int iDayOfWeek, int iMonth, int iYear)
{
	BOOL bReturn = TRUE;
	BOOL bContinue = TRUE;
	int iActualCount = 0;
	COleDateTimeEx dtTemp;
	CString strStart = CStr(iMonth); strStart += "/"; strStart += "01/"; strStart += CStr(iYear);

	dtTemp.SetDate(iYear, iMonth, 1);

	while (bContinue && dtTemp.GetStatus() == COleDateTime::valid)
	{
		if (dtTemp.GetDayOfWeek() == iDayOfWeek)
		{
			iActualCount++;

			if (iActualCount == iCount)
			{
				m_dt = dtTemp.m_dt;
				m_status = dtTemp.m_status;
				bContinue = FALSE;
			}
		}


		dtTemp += 1;
	}

	return bReturn;
}

void COleDateTimeEx::SetHourOption(long lHourOptions)
{
	if (lHourOptions == OLEDATEEX_HOUR_DETECT_DEFAULT ||
		lHourOptions == OLEDATEEX_HOUR_DETECT_CURRENT_HOUR ||
		lHourOptions == OLEDATEEX_HOUR_DETECT_USE_CUTOFF ||
		lHourOptions == OLEDATEEX_HOUR_DETECT_LEAVE)
	{
		m_lHourOptions = lHourOptions;
	}
	else
	{
		ASSERT(FALSE);		// invalid parsing option
	}
}

long COleDateTimeEx::GetHourOption()
{
	return m_lHourOptions;
}

void COleDateTimeEx::SetHourThreshold(int lHourCutoff)
{
	if (lHourCutoff >= 1 && lHourCutoff <= 11)
	{
		m_lHourCutoff = lHourCutoff;
	}
	else
	{
		ASSERT(FALSE);		// invalid cutoff
	}
}

int COleDateTimeEx::GetHourThreshold()
{
	return m_lHourCutoff;
}

BOOL COleDateTimeEx::IsDayType(int iType)
{
	BOOL bReturn = FALSE;

	switch (iType)
	{
	case OLEDATEEX_DAY: {bReturn = TRUE; break;}
	case OLEDATEEX_WEEK_DAY: {bReturn = IsWeekDay(); break;}
	case OLEDATEEX_WEEKEND_DAY: {bReturn = IsWeekendDay(); break;}
	case OLEDATEEX_SUNDAY: {bReturn = IsSunday(); break;}
	case OLEDATEEX_MONDAY: {bReturn = IsMonday(); break;}
	case OLEDATEEX_TUESDAY: {bReturn = IsTuesday(); break;}
	case OLEDATEEX_WEDNESDAY: {bReturn = IsWednesday(); break;}
	case OLEDATEEX_THURSDAY: {bReturn = IsThursday(); break;}
	case OLEDATEEX_FRIDAY: {bReturn = IsFriday(); break;}
	case OLEDATEEX_SATURDAY: {bReturn = IsSaturday(); break;}
	default:
		{
			ASSERT(FALSE);	// invalid type specified
			break;
		}
	}

	return bReturn;
}

// this function is responsible for converting "A.M.", "A M", "A.M", "A M." and "AM." into "AM"
//														AND
//											   "P.M.", "P M", "P.M", "P M." and "PM." into "PM"
CString COleDateTimeEx::DealWithAMPMIssues(CString &strInput)
{
	CString strReturn = strInput;
	int iPos = -1;
	BOOL bStop = FALSE;

	strInput.MakeUpper();

	// first, lets look for AM variants
	iPos = strInput.Find("A.M.");
	if (iPos > 0)
	{
		CString strPart1 = strInput.Left(iPos);
		CString strPart2 = strInput.Mid(iPos+4);
		strPart1.TrimRight();
		strPart2.TrimLeft();

		strReturn = strPart1;
		strReturn += " AM ";
		strReturn += strPart2;
		bStop = TRUE;
	}

	if (!bStop)
	{
		iPos = strInput.Find("A M");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " AM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("A.M");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " AM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("A M.");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+4);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " AM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("AM.");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " AM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	// now, look for PM variants
	if (!bStop)
	{
		iPos = strInput.Find("P.M.");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+4);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " PM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("P M");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " PM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("P.M");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " PM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("P M.");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+4);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " PM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}

	if (!bStop)
	{
		iPos = strInput.Find("PM.");
		if (iPos > 0)
		{
			CString strPart1 = strInput.Left(iPos);
			CString strPart2 = strInput.Mid(iPos+3);
			strPart1.TrimRight();
			strPart2.TrimLeft();

			strReturn = strPart1;
			strReturn += " PM ";
			strReturn += strPart2;
			bStop = TRUE;
		}
	}


	return strReturn;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions