// Date.cpp : implementation file
//
// IDate Implementation
//
// Written by Paul E. Bible <pbible@littlefishsoftware.com>
// Copyright (c) 2000. All Rights Reserved.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is
// not sold for profit without the authors written consent, and
// providing that this notice and the authors name and all copyright
// notices remains intact. If the source code in this file is used in
// any commercial application then a statement along the lines of
// "Portions copyright (c) Paul E. Bible, 2000" must be included in
// the startup banner, "About" box -OR- printed documentation. An email
// letting me know that you are using it would be nice as well. That's
// not much to ask considering the amount of work that went into this.
// If even this small restriction is a problem send me an email.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// Expect bugs!
//
// Please use and enjoy, and let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into
// this file.
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "DateLib.h"
#include "Date.h"
#include <stdio.h>
/////////////////////////////////////////////////////////////////////////////
// CDate Error Handling
//
STDMETHODIMP CDate::InterfaceSupportsErrorInfo(REFIID riid)
{
static const IID* arr[] =
{
&IID_IDate
};
for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
if (InlineIsEqualGUID(*arr[i],riid))
return S_OK;
}
return S_FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CDate Private Methods
//
BOOL CDate::IsLeapYear(const int &nYear)
{
return ((nYear % 4 == 0 && nYear % 100 != 0) || (nYear % 400 == 0)) ? TRUE : FALSE;
}
void CDate::GetMonthString(const int &nMonth, TCHAR *pszMonth)
{
switch(nMonth)
{
case 1: _tcscpy(pszMonth, _T("Jan")); return;
case 2: _tcscpy(pszMonth, _T("Feb")); return;
case 3: _tcscpy(pszMonth, _T("Mar")); return;
case 4: _tcscpy(pszMonth, _T("Apr")); return;
case 5: _tcscpy(pszMonth, _T("May")); return;
case 6: _tcscpy(pszMonth, _T("Jun")); return;
case 7: _tcscpy(pszMonth, _T("Jul")); return;
case 8: _tcscpy(pszMonth, _T("Aug")); return;
case 9: _tcscpy(pszMonth, _T("Sep")); return;
case 10: _tcscpy(pszMonth, _T("Oct")); return;
case 11: _tcscpy(pszMonth, _T("Nov")); return;
case 12: _tcscpy(pszMonth, _T("Dec")); return;
default: _tcscpy(pszMonth, _T("Unk")); return;
}
}
/////////////////////////////////////////////////////////////////////////////
// CDate Conversion Methods (Public)
//
STDMETHODIMP CDate::Now(DATE *pdtDate)
{
SYSTEMTIME stDate;
GetLocalTime(&stDate);
DATE dtDate;
if (SystemTimeToVariantTime(&stDate, &dtDate) == 0)
return Error("Conversion Error - IDate::Now");
*pdtDate = dtDate;
return S_OK;
}
STDMETHODIMP CDate::OLE2Oracle(DATE dtDate, BSTR *pbstrDate)
{
USES_CONVERSION;
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error - IDate::OLE2Oracle");
int nMonth = static_cast<int>(stDate.wMonth);
TCHAR szMonth[4];
GetMonthString(nMonth, szMonth);
TCHAR szDate[15];
_stprintf(szDate, _T("%.2d-%s-%.4d"), static_cast<int>(stDate.wDay),
szMonth,
static_cast<int>(stDate.wYear));
CComBSTR bstrNew = szDate;
*pbstrDate = bstrNew.Detach();
return S_OK;
}
STDMETHODIMP CDate::Int2Oracle(short nMonth, short nDay, short nYear, BSTR *pbstrDate)
{
TCHAR szMonth[4];
GetMonthString(nMonth, szMonth);
TCHAR szDate[15];
_stprintf(szDate, _T("%.2d-%s-%.4d"), nDay, szMonth, nYear);
CComBSTR bstrNew = szDate;
*pbstrDate = bstrNew.Detach();
return S_OK;
}
STDMETHODIMP CDate::Int2OLE(short nMonth, short nDay, short nYear, DATE *pdtDate)
{
SYSTEMTIME stDate;
stDate.wDay = static_cast<WORD>(nDay);
stDate.wMonth = static_cast<WORD>(nMonth);
stDate.wYear = static_cast<WORD>(nYear);
stDate.wHour = 0;
stDate.wMinute = 0;
stDate.wSecond = 1;
DATE dtDate;
if (SystemTimeToVariantTime(&stDate, &dtDate) == 0)
return Error("Conversion Error - IDate::Int2OLE");
*pdtDate = dtDate;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CDate Calculation Methods (Public)
//
STDMETHODIMP CDate::GetLastDay(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetLastDay");
int nMonth = static_cast<int>(stDate.wMonth);
int nYear = static_cast<int>(stDate.wYear);
int nDay = 0;
// Calculate the last day of the month
switch (nMonth)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
nDay = 31;
break;
case 4:
case 6:
case 9:
case 11:
nDay = 30;
break;
case 2:
if (IsLeapYear(nYear))
nDay = 29;
else
nDay = 28;
break;
}
// Update SYSTEMTIME variable
stDate.wDay = static_cast<WORD>(nDay);
stDate.wHour = 0;
stDate.wMinute = 0;
stDate.wSecond = 0;
stDate.wMilliseconds = 1;
// Calc and assign new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (2) - IDate::GetLastDay");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetFirstDay(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetFirstDay");
stDate.wDay = static_cast<WORD>(1);
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (2) - IDate::GetFirstDay");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetPreviousDay(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetPreviousDay");
// Adjust day (and month/year)
if (stDate.wDay == 1)
{
stDate.wMonth--;
if (stDate.wMonth < 1)
{
stDate.wMonth = 12;
stDate.wYear--;
}
// Get the last day of the previous month
DATE dtCheck;
if (FAILED(Int2OLE(static_cast<short>(stDate.wMonth), 1, static_cast<short>(stDate.wYear), &dtCheck)))
return Error("Int2OLE failed in IDate::GetPreviousDay");
DATE dtLast;
if (FAILED(GetLastDay(dtCheck, &dtLast)))
return Error("GetLastDay failed in IDate::GetPreviousDay");
SYSTEMTIME stCheck;
if (FALSE == VariantTimeToSystemTime(dtLast, &stCheck))
return Error("Conversion Error (2) - IDate::GetPreviousDay");
stDate.wDay = stCheck.wDay;
}
else
stDate.wDay--;
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetPreviousDay");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetPreviousWeek(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetPreviousWeek");
// Adjust day (and month/year)
if (stDate.wDay <= 7)
{
int nDiff = 7 - static_cast<int>(stDate.wDay);
stDate.wMonth--;
if (stDate.wMonth < 1)
{
stDate.wMonth = 12;
stDate.wYear--;
}
// Check for month-end exceeded
DATE dtCheck;
if (FAILED(Int2OLE(static_cast<short>(stDate.wMonth), 1, static_cast<short>(stDate.wYear), &dtCheck)))
return Error("Int2OLE failed in IDate::GetPreviousWeek");
DATE dtLast;
if (FAILED(GetLastDay(dtCheck, &dtLast)))
return Error("GetLastDay failed in IDate::GetPreviousWeek");
SYSTEMTIME stCheck;
if (FALSE == VariantTimeToSystemTime(dtLast, &stCheck))
return Error("Conversion Error (2) - IDate::GetPreviousWeek");
stDate.wDay = stCheck.wDay - nDiff;
}
else
stDate.wDay = stDate.wDay - 7;
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetPreviousDay");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetPreviousMonth(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetPreviousMonth");
// Adjust month (and year)
if (stDate.wMonth == 1)
{
stDate.wMonth = 12;
stDate.wYear--;
}
else
stDate.wMonth--;
// Check for month-end exceeded
DATE dtCheck;
if (FAILED(Int2OLE(static_cast<short>(stDate.wMonth), 1, static_cast<short>(stDate.wYear), &dtCheck)))
return Error("Int2OLE failed in IDate::GetPreviousMonth");
DATE dtLast;
if (FAILED(GetLastDay(dtCheck, &dtLast)))
return Error("GetLastDay failed in IDate::GetPreviousMonth");
SYSTEMTIME stCheck;
if (FALSE == VariantTimeToSystemTime(dtLast, &stCheck))
return Error("Conversion Error (2) - IDate::GetPreviousMonth");
if (stDate.wDay > stCheck.wDay)
stDate.wDay = stCheck.wDay;
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetPreviousMonth");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetPreviousYear(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetPreviousYear");
// Adjust the year
stDate.wYear--;
// Check for month-end exceeded
DATE dtCheck;
if (FAILED(Int2OLE(static_cast<short>(stDate.wMonth), 1, static_cast<short>(stDate.wYear), &dtCheck)))
return Error("Int2OLE failed in IDate::GetPreviousYear");
DATE dtLast;
if (FAILED(GetLastDay(dtCheck, &dtLast)))
return Error("GetLastDay failed in IDate::GetPreviousYear");
SYSTEMTIME stCheck;
if (FALSE == VariantTimeToSystemTime(dtLast, &stCheck))
return Error("Conversion Error (2) - IDate::GetPreviousYear");
if (stDate.wDay > stCheck.wDay)
stDate.wDay = stCheck.wDay;
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetPreviousYear");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetNextMonth(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetNextMonth");
// Adjust month (and year)
if (stDate.wMonth == 12)
{
stDate.wMonth = 1;
stDate.wYear++;
}
else
stDate.wMonth++;
// Check for month-end exceeded
DATE dtCheck;
if (FAILED(Int2OLE(static_cast<short>(stDate.wMonth), 1, static_cast<short>(stDate.wYear), &dtCheck)))
return Error("Int2OLE failed in IDate::GetNextMonth");
DATE dtLast;
if (FAILED(GetLastDay(dtCheck, &dtLast)))
return Error("GetLastDay failed in IDate::GetNextMonth");
SYSTEMTIME stCheck;
if (FALSE == VariantTimeToSystemTime(dtLast, &stCheck))
return Error("Conversion Error (2) - IDate::GetNextMonth");
if (stDate.wDay > stCheck.wDay)
stDate.wDay = stCheck.wDay;
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetNextMonth");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetNextDay(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetNextDay");
DATE dtLastDay;
if (FAILED(GetLastDay(dtDate, &dtLastDay)))
return Error("GetLastDay failed in IDate::GetNextDay");
// Increment the day
stDate.wDay++;
SYSTEMTIME stLastDay;
if (FALSE == VariantTimeToSystemTime(dtLastDay, &stLastDay))
return Error("Conversion Error (2) - IDate::GetNextDay");
// Check if past month-end
if (stDate.wDay > stLastDay.wDay)
{
stDate.wDay = 1;
stDate.wMonth++;
if (stDate.wMonth == 13)
{
stDate.wMonth = 1;
stDate.wYear++;
}
}
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetNextDay");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetNextYear(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetNextYear");
// Adjust year
stDate.wYear++;
// Check for leap year and adjust day (if necessary)
if (!IsLeapYear(static_cast<int>(stDate.wYear)))
{
if ((stDate.wMonth == 2) && (stDate.wDay == 29))
stDate.wDay--;
}
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (2) - IDate::GetNextYear");
*pdtDate = dtNew;
return S_OK;
}
STDMETHODIMP CDate::GetNextWeek(DATE dtDate, DATE *pdtDate)
{
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error (1) - IDate::GetNextWeek");
DATE dtLastDay;
if (FAILED(GetLastDay(dtDate, &dtLastDay)))
return Error("GetLastDay failed in IDate::GetNextWeek");
// Increment the day by 7
stDate.wDay = stDate.wDay + 7;
SYSTEMTIME stLastDay;
if (FALSE == VariantTimeToSystemTime(dtLastDay, &stLastDay))
return Error("Conversion Error (2) - IDate::GetNextWeek");
// Check if past month-end
if (stDate.wDay > stLastDay.wDay)
{
WORD wDiff = stDate.wDay - stLastDay.wDay;
stDate.wDay = wDiff;
stDate.wMonth++;
if (stDate.wMonth == 13)
{
stDate.wMonth = 1;
stDate.wYear++;
}
}
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error (3) - IDate::GetNextWeek");
*pdtDate = dtNew;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CDate Parsing Methods (Public)
//
STDMETHODIMP CDate::ParseOracle2OLE(BSTR bstrDate, DATE *pdtDate)
{
USES_CONVERSION;
// Extract the string
const TCHAR* pszDate = OLE2T(bstrDate);
int nLength = _tcslen(pszDate);
TCHAR* pszResult;
pszResult = new TCHAR[15];
// Extract the month
TCHAR *pDest1;
pDest1 = _tcsstr(pszDate, _T("/"));
if (pDest1 == NULL)
return E_FAIL;
int nPos1 = pDest1 - pszDate + 1;
memset(pszResult, '\0', 15 * sizeof(TCHAR));
_tcsncpy(pszResult, &pszDate[0], nPos1-1);
int nMonth = _ttoi(pszResult);
// Extract the day
TCHAR *pDest2;
pDest2 = _tcsstr(&pszDate[nPos1], _T("/"));
if (pDest2 == NULL)
return E_FAIL;
int nPos2 = pDest2 - pszDate;
memset(pszResult, '\0', 15 * sizeof(TCHAR));
_tcsncpy(pszResult, &pszDate[nPos1], nPos2-nPos1);
int nDay = _ttoi(pszResult);
// Extract the year
memset(pszResult, '\0', 15 * sizeof(TCHAR));
_tcsncpy(pszResult, pDest2+1, nLength - nPos2);
int nYear = _ttoi(pszResult);
if (nYear < 1900)
{
if (nYear > 50)
nYear += 1900;
else
nYear += 2000;
}
// Build the DATE
SYSTEMTIME stDate;
GetSystemTime(&stDate);
stDate.wDay = static_cast<WORD>(nDay);
stDate.wMonth = static_cast<WORD>(nMonth);
stDate.wYear = static_cast<WORD>(nYear);
// Assign the new date
DATE dtNew;
if (SystemTimeToVariantTime(&stDate, &dtNew) == 0)
return Error("Conversion Error - IDate::ParseOracle2OLE");
*pdtDate = dtNew;
// Cleanup
delete [] pszResult;
return S_OK;
}
STDMETHODIMP CDate::ParseOracle2String(BSTR bstrDate, BSTR *pbstrDate)
{
DATE dtNewDate;
if (FAILED(ParseOracle2OLE(bstrDate, &dtNewDate)))
return Error("ParseOracle2OLE failed in IDate::ParseOracle2String");
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtNewDate, &stDate))
return Error("Conversion Error - IDate::ParseOracle2String");
TCHAR* pszDate;
pszDate = new TCHAR[15];
memset(pszDate, '\0', 15 * sizeof(TCHAR));
_stprintf(pszDate, _T("%.2d/%.2d/%.4d"), static_cast<int>(stDate.wMonth),
static_cast<int>(stDate.wDay),
static_cast<int>(stDate.wYear));
// Assign the new date
CComBSTR bstrNew = pszDate;
*pbstrDate = bstrNew.Detach();
// Cleanup
delete [] pszDate;
return S_OK;
}
STDMETHODIMP CDate::ParseOracle2Oracle(BSTR bstrDate, BSTR *pbstrDate)
{
DATE dtNewDate;
if (FAILED(ParseOracle2OLE(bstrDate, &dtNewDate)))
return Error("ParseOracle2OLE failed in IDate::ParseOracle2Oracle");
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtNewDate, &stDate))
return Error("Conversion Error - IDate::ParseOracle2Oracle");
CComBSTR bstrNew;
if (FAILED(Int2Oracle(static_cast<int>(stDate.wMonth), static_cast<int>(stDate.wDay),
static_cast<int>(stDate.wYear), &bstrNew)))
return Error("Int2Oracle failed in IDate::ParseOracle2Oracle");
*pbstrDate = bstrNew.Detach();
return S_OK;
}
STDMETHODIMP CDate::OLE2String(DATE dtDate, BSTR *pbstrDate)
{
USES_CONVERSION;
SYSTEMTIME stDate;
if (FALSE == VariantTimeToSystemTime(dtDate, &stDate))
return Error("Conversion Error - IDate::OLE2String");
TCHAR* pszDate;
pszDate = new TCHAR[15];
memset(pszDate, '\0', 15 * sizeof(TCHAR));
_stprintf(pszDate, _T("%.2d/%.2d/%.4d"), static_cast<int>(stDate.wMonth),
static_cast<int>(stDate.wDay),
static_cast<int>(stDate.wYear));
// Assign the new date
CComBSTR bstrNew = pszDate;
*pbstrDate = bstrNew.Detach();
// Cleanup
delete [] pszDate;
return S_OK;
}