1044 lines
28 KiB
C++
1044 lines
28 KiB
C++
|
/**********************************************************************/
|
||
|
/** Microsoft Windows/NT **/
|
||
|
/** Copyright(c) Microsoft Corporation, 1995 - 1999 **/
|
||
|
/**********************************************************************/
|
||
|
|
||
|
/*
|
||
|
FILE HISTORY:
|
||
|
|
||
|
*/
|
||
|
|
||
|
#define OEMRESOURCE
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <memory.h>
|
||
|
#include <ctype.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "dbgutil.h"
|
||
|
#include "objplus.h"
|
||
|
#include "intltime.h"
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
#undef THIS_FILE
|
||
|
static char BASED_CODE THIS_FILE[] = __FILE__;
|
||
|
#endif
|
||
|
|
||
|
#define new DEBUG_NEW
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// FormatDateTime
|
||
|
//
|
||
|
// Generates a current local date/time string
|
||
|
//
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
InternalFormatDateTime(CString & strOutput, SYSTEMTIME * psystemtime, BOOL fLongDate)
|
||
|
{
|
||
|
int nLen;
|
||
|
CString strDate, strTime;
|
||
|
DWORD dwFlags = 0;
|
||
|
|
||
|
dwFlags = fLongDate ? DATE_LONGDATE : DATE_SHORTDATE;
|
||
|
|
||
|
// call once to get the length, and again to format the string
|
||
|
nLen = GetDateFormat(GetThreadLocale(), dwFlags, psystemtime, NULL, NULL, 0);
|
||
|
nLen = GetDateFormat(GetThreadLocale(), dwFlags, psystemtime, NULL, strDate.GetBuffer(nLen + 1), nLen + 1);
|
||
|
strDate.ReleaseBuffer();
|
||
|
|
||
|
// now the time
|
||
|
nLen = GetTimeFormat(GetThreadLocale(), 0, psystemtime, NULL, NULL, 0);
|
||
|
nLen = GetTimeFormat(GetThreadLocale(), 0, psystemtime, NULL, strTime.GetBuffer(nLen + 1), nLen + 1);
|
||
|
strTime.ReleaseBuffer();
|
||
|
|
||
|
strOutput = strDate + _T(" ") + strTime;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
FormatDateTime(CString & strOutput, SYSTEMTIME * psystemtime, BOOL fLongDate)
|
||
|
{
|
||
|
InternalFormatDateTime(strOutput, psystemtime, fLongDate);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
FormatDateTime(CString & strOutput, FILETIME * pfiletime, BOOL fLongDate)
|
||
|
{
|
||
|
FILETIME localTime;
|
||
|
SYSTEMTIME systemtime;
|
||
|
|
||
|
if (!FileTimeToLocalFileTime(pfiletime, &localTime))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!FileTimeToSystemTime(&localTime, &systemtime))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
InternalFormatDateTime(strOutput, &systemtime, fLongDate);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
FormatDateTime(CString & strOutput, CTime & time, BOOL fLongDate)
|
||
|
{
|
||
|
SYSTEMTIME systemtime;
|
||
|
struct tm * ptm = time.GetLocalTm(NULL);
|
||
|
|
||
|
if (ptm != NULL)
|
||
|
{
|
||
|
systemtime.wYear = (WORD) (1900 + ptm->tm_year);
|
||
|
systemtime.wMonth = (WORD) (1 + ptm->tm_mon);
|
||
|
systemtime.wDayOfWeek = (WORD) ptm->tm_wday;
|
||
|
systemtime.wDay = (WORD) ptm->tm_mday;
|
||
|
systemtime.wHour = (WORD) ptm->tm_hour;
|
||
|
systemtime.wMinute = (WORD) ptm->tm_min;
|
||
|
systemtime.wSecond = (WORD) ptm->tm_sec;
|
||
|
systemtime.wMilliseconds = 0;
|
||
|
|
||
|
InternalFormatDateTime(strOutput, &systemtime, fLongDate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
strOutput.Empty();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
// CIntlTime
|
||
|
//
|
||
|
// These allocations cause a phoney "memory leak" error, since
|
||
|
// they're not freed until after the audit-check. Anyway
|
||
|
// around this?
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// Initialise static members
|
||
|
CIntlTime::INTL_TIME_SETTINGS CIntlTime::m_itsInternationalSettings;
|
||
|
BOOL CIntlTime::m_fIntlOk = CIntlTime::SetIntlTimeSettings();
|
||
|
CString CIntlTime::m_strBadDate("--");
|
||
|
CString CIntlTime::m_strBadTime("--");
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::SetIntlTimeSettings
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* This is a static function which initialises the international
|
||
|
* settings (date seperator, etc) of the CIntlTime class.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* TRUE if the international settings are properly initialised,
|
||
|
* or FALSE if they are not.
|
||
|
*
|
||
|
*/
|
||
|
BOOL CIntlTime::SetIntlTimeSettings ()
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
#define MAXSTR 128
|
||
|
|
||
|
BOOL fOk;
|
||
|
TCHAR str[MAXSTR];
|
||
|
|
||
|
#define GETCSTRINGFIELD(field,cstring)\
|
||
|
::GetLocaleInfo(GetUserDefaultLCID(), field, cstring.GetBuffer(MAXSTR), MAXSTR);\
|
||
|
cstring.ReleaseBuffer()
|
||
|
#define GETINTFIELD(field, integer)\
|
||
|
::GetLocaleInfo(GetUserDefaultLCID(), field, str, MAXSTR);\
|
||
|
integer = _ttol(str)
|
||
|
#define GETBOOLFIELD(field, boolean)\
|
||
|
::GetLocaleInfo(GetUserDefaultLCID(), field, str, MAXSTR);\
|
||
|
boolean=*str == '1'
|
||
|
|
||
|
fOk = GETCSTRINGFIELD(LOCALE_SDATE, CIntlTime::m_itsInternationalSettings.strDateSeperator);
|
||
|
fOk &= GETCSTRINGFIELD(LOCALE_STIME, CIntlTime::m_itsInternationalSettings.strTimeSeperator);
|
||
|
fOk &= GETINTFIELD(LOCALE_IDATE, CIntlTime::m_itsInternationalSettings.nDateFormat);
|
||
|
ASSERT((CIntlTime::m_itsInternationalSettings.nDateFormat >= 0) && (CIntlTime::m_itsInternationalSettings.nDateFormat <= 2));
|
||
|
fOk &= GETBOOLFIELD(LOCALE_ITIME, CIntlTime::m_itsInternationalSettings.f24HourClock);
|
||
|
fOk &= GETBOOLFIELD(LOCALE_ICENTURY, CIntlTime::m_itsInternationalSettings.fCentury);
|
||
|
fOk &= GETBOOLFIELD(LOCALE_ITLZERO, CIntlTime::m_itsInternationalSettings.fLeadingTimeZero);
|
||
|
fOk &= GETBOOLFIELD(LOCALE_IDAYLZERO, CIntlTime::m_itsInternationalSettings.fLeadingDayZero);
|
||
|
fOk &= GETBOOLFIELD(LOCALE_IMONLZERO, CIntlTime::m_itsInternationalSettings.fLeadingMonthZero);
|
||
|
if (CIntlTime::m_itsInternationalSettings.f24HourClock)
|
||
|
{
|
||
|
CIntlTime::m_itsInternationalSettings.strAM = "";
|
||
|
CIntlTime::m_itsInternationalSettings.strPM = "";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fOk &= GETCSTRINGFIELD(LOCALE_S1159, CIntlTime::m_itsInternationalSettings.strAM);
|
||
|
fOk &= GETCSTRINGFIELD(LOCALE_S2359, CIntlTime::m_itsInternationalSettings.strPM);
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
if (!fOk)
|
||
|
{
|
||
|
Trace0("There was a problem with some of the intl time settings\n");
|
||
|
}
|
||
|
#endif // _DEBUG
|
||
|
|
||
|
return(fOk);
|
||
|
|
||
|
#endif // _WIN32
|
||
|
|
||
|
#ifdef _WIN16
|
||
|
|
||
|
#define MAXSTR 128
|
||
|
|
||
|
CString strMisc;
|
||
|
|
||
|
#define GETCSTRINGFIELD(field,cstring,defstring)\
|
||
|
::GetProfileString("Intl", field, defstring, cstring.GetBuffer(MAXSTR), MAXSTR);\
|
||
|
cstring.ReleaseBuffer()
|
||
|
#define GETINTFIELD(field, integer, defint)\
|
||
|
integer = ::GetProfileInt("Intl", field, defint)
|
||
|
#define GETBOOLFIELD(field, boolean, defint)\
|
||
|
boolean = ::GetProfileInt("Intl", field, defint)==1
|
||
|
|
||
|
// Get the values. Assume American defaults in case of failure.
|
||
|
|
||
|
GETCSTRINGFIELD("sDate", CIntlTime::m_itsInternationalSettings.strDateSeperator, "/");
|
||
|
GETCSTRINGFIELD("sTime", CIntlTime::m_itsInternationalSettings.strTimeSeperator, ":");
|
||
|
GETINTFIELD("iDate", CIntlTime::m_itsInternationalSettings.nDateFormat, 0);
|
||
|
ASSERT((CIntlTime::m_itsInternationalSettings.nDateFormat >= 0) && (CIntlTime::m_itsInternationalSettings.nDateFormat <= 2));
|
||
|
GETBOOLFIELD("iTime", CIntlTime::m_itsInternationalSettings.f24HourClock, FALSE);
|
||
|
GETBOOLFIELD("iTLZero", CIntlTime::m_itsInternationalSettings.fLeadingTimeZero, FALSE);
|
||
|
if (CIntlTime::m_itsInternationalSettings.f24HourClock)
|
||
|
{
|
||
|
CIntlTime::m_itsInternationalSettings.strAM = "";
|
||
|
CIntlTime::m_itsInternationalSettings.strPM = "";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GETCSTRINGFIELD("s1159", CIntlTime::m_itsInternationalSettings.strAM, "AM");
|
||
|
GETCSTRINGFIELD("s2359", CIntlTime::m_itsInternationalSettings.strPM, "PM");
|
||
|
}
|
||
|
|
||
|
|
||
|
GETCSTRINGFIELD("sShortDate", strMisc, "M/d/yy");
|
||
|
// These settings are determined from the short date sample, as
|
||
|
// there is no direct equivalent in the win.ini
|
||
|
CIntlTime::m_itsInternationalSettings.fCentury = strMisc.Find("yyyy") != -1;
|
||
|
CIntlTime::m_itsInternationalSettings.fLeadingDayZero = strMisc.Find("dd") != -1;
|
||
|
CIntlTime::m_itsInternationalSettings.fLeadingMonthZero = strMisc.Find("MM") != -1;
|
||
|
|
||
|
return(TRUE);
|
||
|
|
||
|
#endif // _WIN16
|
||
|
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::Reset()
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Reset the international settings. Usually in response to
|
||
|
* a change in those international settings by the user.
|
||
|
*
|
||
|
* Notes:
|
||
|
*
|
||
|
* This is a publically available static function.
|
||
|
*
|
||
|
*/
|
||
|
void CIntlTime::Reset()
|
||
|
{
|
||
|
CIntlTime::m_fIntlOk = CIntlTime::SetIntlTimeSettings();
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::IsLeapYear
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Determine if the given year is/was a leap year
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* int nYear The year in question.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* TRUE if the year is/was a leap year, or FALSE otherwise.
|
||
|
*
|
||
|
* Comments:
|
||
|
*
|
||
|
* A year is a leap year, if is divisible by 4, but not by a 100, unless
|
||
|
* it is divisible by 400. e.g. 1900 was not a leap year, but 2000 will
|
||
|
* be.
|
||
|
*
|
||
|
*/
|
||
|
BOOL CIntlTime::IsLeapYear(UINT nYear)
|
||
|
{
|
||
|
return(!(nYear % 4) && ( (nYear % 100) || !(nYear % 400) ));
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::IsValidDate
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Determine if the given month, day year values are
|
||
|
* valid.
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* int nMonth Month
|
||
|
* int nDay Day
|
||
|
* int nYear Year
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* TRUE for a valid date, FALSE otherwise.
|
||
|
*
|
||
|
*/
|
||
|
BOOL CIntlTime::IsValidDate(UINT nMonth, UINT nDay, UINT nYear)
|
||
|
{
|
||
|
// Sanity Check:
|
||
|
BOOL fOk = ((nYear <100) || (nYear >= 1970)) &&
|
||
|
(nYear <= 2037) &&
|
||
|
((nMonth >= 1) && (nMonth <= 12)) &&
|
||
|
((nDay >= 1) && (nDay <= 31));
|
||
|
|
||
|
// Detailed check of days per month
|
||
|
if (fOk)
|
||
|
{
|
||
|
switch(nMonth)
|
||
|
{
|
||
|
case 1:
|
||
|
case 3:
|
||
|
case 5:
|
||
|
case 7:
|
||
|
case 8:
|
||
|
case 10:
|
||
|
case 12:
|
||
|
break;
|
||
|
case 4:
|
||
|
case 6:
|
||
|
case 9:
|
||
|
case 11:
|
||
|
fOk = (nDay <= 30);
|
||
|
break;
|
||
|
case 2:
|
||
|
fOk = (nDay <= (UINT)(IsLeapYear(nYear) ? 29 : 28));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(fOk);
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::IsValidTime
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Determine if the given hour, minute, second values
|
||
|
* valid.
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* int nHour Hour
|
||
|
* int nMinute Minute
|
||
|
* int nSecond Second
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* TRUE for a valid time, FALSE otherwise.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
BOOL CIntlTime::IsValidTime(UINT nHour, UINT nMinute, UINT nSecond)
|
||
|
{
|
||
|
return ((nHour < 24) && (nMinute < 60) && (nSecond < 60));
|
||
|
}
|
||
|
|
||
|
// Constructors. m_fInitOk will indicate whether or not the object
|
||
|
// was succesfully constructed. This can be checked at runtime by
|
||
|
// the IsValid() member function
|
||
|
|
||
|
CIntlTime::CIntlTime()
|
||
|
:CTime()
|
||
|
{
|
||
|
// Time set to 0, always bad.
|
||
|
m_fInitOk = FALSE;
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(const CTime &timeSrc)
|
||
|
:CTime(timeSrc)
|
||
|
{
|
||
|
m_fInitOk = GetTime() > 0L;
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(time_t time)
|
||
|
:CTime(time)
|
||
|
{
|
||
|
m_fInitOk = (time > 0);
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec)
|
||
|
:CTime(nYear, nMonth, nDay, nHour, nMin, nSec)
|
||
|
{
|
||
|
m_fInitOk = IsValidDate(nMonth, nDay, nYear) && IsValidTime(nHour, nMin, nSec);
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(WORD wDosDate, WORD wDosTime)
|
||
|
:CTime(wDosDate, wDosTime)
|
||
|
{
|
||
|
m_fInitOk = GetTime() != 0L;
|
||
|
}
|
||
|
|
||
|
// Constructor taking a string as an argument. The string can contain
|
||
|
// either a time, a date or both. If the string is missing the date,
|
||
|
// the current date will be filled in. If the string is missing the time,
|
||
|
// the current time will be filled in. As with all constructors, be
|
||
|
// sure the call IsValid() to determine proper contruction.
|
||
|
|
||
|
CIntlTime::CIntlTime(const CString & strTime, int nFormat, time_t * ptmOldValue)
|
||
|
:CTime(ConvertFromString(strTime, nFormat, ptmOldValue, &m_fInitOk))
|
||
|
{
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(const CIntlTime &timeSrc)
|
||
|
{
|
||
|
CTime::operator=(timeSrc.GetTime());
|
||
|
m_fInitOk = timeSrc.IsValid();
|
||
|
}
|
||
|
|
||
|
#ifdef _WIN32
|
||
|
CIntlTime::CIntlTime(const SYSTEMTIME& sysTime)
|
||
|
: CTime(sysTime)
|
||
|
{
|
||
|
m_fInitOk = IsValidDate((UINT)sysTime.wMonth, (UINT)sysTime.wDay, (UINT)sysTime.wYear)
|
||
|
&& IsValidTime((UINT)sysTime.wHour, (UINT)sysTime.wMinute, (UINT)sysTime.wSecond);
|
||
|
}
|
||
|
|
||
|
CIntlTime::CIntlTime(const FILETIME& fileTime)
|
||
|
: CTime(fileTime)
|
||
|
{
|
||
|
m_fInitOk = GetTime() != 0L;
|
||
|
}
|
||
|
|
||
|
#endif // _WIN32
|
||
|
// Desctructor
|
||
|
CIntlTime::~CIntlTime()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
// Assignment operators. As with constructors, be sure to check the
|
||
|
// IsValid() member function to determine succesfull assignment, as
|
||
|
// assignment operators do set the m_fInitOk member variable.
|
||
|
|
||
|
const CIntlTime& CIntlTime::operator =(const CString & strValue)
|
||
|
{
|
||
|
time_t tmValue = ConvertFromString (strValue, CIntlTime::TFRQ_TIME_OR_DATE, NULL, &m_fInitOk);
|
||
|
if (m_fInitOk)
|
||
|
{
|
||
|
CTime::operator=(tmValue);
|
||
|
}
|
||
|
return(*this);
|
||
|
}
|
||
|
|
||
|
// Assignment operator taking a time_t argument
|
||
|
const CIntlTime& CIntlTime::operator =(time_t tmValue)
|
||
|
{
|
||
|
CTime::operator=(tmValue);
|
||
|
m_fInitOk = (tmValue > 0);
|
||
|
return(*this);
|
||
|
}
|
||
|
|
||
|
const CIntlTime& CIntlTime::operator =(const CTime & time)
|
||
|
{
|
||
|
CTime::operator=(time.GetTime());
|
||
|
m_fInitOk = (GetTime() > 0);
|
||
|
return(*this);
|
||
|
}
|
||
|
|
||
|
const CIntlTime& CIntlTime::operator =(const CIntlTime & time)
|
||
|
{
|
||
|
CTime::operator=(time.GetTime());
|
||
|
m_fInitOk = (GetTime() > 0);
|
||
|
return(*this);
|
||
|
}
|
||
|
|
||
|
// Conversion operators
|
||
|
CIntlTime::operator const time_t() const
|
||
|
{
|
||
|
return(GetTime());
|
||
|
}
|
||
|
|
||
|
// Conversion operator that returns the date followed by the time
|
||
|
// in international format as a CString.
|
||
|
|
||
|
CIntlTime::operator const CString() const
|
||
|
{
|
||
|
return(ConvertToString(TFRQ_TIME_AND_DATE));
|
||
|
}
|
||
|
|
||
|
CIntlTime::operator CString() const
|
||
|
{
|
||
|
return(ConvertToString(TFRQ_TIME_AND_DATE));
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::GetDateString()
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Represent the current date in a format consistent with the current
|
||
|
* international settings in a CString.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* A CString containing the date in string format, or "--" if
|
||
|
* the date is invalid.
|
||
|
*
|
||
|
*/
|
||
|
const CString CIntlTime::GetDateString() const
|
||
|
{
|
||
|
CString strIntl;
|
||
|
|
||
|
if (!IsValid())
|
||
|
{
|
||
|
return(CIntlTime::m_strBadDate);
|
||
|
}
|
||
|
|
||
|
TCHAR szPct02D[] = _T("%02d");
|
||
|
TCHAR szPctD[] = _T("%d");
|
||
|
TCHAR szDay[3], szMonth[16], szYear[8];
|
||
|
TCHAR *first, *second, *third;
|
||
|
int i;
|
||
|
|
||
|
i = GetYear();
|
||
|
if(!CIntlTime::m_itsInternationalSettings.fCentury)
|
||
|
{
|
||
|
i %= 100;
|
||
|
}
|
||
|
|
||
|
// fix year 2000 problem -- ericdav
|
||
|
//::_itot(i, szYear, 10);
|
||
|
::wsprintf (szYear, szPct02D, i);
|
||
|
::wsprintf (szMonth, CIntlTime::m_itsInternationalSettings.fLeadingMonthZero
|
||
|
? szPct02D : szPctD, GetMonth());
|
||
|
::wsprintf (szDay, CIntlTime::m_itsInternationalSettings.fLeadingDayZero
|
||
|
? szPct02D : szPctD, GetDay());
|
||
|
|
||
|
if (CIntlTime::m_itsInternationalSettings.nDateFormat == _DFMT_YMD)
|
||
|
{
|
||
|
first = szYear;
|
||
|
second = szMonth;
|
||
|
third = szDay;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
third = szYear;
|
||
|
if (CIntlTime::m_itsInternationalSettings.nDateFormat == _DFMT_DMY)
|
||
|
{
|
||
|
first = szDay;
|
||
|
second = szMonth;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
first = szMonth;
|
||
|
second = szDay;
|
||
|
}
|
||
|
}
|
||
|
::wsprintf (strIntl.GetBuffer(80),
|
||
|
_T("%s%s%s%s%s"),
|
||
|
first,
|
||
|
(LPCTSTR)CIntlTime::m_itsInternationalSettings.strDateSeperator,
|
||
|
second,
|
||
|
(LPCTSTR)CIntlTime::m_itsInternationalSettings.strDateSeperator,
|
||
|
third);
|
||
|
strIntl.ReleaseBuffer();
|
||
|
|
||
|
return(strIntl);
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::GetTimeString()
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Represent the current time in a format consistent with the current
|
||
|
* international settings in a CString.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* A CString containing the time in string format, or "--" if
|
||
|
* the time is invalid.
|
||
|
*
|
||
|
*/
|
||
|
const CString CIntlTime::GetTimeString() const
|
||
|
{
|
||
|
CString strIntl;
|
||
|
|
||
|
if (!IsValid())
|
||
|
{
|
||
|
return(CIntlTime::m_strBadTime);
|
||
|
}
|
||
|
|
||
|
int hour = GetHour();
|
||
|
int minute = GetMinute();
|
||
|
int second = GetSecond();
|
||
|
|
||
|
// Set AM/PM depending on non-24 hour clock, and the time
|
||
|
// of day. Note: a space is prepended for readability.
|
||
|
CString strAMPM(CIntlTime::m_itsInternationalSettings.f24HourClock
|
||
|
? "" : " " + ((hour < 12)
|
||
|
? CIntlTime::m_itsInternationalSettings.strAM
|
||
|
: CIntlTime::m_itsInternationalSettings.strPM)
|
||
|
);
|
||
|
|
||
|
if ((!CIntlTime::m_itsInternationalSettings.f24HourClock) && (!(hour %= 12)))
|
||
|
{
|
||
|
hour = 12;
|
||
|
}
|
||
|
|
||
|
::wsprintf (strIntl.GetBuffer(30), CIntlTime::m_itsInternationalSettings.fLeadingTimeZero
|
||
|
? _T("%02d%s%02d%s%02d%s") : _T("%d%s%02d%s%02d%s"),
|
||
|
hour,
|
||
|
(LPCTSTR)CIntlTime::m_itsInternationalSettings.strTimeSeperator,
|
||
|
minute,
|
||
|
(LPCTSTR)CIntlTime::m_itsInternationalSettings.strTimeSeperator,
|
||
|
second,
|
||
|
(LPCTSTR)strAMPM);
|
||
|
|
||
|
strIntl.ReleaseBuffer();
|
||
|
return(strIntl);
|
||
|
}
|
||
|
|
||
|
const CString CIntlTime::GetMilitaryTime() const
|
||
|
{
|
||
|
CString strIntl;
|
||
|
|
||
|
if (!IsValid())
|
||
|
{
|
||
|
return(CIntlTime::m_strBadTime);
|
||
|
}
|
||
|
|
||
|
int hour = GetHour();
|
||
|
int minute = GetMinute();
|
||
|
int second = GetSecond();
|
||
|
|
||
|
::wsprintf (strIntl.GetBuffer(30),
|
||
|
_T("%02d:%02d:%02d"),
|
||
|
hour,
|
||
|
minute,
|
||
|
second);
|
||
|
|
||
|
strIntl.ReleaseBuffer();
|
||
|
return(strIntl);
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::ConvertToString(int nFormat)
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Convert the curent time/date to a string
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* int nFormat Format request ID, can be one of the following
|
||
|
* values (enumerated in CIntlTime):
|
||
|
*
|
||
|
* TFRQ_TIME_ONLY Only give me the time.
|
||
|
* TFRQ_DATE_ONLY Only give me the date.
|
||
|
* TFRQ_TIME_AND_DATE Give me the time and the date.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* A CString containing the time and/or date in international format.
|
||
|
*
|
||
|
*/
|
||
|
const CString CIntlTime::ConvertToString(int nFormat) const
|
||
|
{
|
||
|
switch(nFormat)
|
||
|
{
|
||
|
case TFRQ_TIME_ONLY:
|
||
|
return(GetTimeString());
|
||
|
|
||
|
case TFRQ_DATE_ONLY:
|
||
|
return(GetDateString());
|
||
|
|
||
|
case TFRQ_TIME_AND_DATE:
|
||
|
return(GetDateString() + CString(" ") + GetTimeString());
|
||
|
|
||
|
case TFRQ_MILITARY_TIME:
|
||
|
return(GetMilitaryTime());
|
||
|
|
||
|
case TFRQ_TIME_OR_DATE:
|
||
|
default:
|
||
|
Trace1("Invalid time/date format code %d requested.\n", nFormat);
|
||
|
return(CIntlTime::m_strBadDate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***
|
||
|
*
|
||
|
* CIntlTime::ConvertFromString
|
||
|
*
|
||
|
* Purpose:
|
||
|
*
|
||
|
* Convert a given CString into a time_t
|
||
|
*
|
||
|
* Arguments:
|
||
|
*
|
||
|
* const CString & str The string to convert
|
||
|
* int nFormat Format request ID, can be one of the following
|
||
|
* values (enumerated in CIntlTime):
|
||
|
*
|
||
|
* TFRQ_TIME_ONLY Only give me the time.
|
||
|
* TFRQ_DATE_ONLY Only give me the date.
|
||
|
* TFRQ_TIME_AND_DATE Give me the time and the date.
|
||
|
* TFRQ_TIME_OR_DATE Give me time or date (or both).
|
||
|
*
|
||
|
* time_t * ptmOldValue This time_t will be used to fill in the fields
|
||
|
* not given in the string. If it is NULL, the current
|
||
|
* time or date will be used.
|
||
|
* BOOL * pfOk Returns TRUE for succesfull conversion, FALSE
|
||
|
* otherwise.
|
||
|
*
|
||
|
* Returns:
|
||
|
*
|
||
|
* A time_t representing the time/date string, or 0 in case of error.
|
||
|
*
|
||
|
* Notes:
|
||
|
*
|
||
|
* Full validation of all paremeters will be done, e.g. No Feb 29 in
|
||
|
* a non-leap year will be accepted.
|
||
|
*
|
||
|
* [CAVEAT] Time, date seperators longer than one character will not
|
||
|
* work.
|
||
|
*
|
||
|
*/
|
||
|
time_t CIntlTime::ConvertFromString (
|
||
|
const CString & str,
|
||
|
int nFormat,
|
||
|
time_t * ptmOldValue, // If only getting time or date, count on remaining
|
||
|
// fields to be provided here (optionally);
|
||
|
BOOL * pfOk)
|
||
|
{
|
||
|
#define MAXSTRLEN 40
|
||
|
|
||
|
TCHAR dtseps[10] ; // Date/Time separators passed to _tcstok
|
||
|
TCHAR *pchToken;
|
||
|
TCHAR szDateString[MAXSTRLEN+1];
|
||
|
BOOL fGotDate = FALSE;
|
||
|
BOOL fGotTime = FALSE;
|
||
|
BOOL fPM = FALSE;
|
||
|
BOOL fAM = FALSE;
|
||
|
int i;
|
||
|
UINT anValues[6] = { 0, 0, 0, 0, 0, 0 };
|
||
|
CTime tmTmp;
|
||
|
|
||
|
*pfOk = FALSE; // Assume failure.
|
||
|
|
||
|
if (ptmOldValue != NULL)
|
||
|
{
|
||
|
tmTmp = *ptmOldValue;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
tmTmp = CTime::GetCurrentTime();
|
||
|
}
|
||
|
|
||
|
if (str.GetLength() > MAXSTRLEN)
|
||
|
{
|
||
|
// Too long to be a proper time/date string
|
||
|
return(0);
|
||
|
}
|
||
|
::lstrcpy(szDateString, (LPCTSTR)str);
|
||
|
|
||
|
int nIndex = 0;
|
||
|
|
||
|
// If we're looking for something specific, only
|
||
|
// accept specific seperators (time, date, both, either)
|
||
|
if ((nFormat == TFRQ_DATE_ONLY) || (nFormat == TFRQ_TIME_AND_DATE) || (nFormat == TFRQ_TIME_OR_DATE))
|
||
|
{
|
||
|
dtseps[nIndex++] = '/';
|
||
|
dtseps[nIndex++] = '-';
|
||
|
dtseps[nIndex++] = ',';
|
||
|
dtseps[nIndex++] = CIntlTime::m_itsInternationalSettings.strDateSeperator[0];
|
||
|
}
|
||
|
|
||
|
if ((nFormat == TFRQ_TIME_ONLY) || (nFormat == TFRQ_TIME_AND_DATE) || (nFormat == TFRQ_TIME_OR_DATE))
|
||
|
{
|
||
|
dtseps[nIndex++] = ':';
|
||
|
dtseps[nIndex++] = '.';
|
||
|
dtseps[nIndex++] = ' ';
|
||
|
dtseps[nIndex++] = CIntlTime::m_itsInternationalSettings.strTimeSeperator[0];
|
||
|
}
|
||
|
|
||
|
ASSERT(nIndex != 0); // Make sure we asked for something.
|
||
|
if (nIndex == 0)
|
||
|
{
|
||
|
// Request type is illegal
|
||
|
return(0);
|
||
|
}
|
||
|
dtseps[nIndex++] = '\0';
|
||
|
|
||
|
Trace3("CIntlTime::ConvertFromString. String: %s Format = %d Seps: %s\n", str, nFormat, dtseps);
|
||
|
|
||
|
i = 0;
|
||
|
pchToken = ::_tcstok(szDateString, dtseps);
|
||
|
while (pchToken != NULL)
|
||
|
{
|
||
|
if (i > 6) // 7 fields max (date, time + AM/PM maximum)
|
||
|
{
|
||
|
// Too many values, reject the string.
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// Determine if its a number (can't _ttoi, since it will
|
||
|
// merely return 0 for inappropriate values)
|
||
|
|
||
|
BOOL fProperNumber = TRUE;
|
||
|
int l = ::lstrlen(pchToken);
|
||
|
if ( (l == 0) || (l == 3) || (l > 4) )
|
||
|
{
|
||
|
fProperNumber = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int j;
|
||
|
for (j=0; j < l; ++j)
|
||
|
{
|
||
|
if (!isdigit(*(pchToken+j)))
|
||
|
{
|
||
|
fProperNumber = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fProperNumber)
|
||
|
{
|
||
|
// Ok, this is not a proper numeric field. Only
|
||
|
// if it's AM or PM at the end of the string can this
|
||
|
// string be saved.
|
||
|
fGotTime = TRUE;
|
||
|
if ((CIntlTime::m_itsInternationalSettings.f24HourClock) ||
|
||
|
(::_tcstok(NULL, dtseps) != NULL))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
if (!CIntlTime::m_itsInternationalSettings.strAM.CompareNoCase(pchToken))
|
||
|
{
|
||
|
fAM = TRUE;
|
||
|
}
|
||
|
else if (!CIntlTime::m_itsInternationalSettings.strPM.CompareNoCase(pchToken))
|
||
|
{
|
||
|
fPM = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Neither AM nor PM
|
||
|
return(0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Value is acceptable
|
||
|
anValues[i++] = (UINT)::_ttoi(pchToken);
|
||
|
}
|
||
|
|
||
|
pchToken = ::_tcstok(NULL, dtseps);
|
||
|
}
|
||
|
// Now what did we get, exactly?
|
||
|
|
||
|
ASSERT(!fAM || !fPM); // Make sure we didn't set both somehow.
|
||
|
if (i == 0)
|
||
|
{
|
||
|
// String without values
|
||
|
return(0);
|
||
|
}
|
||
|
switch(i)
|
||
|
{
|
||
|
case 1: // Hour
|
||
|
case 2: // Hour, minutes
|
||
|
Trace0("We got time\n");
|
||
|
fGotTime = TRUE;
|
||
|
break;
|
||
|
case 3:
|
||
|
|
||
|
// This one might be ambiguous, try to intelligently decide what
|
||
|
// we have. First check if only time or date only was requested,
|
||
|
// then check for out of bounds time values, and lastly check for
|
||
|
// the presence of a time seperator.
|
||
|
|
||
|
if (!fGotTime) // If we didn't already have AM/PM
|
||
|
{
|
||
|
Trace0("Picking between time and date by seperator\n");
|
||
|
if (nFormat == TFRQ_DATE_ONLY)
|
||
|
{
|
||
|
fGotDate = TRUE;
|
||
|
}
|
||
|
else if (nFormat == TFRQ_TIME_ONLY)
|
||
|
{
|
||
|
fGotTime = TRUE;
|
||
|
}
|
||
|
else if ((anValues[0] > 23) || (anValues[1] > 59) || (anValues[2] > 59))
|
||
|
{
|
||
|
fGotDate = TRUE;
|
||
|
}
|
||
|
else if (str.Find(CIntlTime::m_itsInternationalSettings.strTimeSeperator) != -1)
|
||
|
{
|
||
|
fGotTime = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fGotDate = TRUE;
|
||
|
}
|
||
|
Trace1("Decided on %s", (fGotDate ? "date\n" : "time\n"));
|
||
|
}
|
||
|
break;
|
||
|
case 4: // Date, hour
|
||
|
case 5: // Date, hours, minutes
|
||
|
case 6: // Date, hours, minutes, seconds
|
||
|
Trace0("We got date and time\n");
|
||
|
fGotDate = TRUE;
|
||
|
fGotTime = TRUE;
|
||
|
break;
|
||
|
default:
|
||
|
ASSERT(0 && "Incorrect number of values!");
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// Was that what we're looking for?
|
||
|
if ( ((nFormat == TFRQ_DATE_ONLY) && fGotTime) ||
|
||
|
((nFormat == TFRQ_TIME_ONLY) && fGotDate) ||
|
||
|
((nFormat == TFRQ_TIME_AND_DATE) && (!fGotTime || !fGotDate))
|
||
|
)
|
||
|
{
|
||
|
Trace0("Entry didn't match expectations\n");
|
||
|
return(0);
|
||
|
|
||
|
}
|
||
|
i = 0;
|
||
|
|
||
|
int h, m, s, D, M, Y; // Array indices;
|
||
|
// Now determine where to find what.
|
||
|
if (fGotDate) // Date always goes first
|
||
|
{
|
||
|
switch(CIntlTime::m_itsInternationalSettings.nDateFormat)
|
||
|
{
|
||
|
case _DFMT_MDY:
|
||
|
M = i++;
|
||
|
D = i++;
|
||
|
Y = i++;
|
||
|
break;
|
||
|
|
||
|
case _DFMT_DMY:
|
||
|
D = i++;
|
||
|
M = i++;
|
||
|
Y = i++;
|
||
|
break;
|
||
|
|
||
|
case _DFMT_YMD:
|
||
|
Y = i++;
|
||
|
M = i++;
|
||
|
D = i++;
|
||
|
break;
|
||
|
}
|
||
|
// If only 2 digits are given, determine if we're talking about
|
||
|
// the 21st or 20th century
|
||
|
if (anValues[Y] < 100)
|
||
|
{
|
||
|
anValues[Y] += (anValues[Y] > 37) ? 1900 : 2000;
|
||
|
}
|
||
|
Trace3("Month = %d Day = %d Year = %d\n", anValues[M], anValues[D], anValues[Y]);
|
||
|
|
||
|
// Validation.
|
||
|
if (!IsValidDate(anValues[M], anValues[D], anValues[Y]))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (fGotTime)
|
||
|
{
|
||
|
h = i++;
|
||
|
m = i++;
|
||
|
s = i++;
|
||
|
|
||
|
Trace3("Hours = %d Minutes = %d Seconds = %d\n", anValues[h], anValues[m], anValues[s]);
|
||
|
|
||
|
// Shouldn't specify AM or PM with 24 hour clock value.
|
||
|
if ((anValues[h] > 12) && (fAM || fPM))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
// Adjust for AM/PM modifiers
|
||
|
if (fPM)
|
||
|
{
|
||
|
if (anValues[h] != 12)
|
||
|
{
|
||
|
anValues[h] += 12;
|
||
|
}
|
||
|
}
|
||
|
else if (fAM)
|
||
|
{
|
||
|
if ( anValues[h] == 12)
|
||
|
{
|
||
|
anValues[h] -= 12;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Sanity Check:
|
||
|
if (!IsValidTime(anValues[h], anValues[m], anValues[s]))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Fill in the missing fields
|
||
|
CIntlTime tm( fGotDate ? anValues[Y] : tmTmp.GetYear(),
|
||
|
fGotDate ? anValues[M] : tmTmp.GetMonth(),
|
||
|
fGotDate ? anValues[D] : tmTmp.GetDay(),
|
||
|
fGotTime ? anValues[h] : tmTmp.GetHour(),
|
||
|
fGotTime ? anValues[m] : tmTmp.GetMinute(),
|
||
|
fGotTime ? anValues[s] : tmTmp.GetSecond()
|
||
|
);
|
||
|
|
||
|
*pfOk = (tm.GetTime() > (time_t)0);
|
||
|
|
||
|
return(tm);
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
|
||
|
// Dump to debug device
|
||
|
CDumpContext& AFXAPI operator<<(CDumpContext& dc, const CIntlTime& tim)
|
||
|
{
|
||
|
dc << _T("\nDate Seperator: ") << tim.m_itsInternationalSettings.strDateSeperator;
|
||
|
dc << _T("\nTime Seperator: ") << tim.m_itsInternationalSettings.strTimeSeperator;
|
||
|
dc << _T("\nAM String: ") << tim.m_itsInternationalSettings.strAM;
|
||
|
dc << _T("\nPM String: ") << tim.m_itsInternationalSettings.strPM;
|
||
|
dc << _T("\nDate Format: ") << tim.m_itsInternationalSettings.nDateFormat;
|
||
|
dc << _T("\n24 Hour Clock: ") << (tim.m_itsInternationalSettings.f24HourClock ? "TRUE" : "FALSE");
|
||
|
dc << _T("\n4 Digit Century: ") << (tim.m_itsInternationalSettings.fCentury ? "TRUE" : "FALSE");
|
||
|
dc << _T("\nTime Leading Zero: ") << (tim.m_itsInternationalSettings.fLeadingTimeZero ? "TRUE" : "FALSE");
|
||
|
dc << _T("\nDay Leading Zero ") << (tim.m_itsInternationalSettings.fLeadingDayZero ? "TRUE" : "FALSE");
|
||
|
dc << _T("\nMonth Leading Zero: ") << (tim.m_itsInternationalSettings.fLeadingMonthZero ? "TRUE" : "FALSE");
|
||
|
dc << _T("\n\ntime_t: ") << tim.GetTime();
|
||
|
return(dc);
|
||
|
}
|
||
|
|
||
|
#endif // _DEBUG
|