Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Format Date and Time As Per User's Locale Settings

0.00/5 (No votes)
19 Aug 2008 1  
Convert date and time to a string using format settings specified in Control Panel -> Regional Options.

date_and_time_screenshot.PNG

Introduction

Some time ago, in one of my projects, I needed to print the current date and time in the page footer. Since the program was in MFC, I just went ahead and quickly added three lines:

CTime time = CTime::GetCurrentTime();
CString strDate = time.Format("%x");
CString strTime = time.Format ("%X");

Well, I noticed right away that the output looked like this:

12/30/05
19:10:23

Not quite the same as I set in my Windows' Regional Settings:

2005-12-30
19:10:23 PM

Sample Image - regional_options_date.png

There must be an easy way to match the user's settings, I thought. After digging into MSDN, I found that the API function that I should use is GetLocaleInfo. It can be queried to get all kinds of information, including the format string used by the user for the date and time. So then, I wrote two functions to parse the format strings for date and time and build the output string. These functions are shown at the end (Listing 2).

Update 2008-08-19

The great thing about CodeProject is that it is a two-way street: everybody can comment on your code and suggest better ways. Well, thanks to Vladimir Alemasov for pointing out setlocale. This is what I was missing in my simple three-liner above. If I set the CRT's locale as per user settings, I'd get exactly the same format as he/she set in the Control Panel. Here's the way to set CRT's locale, suggested by Chris Grimes in his article:

::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, szBuf, STR_SZ);
_tcscpy(szLocale, szBuf);
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGCOUNTRY, szBuf, STR_SZ);
if (_tcsclen(szBuf) != 0){
    _tcscat(szLocale, _T("_"));
    _tcscat(szLocale, szBuf);
}
::GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_IDEFAULTANSICODEPAGE, szBuf, STR_SZ);
if (_tcsclen(szBuf) != 0){
    _tcscat(szLocale, _T("."));
    _tcscat(szLocale, szBuf);
}

_tsetlocale(LC_ALL, szLocale); // e.g. szLocale = "English_United States.1252"

Note, that I use LOCALE_SYSTEM_DEFAULT for the call to get the default code page. There's not much about it on MSDN, but I found this by trial and error.

Also note that if you are not doing anything else locale specific in the rest of your program, you should reset the locale back to default after you are done with formatting the date and time. Otherwise, you might get some unexpected surprises when outputting or parsing numbers.

Listing 1

This code sets the CRT library's locale to match the user settings specified in the Regional Options. Then, it uses simple formatting functions to create a string with the current date and time. Both Win32 and MFC formatting ways are shown. Make sure to reset the locale back to default after you are done. This code will work for Unicode and non-Unicode programs.

// Set CRT library locale to user and system
// defaults to get correct date/time formatting
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGLANGUAGE, szBuf, STR_SZ);
_tcscpy(szLocale, szBuf);
::GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SENGCOUNTRY, szBuf, STR_SZ);
if (_tcsclen(szBuf) != 0){
    _tcscat(szLocale, _T("_"));
    _tcscat(szLocale, szBuf);
}
::GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, 
     LOCALE_IDEFAULTANSICODEPAGE, szBuf, STR_SZ);
if (_tcsclen(szBuf) != 0){
    _tcscat(szLocale, _T("."));
    _tcscat(szLocale, szBuf);
}

_tsetlocale(LC_ALL, szLocale);
// e.g. szLocale = "English_United States.1252"

// Win32 way
{
    TCHAR strDate[STR_SZ];
    TCHAR strTime[STR_SZ];

    time_t lt;
    time (&lt);
    tm* timeptr = localtime (&lt); // get current time

    _tcsftime(strDate, STR_SZ, _T("%x"), timeptr); // format date
    _tcsftime(strTime, STR_SZ, _T("%X"), timeptr); // format time
}


// MFC way
{
    CTime time = CTime::GetCurrentTime();
    CString strDate = time.Format("%x");
    CString strTime = time.Format ("%X");
}

Listing 2

This code shows two functions, one for formatting date and the other for formatting time. Each function retrieves the appropriate formatting string from locale settings, then it parses this string to build the output string for date or time. This code does not set the CRT library locale, so you don't need to worry about switching it back. It uses MFC, and will work for Unicode and non-Unicode programs.

CString get_date_in_user_format (CTime& time)
{
    CString strTmpFormat;
    CString strDate;
    WCHAR* szData = NULL;
    int num_chars = 
      GetLocaleInfoW(LOCALE_USER_DEFAULT, LOCALE_SSHORTDATE, szData, 0);
    if (num_chars != 0)
    {
        szData = new WCHAR[num_chars+1];
        szData[num_chars] = '\0';
        GetLocaleInfoW(LOCALE_USER_DEFAULT, 
              LOCALE_SSHORTDATE, szData, num_chars);
        CString strTmp (szData);
        int ind = 0;
        int len = strTmp.GetLength();
        while (ind < len)
        {
            switch (strTmp[ind])
            {
                case 'y':
                {
                    int year_type = 0;
                    while (ind < len && strTmp[ind] == 'y'){ 
                        ind++;
                        year_type++;
                    }
                    ind--;
                    switch (year_type){
                        case 4: strTmpFormat.Format(_T("%d"), time.GetYear());
                                strDate += strTmpFormat; break;
                        case 2: strTmpFormat.Format(_T("%02d"), time.GetYear() % 100);
                                strDate += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetYear() % 10);
                                strDate += strTmpFormat; break;
                    }
                    break;
                }
                case 'M':
                {
                    int month_type = 0;
                    while (ind < len && strTmp[ind] == 'M'){ 
                        ind++;
                        month_type++;
                    }
                    ind--;
                    switch (month_type){
                        case 4:
                        {
                            WCHAR szMonth[500]={0};
                            if (0<GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                                    LOCALE_SMONTHNAME1+time.GetMonth()-1, szMonth, 499)){
                                strDate += szMonth;
                            }
                            break;
                        }
                        case 3:
                        {
                            WCHAR szMonth[500]={0};
                            if (0<GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                                   LOCALE_SABBREVMONTHNAME1+time.GetMonth()-1, 
                                   szMonth, 499)){
                                strDate += szMonth;
                            }
                            break;
                        }
                        case 2: strTmpFormat.Format(_T("02d"), time.GetMonth());
                                strDate += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetMonth());
                                strDate += strTmpFormat; break;
                    }
                    break;
                }
                case 'd':
                {
                    int day_type = 0;
                    while (ind < len && strTmp[ind] == 'd'){ 
                        ind++;
                        day_type++;
                    }
                    ind--;
                    switch (day_type){
                        case 4:
                        {
                            UINT DayOfWeekFull[] = {
                                LOCALE_SDAYNAME7,   // Sunday
                                LOCALE_SDAYNAME1,   
                                LOCALE_SDAYNAME2,
                                LOCALE_SDAYNAME3,
                                LOCALE_SDAYNAME4, 
                                LOCALE_SDAYNAME5, 
                                LOCALE_SDAYNAME6   // Saturday
                            };
                            WCHAR szDayOfWeek[500]={0};
                            if (0<GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                                    DayOfWeekFull[time.GetDayOfWeek()-1], 
                                    szDayOfWeek, 499)){
                                strDate += szDayOfWeek;
                            }
                            break;
                        }
                        case 3:
                        {
                            UINT DayOfWeekAbbr[] = {
                                LOCALE_SABBREVDAYNAME7,   // Sunday
                                LOCALE_SABBREVDAYNAME1,   
                                LOCALE_SABBREVDAYNAME2,
                                LOCALE_SABBREVDAYNAME3,
                                LOCALE_SABBREVDAYNAME4, 
                                LOCALE_SABBREVDAYNAME5, 
                                LOCALE_SABBREVDAYNAME6   // Saturday
                            };
                            WCHAR szDayOfWeek[500]={0};
                            if (0<GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                                    DayOfWeekAbbr[time.GetDayOfWeek()-1], 
                                    szDayOfWeek, 499)){
                                strDate += szDayOfWeek;
                            }
                            break;
                        }
                        case 2: strTmpFormat.Format(_T("%02d"), time.GetDay());
                                strDate += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetDay());
                                strDate += strTmpFormat; break;
                    }
                    break;
                }
                default:
                    strDate += CString(strTmp[ind]);
                    break;
            }
            ind++;
        }
        delete szData;
    }

    if (strDate.IsEmpty()){
        strDate = time.Format(_T("%x")); // fallback mechanism
    }

    return strDate;
}
 
CString get_time_in_user_format (CTime& time)
{
    CString strTmpFormat;
    CString strTime;
    WCHAR* szData = NULL;
    int num_chars = GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                        LOCALE_STIMEFORMAT, szData, 0);
    if (num_chars != 0)
    {
        szData = new WCHAR[num_chars+1];
        szData[num_chars] = '\0';
        GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                       LOCALE_STIMEFORMAT, szData, num_chars);
        CString strTmp (szData);
        int ind = 0;
        int len = strTmp.GetLength();
        while (ind < len)
        {
            switch (strTmp[ind])
            {
                case 't':
                {
                    int time_marker_type = 0;
                    while (ind < len && strTmp[ind] == 't'){ 
                        ind++;
                        time_marker_type++;
                    }
                    ind--;
                    switch (time_marker_type){
                        case 2:
                        case 1:
                        {
                            WCHAR szTimemarker[500]={0};
                            LCTYPE am_or_pm = LOCALE_S1159; //AM
                            if (time.GetHour() >= 0 && time.GetHour() < 12){
                                am_or_pm = LOCALE_S1159; //AM
                            }else{
                                am_or_pm = LOCALE_S2359; //PM
                            }
                            if (0<GetLocaleInfoW(LOCALE_USER_DEFAULT, 
                                           am_or_pm, szTimemarker, 499)){
                                if (time_marker_type == 1){
                                    strTime += CString(szTimemarker, 1);
                                }else{
                                    strTime += szTimemarker;
                                }
                            }
                            break;
                        }
                    }
                    break;
                }
                case 's':
                {
                    int seconds_type = 0;
                    while (ind < len && strTmp[ind] == 's'){ 
                        ind++;
                        seconds_type++;
                    }
                    ind--;
                    switch (seconds_type){
                        case 2: strTmpFormat.Format(_T("%02d"), time.GetSecond());
                                strTime += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetSecond());
                                strTime += strTmpFormat; break;
                    }
                    break;
                }
                case 'm':
                {
                    int minute_type = 0;
                    while (ind < len && strTmp[ind] == 'm'){ 
                        ind++;
                        minute_type++;
                    }
                    ind--;
                    switch (minute_type){
                        case 2: strTmpFormat.Format(_T("%02d"), time.GetMinute());
                                strTime += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetMinute());
                                strTime += strTmpFormat; break;
                    }
                    break;
                }
                case 'H':
                {
                    int hour_type = 0;
                    while (ind < len && strTmp[ind] == 'H'){ 
                        ind++;
                        hour_type++;
                    }
                    ind--;
                    switch (hour_type){
                        case 2: strTmpFormat.Format(_T("02d"), time.GetHour());
                                strTime += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), time.GetHour());
                                strTime += strTmpFormat; break;
                    }
                    break;
                }
                case 'h':
                {
                    int hour_12_format = time.GetHour() % 12;
                    if (hour_12_format==0){
                        hour_12_format = 12;
                    }
                    int hour_type = 0;
                    while (ind < len && strTmp[ind] == 'h'){ 
                        ind++;
                        hour_type++;
                    }
                    ind--;
                    switch (hour_type){
                        case 2: strTmpFormat.Format(_T("02d"), hour_12_format);
                                strTime += strTmpFormat; break;
                        case 1: strTmpFormat.Format(_T("%d"), hour_12_format);
                                strTime += strTmpFormat; break;
                    }
                    break;
                }
                default:
                    strTime += CString(strTmp[ind]);
                    break;
            }
            ind++;
        }
        delete szData;
    }

    if (strTime.IsEmpty()){
        strTime = time.Format(_T("%X")); //fallback mechanism
    }

    return strTime;
}

Further Reading

For more information, see MSDN's topic on GetLocaleInfo. Also read about setlocale on MSDN.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here