| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | --- | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  | title: Dates and Times | 
					
						
							| 
									
										
										
										
											2023-08-20 20:39:35 +00:00
										 |  |  | sidebar_position: 1 | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | --- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  | import Tabs from '@theme/Tabs'; | 
					
						
							|  |  |  | import TabItem from '@theme/TabItem'; | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>File Format Support</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2023-06-29 21:07:52 +00:00
										 |  |  | options to use the traditional date codes. | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | :::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 | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  | shown on this page will be the time displayed in Excel. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <Tabs groupId="live"> | 
					
						
							|  |  |  |   <TabItem value="react" label="React (Live Demo)"> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```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 */ | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  |     const wb = XLSX.utils.book_new(ws, "Sheet1"); | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  |     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> | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  |   </> ); | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  |   </TabItem> | 
					
						
							|  |  |  |   <TabItem value="js" label="JavaScript (Explanation)"> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::note pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 1) Create a new Date object and set milliseconds to 0 (to avoid date rounding): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* starting date */ | 
					
						
							|  |  |  | const date = new Date(); | 
					
						
							|  |  |  | /* to avoid confusion, set milliseconds to 0 */ | 
					
						
							|  |  |  | date.setMilliseconds(0); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 2) Construct an array of arrays to store the date. It will be placed in cell A1: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* generate array of arrays */ | 
					
						
							|  |  |  | const aoa = [[date]]; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 3) [Create a worksheet](/docs/api/utilities/array#array-of-arrays-input): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* generate workbook */ | 
					
						
							|  |  |  | const ws = XLSX.utils.aoa_to_sheet(aoa, {dense: true}); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 4) Adjust the date format using a [custom number format](/docs/csf/features/nf): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* set cell A1 number format */ | 
					
						
							|  |  |  | ws["!data"][0][0].z = "yyyy-mm-dd hh:mm:ss" | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 5) Adjust the [column width](/docs/csf/features/colprops) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* adjust column width */ | 
					
						
							|  |  |  | ws["!cols"] = [{wch: 20}]; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 6) [Create a workbook](/docs/api/utilities/wb): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* create workbook object */ | 
					
						
							|  |  |  | const wb = XLSX.utils.book_new(ws, "Sheet1"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 7) [Write XLSX file](/docs/api/write-options): | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | /* generate XLSX workbook and attempt to download */ | 
					
						
							|  |  |  | XLSX.writeFile(wb, "SheetJSNow.xlsx"); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   </TabItem> | 
					
						
							|  |  |  | </Tabs> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | ## How Spreadsheets Understand Time
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Excel stores dates as numbers.  When displaying dates, the format code should | 
					
						
							| 
									
										
										
										
											2023-06-29 21:07:52 +00:00
										 |  |  | include special date and time tokens like `yyyy` for long year. `EDATE` and | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 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: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Common Date-Time Formats</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | | 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")      | | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 03:59:48 +00:00
										 |  |  | :::note pass | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | `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 */ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Why does the 1904 date system exist?</b> (click to show) </summary> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | @date(0,2,30) -> ERR   // Lotus rejects 2/30/1900 | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Excel extends the tradition in the default date system.  The 1904 date system | 
					
						
							|  |  |  | starts the count in 1904, skipping the bad date. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | </details> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ### 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Technical Details</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | </details> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | ## 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} | 
					
						
							|  |  |  | </>)} | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 03:59:48 +00:00
										 |  |  | :::caution pass | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 04:47:04 +00:00
										 |  |  | <details> | 
					
						
							|  |  |  |   <summary><b>Live Demo</b> (click to show)</summary> | 
					
						
							| 
									
										
										
										
											2023-06-25 19:57:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ```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> | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## How JSON and APIs Understand Time
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | JSON does not have a native representation for JavaScript Date objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Starting from a Date object, the `JSON.stringify` method will encode the object | 
					
						
							|  |  |  | as a ISO 8601 date string. Applying `JSON.parse` to the result will return the | 
					
						
							|  |  |  | string rather than a proper Date object. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```mermaid | 
					
						
							|  |  |  | flowchart LR | 
					
						
							|  |  |  |   ws(("new Date#40;#41;"\nObject)) | 
					
						
							| 
									
										
										
										
											2024-06-19 11:22:00 +00:00
										 |  |  |   jstr[["'#quot;2048-10-06T00:00:00.000Z#quot;'"\nEncoded String]] | 
					
						
							|  |  |  |   js[["#quot;2048-10-06T00:00:00.000Z#quot;"\nJavaScript String]] | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  |   ws --> |JSON\nstringify| jstr | 
					
						
							|  |  |  |   jstr --> |JSON.parse\n\n| js | 
					
						
							|  |  |  |   js --> |\nJSON.stringify| jstr | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SheetJS utility functions will not try to interpret those strings as dates. | 
					
						
							|  |  |  | Instead, the strings will be translated to text. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | In the following example, the "ISO Text" data will be converted to a string cell | 
					
						
							|  |  |  | while the "Date Obj" data will be converted to a spreadsheet date. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```jsx live | 
					
						
							|  |  |  | function SheetJSONDates() { return ( <button onClick={() => { | 
					
						
							|  |  |  |   const aoa = [ | 
					
						
							| 
									
										
										
										
											2024-06-19 11:22:00 +00:00
										 |  |  |     ["ISO Text", "2048-10-06T00:00:00.000Z"],          // B1 will be text | 
					
						
							|  |  |  |     ["Date Obj", new Date("2048-10-06T00:00:00.000Z")] // B2 will be a date | 
					
						
							| 
									
										
										
										
											2024-03-18 08:24:41 +00:00
										 |  |  |   ]; | 
					
						
							|  |  |  |   const ws = XLSX.utils.aoa_to_sheet(aoa); | 
					
						
							|  |  |  |   const wb = XLSX.utils.book_new(ws, "Data"); | 
					
						
							|  |  |  |   XLSX.writeFile(wb, "SheetJSONDates.xlsx"); | 
					
						
							|  |  |  | }}>Click to Export Sample Data</button> ); } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Many API wrapper libraries return dates as strings instead of Date objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If the SheetJS operations generate string cells, review the documentation for | 
					
						
							|  |  |  | the wrapper library to ensure the other library is properly handling dates. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Fixing Arrays of Objects
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Many APIs will return data as JSON objects. When particular fields are known to | 
					
						
							|  |  |  | contain date strings, they can be manually fixed. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | For example, the [Export Tutorial](/docs/getting-started/examples/export) makes | 
					
						
							|  |  |  | a final array of objects with birthdays stored as strings: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const rows = [ | 
					
						
							|  |  |  |   { name: "George Washington", birthday: "1732-02-22" }, | 
					
						
							|  |  |  |   { name: "John Adams", birthday: "1735-10-19" }, | 
					
						
							|  |  |  |   // ... one row per President | 
					
						
							|  |  |  | ]; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If this dataset is exported, the `birthday` column will contain raw text values. | 
					
						
							|  |  |  | A single `Array#map` operation can create a fixed dataset: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | const new_rows = rows.map(({birthday, ...rest}) => ({birthday: new Date(birthday), ...rest})) | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `Date` constructor interprets the dates in local time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :::caution pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Excel and other spreadsheet software do not typically support dates before 1900. | 
					
						
							|  |  |  | If there are dates before the threshold, it is strongly recommended to pass | 
					
						
							|  |  |  | strings instead of `Date` objects. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-14 07:40:38 +00:00
										 |  |  | :::danger pass | 
					
						
							| 
									
										
										
										
											2024-04-01 10:44:10 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | JavaScript string to `Date` conversion is "implementation-dependent" and may | 
					
						
							|  |  |  | misinterpret some date formats. When designing APIs, it is strongly recommended | 
					
						
							|  |  |  | to pass ISO 8601 strings when possible. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ::: |