How to fill in that number grouping member of NUMBERFMT

Date:April 18, 2006 / year-entry #137
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20060418-11/?p=31493
Comments:    9
Summary:If you look at the NUMBERFMT structure, the way groups are expressed by the Grouping member do not match the value returned by LOCALE_SGROUPING: LOCALE_SGROUPING Grouping Sample Culture 3;0 3 1,234,567 United States 3;2;0 32 12,34,567 India 3 30 1234,567 (none I know of) LOCALE_SGROUPING expresses grouping as a series of semicolon-separated numbers, each expressing...

If you look at the NUMBERFMT structure, the way groups are expressed by the Grouping member do not match the value returned by LOCALE_SGROUPING:

LOCALE_
SGROUPING
Grouping Sample Culture
3;0 3 1,234,567 United States
3;2;0 32 12,34,567 India
3 30 1234,567 (none I know of)

LOCALE_SGROUPING expresses grouping as a series of semicolon-separated numbers, each expressing the number of digits in each group (least-significant group first). A trailing zero indicates that the last grouping should be repeated indefinitely. For example, "3;2;0" means "Group the three least significant digits, then in twos until you run out of digits." If there is no trailing ";0", then there are no commas past that point. For example, "3" means "Group the three least significant digits, then stop."

The Grouping member expresses the grouping rules differently. Each significant digit represents a group, with the most significant digit representing the least-significant group, with the units digit repeated indefinitely. For example, "32" means "make a group of three digits, then group by twos thereafter." To suppress the repetition, multiply by ten.

In other words, the two systems are basically the same, with the Grouping consisting of the LOCALE_SGROUPING string with the semicolons removed. Except that the meaning of the trailing zero is reversed, so if LOCALE_SGROUPING has a trailing zero, you have to remove it to get the Grouping, and if it lacks a trailing zero, then you have to add one to the Grouping.

It's kind of strange that the two systems differ, considering that they both came from the same NLS team! It's probably a case of parallel evolution, wherein the locale-string folks and the number-formatting folks came up with their respective systems independently.

Writing code to implement this conversion from LOCALE_SGROUPING to Grouping shouldn't be hard once you understand the algorithm, so I'll leave that as an exercise.

Fortunately, in real life you rarely have need to perform this conversion, for you can just pass the desired locale as the first parameter to the GetNumberFormat (or even better, LOCALE_USER_DEFAULT), pass a NULL pointer as the lpNumberFormat, and let NLS do all the work.


Comments (9)
  1. Yesterday, when I talked about that post from Raymond about numeric grouping the locale sensitive way,…

  2. Daev says:

    Are there cultures that group decimal digits on the right-hand side of the decimal point as well?

    For instance:  3.141,592,635,5

  3. Norman Diamond says:

    Tuesday, April 18, 2006 12:24 PM by Daev

    > Are there cultures that group decimal digits

    > on the right-hand side of the decimal point

    > as well?

    I wouldn’t call it a culture, but I saw that in some old ACM articles a few times.  It took a moment to get used to it.

    A bit more frequently I’ve seen spaces on the right-hand side of the decimal point.

  4. strik says:

    I find it puzzling that Windows insists on formatting for Germany like "1.234.567,89" (cf. http://blogs.msdn.com/oldnewthing/archive/2006/04/17/577483.aspx). Although this is the "official" way to do it, from experience, almost no-one uses this scheme when hand-writing. Rather, the dots are replaced by spaces (thus, "1 234 567,89". Much more interesting, some people really have problems if they got values with dots ("1.234" will be treated as 1 + 234/1000 instead of 1234 by many people I know).

    For example, I have yet to see any school teaching writing the dots for separating thousands; it is always a small space between the groups.

    Is there anyone out there who feels the same like me?

  5. Goran says:

    "1.234" will be treated as 1 + 234/1000 instead of 1234 by many people I know"

    Probably wasn’t the case before computers (with programs that don’t cater for different locales).

    Example: when I was in school, we wrote dates like this: 21. VI 2006 (june 21st, 2006). It’s rarely done now. I don’t think it’s even possible to do it with computers. Pitty, no?

  6. Mark Steward says:

    Goran: here you go!  This is in PHP, as the C++ equivalent is about 20 lines. Requires a font with the appropriate codepoints.

    <font face="Arial Unicode MS">

    <?php

     echo date(‘j’) . ‘. &#’ . (intval(date(‘n’)) + 0x215f) . ‘; ‘ . date(‘Y’);

     // Use 0x216f for lowercase roman numerals.  And date(‘n’) should be checked for errors.

    ?>

    </font>

  7. Mark Steward says:

    Ahem.  I feel a bit dirty posting PHP here, even on a silly hack, so:

    DateTime Now = DateTime.Now;

    string Month = (Now.Month < 1 || Now.Month > 12) ? "MM" : "’" + (char)(0x215f + Now.Month) + "’";

    string Date = Now.ToString("dd’.’ " + Month + " yyyy");

    Not suggesting that anybody *does* this, of course…

    Although it suddenly occurs to me that you could get the same effect by putting the roman numerals as the "short name" for a month (perhaps the ELKs could help).

  8. me says:

    […] like "1.234.567,89" (cf. http://blogs.msdn.com/oldnewthing/archive/2006/04/17/577483.aspx). Although this is the "official" way to do it […]

    German standard DIN 5008:2001 clearly says to write numbers like "1 234 567,89". Only amounts of money should be written "1.234.567,89 EUR".

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index