rn-date 1.0.3 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,17 +1,179 @@
1
1
  # rn-date
2
2
 
3
- `rn-date` is a zero-dependency library which fixes the date parsing issue in React Native with Android.
3
+ `rn-date` is a zero-dependency TypeScript library which fixes the date parsing issues in React Native with Android.
4
+
5
+ ## Background
6
+
7
+ React Native on Android has inconsistent date parsing behavior compared to iOS and web. The native `Date` constructor may parse date strings differently depending on the platform and format. This library provides consistent, reliable date parsing across all platforms.
8
+
9
+ ## Features
10
+
11
+ - **Zero runtime dependencies** - Minimal bundle size impact
12
+ - **TypeScript support** - Full type definitions included
13
+ - **Consistent parsing** - Same behavior across iOS, Android, and web
14
+ - **Multiple format support**:
15
+ - Date-only: `YYYY-MM-DD`
16
+ - DateTime: `YYYY-MM-DD HH:MM:SS`
17
+ - ISO 8601: `YYYY-MM-DDTHH:MM:SS.sssZ`
18
+ - **Utility methods** - Convenient formatting and validation
4
19
 
5
20
  ## Installation
6
21
 
7
22
  ```bash
8
23
  yarn add rn-date
24
+ # or
25
+ npm install rn-date
9
26
  ```
10
27
 
11
28
  ## Usage
12
29
 
30
+ ### Basic Import
31
+
13
32
  ```ts
14
33
  import { RnDate } from 'rn-date';
34
+ ```
35
+
36
+ ### Creating Dates
37
+
38
+ ```ts
39
+ // Current date and time
40
+ const now = new RnDate();
15
41
 
16
- const date = new RnDate('2020-01-01T00:00:00.000Z'); // instead of new Date('2020-01-01T00:00:00.000Z')
42
+ // Date-only format (parsed as UTC)
43
+ const date = new RnDate('2022-01-01');
44
+
45
+ // DateTime with space separator (parsed as local time)
46
+ const dateTime = new RnDate('2022-01-01 17:04:03');
47
+
48
+ // ISO 8601 format (UTC with timezone)
49
+ const isoDate = new RnDate('2022-01-01T00:00:00.000Z');
17
50
  ```
51
+
52
+ ### Using with Date Methods
53
+
54
+ `RnDate` extends the native `Date` class, so all standard Date methods are available:
55
+
56
+ ```ts
57
+ const date = new RnDate('2022-01-01 17:04:03');
58
+
59
+ // Standard Date methods work as expected
60
+ date.getFullYear(); // 2022
61
+ date.getMonth(); // 0 (January)
62
+ date.getDate(); // 1
63
+ date.getHours(); // 17
64
+ date.getMinutes(); // 4
65
+ date.getSeconds(); // 3
66
+
67
+ // Format methods
68
+ date.toISOString(); // "2022-01-01T16:04:03.000Z" (UTC)
69
+ date.toDateString(); // "Sat Jan 01 2022"
70
+ date.toString(); // Full date string
71
+
72
+ // Timestamp
73
+ date.getTime(); // 1641056643000
74
+ ```
75
+
76
+ ## API Reference
77
+
78
+ ### Constructor
79
+
80
+ #### `new RnDate(dateString?: string)`
81
+
82
+ Creates a new RnDate instance.
83
+
84
+ **Parameters:**
85
+ - `dateString` (`string | undefined`) - The date string to parse
86
+
87
+ **Supported formats:**
88
+ - `YYYY-MM-DD` - Date only (parsed as UTC)
89
+ - `YYYY-MM-DD HH:MM:SS` - DateTime (parsed as local time)
90
+ - `YYYY-MM-DDTHH:MM:SS.sssZ` - ISO 8601 format (UTC)
91
+ - `undefined` or `null` - Current date and time
92
+
93
+ **Throws:**
94
+ - `TypeError` - If `dateString` is not a string or undefined
95
+
96
+ **Examples:**
97
+
98
+ ```ts
99
+ // Current date
100
+ const now = new RnDate();
101
+ const alsoNow = new RnDate(undefined);
102
+
103
+ // Specific date (UTC)
104
+ const date = new RnDate('2022-01-01');
105
+
106
+ // Specific datetime (local time)
107
+ const dateTime = new RnDate('2022-01-01 17:04:03');
108
+
109
+ // ISO format (UTC)
110
+ const isoDate = new RnDate('2022-01-01T00:00:00.000Z');
111
+
112
+ // Invalid date returns Invalid Date
113
+ const invalid = new RnDate('invalid-date');
114
+ console.log(invalid.toString()); // "Invalid Date"
115
+ ```
116
+
117
+ ### Methods
118
+
119
+ #### `isValid(): boolean`
120
+
121
+ Checks if this RnDate represents a valid date.
122
+
123
+ **Returns:** `boolean` - `true` if the date is valid, `false` otherwise
124
+
125
+ **Example:**
126
+
127
+ ```ts
128
+ const validDate = new RnDate('2022-01-01');
129
+ validDate.isValid(); // true
130
+
131
+ const invalidDate = new RnDate('invalid');
132
+ invalidDate.isValid(); // false
133
+ ```
134
+
135
+ ---
136
+
137
+ #### `toDateFormat(): string`
138
+
139
+ Formats the date as a string in the format `YYYY-MM-DD` (UTC).
140
+
141
+ **Returns:** `string` - The formatted date string
142
+
143
+ **Example:**
144
+
145
+ ```ts
146
+ const date = new RnDate('2022-01-01 17:04:03');
147
+ date.toDateFormat(); // "2022-01-01"
148
+ ```
149
+
150
+ ---
151
+
152
+ #### `toDateTimeFormat(): string`
153
+
154
+ Formats the date and time as a string in the format `YYYY-MM-DD HH:MM:SS` (local time).
155
+
156
+ **Returns:** `string` - The formatted datetime string
157
+
158
+ **Example:**
159
+
160
+ ```ts
161
+ const date = new RnDate('2022-01-01 17:04:03');
162
+ date.toDateTimeFormat(); // "2022-01-01 17:04:03"
163
+ ```
164
+
165
+ ## Platform Differences
166
+
167
+ The native `Date` constructor has platform-specific behaviors:
168
+
169
+ | Format | iOS/Web | Android (without fix) | Android (with RnDate) |
170
+ |--------|---------|----------------------|----------------------|
171
+ | `YYYY-MM-DD` | UTC | Local (inconsistent) | UTC (consistent) |
172
+ | `YYYY-MM-DD HH:MM:SS` | Local | Local | Local |
173
+ | `YYYY-MM-DDTHH:MM:SS.sssZ` | UTC | UTC | UTC |
174
+
175
+ `RnDate` ensures consistent behavior across all platforms.
176
+
177
+ ## License
178
+
179
+ MIT
package/build/date.d.ts CHANGED
@@ -1,3 +1,81 @@
1
+ /**
2
+ * RnDate - A Date class extension that fixes Android date parsing issues in React Native.
3
+ *
4
+ * This class addresses the date parsing inconsistencies that occur specifically on
5
+ * Android devices in React Native applications. It provides reliable parsing for:
6
+ * - Date-only format: YYYY-MM-DD
7
+ * - DateTime format: YYYY-MM-DD HH:MM:SS
8
+ * - ISO 8601 format: YYYY-MM-DDTHH:MM:SS.sssZ
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { RnDate } from 'rn-date';
13
+ *
14
+ * const date = new RnDate('2022-01-01');
15
+ * const dateTime = new RnDate('2022-01-01 17:04:03');
16
+ * const isoDate = new RnDate('2022-01-01T00:00:00.000Z');
17
+ * ```
18
+ *
19
+ * @class RnDate
20
+ * @extends {Date}
21
+ */
1
22
  export declare class RnDate extends Date {
23
+ /**
24
+ * Creates a new RnDate instance.
25
+ *
26
+ * @param {string | undefined} dateString - The date string to parse. Supports formats:
27
+ * - YYYY-MM-DD (date only)
28
+ * - YYYY-MM-DD HH:MM:SS (date and time separated by space)
29
+ * - YYYY-MM-DDTHH:MM:SS.sssZ (ISO 8601 format)
30
+ * - If undefined or empty, creates a date with the current date and time
31
+ * @throws {TypeError} If dateString is not a string or undefined
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * new RnDate() // Current date
36
+ * new RnDate('2022-01-01') // Date only
37
+ * new RnDate('2022-01-01 17:04:03') // DateTime with space
38
+ * new RnDate('2022-01-01T00:00:00.000Z') // ISO format
39
+ * ```
40
+ */
2
41
  constructor(dateString?: string);
42
+ /**
43
+ * Checks if this RnDate represents a valid date.
44
+ *
45
+ * @returns {boolean} True if the date is valid, false otherwise
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * const validDate = new RnDate('2022-01-01');
50
+ * validDate.isValid(); // true
51
+ *
52
+ * const invalidDate = new RnDate('invalid');
53
+ * invalidDate.isValid(); // false
54
+ * ```
55
+ */
56
+ isValid(): boolean;
57
+ /**
58
+ * Formats the date as a string in the format YYYY-MM-DD.
59
+ *
60
+ * @returns {string} The formatted date string
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const date = new RnDate('2022-01-01 17:04:03');
65
+ * date.toDateFormat(); // "2022-01-01"
66
+ * ```
67
+ */
68
+ toDateFormat(): string;
69
+ /**
70
+ * Formats the date and time as a string in the format YYYY-MM-DD HH:MM:SS.
71
+ *
72
+ * @returns {string} The formatted datetime string
73
+ *
74
+ * @example
75
+ * ```ts
76
+ * const date = new RnDate('2022-01-01 17:04:03');
77
+ * date.toDateTimeFormat(); // "2022-01-01 17:04:03"
78
+ * ```
79
+ */
80
+ toDateTimeFormat(): string;
3
81
  }
package/build/date.js CHANGED
@@ -1,21 +1,215 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RnDate = void 0;
4
+ /**
5
+ * RnDate - A Date class extension that fixes Android date parsing issues in React Native.
6
+ *
7
+ * This class addresses the date parsing inconsistencies that occur specifically on
8
+ * Android devices in React Native applications. It provides reliable parsing for:
9
+ * - Date-only format: YYYY-MM-DD
10
+ * - DateTime format: YYYY-MM-DD HH:MM:SS
11
+ * - ISO 8601 format: YYYY-MM-DDTHH:MM:SS.sssZ
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { RnDate } from 'rn-date';
16
+ *
17
+ * const date = new RnDate('2022-01-01');
18
+ * const dateTime = new RnDate('2022-01-01 17:04:03');
19
+ * const isoDate = new RnDate('2022-01-01T00:00:00.000Z');
20
+ * ```
21
+ *
22
+ * @class RnDate
23
+ * @extends {Date}
24
+ */
4
25
  class RnDate extends Date {
26
+ /**
27
+ * Creates a new RnDate instance.
28
+ *
29
+ * @param {string | undefined} dateString - The date string to parse. Supports formats:
30
+ * - YYYY-MM-DD (date only)
31
+ * - YYYY-MM-DD HH:MM:SS (date and time separated by space)
32
+ * - YYYY-MM-DDTHH:MM:SS.sssZ (ISO 8601 format)
33
+ * - If undefined or empty, creates a date with the current date and time
34
+ * @throws {TypeError} If dateString is not a string or undefined
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * new RnDate() // Current date
39
+ * new RnDate('2022-01-01') // Date only
40
+ * new RnDate('2022-01-01 17:04:03') // DateTime with space
41
+ * new RnDate('2022-01-01T00:00:00.000Z') // ISO format
42
+ * ```
43
+ */
5
44
  constructor(dateString) {
45
+ // Initialize with NaN, will be set below
46
+ super(NaN);
47
+ // Handle undefined
6
48
  if (dateString === undefined || dateString === null) {
7
- super();
49
+ this.setTime(Date.now());
50
+ return;
8
51
  }
9
- else {
10
- const dateParam = dateString.split(/[\s-:]/);
11
- if (dateParam.length > 3) {
12
- dateParam[1] = (parseInt(dateParam[1], 10) - 1).toString();
13
- super(...dateParam);
52
+ // Validate input type
53
+ if (typeof dateString !== 'string') {
54
+ throw new TypeError(`RnDate expects a string argument, received ${typeof dateString}`);
55
+ }
56
+ // Handle empty string - should return Invalid Date like native Date
57
+ if (dateString === '') {
58
+ // Leave as NaN (Invalid Date)
59
+ return;
60
+ }
61
+ // Trim whitespace
62
+ const trimmedDate = dateString.trim();
63
+ // Check for ISO format (contains 'T')
64
+ if (trimmedDate.includes('T')) {
65
+ // ISO format - let native Date handle it
66
+ const tempDate = new Date(trimmedDate);
67
+ this.setTime(tempDate.getTime());
68
+ return;
69
+ }
70
+ // Check for space-separated datetime format (YYYY-MM-DD HH:MM:SS)
71
+ const spaceIndex = trimmedDate.indexOf(' ');
72
+ if (spaceIndex !== -1) {
73
+ // Split into date and time parts
74
+ const datePart = trimmedDate.substring(0, spaceIndex);
75
+ const timePart = trimmedDate.substring(spaceIndex + 1);
76
+ // Parse date components (YYYY-MM-DD)
77
+ const dateComponents = datePart.split('-');
78
+ if (dateComponents.length !== 3) {
79
+ // Invalid format, fall back to native parsing
80
+ const tempDate = new Date(trimmedDate);
81
+ this.setTime(tempDate.getTime());
82
+ return;
83
+ }
84
+ const [yearStr, monthStr, dayStr] = dateComponents;
85
+ const year = parseInt(yearStr, 10);
86
+ const monthValue = parseInt(monthStr, 10); // 1-based month
87
+ const day = parseInt(dayStr, 10);
88
+ // Validate date components (month 1-12, day 1-31)
89
+ if (isNaN(year) ||
90
+ isNaN(monthValue) ||
91
+ isNaN(day) ||
92
+ monthValue < 1 ||
93
+ monthValue > 12 ||
94
+ day < 1 ||
95
+ day > 31) {
96
+ // Invalid date, fall back to native parsing
97
+ const tempDate = new Date(trimmedDate);
98
+ this.setTime(tempDate.getTime());
99
+ return;
100
+ }
101
+ const month = monthValue - 1; // Convert to 0-based month
102
+ // Parse time components (HH:MM:SS)
103
+ const timeComponents = timePart.split(':');
104
+ let hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
105
+ if (timeComponents.length >= 1) {
106
+ hours = parseInt(timeComponents[0], 10);
107
+ }
108
+ if (timeComponents.length >= 2) {
109
+ minutes = parseInt(timeComponents[1], 10);
14
110
  }
15
- else {
16
- super(dateString);
111
+ if (timeComponents.length >= 3) {
112
+ // Handle potential milliseconds (e.g., "SS.fff" or "SS")
113
+ const secondsPart = timeComponents[2];
114
+ const dotIndex = secondsPart.indexOf('.');
115
+ if (dotIndex !== -1) {
116
+ seconds = parseInt(secondsPart.substring(0, dotIndex), 10);
117
+ const msStr = secondsPart.substring(dotIndex + 1);
118
+ // Pad or truncate milliseconds to 3 digits
119
+ milliseconds = parseInt(msStr.padEnd(3, '0').substring(0, 3), 10);
120
+ }
121
+ else {
122
+ seconds = parseInt(secondsPart, 10);
123
+ }
17
124
  }
125
+ // Use local time for space-separated datetime (matching native behavior)
126
+ const tempDate = new Date(year, month, day, hours, minutes, seconds, milliseconds);
127
+ this.setTime(tempDate.getTime());
128
+ return;
18
129
  }
130
+ // Check for date-only format (YYYY-MM-DD)
131
+ const dateComponents = trimmedDate.split('-');
132
+ if (dateComponents.length === 3) {
133
+ const [yearStr, monthStr, dayStr] = dateComponents;
134
+ const year = parseInt(yearStr, 10);
135
+ const monthValue = parseInt(monthStr, 10); // 1-based month
136
+ const day = parseInt(dayStr, 10);
137
+ // Validate date components format and values
138
+ // Month should be 1-12, day should be 1-31 (basic validation)
139
+ if (!isNaN(year) &&
140
+ !isNaN(monthValue) &&
141
+ !isNaN(day) &&
142
+ yearStr.length === 4 &&
143
+ monthStr.length >= 1 &&
144
+ monthStr.length <= 2 &&
145
+ dayStr.length >= 1 &&
146
+ dayStr.length <= 2 &&
147
+ monthValue >= 1 &&
148
+ monthValue <= 12 &&
149
+ day >= 1 &&
150
+ day <= 31) {
151
+ const month = monthValue - 1; // Convert to 0-based month
152
+ // Use Date.UTC to create UTC timestamp (matching native behavior)
153
+ const time = Date.UTC(year, month, day);
154
+ this.setTime(time);
155
+ return;
156
+ }
157
+ }
158
+ // Fallback: try native parsing for any other format
159
+ const tempDate = new Date(trimmedDate);
160
+ this.setTime(tempDate.getTime());
161
+ }
162
+ /**
163
+ * Checks if this RnDate represents a valid date.
164
+ *
165
+ * @returns {boolean} True if the date is valid, false otherwise
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * const validDate = new RnDate('2022-01-01');
170
+ * validDate.isValid(); // true
171
+ *
172
+ * const invalidDate = new RnDate('invalid');
173
+ * invalidDate.isValid(); // false
174
+ * ```
175
+ */
176
+ isValid() {
177
+ return !isNaN(this.getTime());
178
+ }
179
+ /**
180
+ * Formats the date as a string in the format YYYY-MM-DD.
181
+ *
182
+ * @returns {string} The formatted date string
183
+ *
184
+ * @example
185
+ * ```ts
186
+ * const date = new RnDate('2022-01-01 17:04:03');
187
+ * date.toDateFormat(); // "2022-01-01"
188
+ * ```
189
+ */
190
+ toDateFormat() {
191
+ const year = this.getUTCFullYear();
192
+ const month = String(this.getUTCMonth() + 1).padStart(2, '0');
193
+ const day = String(this.getUTCDate()).padStart(2, '0');
194
+ return `${year}-${month}-${day}`;
195
+ }
196
+ /**
197
+ * Formats the date and time as a string in the format YYYY-MM-DD HH:MM:SS.
198
+ *
199
+ * @returns {string} The formatted datetime string
200
+ *
201
+ * @example
202
+ * ```ts
203
+ * const date = new RnDate('2022-01-01 17:04:03');
204
+ * date.toDateTimeFormat(); // "2022-01-01 17:04:03"
205
+ * ```
206
+ */
207
+ toDateTimeFormat() {
208
+ const date = this.toDateFormat();
209
+ const hours = String(this.getHours()).padStart(2, '0');
210
+ const minutes = String(this.getMinutes()).padStart(2, '0');
211
+ const seconds = String(this.getSeconds()).padStart(2, '0');
212
+ return `${date} ${hours}:${minutes}:${seconds}`;
19
213
  }
20
214
  }
21
215
  exports.RnDate = RnDate;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rn-date",
3
- "version": "1.0.3",
3
+ "version": "1.1.1",
4
4
  "author": "maxgfr",
5
5
  "license": "MIT",
6
6
  "description": "A zero-dependency library which fixes the date parsing issue in React Native with Android",
@@ -46,22 +46,22 @@
46
46
  "@semantic-release/github": "^8.0.7",
47
47
  "@semantic-release/npm": "^9.0.1",
48
48
  "@semantic-release/release-notes-generator": "^10.0.3",
49
- "@swc-node/register": "1.5.4",
50
- "@swc/cli": "0.1.57",
51
- "@swc/core": "1.3.21",
52
- "@swc/jest": "0.2.23",
53
- "@types/jest": "29.2.3",
54
- "@types/node": "18.11.10",
55
- "@typescript-eslint/eslint-plugin": "5.45.0",
56
- "@typescript-eslint/parser": "5.45.0",
57
- "eslint": "8.29.0",
58
- "eslint-config-prettier": "8.5.0",
59
- "eslint-plugin-jest": "27.1.6",
60
- "jest": "29.3.1",
61
- "nodemon": "2.0.20",
62
- "prettier": "2.8.0",
49
+ "@swc-node/register": "1.11.1",
50
+ "@swc/cli": "0.7.9",
51
+ "@swc/core": "1.15.3",
52
+ "@swc/jest": "0.2.39",
53
+ "@types/jest": "29.5.14",
54
+ "@types/node": "18.19.130",
55
+ "@typescript-eslint/eslint-plugin": "5.62.0",
56
+ "@typescript-eslint/parser": "5.62.0",
57
+ "eslint": "8.57.1",
58
+ "eslint-config-prettier": "8.10.2",
59
+ "eslint-plugin-jest": "27.9.0",
60
+ "jest": "29.7.0",
61
+ "nodemon": "2.0.22",
62
+ "prettier": "2.8.8",
63
63
  "rimraf": "3.0.2",
64
64
  "semantic-release": "19.0.5",
65
- "typescript": "4.9.3"
65
+ "typescript": "4.9.5"
66
66
  }
67
67
  }