scdate 1.1.0 → 2.0.0
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 +5 -1
- package/dist/sDate.d.ts +37 -1
- package/dist/sDate.js +52 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -104,7 +104,11 @@ const shortDateStr = getShortDateString(date1, 'America/Puerto_Rico', 'en-US', {
|
|
|
104
104
|
|
|
105
105
|
- **`getDateForLastDayOfMonth(date)`**: Returns a new date set to the last day of the month, which varies depending on the month and year (accounting for leap years).
|
|
106
106
|
|
|
107
|
-
- **`addMonthsToDate(date, months)`**:
|
|
107
|
+
- **`addMonthsToDate(date, months, options?)`**: Properly handles month boundaries by clamping to the last day of the target month. For example, adding one month to January 31 will result in February 28/29 (depending on leap year), adding 3 months will result in April 30, and adding 5 months will result in June 30. This ensures consistent and predictable date handling when crossing between months with different numbers of days.
|
|
108
|
+
|
|
109
|
+
Accepts an optional `options` object with:
|
|
110
|
+
|
|
111
|
+
- `capToCommonDate`: When set to `true`, dates greater than the 28th will always be capped to the 28th of the target month (the last date common to all months). For example, `addMonthsToDate('2023-01-31', 3, { capToCommonDate: true })` will result in `'2023-04-28'` rather than `'2023-04-30'`. This is useful for scheduling scenarios where you need consistent date behavior across all months.
|
|
108
112
|
|
|
109
113
|
- **`isDateToday(date, timeZone)`**: The comparison is time-zone aware, so a date that is "today" in one time zone might not be "today" in another time zone.
|
|
110
114
|
|
package/dist/sDate.d.ts
CHANGED
|
@@ -191,11 +191,47 @@ export declare const addDaysToDate: (date: string | SDate, days: number) => SDat
|
|
|
191
191
|
* number of months to the given date. Because it just adds to the month
|
|
192
192
|
* component of the date, this operation is not affected by time zones.
|
|
193
193
|
*
|
|
194
|
+
* When the original date's day exceeds the number of days in the target month,
|
|
195
|
+
* the function will automatically clamp to the last day of the target month
|
|
196
|
+
* rather than rolling over to the next month. For example, adding 1 month to
|
|
197
|
+
* January 31 will result in February 28/29 (depending on leap year), not March 3.
|
|
198
|
+
*
|
|
194
199
|
* @param date The date to add months to. It can be an SDate or a string in the
|
|
195
200
|
* YYYY-MM-DD format.
|
|
196
201
|
* @param months The number of months to add to the date.
|
|
202
|
+
* @param options Additional options for controlling the behavior of the function.
|
|
203
|
+
* @param options.capToCommonDate When true, if the original date is the 29th,
|
|
204
|
+
* 30th, or 31st, the result will be capped to the 28th of the month (the last
|
|
205
|
+
* date common to all months) rather than the last day of the target month.
|
|
206
|
+
* This ensures consistent date handling across all months.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* addMonthsToDate('2023-01-31', 1)
|
|
211
|
+
* //=> '2023-02-28' (February has fewer days than January)
|
|
212
|
+
* ```
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* addMonthsToDate('2023-01-31', 3)
|
|
217
|
+
* //=> '2023-04-30' (April has 30 days)
|
|
218
|
+
* ```
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* ```ts
|
|
222
|
+
* addMonthsToDate('2024-01-31', 1)
|
|
223
|
+
* //=> '2024-02-29' (February in leap year)
|
|
224
|
+
* ```
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* addMonthsToDate('2023-01-31', 3, { capToCommonDate: true })
|
|
229
|
+
* //=> '2023-04-28' (capped to the 28th regardless of month length)
|
|
230
|
+
* ```
|
|
197
231
|
*/
|
|
198
|
-
export declare const addMonthsToDate: (date: string | SDate, months: number
|
|
232
|
+
export declare const addMonthsToDate: (date: string | SDate, months: number, options?: {
|
|
233
|
+
capToCommonDate?: boolean;
|
|
234
|
+
}) => SDate;
|
|
199
235
|
/**
|
|
200
236
|
* Returns a new SDate instance with the date resulting from adding the given
|
|
201
237
|
* number of years to the given date. Because this only adds to the year
|
package/dist/sDate.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { UTCDateMini } from '@date-fns/utc';
|
|
1
2
|
import { getTimezoneOffset } from 'date-fns-tz';
|
|
2
3
|
import { SDate } from './internal/SDate.js';
|
|
3
4
|
import { DayToWeekday, DaysInWeek, MillisecondsInDay, } from './internal/constants.js';
|
|
@@ -289,14 +290,63 @@ export const addDaysToDate = (date, days) => {
|
|
|
289
290
|
* number of months to the given date. Because it just adds to the month
|
|
290
291
|
* component of the date, this operation is not affected by time zones.
|
|
291
292
|
*
|
|
293
|
+
* When the original date's day exceeds the number of days in the target month,
|
|
294
|
+
* the function will automatically clamp to the last day of the target month
|
|
295
|
+
* rather than rolling over to the next month. For example, adding 1 month to
|
|
296
|
+
* January 31 will result in February 28/29 (depending on leap year), not March 3.
|
|
297
|
+
*
|
|
292
298
|
* @param date The date to add months to. It can be an SDate or a string in the
|
|
293
299
|
* YYYY-MM-DD format.
|
|
294
300
|
* @param months The number of months to add to the date.
|
|
301
|
+
* @param options Additional options for controlling the behavior of the function.
|
|
302
|
+
* @param options.capToCommonDate When true, if the original date is the 29th,
|
|
303
|
+
* 30th, or 31st, the result will be capped to the 28th of the month (the last
|
|
304
|
+
* date common to all months) rather than the last day of the target month.
|
|
305
|
+
* This ensures consistent date handling across all months.
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* ```ts
|
|
309
|
+
* addMonthsToDate('2023-01-31', 1)
|
|
310
|
+
* //=> '2023-02-28' (February has fewer days than January)
|
|
311
|
+
* ```
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```ts
|
|
315
|
+
* addMonthsToDate('2023-01-31', 3)
|
|
316
|
+
* //=> '2023-04-30' (April has 30 days)
|
|
317
|
+
* ```
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* addMonthsToDate('2024-01-31', 1)
|
|
322
|
+
* //=> '2024-02-29' (February in leap year)
|
|
323
|
+
* ```
|
|
324
|
+
*
|
|
325
|
+
* @example
|
|
326
|
+
* ```ts
|
|
327
|
+
* addMonthsToDate('2023-01-31', 3, { capToCommonDate: true })
|
|
328
|
+
* //=> '2023-04-28' (capped to the 28th regardless of month length)
|
|
329
|
+
* ```
|
|
295
330
|
*/
|
|
296
|
-
export const addMonthsToDate = (date, months) => {
|
|
331
|
+
export const addMonthsToDate = (date, months, options) => {
|
|
297
332
|
const sDateValue = sDate(date);
|
|
298
333
|
const nativeDate = getDateAsUTCDateMini(sDateValue);
|
|
299
|
-
nativeDate.
|
|
334
|
+
const currentDay = nativeDate.getDate();
|
|
335
|
+
const currentMonth = nativeDate.getMonth();
|
|
336
|
+
// First set day to 1 to avoid month overflow
|
|
337
|
+
nativeDate.setDate(1);
|
|
338
|
+
// Then set the new month
|
|
339
|
+
nativeDate.setMonth(currentMonth + months);
|
|
340
|
+
// If capToCommonDate is true and the original day is greater than 28, cap to 28
|
|
341
|
+
if (options?.capToCommonDate && currentDay > 28) {
|
|
342
|
+
nativeDate.setDate(28);
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
// Get the last day of the target month
|
|
346
|
+
const lastDayOfMonth = new UTCDateMini(nativeDate.getFullYear(), nativeDate.getMonth() + 1, 0).getDate();
|
|
347
|
+
// Set the day, clamping to the last day of the month if necessary
|
|
348
|
+
nativeDate.setDate(Math.min(currentDay, lastDayOfMonth));
|
|
349
|
+
}
|
|
300
350
|
return sDate(getISODateFromZonedDate(nativeDate));
|
|
301
351
|
};
|
|
302
352
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scdate",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js"
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test:utc:watch": "TZ=Etc/Universal yarn test:watch",
|
|
25
25
|
"smoke": "yarn build && yarn lint && yarn test:utc",
|
|
26
26
|
"-- PRE-COMMIT HOOKS --": "",
|
|
27
|
-
"localAfterInstall": "
|
|
27
|
+
"localAfterInstall": "husky || true",
|
|
28
28
|
"prepublishOnly": "pinst --disable",
|
|
29
29
|
"postpublish": "pinst --enable"
|
|
30
30
|
},
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"rimraf": "^6.0.1",
|
|
46
46
|
"typescript": "^5.8.3",
|
|
47
47
|
"typescript-eslint": "^8.30.1",
|
|
48
|
-
"vitest": "^3.1.
|
|
48
|
+
"vitest": "^3.1.2"
|
|
49
49
|
},
|
|
50
50
|
"prettier": {
|
|
51
51
|
"tabWidth": 2,
|