diff --git a/docz/docs/02-getting-started/02-example.mdx b/docz/docs/02-getting-started/02-example.mdx
index 97fcc3e..fa06495 100644
--- a/docz/docs/02-getting-started/02-example.mdx
+++ b/docz/docs/02-getting-started/02-example.mdx
@@ -26,7 +26,7 @@ The ["Live Demo"](#live-demo) section includes a working demo in this page!
 ["Run the Demo Locally"](#run-the-demo-locally) shows how to run the workflow in
 iOS / Android apps, desktop apps, NodeJS scripts and other environments.
 
-The follow sequence diagram shows the process:
+The following sequence diagram shows the process:
 
 ```mermaid
 sequenceDiagram
@@ -934,7 +934,7 @@ Save the following to `package.json`:
   "version": "0.0.0",
   "main": "SheetJSNW.html",
   "dependencies": {
-    "nw": "~0.66.0",
+    "nw": "0.77.0",
     "xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
   }
 }`}
diff --git a/docz/docs/02-getting-started/04-zen.md b/docz/docs/02-getting-started/04-zen.md
index 259c64d..c59f749 100644
--- a/docz/docs/02-getting-started/04-zen.md
+++ b/docz/docs/02-getting-started/04-zen.md
@@ -16,8 +16,8 @@ Web Workers and future APIs.
 ### JavaScript is a powerful language for data processing
 
 The ["Common Spreadsheet Format"](/docs/csf/general) is a simple object
-representation of the core concepts of a workbook.  The various functions in the
-library provide low-level tools for working with the object.
+representation of the core concepts of a workbook. [Utilities](/docs/api/utilities/)
+provide low-level tools for working with the object.
 
 For friendly JS processing, there are utility functions for converting parts of
 a worksheet to/from an Array of Arrays.  The [Tutorial](/docs/getting-started/example)
@@ -35,3 +35,10 @@ with the data ecosystem.
 To the greatest extent possible, data processing code should not have to worry
 about the specific file formats involved.
 
+### Data processing should be confidential
+
+All SheetJS-related methods run locally. No data is sent to a third party in
+processing data. No telemetry is collected.
+
+SheetJS libraries are regularly used in offline scenarios to process personally
+identifiable information (PII) and other classified data.
diff --git a/docz/docs/03-demos/03-net/index.md b/docz/docs/03-demos/03-net/index.md
index 377130c..3eb630f 100644
--- a/docz/docs/03-demos/03-net/index.md
+++ b/docz/docs/03-demos/03-net/index.md
@@ -8,11 +8,19 @@ import DocCardList from '@theme/DocCardList';
 import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
 
 SheetJS libraries are commonly used in data pipelines for processing personally
-identifiable information (PII).  The libraries never attempt to perform network
-requests and never collect telemetry.
+identifiable information (PII).
+
+**Libraries never attempt to make network requests and never collect telemetry.**
 
 In practice, there are many interesting networking use cases including server
 processing of user-submitted files and fetching files from an external source.
+
+When processing data from an external source, a platform-specific operation will
+obtain binary data and SheetJS libraries will process the data.
+
+When exporting data, SheetJS libraries will generate raw data and
+platform-specific operations will distribute the data.
+
 The demos in this section cover common use cases:
 
 <ul>{useCurrentSidebarCategory().items.map((item, index) => {
diff --git a/docz/docs/03-demos/04-static/01-lume.md b/docz/docs/03-demos/04-static/01-lume.md
index 7e68983..a78d71b 100644
--- a/docz/docs/03-demos/04-static/01-lume.md
+++ b/docz/docs/03-demos/04-static/01-lume.md
@@ -1,21 +1,36 @@
 ---
 title: Lume
+sidebar_label: Lume
+description: Make static websites from spreadsheets using Lume. Seamlessly integrate data into your website using SheetJS. Illuminate data without leaving the comfort of Excel.
 pagination_prev: demos/net/index
 pagination_next: demos/mobile/index
 sidebar_custom_props:
   type: native
 ---
 
-Lume is a lightweight, fast and flexible static site generator.
+# Illuminating Data with Lume
 
-The official [Sheets plugin](https://lume.land/plugins/sheets/) uses SheetJS to
-load data from spreadsheets.  New users should consult the official docs.
+[Lume](https://lume.land/) is a lightweight unopinionated static site generator.
+It has a rich ecosystem of JavaScript-powered plugins[^1]
+
+[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
+data from spreadsheets.
+
+This demo uses Lume and SheetJS (through the official "Sheets" plugin) to pull
+data from a spreadsheet and display the content in an HTML table.
+
+The ["Complete Example"](#complete-example) section includes a complete website
+powered by an XLSX spreadsheet.
+
+## Integration Details
+
+The official "Sheets" plugin[^2] uses SheetJS to load data from spreadsheets.
+Under the hood, the plugin uses the SheetJS `read`[^3] method to parse files and
+the `sheet_to_json`[^4] method to generate arrays of objects.
 
 Lume supports refreshing data during development. The generated static sites
 include the raw data without referencing the underlying spreadsheet files.
 
-## Integration Details
-
 ### Installation
 
 The `sheets` plugin can be imported and invoked in `_config.ts`:
@@ -33,19 +48,19 @@ site.use(sheets());
 export default site;
 ```
 
-### Usage
+:::info pass
 
-:::note
-
-The official documentation includes notes for more advanced use cases.
+The lines are automatically added if `sheets` plugin is enabled during setup.
 
 :::
 
+### Usage
+
 Spreadsheet files added in the `_data` subdirectory are accessible from template
 files using the name stem.
 
-For example, [`pres.numbers`](https://sheetjs.com/pres.numbers) can be accessed
-using the variable `pres` in a template.
+For example, [`pres.xlsx`](https://sheetjs.com/pres.xlsx) can be accessed using
+the variable `pres` in a template.
 
 #### Single-Sheet Workbooks
 
@@ -81,9 +96,9 @@ _Reading all Worksheets_
 The default behavior, when workbooks have multiple sheets, is to present objects
 whose keys are worksheet names and whose values are arrays of row objects.
 
-For example, if `pres.numbers` had a sheet named `"Presidents"` and another
-sheet named `"VicePresidents"`, then the following snippet would print data
-from the `"Presidents"` sheet:
+For example, if `pres.xlsx` had a sheet named `"Presidents"` and another sheet
+named `"VicePresidents"`, then the following snippet would print data from the
+`"Presidents"` sheet:
 
 ```liquid title="multi.njk"
 <table><thead><th>Name</th><th>Index</th></thead>
@@ -98,18 +113,35 @@ from the `"Presidents"` sheet:
 </table>
 ```
 
+#### File Formats
+
+As explained in the official plugin documentation[^5], the loader loads XLSX.
+NUMBERS, and CSV files. Other extensions can be added through the `extensions`
+property in the argument to the `sheets` plugin:
+
+```ts
+site.use(sheets({
+  // highlight-next-line
+  extensions: [".xlsx", ".xlsb", ".xls"]
+}));
+```
+
 
 ## Complete Example
 
 :::note
 
-This was tested against `lume v1.16.2` on 2023 April 18.
+This was tested against `lume v1.17.5` on 2023 June 25.
 
 This example uses the Nunjucks template format. Lume plugins support additional
 template formats, including Markdown and JSX.
 
 :::
 
+### Initial Setup
+
+0) Install Deno[^6]
+
 1) Create a stock site:
 
 ```bash
@@ -126,15 +158,14 @@ When prompted, enter the following options:
 
 The project will be configured and modules will be installed.
 
-2) Download <https://sheetjs.com/pres.numbers> and place in a `_data` folder:
+2) Download <https://sheetjs.com/pres.xlsx> and place in a `_data` folder:
 
 ```bash
 mkdir -p _data
-curl -L -o _data/pres.numbers https://sheetjs.com/pres.numbers
+curl -L -o _data/pres.xlsx https://sheetjs.com/pres.xlsx
 ```
 
-3) Create a `index.njk` file that references the file.  Since the file is
-   `pres.numbers`, the parameter name is `pres`:
+3) Create a `index.njk` file that references the file:
 
 ```liquid title="index.njk"
 <h2>Presidents</h2>
@@ -150,35 +181,51 @@ curl -L -o _data/pres.numbers https://sheetjs.com/pres.numbers
 </table>
 ```
 
+Since the file name is `pres.xlsx`, the parameter name is `pres`:
+
+### Live Refresh
+
 4) Run the development server:
 
 ```bash
-deno task lume --serve
+deno task serve --port 7262
 ```
 
-To verify it works, access `http://localhost:3000` from your web browser. Open
-`_data/pres.numbers` and add a new row to the bottom of the sheet. The page will
-refresh and show the new contents.
+To verify it works, access `http://localhost:7262` from your web browser. The
+page will show the contents of the spreadsheet.
 
-:::caution
+5) While the server is still running, open `_data/pres.xlsx` in a spreadsheet
+editor and add a new row at the bottom of the sheet.
 
-There is a known bug with Deno hot reloading.  If the page does not refresh
-automatically, upgrade with `deno upgrade` and restart the development server.
+The page will refresh and show the new contents.
 
-:::
+### Static Site
 
-5) Stop the server (press `CTRL+C` in the terminal window) and run
+6) Stop the server (press `CTRL+C` in the terminal window) and run
 
 ```bash
 deno task lume
 ```
 
-This will create a static site in the `_site` folder, which can be served with:
+This will create a static site in the `_site` folder
+
+7) Test the generated site by running
 
 ```bash
 npx http-server _site
 ```
 
-Accessing the page `http://localhost:8080` will show the page contents.
+The program will display a URL (typically `http://localhost:8080`). Accessing
+the page will show the contents of the spreadsheet.
+
+View the page source and confirm that the page only includes an HTML table. No
+scripts are included in this page.
 
 This site is self-contained and ready for deployment!
+
+[^1]: See ["Plugins"](https://lume.land/plugins/?status=all) in the Lume documentation
+[^2]: See ["Sheets"](https://lume.land/plugins/sheets/) in the Lume documentation
+[^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
+[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
+[^5]: See ["Formats"](https://lume.land/plugins/sheets/#formats) in the Lume documentation
+[^6]: See ["Installation"](https://deno.com/manual/getting_started/installation) in the Deno documentation
\ No newline at end of file
diff --git a/docz/docs/03-demos/04-static/index.md b/docz/docs/03-demos/04-static/index.md
index f4bc127..0c79248 100644
--- a/docz/docs/03-demos/04-static/index.md
+++ b/docz/docs/03-demos/04-static/index.md
@@ -38,15 +38,18 @@ the browser refreshes to show the new content.
 :::note Recommendation
 
 It is strongly recommended to use a framework that provides an official plugin
-for working with SheetJS. Lume is a great choice for getting started. GatsbyJS
-is excellent for teams well-versed in the React JS framework.
+for working with SheetJS.
+
+Lume is a great choice for lightweight sites.
+
+GatsbyJS is excellent for teams well-versed in the ReactJS framework.
 
 :::
 
 ### Official
 
-Some frameworks provide official extensions  They are strongly recommended for
-greenfield projects.  Demos:
+Some frameworks provide official extensions. They are strongly recommended for
+greenfield projects.
 
 <ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.type == "native").map(item => {
   const listyle = (item.customProps?.icon) ? {
@@ -61,7 +64,7 @@ greenfield projects.  Demos:
 ### Bundlers
 
 Bundlers can run JS code and process assets during development and during site
-builds. Custom plugins can extract data from spreadsheets.  Demos:
+builds. Custom plugins can extract data from spreadsheets.
 
 <ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.type == "bundler").map(item => {
   const listyle = (item.customProps?.icon) ? {
diff --git a/docz/docs/03-demos/06-desktop/index.md b/docz/docs/03-demos/06-desktop/index.md
index 7757350..801382c 100644
--- a/docz/docs/03-demos/06-desktop/index.md
+++ b/docz/docs/03-demos/06-desktop/index.md
@@ -7,9 +7,12 @@ pagination_next: demos/data/index
 import DocCardList from '@theme/DocCardList';
 import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
 
-Web technologies like JavaScript and HTML have been adapted to the traditional
-app space.  Typically these frameworks bundle a JavaScript engine as well as a
-windowing framework. SheetJS is compatible with many app frameworks.
+Web technologies including JavaScript and HTML can power traditional software.
+
+## Desktop Apps
+
+Desktop app frameworks bundle a JavaScript engine and a windowing framework to
+enable graphical apps. SheetJS is compatible with many app frameworks.
 
 Demos for common desktop tools are included in separate pages:
 
@@ -22,17 +25,6 @@ Demos for common desktop tools are included in separate pages:
   </li>);
 })}</ul>
 
-Demos for common command-line tools are included in separate pages:
-
-<ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.cli).map((item, index) => {
-  const listyle = (item.customProps?.icon) ? {
-    listStyleImage: `url("${item.customProps.icon}")`
-  } : {};
-  return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
-    <a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
-  </li>);
-})}</ul>
-
 :::note Desktop Recommendation
 
 Electron is the most established and widely-used framework. With deep support
@@ -45,3 +37,19 @@ other programming languages.
 Frameworks like React Native generate applications that use native UI elements.
 
 :::
+
+## Command-Line Tools
+
+Command-line tools bundle a JavaScript engine and a system runtime. The runtime
+provides low-level access to computer resources.
+
+Demos for common command-line tools are included in separate pages:
+
+<ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.cli).map((item, index) => {
+  const listyle = (item.customProps?.icon) ? {
+    listStyleImage: `url("${item.customProps.icon}")`
+  } : {};
+  return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
+    <a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
+  </li>);
+})}</ul>
diff --git a/docz/docs/03-demos/08-local/05-clipboard.md b/docz/docs/03-demos/08-local/05-clipboard.md
index 524ce7d..8b6c695 100644
--- a/docz/docs/03-demos/08-local/05-clipboard.md
+++ b/docz/docs/03-demos/08-local/05-clipboard.md
@@ -23,7 +23,7 @@ Clipboard data can be read from a `paste` event, accessible from the event
 
 ```js
 document.onpaste = function(e) {
-  /* get TSV */
+  /* get HTML */
   var str = e.clipboardData.getData('text/html');
   /* parse */
   var wb = XLSX.read(str, {type: "string"});
diff --git a/docz/docs/03-demos/08-local/index.md b/docz/docs/03-demos/08-local/index.md
index 86e56c8..bbecbb7 100644
--- a/docz/docs/03-demos/08-local/index.md
+++ b/docz/docs/03-demos/08-local/index.md
@@ -12,7 +12,7 @@ There is no standard cross-platform approach to read and write files and data.
 the file read and write operations.  Not all platforms support the APIs used in
 the library.
 
-The demos in this section cover APIs that are not supported out-of-the-box:
+Demos in this section cover local APIs that are not embedded in the library:
 
 <ul>{useCurrentSidebarCategory().items.map((item, index) => {
   const listyle = (item.customProps?.icon) ? {
diff --git a/docz/docs/03-demos/09-cloud/05-dropbox.mdx b/docz/docs/03-demos/09-cloud/05-dropbox.mdx
index cfec5be..1b5f008 100644
--- a/docz/docs/03-demos/09-cloud/05-dropbox.mdx
+++ b/docz/docs/03-demos/09-cloud/05-dropbox.mdx
@@ -62,6 +62,7 @@ function SheetJSChoisissez() {
   const [msg, setMsg] = React.useState("Press the button to show a Chooser");
   const btn = useRef(), tbl = useRef();
   React.useEffect(() => {
+    if(typeof Dropbox == "undefined") return setMsg("Dropbox is not defined");
     /* create button */
     var button = Dropbox.createChooseButton({
       /* required settings */
@@ -131,6 +132,7 @@ function SheetJSEnregistrez() {
   const [msg, setMsg] = React.useState("Press the button to write XLS file");
   const btn = useRef(), tbl = useRef();
   React.useEffect(async() => {
+    if(typeof Dropbox == "undefined") return setMsg("Dropbox is not defined");
     /* fetch data and write table (sample data) */
     const f = await(await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
     const wb = XLSX.read(f);
diff --git a/docz/docs/03-demos/10-extensions/index.md b/docz/docs/03-demos/10-extensions/index.md
index 183ac64..45f4a22 100644
--- a/docz/docs/03-demos/10-extensions/index.md
+++ b/docz/docs/03-demos/10-extensions/index.md
@@ -12,7 +12,7 @@ language for writing extensions for apps. Some applications like Chromium use V8
 while others use engines that only support ES3 JavaScript. With conservative use
 of modern language features, SheetJS can be used in many app extensions.
 
-Demos for common apps are included in separate pages:
+Demos for common applications are included in separate pages:
 
 <ul>{useCurrentSidebarCategory().items.map((item, index) => {
   const listyle = (item.customProps?.icon) ? {
diff --git a/docz/docs/03-demos/11-bigdata/index.md b/docz/docs/03-demos/11-bigdata/index.md
index 66dec2d..b5884cf 100644
--- a/docz/docs/03-demos/11-bigdata/index.md
+++ b/docz/docs/03-demos/11-bigdata/index.md
@@ -15,8 +15,10 @@ been integrated into the ReactJS framework and other foundational JS libraries.
 JS Engines have improved over the years, but there are some hard limits to
 browser support using traditional methods of data processing.  Vendors have
 introduced APIs and techniques for representing and processing very large binary
-and textual files. Since many of the techniques only work in a few engines, they
-are recommended only when the traditional approaches falter:
+and textual files.
+
+Since many of the techniques only work in a few engines, they are not embedded
+in the library. They are recommended only when traditional approaches falter.
 
 <ul>{useCurrentSidebarCategory().items.map((item, index) => {
   const listyle = (item.customProps?.icon) ? {
diff --git a/docz/docs/07-csf/07-features/03-dates.md b/docz/docs/07-csf/07-features/03-dates.md
index bb0d811..9ba8abd 100644
--- a/docz/docs/07-csf/07-features/03-dates.md
+++ b/docz/docs/07-csf/07-features/03-dates.md
@@ -1,498 +1,502 @@
----
-sidebar_position: 3
----
-
-# Dates and Times
-
-<details>
-  <summary><b>File Format Support</b> (click to show)</summary>
-
-Dates are a core concept in nearly every spreadsheet application in existence.
-Some legacy spreadsheet apps only supported dates.  Others supported times as a
-distinct concept from dates.
-
-Some file formats store dates in a textual format, while others store dates with
-[numbers representing a difference from an epoch](#relative-epochs).
-
-Many spreadsheet apps use special number formats to signal that values are dates
-or times.  Quattro Pro for DOS had a distinct set of Date number formats and
-Time number formats, but did not have a mixed Date + Time format.
-
-Lotus 1-2-3 used a ["1900" date system](#1904-and-1900-date-systems), while
-Numbers exclusively supports 1904 under the hood. Excel file formats typically
-include options for specifying the date system
-
-| Formats           | Date | Time | D+T | Date Storage         | Date System |
-|:------------------|:----:|:----:|:---:|:--------------------:|:------------|
-| NUMBERS           |   ✔  |   ✔  |  ✔  | Number               | 1904 Only   |
-| XLSX / XLSM       |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| XLSX (Strict ISO) |   ✔  |   ✔  |  ✔  | Relative Date        | 1900 + 1904 |
-| XLSB              |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| XLML              |   ✔  |   ✔  |  ✔  | Relative Date        | 1900 + 1904 |
-| XLS (BIFF5/8)     |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| XLS (BIFF2/3/4)   |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| XLR (Works)       |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| ET (WPS 电子表格)  |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
-| ODS / FODS / UOS  |   ✔  |   ✔  |  ✔  | ISO Duration or Date | Arbitrary   |
-| HTML              |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
-| CSV / TSV / Text  |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
-| DBF               |   ✔  |   *  |  *  | Number or Plaintext  | Calendar    |
-| DIF               |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
-| WK1               |   ✔  |   ✔  |  ✕  | Number               | 1900        |
-| WKS (Works)       |   ✔  |   ✔  |  ✕  | Number               | 1900        |
-| WQ1               |   ✔  |      |  ✕  | Number               | 1900        |
-| QPW               |   ✔  |   ✔  |  *  | Number               | 1900        |
-
-X (✕) marks features that are not supported by the file formats. For example,
-the WK1 file format had date-only formats and time-only formats but no mixed
-date-time formats.
-
-Newer DBF levels support a special `T` field type that represents date + time.
-
-The QPW file format supports mixed date + time formats in custom number formats.
-
-</details>
-
-Lotus 1-2-3, Excel, and other spreadsheet software do not have a true concept
-of date or time.  Instead, dates and times are stored as offsets from an epoch.
-The magic behind date interpretations is hidden in functions or number formats.
-
-SheetJS attempts to create a friendly JS date experience while also exposing
-options to use the traditional date codes
-
-:::tip pass
-
-Date and time handling was overhauled in version `0.20.0`. It is strongly
-recommended to [upgrade](/docs/getting-started/installation/).
-
-:::
-
-The following example exports the current time to XLSX spreadsheet. The time
-shown on this page will be the time displayed in Excel
-
-```jsx live
-function SheetJSNow() {
-  const [date, setDate] = React.useState(new Date());
-  const xport = React.useCallback(() => {
-    /* generate array of arrays */
-    const aoa = [[date]];
-    /* to avoid confusion, set milliseconds to 0 */
-    aoa[0][0].setMilliseconds(0);
-    /* generate workbook */
-    const ws = XLSX.utils.aoa_to_sheet(aoa, {dense: true});
-    /* set cell A1 number format */
-    ws["!data"][0][0].z = "yyyy-mm-dd hh:mm:ss"
-    ws["!cols"] = [{wch: 20}];
-
-    /* generate workbook and export */
-    const wb = XLSX.utils.book_new();
-    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
-    XLSX.writeFile(wb, "SheetJSNow.xlsx");
-  }, []);
-  return ( <>
-    <p>
-      <b>Local Time:</b>{date.toString()}
-      <button onClick={()=>setDate(new Date())}>Refresh</button>
-    </p>
-    <button onClick={xport}>Export XLSX</button>
-  </> )
-}
-```
-
-## How Spreadsheets Understand Time
-
-Excel stores dates as numbers.  When displaying dates, the format code should
-include special date and time tokens like `yyyyy` for long year. `EDATE` and
-other date functions operate on and return date numbers.
-
-For date formats like `yyyy-mm-dd`, the integer part represents the number of
-days from a starting epoch.  For example, the date `19-Feb-17` is stored as the
-number `42785` with a number format of `d-mmm-yy`.
-
-The fractional part of the date code serves as the time marker.  Excel assumes
-each day has exactly 86400 seconds.  For example, the date code `0.25` has a
-time component corresponding to 6:00 AM.
-
-For absolute time formats like `[hh]:mm`, the integer part represents a whole
-number of 24-hour (or 1440 minute) intervals.  The value `1.5` in the format
-`[hh]:mm` is interpreted as 36 hours 0 minutes.
-
-### Date and Time Number Formats
-
-Assuming a cell has a formatted date, re-formatting as "General" will reveal
-the underlying value.  Alternatively, the `TEXT` function can be used to return
-the date code.
-
-The following table covers some common formats:
-
-<details><summary><b>Common Date-Time Formats</b> (click to show)</summary>
-
-| Fragment | Interpretation               |
-|:---------|:-----------------------------|
-| `yy`     | Short (2-digit) year         |
-| `yyyy`   | Long (4-digit) year          |
-| `m`      | Short (1-digit) month        |
-| `mm`     | Long (2-digit) month         |
-| `mmm`    | Short (3-letter) month name  |
-| `mmmm`   | Full month name              |
-| `mmmmm`  | First letter of month name   |
-| `d`      | Short (1-digit) day of month |
-| `dd`     | Long (2-digit) day of month  |
-| `ddd`    | Short (3-letter) day of week |
-| `dddd`   | Full day of week             |
-| `h`      | Short (1-digit) hours        |
-| `hh`     | Long (2-digit) hours         |
-| `m`      | Short (1-digit) minutes      |
-| `mm`     | Long (2-digit) minutes       |
-| `s`      | Short (1-digit) seconds      |
-| `ss`     | Long (2-digit) seconds       |
-| `A/P`    | Meridiem ("A" or "P")        |
-| `AM/PM`  | Meridiem ("AM" or "PM")      |
-
-:::note
-
-`m` and `mm` are context-dependent.  It is interpreted as "minutes" when the
-previous or next date token represents a time (hours or seconds):
-
-```
-yyyy-mm-dd hh:mm:ss
-     ^^       ^^
-    month    minutes
-```
-
-:::
-
-</details>
-
-### 1904 and 1900 Date Systems
-
-The interpretation of date codes requires a shared understanding of date code
-`0`, otherwise known as the "epoch".  Excel supports two epochs:
-
-- The default epoch is "January 0 1900". The `0` value is 00:00 on December 31
-  of the year 1899, but it is formatted as January 0 1900.
-
-- Enabling "1904 Date System" sets the default epoch to "January 1 1904".  The
-  `0` value is 00:00 on January 1 of the year 1904.
-
-The workbook's epoch can be determined by examining the workbook's `wb.Workbook.WBProps.date1904` property:
-
-```js
-if(!(wb?.Workbook?.WBProps?.date1904)) {
-  /* uses 1904 date system */
-} else {
-  /* uses 1900 date system */
-}
-```
-
-:::note Why does the 1904 date system exist?
-
-1900 was not a leap year.  For the Gregorian calendar, the general rules are:
-- every multiple of 400 is a leap year
-- every multiple of 100 that is not a multiple of 400 is not a leap year
-- every multiple of 4 that is not a multiple of 100 is a leap year
-- all other years are not leap years.
-
-Lotus 1-2-3 erroneously treated 1900 as a leap year. This can be verified with
-the `@date` function:
-
-```
-@date(0,2,28) -> 59    // Lotus accepts 2/28/1900
-@date(0,2,29) -> 60    // <--2/29/1900 was not a real date
-@date(0.2,30) -> ERR   // Lotus rejects 2/30/1900
-```
-
-Excel extends the tradition in the default date system.  The 1904 date system
-starts the count in 1904, skipping the bad date.
-
-:::
-
-### Relative Epochs
-
-The epoch is based on the system timezone.  The epoch in New York is midnight
-in Eastern time, while the epoch in Seattle is midnight in Pacific time.
-
-This design has the advantage of uniform time display: "12 PM" is 12 PM
-irrespective of the timezone of the viewer.  However, this design precludes any
-international coordination (there is no way to create a value that represents
-an absolute time) and makes JavaScript processing somewhat ambiguous (since
-JavaScript Date objects are timezone-aware)
-
-This is a deficiency of the spreadsheet software. Excel has no native concept
-of universal time.
-
-## How Files Store Dates and Times
-
-XLS, XLSB, and most binary formats store the raw date codes.  Special number
-formats are used to indicate that the values are intended to be dates/times.
-
-CSV and other text formats typically store actual formatted date values.  They
-are interpreted as dates and times in the user timezone.
-
-XLSX actually supports both!  Typically dates are stored as `n` numeric cells,
-but the format supports a special type `d` where the data is an ISO 8601 date
-string. This is not used in the default Excel XLSX export and third-party
-support is poor.
-
-ODS does support absolute time values but drops the actual timezone indicator
-when parsing.  In that sense, LibreOffice follows the same behavior as Excel.
-
-Numbers uses a calendar date system, but records pure time values as if they are
-absolute times in 1904 January 01. It is spiritually equivalent to the 1904 mode
-in Excel and other spreadsheet applications.
-
-## How JavaScript Engines Understand Time
-
-JavaScript provides a `Date` object which represents an *absolute* time. Under
-the hood, `Date` uses the "UNIX" epoch of 1970 January 01 midnight in UTC. This
-means the actual zero date is different in different timezones!
-
-| Location    | IANA Timezone         | `new Date(0)` in local time |
-|:------------|:----------------------|:----------------------------|
-| Honolulu    | `Pacific/Honolulu`    | `1969-12-31 02:00 PM`       |
-| Los Angeles | `America/Los_Angeles` | `1969-12-31 04:00 PM`       |
-| New York    | `America/New_York`    | `1969-12-31 07:00 PM`       |
-| Sao Paulo   | `America/Sao_Paulo`   | `1969-12-31 09:00 PM`       |
-| London      | `Europe/London`       | `1970-01-01 01:00 AM`       |
-| Cairo       | `Africa/Cairo`        | `1970-01-01 02:00 AM`       |
-| Djibouti    | `Africa/Djibouti`     | `1970-01-01 03:00 AM`       |
-| Chennai     | `Asia/Kolkata`        | `1970-01-01 05:30 AM`       |
-| Shanghai    | `Asia/Shanghai`       | `1970-01-01 08:00 AM`       |
-| Seoul       | `Asia/Seoul`          | `1970-01-01 09:00 AM`       |
-| Sydney      | `Australia/Sydney`    | `1970-01-01 10:00 AM`       |
-
-In modern environments, the IANA Timezone and timezone offset can be discovered
-through the `Intl` and `Date` objects:
-
-```jsx live
-function LocalInfo() {
-  const date = new Date();
-  return ( <>
-  <b>Local Time</b>: {date.toString()}<br/>
-  <b>Time offset (relative to UTC)</b>: {-date.getTimezoneOffset()/60} hours <br/>
-  <b>IANA Timezone</b>: {Intl.DateTimeFormat().resolvedOptions().timeZone}
-</>)}
-```
-
-:::caution
-
-The timezone information is provided by the JavaScript engine and local settings.
-There are outstanding Google Chrome and V8 bugs related to rounded offsets for
-timezones under a lunar calendar. The last timezone to switch to the Gregorian
-calendar was `Africa/Monrovia` (in 1972).
-
-SheetJS utilities attempt to work around the browser bugs.
-
-:::
-
-### UTC and Local Time
-
-The `Date` object has a number of prototype methods for inspecting the object.
-Some methods interact with the true value, while others convert to the local
-timezone.  Some methods are listed in the table below:
-
-| Feature          | Local Time method | UTC method       |
-|:-----------------|:------------------|:-----------------|
-| Year             | `getFullYear`     | `getUTCFullYear` |
-| Month (0-11)     | `getMonth`        | `getUTCMonth`    |
-| Day of the month | `getDate`         | `getUTCDate`     |
-| Hours            | `getHours`        | `getUTCHours`    |
-| Minutes          | `getMinutes`      | `getUTCMinutes`  |
-| Seconds          | `getSeconds`      | `getUTCSeconds`  |
-| Entire date      | `toString`        | `toUTCString`    |
-
-It is typical for websites and other applications to present data in local time.
-To serve an international audience, backend servers typically use UTC time.
-
-The following example shows the time when the page was loaded. The same absolute
-time will appear to be different under local and UTC interpretations:
-
-```jsx live
-function LocalUTC() {
-  const d = new Date();
-  /* display number with 2 digits, prepending `0` if necessary */
-  const f = (n) => n.toString().padStart(2, "0");
-  /* HH:MM:SS using local interpretation */
-  const local = `${f(d.getHours())}:${f(d.getMinutes())}:${f(d.getSeconds())}`;
-  /* HH:MM:SS using UTC interpretation */
-  const utc = `${f(d.getUTCHours())}:${f(d.getUTCMinutes())}:${f(d.getUTCSeconds())}`;
-  return ( <>
-    <b>Local Interpretation</b><br/>
-    <code>toString</code>: {d.toString()}<br/>
-    24-hour time: {local}<br/>
-    <br/>
-    <b>UTC Interpretation</b><br/>
-    <code>toUTCString</code>: {d.toUTCString()}<br/>
-    24-hour time: {utc}<br/>
-</>)}
-```
-
-## How SheetJS handles Dates and Times
-
-SheetJS attempts to reconcile the spreadsheet and JavaScript date concepts.
-
-The default behavior for all parsers is to generate number cells. Setting
-`cellDates` to true will force the parsers to store dates.
-
-```jsx live
-function SheetJSCellDates() {
-  var csv = "Date,10/6/2048";
-
-  // cell B1 will be { t: 'n', v: 54337 }
-  var wb_sans_date = XLSX.read(csv, {type:"binary"});
-  var ws_sans_date = wb_sans_date.Sheets.Sheet1;
-
-  // cell B1 will be { t: 'd', v: <Date: 2048-10-06 00:00:00 UTC> }
-  var wb_with_date = XLSX.read(csv, {type:"binary", cellDates: true});
-  var ws_with_date = wb_with_date.Sheets.Sheet1;
-
-  return (<>
-  <b>CSV:</b><pre>{csv}</pre>
-  <b>Cell B1:</b><br/><br/>
-  <table><tr><th>cellDates</th><th>type</th><th>value</th></tr>
-    <tr><td>(unspecified)</td>
-      <td><code>{ws_sans_date["B1"].t}</code></td>
-      <td><code>{ws_sans_date["B1"].v}</code></td>
-    </tr>
-    <tr><td>true</td>
-      <td><code>{ws_with_date["B1"].t}</code></td>
-      <td><code>{ws_with_date["B1"].v.toISOString()}</code> (Date object)</td>
-    </tr>
-  </table>
-  </>);
-}
-```
-
-When writing, date cells are automatically translated back to numeric cells
-with an appropriate number format.
-
-The value formatting logic understands date formats and converts when relevant.
-It always uses the UTC interpretation of Date objects.
-
-### Date Objects
-
-The actual values stored in cells are intended to be correct when interpreted
-using UTC date methods.
-
-For example, [`DateTime.xlsx`](pathname:///DateTime.xlsx) is a test file with the following data:
-
-| Type     | Value                 |
-|:---------|----------------------:|
-| Date     |          `2048-10-06` |
-| Time     |               `15:00` |
-| DateTime | `2048-10-06 15:00:00` |
-
-The raw data values are shown in the live demo.  The UTC date string will show
-the same value as Excel irrespective of the local timezone.
-
-```jsx live
-function SheetJSDateTimeXlsxValues() {
-  const [data, setData] = React.useState([[]]);
-  React.useEffect(() => { (async() => {
-    const ab = await (await fetch("/DateTime.xlsx")).arrayBuffer();
-    const wb = XLSX.read(ab, {cellDates: true, dense: true});
-    setData(wb.Sheets.Sheet1["!data"]);
-  })(); });
-  return ( <table><thead>
-    <th>Excel Date</th><th>UTC Date</th><th>Local Date</th>
-  </thead><tbody>
-    {data.slice(1).map((row,R) => ( <tr key={R}>
-      <td>{row[1].w}</td>
-      <td>{row[1].v.toUTCString()}</td>
-      <td>{row[1].v.toString()}</td>
-    </tr> ))}
-  </tbody></table> );
-}
-```
-
-### Utility Functions
-
-Utility functions that deal with JS data accept a `cellDates` argument which
-dictates how dates should be handled.
-
-Functions that create a worksheet will adjust date cells and use a number
-format like `m/d/yy` to mark dates:
-
-```js
-// Cell A1 will be a numeric cell whose value is the date code
-var ws = XLSX.utils.aoa_to_sheet([[new Date()]]);
-
-// Cell A1 will be a date cell
-var ws = XLSX.utils.aoa_to_sheet([[new Date()]], { cellDates: true });
-```
-
-Functions that create an array of JS objects with raw values will keep the
-native representation:
-
-```js
-// Cell A1 is numeric -> output is a number
-var ws = XLSX.utils.aoa_to_sheet([[new Date()]]);
-var A1 = XLSX.utils.sheet_to_json(ws, { header: 1 })[0][0];
-
-// Cell A1 is a date -> output is a date
-var ws = XLSX.utils.aoa_to_sheet([[new Date()]], { cellDates: true });
-var A1 = XLSX.utils.sheet_to_json(ws, { header: 1 })[0][0];
-```
-
-### UTC Option
-
-Some API functions support the `UTC` option to control how dates are handled.
-
-**[`sheet_to_json`](/docs/api/utilities/array#array-output)**
-
-If `UTC` is true, the dates will be correct when interpreted in UTC. By default,
-the dates will be correct when interpreted in local time.
-
-Typically `UTC` is used for data from an API endpoint, as servers typically emit
-UTC dates and expect scripts to localize. The local interpretation is sensible
-when users submit data, as they will be providing times in their local timezone.
-
-**[`aoa_to_sheet` / `sheet_add_aoa`](/docs/api/utilities/array#array-of-arrays-input)** / **[`json_to_sheet` / `sheet_add_json`](/docs/api/utilities/array#array-of-objects-input)**
-
-If `UTC` is true, the UTC interpretation of dates will be used.
-
-Typically `UTC` is used for data from an API endpoint, as servers typically emit
-UTC dates and expect scripts to localize. The local interpretation is sensible
-when date objects are generated in the browser.
-
-
-**[`table_to_book` / `table_to_sheet` / `sheet_add_dom`](/docs/api/utilities/html#html-table-input)**
-
-If `UTC` is true, potential dates are interpreted as if they represent UTC times.
-By default, potential dates are interpreted in local time.
-
-Typically `UTC` is used for data exported from Excel or other spreadsheet apps.
-If the table is programmatically generated in the frontend, the dates and times
-will be in the local timezone and the local interpretation is preferable.
-
-### Number Formats
-
-By default, the number formats are not emitted.  For Excel-based file formats,
-passing the option `cellNF: true` adds the `z` field.
-
-The helper function `XLSX.SSF.is_date` parses formats and returns `true` if the
-format represents a date or time:
-
-```js
-XLSX.SSF.is_date("yyyy-mm-dd"); // true
-
-XLSX.SSF.is_date("0.00"); // false
-```
-
-<details><summary><b>Live Demo</b> (click to show)</summary>
-
-```jsx live
-function SSFIsDate() {
-  const [format, setFormat] = React.useState("yyyy-mm-dd");
-  const cb = React.useCallback((evt) => {
-    setFormat(evt.target.value);
-  });
-  const is_date = XLSX.SSF.is_date(format);
-  return ( <>
-    <div>Format <b>|{format}|</b> is {is_date ? "" : "not"} a date/time</div>
-    <input type="text" onChange={cb}/>
-  </> );
-}
-```
-
-</details>
+---
+sidebar_position: 3
+---
+
+# Dates and Times
+
+<details>
+  <summary><b>File Format Support</b> (click to show)</summary>
+
+Dates are a core concept in nearly every spreadsheet application in existence.
+Some legacy spreadsheet apps only supported dates.  Others supported times as a
+distinct concept from dates.
+
+Some file formats store dates in a textual format, while others store dates with
+[numbers representing a difference from an epoch](#relative-epochs).
+
+Many spreadsheet apps use special number formats to signal that values are dates
+or times.  Quattro Pro for DOS had a distinct set of Date number formats and
+Time number formats, but did not have a mixed Date + Time format. OpenOffice
+uses ISO 8601 duration strings for pure time data.
+
+Lotus 1-2-3 used a ["1900" date system](#1904-and-1900-date-systems), while
+Numbers exclusively supports 1904 under the hood. Excel file formats typically
+include options for specifying the date system. OpenOffice can support arbitrary
+starting dates.
+
+| Formats           | Date | Time | D+T | Date Storage         | Date System |
+|:------------------|:----:|:----:|:---:|:--------------------:|:------------|
+| NUMBERS           |   ✔  |   ✔  |  ✔  | Number               | 1904 Only   |
+| XLSX / XLSM       |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| XLSX (Strict ISO) |   ✔  |   ✔  |  ✔  | Relative Date        | 1900 + 1904 |
+| XLSB              |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| XLML              |   ✔  |   ✔  |  ✔  | Relative Date        | 1900 + 1904 |
+| XLS (BIFF5/8)     |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| XLS (BIFF2/3/4)   |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| XLR (Works)       |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| ET (WPS 电子表格)  |   ✔  |   ✔  |  ✔  | Number               | 1900 + 1904 |
+| ODS / FODS / UOS  |   ✔  |   ✔  |  ✔  | ISO Duration or Date | Arbitrary   |
+| HTML              |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
+| CSV / TSV / Text  |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
+| DBF               |   ✔  |   *  |  *  | Number or Plaintext  | Calendar    |
+| DIF               |   ✔  |   ✔  |  ✔  | Plaintext            | Calendar    |
+| WK1               |   ✔  |   ✔  |  ✕  | Number               | 1900        |
+| WKS (Works)       |   ✔  |   ✔  |  ✕  | Number               | 1900        |
+| WQ1               |   ✔  |      |  ✕  | Number               | 1900        |
+| QPW               |   ✔  |   ✔  |  *  | Number               | 1900        |
+
+X (✕) marks features that are not supported by the file formats. For example,
+the WK1 file format had date-only formats and time-only formats but no mixed
+date-time formats.
+
+Newer DBF levels support a special `T` field type that represents date + time.
+
+The QPW file format supports mixed date + time formats in custom number formats.
+
+</details>
+
+Lotus 1-2-3, Excel, and other spreadsheet software do not have a true concept
+of date or time.  Instead, dates and times are stored as offsets from an epoch.
+The magic behind date interpretations is hidden in functions or number formats.
+
+SheetJS attempts to create a friendly JS date experience while also exposing
+options to use the traditional date codes
+
+:::tip pass
+
+Date and time handling was overhauled in version `0.20.0`. It is strongly
+recommended to [upgrade](/docs/getting-started/installation/).
+
+:::
+
+The following example exports the current time to XLSX spreadsheet. The time
+shown on this page will be the time displayed in Excel
+
+```jsx live
+function SheetJSNow() {
+  const [date, setDate] = React.useState(new Date());
+  const xport = React.useCallback(() => {
+    /* generate array of arrays */
+    const aoa = [[date]];
+    /* to avoid confusion, set milliseconds to 0 */
+    aoa[0][0].setMilliseconds(0);
+    /* generate workbook */
+    const ws = XLSX.utils.aoa_to_sheet(aoa, {dense: true});
+    /* set cell A1 number format */
+    ws["!data"][0][0].z = "yyyy-mm-dd hh:mm:ss"
+    ws["!cols"] = [{wch: 20}];
+
+    /* generate workbook and export */
+    const wb = XLSX.utils.book_new();
+    XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
+    XLSX.writeFile(wb, "SheetJSNow.xlsx");
+  }, []);
+  return ( <>
+    <p>
+      <b>Local Time:</b>{date.toString()}
+      <button onClick={()=>setDate(new Date())}>Refresh</button>
+    </p>
+    <button onClick={xport}>Export XLSX</button>
+  </> )
+}
+```
+
+## How Spreadsheets Understand Time
+
+Excel stores dates as numbers.  When displaying dates, the format code should
+include special date and time tokens like `yyyyy` for long year. `EDATE` and
+other date functions operate on and return date numbers.
+
+For date formats like `yyyy-mm-dd`, the integer part represents the number of
+days from a starting epoch.  For example, the date `19-Feb-17` is stored as the
+number `42785` with a number format of `d-mmm-yy`.
+
+The fractional part of the date code serves as the time marker.  Excel assumes
+each day has exactly 86400 seconds.  For example, the date code `0.25` has a
+time component corresponding to 6:00 AM.
+
+For absolute time formats like `[hh]:mm`, the integer part represents a whole
+number of 24-hour (or 1440 minute) intervals.  The value `1.5` in the format
+`[hh]:mm` is interpreted as 36 hours 0 minutes.
+
+### Date and Time Number Formats
+
+Assuming a cell has a formatted date, re-formatting as "General" will reveal
+the underlying value.  Alternatively, the `TEXT` function can be used to return
+the date code.
+
+The following table covers some common formats:
+
+<details><summary><b>Common Date-Time Formats</b> (click to show)</summary>
+
+| Fragment | Interpretation               |
+|:---------|:-----------------------------|
+| `yy`     | Short (2-digit) year         |
+| `yyyy`   | Long (4-digit) year          |
+| `m`      | Short (1-digit) month        |
+| `mm`     | Long (2-digit) month         |
+| `mmm`    | Short (3-letter) month name  |
+| `mmmm`   | Full month name              |
+| `mmmmm`  | First letter of month name   |
+| `d`      | Short (1-digit) day of month |
+| `dd`     | Long (2-digit) day of month  |
+| `ddd`    | Short (3-letter) day of week |
+| `dddd`   | Full day of week             |
+| `h`      | Short (1-digit) hours        |
+| `hh`     | Long (2-digit) hours         |
+| `m`      | Short (1-digit) minutes      |
+| `mm`     | Long (2-digit) minutes       |
+| `s`      | Short (1-digit) seconds      |
+| `ss`     | Long (2-digit) seconds       |
+| `A/P`    | Meridiem ("A" or "P")        |
+| `AM/PM`  | Meridiem ("AM" or "PM")      |
+
+:::note
+
+`m` and `mm` are context-dependent.  It is interpreted as "minutes" when the
+previous or next date token represents a time (hours or seconds):
+
+```
+yyyy-mm-dd hh:mm:ss
+     ^^       ^^
+    month    minutes
+```
+
+`mmm`, `mmmm`, and `mmmmm` always represent months.
+
+:::
+
+</details>
+
+### 1904 and 1900 Date Systems
+
+The interpretation of date codes requires a shared understanding of date code
+`0`, otherwise known as the "epoch".  Excel supports two epochs:
+
+- The default epoch is "January 0 1900". The `0` value is 00:00 on December 31
+  of the year 1899, but it is formatted as January 0 1900.
+
+- Enabling "1904 Date System" sets the default epoch to "January 1 1904".  The
+  `0` value is 00:00 on January 1 of the year 1904.
+
+The workbook's epoch can be determined by examining the workbook's `wb.Workbook.WBProps.date1904` property:
+
+```js
+if(!(wb?.Workbook?.WBProps?.date1904)) {
+  /* uses 1904 date system */
+} else {
+  /* uses 1900 date system */
+}
+```
+
+:::note Why does the 1904 date system exist?
+
+1900 was not a leap year.  For the Gregorian calendar, the general rules are:
+- every multiple of 400 is a leap year
+- every multiple of 100 that is not a multiple of 400 is not a leap year
+- every multiple of 4 that is not a multiple of 100 is a leap year
+- all other years are not leap years.
+
+Lotus 1-2-3 erroneously treated 1900 as a leap year. This can be verified with
+the `@date` function:
+
+```
+@date(0,2,28) -> 59    // Lotus accepts 2/28/1900
+@date(0,2,29) -> 60    // <--2/29/1900 was not a real date
+@date(0.2,30) -> ERR   // Lotus rejects 2/30/1900
+```
+
+Excel extends the tradition in the default date system.  The 1904 date system
+starts the count in 1904, skipping the bad date.
+
+:::
+
+### Relative Epochs
+
+The epoch is based on the system timezone.  The epoch in New York is midnight
+in Eastern time, while the epoch in Seattle is midnight in Pacific time.
+
+This design has the advantage of uniform time display: "12 PM" is 12 PM
+irrespective of the timezone of the viewer.  However, this design precludes any
+international coordination (there is no way to create a value that represents
+an absolute time) and makes JavaScript processing somewhat ambiguous (since
+JavaScript Date objects are timezone-aware)
+
+This is a deficiency of the spreadsheet software. Excel has no native concept
+of universal time.
+
+## How Files Store Dates and Times
+
+XLS, XLSB, and most binary formats store the raw date codes.  Special number
+formats are used to indicate that the values are intended to be dates/times.
+
+CSV and other text formats typically store actual formatted date values.  They
+are interpreted as dates and times in the user timezone.
+
+XLSX actually supports both!  Typically dates are stored as `n` numeric cells,
+but the format supports a special type `d` where the data is an ISO 8601 date
+string. This is not used in the default Excel XLSX export and third-party
+support is poor.
+
+ODS does support absolute time values but drops the actual timezone indicator
+when parsing.  In that sense, LibreOffice follows the same behavior as Excel.
+
+Numbers uses a calendar date system, but records pure time values as if they are
+absolute times in 1904 January 01. It is spiritually equivalent to the 1904 mode
+in Excel and other spreadsheet applications.
+
+## How JavaScript Engines Understand Time
+
+JavaScript provides a `Date` object which represents an *absolute* time. Under
+the hood, `Date` uses the "UNIX" epoch of 1970 January 01 midnight in UTC. This
+means the actual zero date is different in different timezones!
+
+| Location    | IANA Timezone         | `new Date(0)` in local time |
+|:------------|:----------------------|:----------------------------|
+| Honolulu    | `Pacific/Honolulu`    | `1969-12-31 02:00 PM`       |
+| Los Angeles | `America/Los_Angeles` | `1969-12-31 04:00 PM`       |
+| New York    | `America/New_York`    | `1969-12-31 07:00 PM`       |
+| Sao Paulo   | `America/Sao_Paulo`   | `1969-12-31 09:00 PM`       |
+| London      | `Europe/London`       | `1970-01-01 01:00 AM`       |
+| Cairo       | `Africa/Cairo`        | `1970-01-01 02:00 AM`       |
+| Djibouti    | `Africa/Djibouti`     | `1970-01-01 03:00 AM`       |
+| Chennai     | `Asia/Kolkata`        | `1970-01-01 05:30 AM`       |
+| Shanghai    | `Asia/Shanghai`       | `1970-01-01 08:00 AM`       |
+| Seoul       | `Asia/Seoul`          | `1970-01-01 09:00 AM`       |
+| Sydney      | `Australia/Sydney`    | `1970-01-01 10:00 AM`       |
+
+In modern environments, the IANA Timezone and timezone offset can be discovered
+through the `Intl` and `Date` objects:
+
+```jsx live
+function LocalInfo() {
+  const date = new Date();
+  return ( <>
+  <b>Local Time</b>: {date.toString()}<br/>
+  <b>Time offset (relative to UTC)</b>: {-date.getTimezoneOffset()/60} hours <br/>
+  <b>IANA Timezone</b>: {Intl.DateTimeFormat().resolvedOptions().timeZone}
+</>)}
+```
+
+:::caution
+
+The timezone information is provided by the JavaScript engine and local settings.
+There are outstanding Google Chrome and V8 bugs related to rounded offsets for
+timezones under a lunar calendar. The last timezone to switch to the Gregorian
+calendar was `Africa/Monrovia` (in 1972).
+
+SheetJS utilities attempt to work around the browser bugs.
+
+:::
+
+### UTC and Local Time
+
+The `Date` object has a number of prototype methods for inspecting the object.
+Some methods interact with the true value, while others convert to the local
+timezone.  Some methods are listed in the table below:
+
+| Feature          | Local Time method | UTC method       |
+|:-----------------|:------------------|:-----------------|
+| Year             | `getFullYear`     | `getUTCFullYear` |
+| Month (0-11)     | `getMonth`        | `getUTCMonth`    |
+| Day of the month | `getDate`         | `getUTCDate`     |
+| Hours            | `getHours`        | `getUTCHours`    |
+| Minutes          | `getMinutes`      | `getUTCMinutes`  |
+| Seconds          | `getSeconds`      | `getUTCSeconds`  |
+| Entire date      | `toString`        | `toUTCString`    |
+
+It is typical for websites and other applications to present data in local time.
+To serve an international audience, backend servers typically use UTC time.
+
+The following example shows the time when the page was loaded. The same absolute
+time will appear to be different under local and UTC interpretations:
+
+```jsx live
+function LocalUTC() {
+  const d = new Date();
+  /* display number with 2 digits, prepending `0` if necessary */
+  const f = (n) => n.toString().padStart(2, "0");
+  /* HH:MM:SS using local interpretation */
+  const local = `${f(d.getHours())}:${f(d.getMinutes())}:${f(d.getSeconds())}`;
+  /* HH:MM:SS using UTC interpretation */
+  const utc = `${f(d.getUTCHours())}:${f(d.getUTCMinutes())}:${f(d.getUTCSeconds())}`;
+  return ( <>
+    <b>Local Interpretation</b><br/>
+    <code>toString</code>: {d.toString()}<br/>
+    24-hour time: {local}<br/>
+    <br/>
+    <b>UTC Interpretation</b><br/>
+    <code>toUTCString</code>: {d.toUTCString()}<br/>
+    24-hour time: {utc}<br/>
+</>)}
+```
+
+## How SheetJS handles Dates and Times
+
+SheetJS attempts to reconcile the spreadsheet and JavaScript date concepts.
+
+The default behavior for all parsers is to generate number cells. Setting
+`cellDates` to true will force the parsers to store dates.
+
+```jsx live
+function SheetJSCellDates() {
+  var csv = "Date,10/6/2048";
+
+  // cell B1 will be { t: 'n', v: 54337 }
+  var wb_sans_date = XLSX.read(csv, {type:"binary"});
+  var ws_sans_date = wb_sans_date.Sheets.Sheet1;
+
+  // cell B1 will be { t: 'd', v: <Date: 2048-10-06 00:00:00 UTC> }
+  var wb_with_date = XLSX.read(csv, {type:"binary", cellDates: true});
+  var ws_with_date = wb_with_date.Sheets.Sheet1;
+
+  return (<>
+  <b>CSV:</b><pre>{csv}</pre>
+  <b>Cell B1:</b><br/><br/>
+  <table><tr><th>cellDates</th><th>type</th><th>value</th></tr>
+    <tr><td>(unspecified)</td>
+      <td><code>{ws_sans_date["B1"].t}</code></td>
+      <td><code>{ws_sans_date["B1"].v}</code></td>
+    </tr>
+    <tr><td>true</td>
+      <td><code>{ws_with_date["B1"].t}</code></td>
+      <td><code>{ws_with_date["B1"].v.toISOString()}</code> (Date object)</td>
+    </tr>
+  </table>
+  </>);
+}
+```
+
+When writing, date cells are automatically translated back to numeric cells
+with an appropriate number format.
+
+The value formatting logic understands date formats and converts when relevant.
+It always uses the UTC interpretation of Date objects.
+
+### Date Objects
+
+The actual values stored in cells are intended to be correct when interpreted
+using UTC date methods.
+
+For example, [`DateTime.xlsx`](pathname:///DateTime.xlsx) is a test file with the following data:
+
+| Type     | Value                 |
+|:---------|----------------------:|
+| Date     |          `2048-10-06` |
+| Time     |               `15:00` |
+| DateTime | `2048-10-06 15:00:00` |
+
+The raw data values are shown in the live demo.  The UTC date string will show
+the same value as Excel irrespective of the local timezone.
+
+```jsx live
+function SheetJSDateTimeXlsxValues() {
+  const [data, setData] = React.useState([[]]);
+  React.useEffect(() => { (async() => {
+    const ab = await (await fetch("/DateTime.xlsx")).arrayBuffer();
+    const wb = XLSX.read(ab, {cellDates: true, dense: true});
+    setData(wb.Sheets.Sheet1["!data"]);
+  })(); });
+  return ( <table><thead>
+    <th>Excel Date</th><th>UTC Date</th><th>Local Date</th>
+  </thead><tbody>
+    {data.slice(1).map((row,R) => ( <tr key={R}>
+      <td>{row[1].w}</td>
+      <td>{row[1].v.toUTCString()}</td>
+      <td>{row[1].v.toString()}</td>
+    </tr> ))}
+  </tbody></table> );
+}
+```
+
+### Utility Functions
+
+Utility functions that deal with JS data accept a `cellDates` argument which
+dictates how dates should be handled.
+
+Functions that create a worksheet will adjust date cells and use a number
+format like `m/d/yy` to mark dates:
+
+```js
+// Cell A1 will be a numeric cell whose value is the date code
+var ws = XLSX.utils.aoa_to_sheet([[new Date()]]);
+
+// Cell A1 will be a date cell
+var ws = XLSX.utils.aoa_to_sheet([[new Date()]], { cellDates: true });
+```
+
+Functions that create an array of JS objects with raw values will keep the
+native representation:
+
+```js
+// Cell A1 is numeric -> output is a number
+var ws = XLSX.utils.aoa_to_sheet([[new Date()]]);
+var A1 = XLSX.utils.sheet_to_json(ws, { header: 1 })[0][0];
+
+// Cell A1 is a date -> output is a date
+var ws = XLSX.utils.aoa_to_sheet([[new Date()]], { cellDates: true });
+var A1 = XLSX.utils.sheet_to_json(ws, { header: 1 })[0][0];
+```
+
+### UTC Option
+
+Some API functions support the `UTC` option to control how dates are handled.
+
+**[`sheet_to_json`](/docs/api/utilities/array#array-output)**
+
+If `UTC` is true, the dates will be correct when interpreted in UTC. By default,
+the dates will be correct when interpreted in local time.
+
+Typically `UTC` is used for data from an API endpoint, as servers typically emit
+UTC dates and expect scripts to localize. The local interpretation is sensible
+when users submit data, as they will be providing times in their local timezone.
+
+**[`aoa_to_sheet` / `sheet_add_aoa`](/docs/api/utilities/array#array-of-arrays-input)** / **[`json_to_sheet` / `sheet_add_json`](/docs/api/utilities/array#array-of-objects-input)**
+
+If `UTC` is true, the UTC interpretation of dates will be used.
+
+Typically `UTC` is used for data from an API endpoint, as servers typically emit
+UTC dates and expect scripts to localize. The local interpretation is sensible
+when date objects are generated in the browser.
+
+
+**[`table_to_book` / `table_to_sheet` / `sheet_add_dom`](/docs/api/utilities/html#html-table-input)**
+
+If `UTC` is true, potential dates are interpreted as if they represent UTC times.
+By default, potential dates are interpreted in local time.
+
+Typically `UTC` is used for data exported from Excel or other spreadsheet apps.
+If the table is programmatically generated in the frontend, the dates and times
+will be in the local timezone and the local interpretation is preferable.
+
+### Number Formats
+
+By default, the number formats are not emitted.  For Excel-based file formats,
+passing the option `cellNF: true` adds the `z` field.
+
+The helper function `XLSX.SSF.is_date` parses formats and returns `true` if the
+format represents a date or time:
+
+```js
+XLSX.SSF.is_date("yyyy-mm-dd"); // true
+
+XLSX.SSF.is_date("0.00"); // false
+```
+
+<details><summary><b>Live Demo</b> (click to show)</summary>
+
+```jsx live
+function SSFIsDate() {
+  const [format, setFormat] = React.useState("yyyy-mm-dd");
+  const cb = React.useCallback((evt) => {
+    setFormat(evt.target.value);
+  });
+  const is_date = XLSX.SSF.is_date(format);
+  return ( <>
+    <div>Format <b>|{format}|</b> is {is_date ? "" : "not"} a date/time</div>
+    <input type="text" onChange={cb}/>
+  </> );
+}
+```
+
+</details>
diff --git a/docz/docs/07-csf/07-features/07-vba.md b/docz/docs/07-csf/07-features/07-vba.md
index 38b2ab3..44cb1be 100644
--- a/docz/docs/07-csf/07-features/07-vba.md
+++ b/docz/docs/07-csf/07-features/07-vba.md
@@ -146,7 +146,7 @@ This script will generate `SheetJSVBANeu.xlsm`.
 
 ### Extracting VBA Blobs
 
-To obtain the blob, `bookVBA: 1` must be set in the `read` or `readFile` call.
+To extract blobs, `bookVBA: true` must be set in the `read` or `readFile` call.
 
 The following example extracts the embedded VBA blob in a workbook:
 
diff --git a/docz/docs/08-api/07-utilities/08-wb.md b/docz/docs/08-api/07-utilities/08-wb.md
index 308755e..299d026 100644
--- a/docz/docs/08-api/07-utilities/08-wb.md
+++ b/docz/docs/08-api/07-utilities/08-wb.md
@@ -19,7 +19,7 @@ requirement in the user interface. For example, if the last worksheet is deleted
 in the program, Apple Numbers will automatically create a new blank sheet.
 
 The SheetJS [write functions](/docs/api/write-options) enforce the requirement.
-They will throw errors when trying to export empty worksheets.
+They will throw errors when trying to export empty workbooks.
 
 
 **Append a Worksheet to a Workbook**
@@ -41,7 +41,7 @@ var new_name = XLSX.utils.book_append_sheet(workbook, worksheet, name, true);
 
 If the fourth argument is `true`, the function will start with the specified
 worksheet name.  If the sheet name exists in the workbook, a new worksheet name
-will be chosen by finding the name stem and incrementing the counter:
+will be chosen by finding the name stem and incrementing the counter.
 
 ```js
 XLSX.utils.book_append_sheet(workbook, sheetA, "Sheet2", true); // Sheet2
diff --git a/docz/docs/09-miscellany/02-errors.md b/docz/docs/09-miscellany/02-errors.md
index f2f9a83..6858458 100644
--- a/docz/docs/09-miscellany/02-errors.md
+++ b/docz/docs/09-miscellany/02-errors.md
@@ -282,6 +282,25 @@ import { writeFile } from 'xlsx'; // writeFile will use the global `saveAs`
 
 </details>
 
+#### "Cannot save file" in NodeJS
+
+The `fs` module is automatically loaded in scripts using `require`:
+
+```js
+var XLSX = require("xlsx"); // automatically loads `fs`
+```
+
+Using the [ESM import](/docs/getting-started/installation/nodejs/#esm-import),
+the `fs` module must be imported and passed to the library:
+
+```js
+import * as XLSX from 'xlsx';
+
+/* load 'fs' for readFile and writeFile support */
+import * as fs from 'fs';
+XLSX.set_fs(fs);
+```
+
 ## Data Issues
 
 #### Generated XLSX files are very large!
diff --git a/docz/docs/09-miscellany/04-testing.md b/docz/docs/09-miscellany/04-testing.md
index 44346b7..29ea0a8 100644
--- a/docz/docs/09-miscellany/04-testing.md
+++ b/docz/docs/09-miscellany/04-testing.md
@@ -98,7 +98,7 @@ The test suite also includes tests for various time zones.  To change
 the timezone locally, set the `TZ` environment variable:
 
 ```bash
-$ env TZ="Asia/Kolkata" WTF=1 make test_misc
+env TZ="Asia/Kolkata" WTF=1 make test_misc
 ```
 
 </details>
diff --git a/docz/docs/09-miscellany/07-license.md b/docz/docs/09-miscellany/07-license.md
index b07843c..5268ecc 100644
--- a/docz/docs/09-miscellany/07-license.md
+++ b/docz/docs/09-miscellany/07-license.md
@@ -8,6 +8,9 @@ hide_table_of_contents: true
 SheetJS Community Edition is licensed under the "Apache 2.0 License". All rights
 not explicitly granted by the Apache 2.0 License are reserved by SheetJS LLC.
 
+The Apache 2.0 License is a "permissive" license which allows commercial use but
+requires attribution.
+
 #### Required Attribution
 
 When integrating SheetJS CE in a project or service, the following text must be
diff --git a/docz/docs/09-miscellany/08-references.md b/docz/docs/09-miscellany/08-references.md
index ec30ceb..828b089 100644
--- a/docz/docs/09-miscellany/08-references.md
+++ b/docz/docs/09-miscellany/08-references.md
@@ -9,10 +9,10 @@ Some of our original research is documented at <https://oss.sheetjs.com/notes/>
 
 The specifications list is non-exhaustive.
 
- - Worksheet File Format (From Lotus) December 1984
+ - Worksheet File Format (From Lotus) December 1984[^1]
  - Open Document Format for Office Applications Version 1.3
 
-:::info
+:::info pass
 
 The primary specifications for XLSX are:
 
@@ -26,9 +26,9 @@ most of the public XLSX document community use the spec names interchangeably.
 
 ## Open Specifications Promise
 
-Lotus released their "Worksheet File Format" documentation into the Public
-Domain.  Microsoft opted for the "Open Specifications Promise", a covenant not
-to sue.  The documentation that falls under the promise are listed below.
+Lotus dedicated the "Worksheet File Format" documentation to the Public Domain.
+Microsoft opted for the "Open Specifications Promise", a covenant not to sue.
+The documentation that falls under the promise are listed below.
 
 <details><summary><b>Specifications</b> (click to show)</summary>
 
@@ -60,3 +60,7 @@ to sue.  The documentation that falls under the promise are listed below.
 
 - ISBN 1556155212 "Excel Software Development Kit Version 4"
 - ISBN 1556156324 "Excel Developer's Kit Version 5"
+
+[^1]: The original FTP server is no longer available, but the content has been
+      mirrored at <https://oss.sheetjs.com/notes/lotus/>. Lotus Corporation
+      dedicated the content to the public domain in 1984.
\ No newline at end of file