> );
}
```
-## Values and Formatting
-
-Typically spreadsheets will include formatted text such as currencies (`$3.50`)
-or large numbers with thousands separators (`7,262`) or percentages (`2.19%`).
-
-To simplify editing, the applications will store the underlying values and the
-number formats separately. For example, `$3.50` will be represented as the value
-`3.5` with a number format that mandates a `$` sigil and 2 decimal places.
-
-CSV and other formats only support the formatted text. Applications reading CSV
-files are expected to interpret the values as numbers or dates.
-
-### Dates and Times
-
-Many spreadsheet formats store dates and times using a number that represents
-the number of seconds or days after some epoch. Dates are covered in more detail
-[in the dedicated section](/docs/csf/features/dates).
-
-### Percentages
-
-Percentage formats automatically scale values by 100. Multiple percent symbols
-repeat the effect. For example, a cell with value `2.19%` is typically stored as
-a numeric cell with value `0.0219` and number format `0.00%`
-
-The following table uses the `en-US` locale (`.` as the decimal point symbol):
-
-| Number | Format | `en-US` Text |
-|:---------|---------:|-------------:|
-| `0.0219` | `0.00%` | `2.19%` |
-| `2.19` | `0.00%` | `219%` |
-| `0.0219` | `0.00%%` | `219%%` |
-| `2.19` | `0.00%%` | `21900%%` |
-
## SheetJS Representation
Number formats and values are attached to cells. The following keys are used:
@@ -152,8 +155,7 @@ instructs `XLSX.read` or `XLSX.readFile` to save the formats.
### Number Format Strings
The `z` format string follows the Excel persistence rules as described in
-ECMA-376 18.8.31 (Number Formats). For more info, see the Excel documentation
-article `Create or delete a custom number format`
+ECMA-376 18.8.31 (Number Formats)[^1]
The rules are slightly different from how Excel displays custom number formats.
In particular, literal characters must be wrapped in double quotes or preceded
@@ -195,6 +197,94 @@ function SheetJSExtractNF(props) {
}
```
+## Values and Formatting
+
+### Dates and Times
+
+In XLS and other file formats that extended the Lotus 1-2-3 worksheet file
+format, dates and times are stored as numeric codes. The application uses the
+number format to determine whether the value should be interpreted as a date.
+
+:::note pass
+
+Interpretation of date codes is covered in ["Dates and Times"](/docs/csf/features/dates).
+
+:::
+
+The following repeatable tokens force a date interpretation:
+
+| Tokens | Description |
+|:-----------------|:-------------------------------------------------------|
+| `Y` | Year |
+| `M` | Month or Minute (contextual) |
+| `D` | Day |
+| `H` | Hours (0-23 normally, but 1-12 if meridiem is present) |
+| `S` | Seconds |
+| `A/P` or `AM/PM` | Meridiem |
+| `[h]` or `[hh]` | Absolute hours (duration) |
+| `[m]` or `[mm]` | Absolute minutes (duration) |
+| `[s]` or `[ss]` | Absolute seconds (duration) |
+| `B1` or `B2` | Use Gregorian Calendar (`B1`) or Hijri Calendar (`B2`) |
+| `E` | "Era Year" or standard year depending on locale |
+| `G` | "Era" modifier or empty string depending on locale |
+
+If a format is detected to be a date, the decimal tokens `.0`, `.00` and `.000`
+represent the sub-second portion of the time.
+
+### Percentages
+
+Percentage formats automatically scale values by 100. Multiple percent symbols
+repeat the effect. For example, a cell with value `2.19%` is typically stored as
+a numeric cell with value `0.0219` and number format `0.00%`
+
+The following table uses the `en-US` locale (`.` as the decimal point symbol).
+Formatted text is rendered using the embedded SheetJS `SSF` formatting library.
+
+```jsx live
+function SheetJSPCT() {
+ const data = [
+ { n: 0.0219, z: "0.00%"},
+ { n: 2.19, z: "0.00%"},
+ { n: 0.0219, z: "0.00%%"},
+ { n: 2.19, z: "0.00%%"},
+ ];
+ return (
Number | Format | Text |
+ {data.map(r => (
+ {r.n} |
+ {r.z} |
+ {XLSX.SSF.format(r.z, r.n)} |
+
))}
+
);
+}
+```
+
+### Fractions
+
+Some applications support displaying numbers in fractional form.
+
+Fractions with a fixed denominator are calculated by scaling and rounding the
+fractional part of the number.
+
+Fractions with a variable denominator are typically specified by the number of
+digits in the denominator (for example, "Up to one digit").
+
+:::info pass
+
+The optimal solution from a mathematical perspective is the "Mediant" method.
+This algorithm can be very slow in the worst case, so spreadsheet applications
+tend to use a continued fraction approach.
+
+The common algorithm produces unexpected results for "Up to one digit":
+
+| Value | Mediant | Excel 2019 |
+|:------|--------:|-----------:|
+| `0.3` | `2/7` | `2/7` |
+| `1.3` | `1 2/7` | `1 1/3` |
+| `2.3` | `2 2/7` | `2 2/7` |
+| `3.3` | `3 2/7` | `3 2/7` |
+
+:::
+
## Miscellany
The default formats are listed in ECMA-376 18.8.30:
@@ -270,4 +360,6 @@ desired format and testing with [the Number Format Strings demo](#number-format-
### HTML Override
-[**This feature is discussed in the HTML utilities section**](/docs/api/utilities/html#value-override)
\ No newline at end of file
+[**This feature is discussed in the HTML utilities section**](/docs/api/utilities/html#value-override)
+
+[^1]: On 2023 September 14, [the "Review guidelines for customizing a number format" page](https://support.microsoft.com/en-us/office/review-guidelines-for-customizing-a-number-format-c0a1d1fa-d3f4-4018-96b7-9c9354dd99f5) in the Excel documentation covered custom number format minutiae.
\ No newline at end of file
diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js
index 54da310..dd54aa6 100644
--- a/docz/docusaurus.config.js
+++ b/docz/docusaurus.config.js
@@ -141,7 +141,7 @@ const config = {
prism: {
theme: lightCodeTheme,
darkTheme: darkCodeTheme,
- additionalLanguages: [ "visual-basic", "swift", "java", "csharp", "perl", "ruby", "cpp", "applescript", "liquid", "rust", "dart", "wolfram" ],
+ additionalLanguages: [ "visual-basic", "swift", "java", "csharp", "perl", "ruby", "cpp", "applescript", "liquid", "rust", "dart", "wolfram", "matlab" ],
},
liveCodeBlock: {
playgroundPosition: 'top'