因为公司要统一所有产品的日期、时间显示格式,要求所有程序在显示日期时间的时候,都默认使用操作系统的时间格式。所以想着封装一个基础类供大家共用。
一开始打算使用EnumDateFormatsExEx和EnumTimeFormatsEx,在win7下开发的,结果同事拿到xp下之后发现直接异常了,然后一看msdn才发现这两个api只有vista之后的操作系统才支持。
所以要改用EnumDateFormatsEx和EnumTimeFormats,但是这两个api没有最后一个PARAM,在封装的时候无法把this传递进去,那么回调就只能把返回的数据存储在全局变量中,但是全局变量的话就无法实现线程安全,怎么办呢?
于是想到了之前看到的TLS,定义如下三个变量。
__declspec(thread) CString* _dateStr = NULL;
__declspec(thread) CALID* _calendarID = NULL;
__declspec(thread) CString* _timeStr = NULL;
回调直接把api返回的值存储到这三个TLS中,然后在类CDateFormatReader的构造函数中再去把他取出来,就ok了。
这样即时多个线程同时使用这个辅助类也没关系。
下面是示例代码:
示例代码如下:
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetLongdateformat()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetLongDateFormat());
msg.Format(_T("format:%s, \nvalue: %s"),CDateTimeFormatStringReader::GetLongDateFormat(), strDate);
AfxMessageBox(msg);
}
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetLongtimeformat()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetLongTimeFormat());
msg.Format(_T("format:%s, \nvalue: %s"),CDateTimeFormatStringReader::GetLongTimeFormat(), strDate);
AfxMessageBox(msg);
}
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetLongdatetimeformat3()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetLongDateTimeFormat());
msg.Format(_T("format:%s, \nvalue: %s"),CDateTimeFormatStringReader::GetLongDateTimeFormat(), strDate);
AfxMessageBox(msg);
}
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetShortdateformat2()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetShortDateFormat());
msg.Format(_T("format:%s, \nvalue: %s"),CDateTimeFormatStringReader::GetShortDateFormat(), strDate);
AfxMessageBox(msg);
}
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetShorttimeformat2()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetShortTimeFormat());
msg.Format(_T("format:%s, \nvalue: %s"),CDateTimeFormatStringReader::GetShortTimeFormat(), strDate);
AfxMessageBox(msg);
}
voidCTestGetSystemDateTimeFormatDlg::OnBnClickedBtnGetShortdatetimeformat4()
{
COleDateTimecurrentTime =COleDateTime::GetCurrentTime();
CStringstrDate, msg;
strDate =currentTime.Format(CDateTimeFormatStringReader::GetShortDateTimeFormat());
msg.Format(_T("format:%s, \nvalue: %s"), CDateTimeFormatStringReader::GetShortDateTimeFormat(),strDate);
AfxMessageBox(msg);
}
完整的封装类的代码如下:
DateTimeFormatStringReader.h
#pragma once
/**
* @class CLongDateTimeFormatStringReader
* @brief 获取当前操作系统的日期、时间格式
*/
class CDateTimeFormatStringReader
{
private:
/**
* @class CDateFormatReader
* @brief 日期格式读取器
*/
class CDateFormatReader
{
private:
/** 获取到的时间格式 */
CString m_dateFormat;
/** CalendarID*/
CALID m_calendarID;
/** 是否是短日期格式 */
bool m_isShort;
private:
/** 用于配合api的回调 */
static BOOL CALLBACK EnumDateFormatsProcEx(
__in LPTSTR lpDateFormatString,
__in CALID CalendarID);
public:
CDateFormatReader(bool isShort = false);
public:
CString GetOSDateFormat(){ return m_dateFormat;};
CString GetDateFormat();
CALID GetCalendarID(){ return m_calendarID;};
};
/**
* @class CTimeFormatReader
* @brief 获取系统时间格式
*/
class CTimeFormatReader
{
private:
/** 获取到的时间字符串 */
CString m_timeFormat;
/** 是否为短时间格式 */
bool m_isShort;
private:
static BOOL CALLBACK EnumTimeFormatsProc(
__in LPTSTR lpTimeFormatString);
public:
CTimeFormatReader(bool isShort = false);
CString GetOSTimeFormat(){ return m_timeFormat;};
CString GetTimeFormat();
};
public:
static CString GetLongDateFormat();
static CString GetLongTimeFormat();
static CString GetLongDateTimeFormat();
static CString GetShortDateFormat();
static CString GetShortTimeFormat();
static CString GetShortDateTimeFormat();
/** 短期日、长时间格式,这是推荐的格式 */
static CString GetShortDateLongTimeFormat();
static CString GetShortDateLongTimeFormatWithMilliSecond();
static CALID GetCalendarId();
};
DateTimeFormatStringReader.cpp
#include "StdAfx.h"
#include "DateTimeFormatStringReader.h"
/**
* 本来打算就使用几个文件内的局部变量来存放回调函数返回的只,
* 但是这样的话就不是线程安全的了,所以改用线程局部变量来存储回调函数返回的值,这样就可以实现线程安全
*/
__declspec(thread) CString* _dateStr = NULL;
__declspec(thread) CALID* _calendarID = NULL;
__declspec(thread) CString* _timeStr = NULL;
bool IsWindows7Later()
{
OSVERSIONINFO osvi;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
TCHAR szVersion[10] = {0};
CString strVersion;
strVersion.Format(_T("%d.%d"), osvi.dwMajorVersion, osvi.dwMinorVersion);
return strVersion.Compare(_T("6.1")) >= 0;
}
CDateTimeFormatStringReader::CDateFormatReader::CDateFormatReader( bool isShort ):m_isShort(isShort)
{
m_dateFormat = "";
m_calendarID = 0;
DWORD dwFlags = DATE_LONGDATE;
if(m_isShort)
dwFlags = DATE_SHORTDATE;
BOOL dwReturn = EnumDateFormatsEx(EnumDateFormatsProcEx, LOCALE_USER_DEFAULT, dwFlags);
ASSERT(dwReturn);
if(_dateStr != NULL)
{
this->m_dateFormat = *_dateStr;
delete _dateStr;
_dateStr = NULL;
}
if(_calendarID != NULL)
{
this->m_calendarID = *_calendarID;
delete _calendarID;
_calendarID = NULL;
}
}
BOOL CALLBACK CDateTimeFormatStringReader::CDateFormatReader::EnumDateFormatsProcEx( __in LPTSTR lpDateFormatString, __in CALID calendarID)
{
//把取过来的只存放在tls中,然后在后续的函数方法中去使用和释放
//以便实现线程安全
_dateStr = new CString(lpDateFormatString);
_calendarID = new CALID(calendarID);
return FALSE;
}
CString CDateTimeFormatStringReader::CDateFormatReader::GetDateFormat()
{
CString formatStr = GetOSDateFormat();
formatStr.Replace(_T("'"), _T(""));
if(formatStr.Find(_T("yyyy"))>=0)
formatStr.Replace(_T("yyyy"), _T("%Y"));
if(formatStr.Find(_T("yy"))>=0)
formatStr.Replace(_T("yy"), _T("%y"));
if(formatStr.Find(_T("MMMM"))>=0)
formatStr.Replace(_T("MMMM"), _T("%B"));
else if(formatStr.Find(_T("MMM"))>=0)
formatStr.Replace(_T("MMM"), _T("%b"));
else if(formatStr.Find(_T("MM"))>=0)
formatStr.Replace(_T("MM"), _T("%m"));
else if(formatStr.Find(_T("M"))>=0)
formatStr.Replace(_T("M"), _T("%m"));
if(formatStr.Find(_T("dddd"))>=0)
formatStr.Replace(_T("dddd"), _T("%A"));
if(formatStr.Find(_T("ddd"))>=0)
formatStr.Replace(_T("ddd"), _T("%a"));
if(formatStr.Find(_T("dd"))>=0)
formatStr.Replace(_T("dd"), _T("%d"));
else if(formatStr.Find(_T("d"))>=0)
formatStr.Replace(_T("d"), _T("%d"));
return formatStr;
}
//
CDateTimeFormatStringReader::CTimeFormatReader::CTimeFormatReader(bool isShort):m_isShort(isShort)
{
DWORD dwFlag = 0;
bool isWin7OrLater = IsWindows7Later();
if(isShort && isWin7OrLater)
dwFlag |= TIME_NOSECONDS;
BOOL dwReturn = EnumTimeFormats(EnumTimeFormatsProc, LOCALE_USER_DEFAULT, dwFlag);
ASSERT(dwReturn);
if(_timeStr != NULL)
{
this->m_timeFormat = *_timeStr;
if(isShort && !isWin7OrLater)
m_timeFormat.Replace(_T(":ss"), _T(""));
delete _timeStr;
_timeStr = NULL;
}
}
BOOL CALLBACK CDateTimeFormatStringReader::CTimeFormatReader::EnumTimeFormatsProc( __in LPTSTR lpTimeFormatString)
{
//把取过来的只存放在tls中,然后在后续的函数方法中去使用和释放
//以便实现线程安全
_timeStr = new CString(lpTimeFormatString);
return FALSE;
}
CString CDateTimeFormatStringReader::CTimeFormatReader::GetTimeFormat()
{
CString formatStr = GetOSTimeFormat();
if(formatStr.Find(_T("HH"))>=0)
formatStr.Replace(_T("HH"), _T("%H"));
else if(formatStr.Find(_T("H"))>=0)
formatStr.Replace(_T("H"), _T("%H"));
if(formatStr.Find(_T("hh"))>=0)
formatStr.Replace(_T("hh"), _T("%I"));
else if(formatStr.Find(_T("h"))>=0)
formatStr.Replace(_T("h"), _T("%I"));
if(formatStr.Find(_T("mm"))>=0)
formatStr.Replace(_T("mm"), _T("%M"));
else if(formatStr.Find(_T("m"))>=0)
formatStr.Replace(_T("m"), _T("%M"));
if(formatStr.Find(_T("ss"))>=0)
formatStr.Replace(_T("ss"), _T("%S"));
else if(formatStr.Find(_T("s"))>=0)
formatStr.Replace(_T("s"), _T("%S"));
if(formatStr.Find(_T("tt"))>=0)
formatStr.Replace(_T("tt"), _T("%p"));
return formatStr;
}
//
CString CDateTimeFormatStringReader::GetLongDateFormat()
{
CDateFormatReader dateFormatReader;
return dateFormatReader.GetDateFormat();
}
CString CDateTimeFormatStringReader::GetLongTimeFormat()
{
CTimeFormatReader timeFormatReader;
return timeFormatReader.GetTimeFormat();
}
CString CDateTimeFormatStringReader::GetLongDateTimeFormat()
{
CString result;
result.Format(_T("%s %s"), GetLongDateFormat(), GetLongTimeFormat());
return result;
}
CString CDateTimeFormatStringReader::GetShortDateFormat()
{
CDateFormatReader dateFormatReader(true);
return dateFormatReader.GetDateFormat();
}
CString CDateTimeFormatStringReader::GetShortTimeFormat()
{
CTimeFormatReader timeFormatReader(true);
return timeFormatReader.GetTimeFormat();
}
CString CDateTimeFormatStringReader::GetShortDateTimeFormat()
{
CString result;
result.Format(_T("%s %s"), GetShortDateFormat(), GetShortTimeFormat());
return result;
}
CALID CDateTimeFormatStringReader::GetCalendarId()
{
CDateFormatReader dateFormatReader(true);
return dateFormatReader.GetCalendarID();
}
CString CDateTimeFormatStringReader::GetShortDateLongTimeFormat()
{
CString result;
result.Format(_T("%s %s"), GetShortDateFormat(), GetLongTimeFormat());
return result;
}
CString CDateTimeFormatStringReader::GetShortDateLongTimeFormatWithMilliSecond()
{
CString result;
result.Format(_T("%s %s"), GetShortDateFormat(), GetLongTimeFormat());
if(result.Find(_T("%S")) >= 0)
result.Replace(_T("%S"), _T("%S.milliSecond"));
return result;
}