Click here to Skip to main content
6,631,404 members and growing! (17,207 online)
Email Password   helpLost your password?
General Programming » Date and Time » General     Intermediate License: The Code Project Open License (CPOL)

Format Date and Time As Per User's Locale Settings

By Damir Valiulin

Convert date and time to a string using format settings specified in Control Panel -> Regional Options.
C++, Windows, Visual Studio, MFC, Dev
Posted:30 Dec 2005
Updated:19 Aug 2008
Views:34,625
Bookmarked:18 times
Announcements
Loading...
 
Search    
Advanced Search
Add to IE Search
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
12 votes for this article.
Popularity: 3.72 Rating: 3.45 out of 5
3 votes, 25.0%
1

2
2 votes, 16.7%
3
1 vote, 8.3%
4
6 votes, 50.0%
5

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Damir Valiulin


Member

Occupation: Software Developer
Location: Canada Canada

Other popular Date and Time articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 10 of 10 (Total in Forum: 10) (Refresh)FirstPrevNext
GeneralThis is how I format Dates and Times, using MFC the locale set in the control panel. PinmemberRichard M Willis3:08 9 Sep '09  
Generalanother simple solution PinmemberVladimir Alemasov2:06 2 May '08  
GeneralRe: another simple solution PinmemberDamir Valiulin8:05 19 Aug '08  
Generalsimple solution Pinmemberdis14117:52 15 Feb '06  
GeneralRe: simple solution PinmemberDamir Valiulin8:50 15 Feb '06  
GeneralRe: simple solution Pinmemberetking00720040:09 11 May '09  
GeneralSQL Problem PinmemberVertyg05:23 31 Dec '05  
GeneralRe: SQL Problem PinmemberColin Angus Mackay7:39 31 Dec '05  
GeneralPossible alternative... PinmemberSTRX3:43 31 Dec '05  
GeneralRe: Possible alternative... PinmemberDamir Valiulin9:34 31 Dec '05  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 19 Aug 2008
Editor: Smitha Vijayan
Copyright 2005 by Damir Valiulin
Everything else Copyright © CodeProject, 1999-2009
Web17 | Advertise on the Code Project