scdate 1.0.0 → 1.1.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 CHANGED
@@ -1,42 +1,273 @@
1
1
  # scDate
2
2
 
3
- **Date and time library for dealing with schedules.**
3
+ **Date and time library for working with schedules**
4
4
 
5
5
  [![github license](https://img.shields.io/github/license/ericvera/scdate.svg?style=flat-square)](https://github.com/ericvera/scdate/blob/master/LICENSE)
6
6
  [![npm version](https://img.shields.io/npm/v/scdate.svg?style=flat-square)](https://npmjs.org/package/scdate)
7
7
 
8
- Features:
8
+ ## Overview
9
9
 
10
- - Supports dates, times, time stamps, and active weekdays
11
- - Time zone required for operations only when relevant
12
- - Serializable to simple ISO formatted strings
10
+ scDate is a TypeScript library designed specifically for handling date and time operations in scheduling applications. It provides a set of immutable classes and utility functions that make working with dates, times, timestamps, and weekday patterns simple and predictable.
11
+
12
+ ## Features
13
+
14
+ - **Comprehensive date/time handling**: Work with dates (`SDate`), times (`STime`), timestamps (`STimestamp`), and weekday patterns (`SWeekdays`)
15
+ - **Time zone aware**: Time zone information is only required when performing operations where it's relevant
16
+ - **Serializable**: All objects serialize to simple ISO-formatted strings for easy storage and transmission
17
+ - **Immutable**: All operations return new instances, ensuring data consistency
18
+ - **Flexible inputs**: All methods accept either serialized strings or class instances, simplifying code and improving readability
19
+ - **Schedule-focused**: Built specifically for applications that need to handle schedules and recurring patterns
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install scdate
25
+ # or
26
+ yarn add scdate
27
+ ```
28
+
29
+ ## Basic Usage
30
+
31
+ ```typescript
32
+ import { sDate, sTime, sTimestamp, sWeekdays, Weekday } from 'scdate'
33
+
34
+ // Working with dates
35
+ const today = getDateToday('America/Puerto_Rico')
36
+ const nextMonday = getNextDateByWeekday(today, Weekday.Mon)
37
+
38
+ // Working with times
39
+ const currentTime = getTimeNow('America/Puerto_Rico')
40
+ const inOneHour = addMinutesToTime(currentTime, 60)
41
+
42
+ // Working with timestamps
43
+ const now = getTimestampNow('America/Puerto_Rico')
44
+ const meeting = getTimestampFromDateAndTime(nextMonday, sTime('14:30'))
45
+
46
+ // Working with weekday patterns
47
+ const weekendDays = getWeekdaysFromWeekdayFlags(Weekday.Sat | Weekday.Sun)
48
+ const businessDays = getWeekdaysFromWeekdayFlags(
49
+ Weekday.Mon | Weekday.Tue | Weekday.Wed | Weekday.Thu | Weekday.Fri,
50
+ )
51
+ ```
52
+
53
+ ## API Documentation
54
+
55
+ ### Date Operations (`SDate`)
56
+
57
+ `SDate` represents a date in the ISO 8601 format (`YYYY-MM-DD`).
58
+
59
+ ```typescript
60
+ // Creating dates
61
+ const date1 = sDate('2023-12-25') // From ISO string
62
+ const date2 = getDateToday('America/Puerto_Rico') // Current date in timezone
63
+ const date3 = getDateForFirstDayOfMonth(date1) // First day of month
64
+ const date4 = getDateForLastDayOfMonth(date1) // Last day of month
65
+
66
+ // Date arithmetic
67
+ const nextDay = addDaysToDate(date1, 1) // Add days
68
+ const nextMonth = addMonthsToDate(date1, 1) // Add months
69
+ const nextYear = addYearsToDate(date1, 1) // Add years
70
+
71
+ // Date information
72
+ const year = getYearFromDate(date1) // Get year (number)
73
+ const month = getMonthFromDate(date1) // Get month (0-11)
74
+ const day = getDateFromDate(date1) // Get day of month
75
+ const weekday = getWeekdayFromDate(date1) // Get weekday (0-6)
76
+
77
+ // Date navigation
78
+ const nextTuesday = getNextDateByWeekday(date1, Weekday.Tue)
79
+ const prevFriday = getPreviousDateByWeekday(date1, Weekday.Fri)
80
+
81
+ // Date comparison
82
+ const isEqual = isSameDate(date1, date2)
83
+ const isBefore = isBeforeDate(date1, date2)
84
+ const isAfter = isAfterDate(date1, date2)
85
+ const isSameOrBefore = isSameDateOrBefore(date1, date2)
86
+ const isSameOrAfter = isSameDateOrAfter(date1, date2)
87
+ const isToday = isDateToday(date1, 'America/Puerto_Rico')
88
+
89
+ // Date formatting
90
+ const fullDateStr = getFullDateString(date1, 'en-US')
91
+ const shortDateStr = getShortDateString(date1, 'America/Puerto_Rico', 'en-US', {
92
+ includeWeekday: true,
93
+ onTodayText: () => 'Today',
94
+ })
95
+ ```
96
+
97
+ #### Important Behaviors and Edge Cases
98
+
99
+ - **`getNextDateByWeekday(date, weekday)`**: Always returns a date _after_ the provided date. If the current date falls on the specified weekday, it will return the _next_ occurrence (7 days later), not the current date.
100
+
101
+ - **`getPreviousDateByWeekday(date, weekday)`**: Always returns a date _before_ the provided date. If the current date falls on the specified weekday, it will return the _previous_ occurrence (7 days earlier), not the current date.
102
+
103
+ - **`getDateForFirstDayOfMonth(date)`**: Returns a new date set to the first day of the month from the input date, preserving the year and month.
104
+
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
+
107
+ - **`addMonthsToDate(date, months)`**: Handles month overflow correctly. For example, adding one month to January 31 will result in either February 28 or 29 (depending on leap year), not March 3.
108
+
109
+ - **`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
+
111
+ ### Time Operations (`STime`)
112
+
113
+ `STime` represents a time in the ISO 8601 format (`HH:MM`).
114
+
115
+ ```typescript
116
+ // Creating times
117
+ const time1 = sTime('14:30') // From ISO string
118
+ const time2 = getTimeNow('America/Puerto_Rico') // Current time in timezone
119
+ const time3 = getTimeAtMidnight() // 00:00
120
+ const time4 = getTimeFromMinutes(60) // 01:00 (60 minutes after midnight)
121
+
122
+ // Time arithmetic
123
+ const laterTime = addMinutesToTime(time1, 30) // Add minutes
124
+
125
+ // Time information
126
+ const hours = getHoursFromTime(time1) // Get hours (0-23)
127
+ const minutes = getMinutesFromTime(time1) // Get minutes (0-59)
128
+ const totalMinutes = getTimeInMinutes(time1) // Get total minutes since midnight
129
+
130
+ // Time formatting
131
+ const timeString = get12HourTimeString(time1) // e.g., "2:30 PM"
132
+
133
+ // Time comparison
134
+ const isEqual = isSameTime(time1, time2)
135
+ const isBefore = isBeforeTime(time1, time2)
136
+ const isAfter = isAfterTime(time1, time2)
137
+ const isSameOrBefore = isSameTimeOrBefore(time1, time2)
138
+ const isSameOrAfter = isSameTimeOrAfter(time1, time2)
139
+ const isPM = isTimePM(time1)
140
+ ```
141
+
142
+ #### Important Behaviors and Edge Cases
143
+
144
+ - **`addMinutesToTime(time, minutes)`**: When adding minutes, the time wraps around a 24-hour clock. For example, adding 30 minutes to 23:45 results in 00:15, not 24:15.
145
+
146
+ - **`getTimeInMinutes(time, midnightIs24)`**: By default, midnight (00:00) is represented as 0 minutes. If `midnightIs24` is set to `true`, midnight will be represented as 1440 minutes (24 hours).
147
+
148
+ - **`isTimePM(time)`**: Hours from 12:00 to 23:59 are considered PM, while 00:00 to 11:59 are AM. 12:00 is considered PM, not AM.
149
+
150
+ ### Timestamp Operations (`STimestamp`)
151
+
152
+ `STimestamp` combines a date and time in the ISO 8601 format (`YYYY-MM-DDTHH:MM`).
153
+
154
+ ```typescript
155
+ // Creating timestamps
156
+ const ts1 = sTimestamp('2023-12-25T14:30') // From ISO string
157
+ const ts2 = getTimestampNow('America/Puerto_Rico') // Current timestamp in timezone
158
+ const ts3 = getTimestampFromDateAndTime(date1, time1) // From date and time
159
+ const ts4 = getTimestampFromUTCMilliseconds(
160
+ 1640444400000,
161
+ 'America/Puerto_Rico',
162
+ ) // From UTC milliseconds
163
+
164
+ // Timestamp arithmetic
165
+ const tsNextDay = addDaysToTimestamp(ts1, 1)
166
+ const ts30MinLater = addMinutesToTimestamp(ts1, 30, 'America/Puerto_Rico')
167
+
168
+ // Timestamp breakdown
169
+ const tsDate = getDateFromTimestamp(ts1) // Extract date part
170
+ const tsTime = getTimeFromTimestamp(ts1) // Extract time part
171
+
172
+ // Timestamp conversion
173
+ const tsMilliseconds = getUTCMillisecondsFromTimestamp(
174
+ ts1,
175
+ 'America/Puerto_Rico',
176
+ )
177
+ const tsNativeDate = getTimeZonedDateFromTimestamp(ts1, 'America/Puerto_Rico')
178
+ const secondsToTs = getSecondsToTimestamp(ts1, 'America/Puerto_Rico')
179
+
180
+ // Timestamp formatting
181
+ const tsString = getShortTimestampString(ts1, 'America/Puerto_Rico', 'en-US', {
182
+ includeWeekday: true,
183
+ onTodayAtText: () => 'Today at',
184
+ })
185
+
186
+ // Timestamp comparison
187
+ const isEqual = isSameTimestamp(ts1, ts2)
188
+ const isBefore = isBeforeTimestamp(ts1, ts2)
189
+ const isAfter = isAfterTimestamp(ts1, ts2)
190
+ const isSameOrBefore = isSameTimestampOrBefore(ts1, ts2)
191
+ const isSameOrAfter = isSameTimestampOrAfter(ts1, ts2)
192
+ ```
193
+
194
+ #### Important Behaviors and Edge Cases
195
+
196
+ - **`getTimestampFromUTCMilliseconds(milliseconds, timeZone)`**: Converts UTC milliseconds to a timestamp in the specified time zone, accounting for time zone offsets.
197
+
198
+ - **`addMinutesToTimestamp(timestamp, minutes, timeZone)`**: Time zone awareness is critical for this operation, especially around Daylight Saving Time transitions. When a timestamp lands in the "missing hour" during a spring-forward transition, it's adjusted to the valid time.
199
+
200
+ - **`getSecondsToTimestamp(timestamp, timeZone)`**: Returns a positive value for future timestamps and negative for past timestamps. Handles DST transitions correctly but might produce unexpected results for timestamps that fall in skipped or repeated hours during DST transitions.
201
+
202
+ - **`getUTCMillisecondsFromTimestamp(timestamp, timeZone)`**: Converts a timestamp to UTC milliseconds, accounting for the time zone offset at that specific date and time (important for historical dates with different time zone rules).
203
+
204
+ ### Weekday Operations (`SWeekdays`)
205
+
206
+ `SWeekdays` represents a set of weekdays in the format `SMTWTFS`, where each position corresponds to a day of the week (Sunday to Saturday).
207
+
208
+ ```typescript
209
+ // Creating weekday patterns
210
+ const weekdays1 = sWeekdays('SMTWTFS') // All days
211
+ const weekdays2 = sWeekdays('SM----S') // Sunday, Monday, Saturday
212
+ const weekdays3 = getWeekdaysFromWeekdayFlags(Weekday.Mon | Weekday.Wed) // Monday, Wednesday
213
+ const weekdays4 = getWeekdaysWithAllIncluded() // All days
214
+ const weekdays5 = getWeekdaysWithNoneIncluded() // No days
215
+
216
+ // Weekday operations
217
+ const shiftedWeekdays = shiftWeekdaysForward(weekdays2) // Shift pattern one day forward
218
+ const filteredWeekdays = filterWeekdaysForDates(
219
+ // Filter to days in date range
220
+ weekdays1,
221
+ '2023-12-25',
222
+ '2023-12-31',
223
+ )
224
+ const updatedWeekdays = addWeekdayToWeekdays(weekdays5, Weekday.Fri) // Add Friday to pattern
225
+
226
+ // Weekday queries
227
+ const includesMonday = doesWeekdaysIncludeWeekday(weekdays2, Weekday.Mon)
228
+ const hasOverlap = doesWeekdaysHaveOverlapWithWeekdays(weekdays2, weekdays3)
229
+ ```
230
+
231
+ #### Important Behaviors and Edge Cases
232
+
233
+ - **`sWeekdays(pattern)`**: The pattern must be exactly 7 characters long, with each position representing a day from Sunday to Saturday. Valid characters are the first letter of the English weekday name (S, M, T, W, T, F, S) or a dash '-' for excluded days.
234
+
235
+ - **`shiftWeekdaysForward(weekdays)`**: Shifts the pattern forward by one day with circular wrapping. For example, 'SM----S' becomes 'SMT----'. The last character (Saturday) wraps around to become the first day (Sunday) position.
236
+
237
+ - **`filterWeekdaysForDates(weekdays, fromDate, toDate)`**: Returns a new weekday pattern that only includes the weekdays that fall within the given date range. If the date range spans less than a week, only the applicable days are included.
238
+
239
+ - **`getWeekdaysFromWeekdayFlags(flags)`**: Uses bitwise operations to combine multiple weekday flags. Each weekday is represented by a power of 2, allowing for efficient combination and checking.
13
240
 
14
241
  ## Dependencies
15
242
 
16
243
  This package has the following dependencies:
17
244
 
18
- - `date-fns-tz`: used for time zone calculations
19
- - `date-fns`: it is a peer dependency of `date-fns-tz`
20
- - `@date-fns/utc`: used for its `UTCDateMini` implementation that simplifies some of the time calculations
245
+ - `date-fns-tz`: Used for time zone calculations
246
+ - `date-fns`: Peer dependency of `date-fns-tz`
247
+ - `@date-fns/utc`: Used for its `UTCDateMini` implementation that simplifies time calculations
21
248
 
22
249
  ## Design Decisions
23
250
 
24
- ### ISO formatted values
251
+ ### ISO 8601 Format
252
+
253
+ scDate uses a subset of the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard for all date and time representations. This format was chosen for several key benefits:
25
254
 
26
- A subset of [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) is used as the valid format for SDate, STime, and STimestamp. This was done because:
255
+ - **Human readability**: Dates and times are easy to read and interpret
256
+ - **String sortability**: ISO-formatted strings can be sorted chronologically using simple string comparison
257
+ - **Direct comparison**: Values can be compared directly as strings without conversion
27
258
 
28
- - the format is human readable
29
- - the values are easily sortable as strings
30
- - the values are easily comparable as strings
259
+ ### Minute-Level Precision
31
260
 
32
- ### No seconds in time components
261
+ scDate intentionally omits seconds and milliseconds from time representations. This design choice reflects the library's focus on scheduling applications, where:
33
262
 
34
- The library was designed with schedules in mind that do not require second or smaller granularity as such STime and STimestamp only provide minute granularity.
263
+ - Minute-level granularity is typically sufficient for most scheduling needs
264
+ - Simpler time representations lead to more intuitive API and usage patterns
265
+ - Performance is optimized by avoiding unnecessary precision
35
266
 
36
267
  ## Time zones
37
268
 
38
269
  For a list of valid time zones run `Intl.supportedValuesOf('timeZone')` in your environment.
39
270
 
40
- ## API Reference
271
+ ## License
41
272
 
42
- See [docs](docs/README.md)
273
+ MIT
@@ -1,7 +1,3 @@
1
- import { SDate } from './SDate.js';
2
- import { STimestamp } from './STimestamp.js';
3
- export declare const getMillisecondsInUTCFromTimestamp: (timestamp: STimestamp, timeZone: string) => number;
4
- export declare const getMillisecondsInUTCFromDate: (date: SDate, timeZone: string) => number;
5
1
  /**
6
2
  * @param timeZone For a list of valid time zones run
7
3
  * `Intl.supportedValuesOf('timeZone')` on your environment.
@@ -1,23 +1,4 @@
1
- import { getTimezoneOffset, toZonedTime } from 'date-fns-tz';
2
- import { getDateAsUTCDateMini } from './date.js';
3
- import { getTimestampAsUTCDateMini } from './timestamp.js';
4
- const getValidatedTimeZoneOffset = (timeZone, utcDate) => {
5
- const timeZoneOffset = getTimezoneOffset(timeZone, utcDate);
6
- if (isNaN(timeZoneOffset)) {
7
- throw new Error(`Invalid time zone. Time zone: '${timeZone}'`);
8
- }
9
- return timeZoneOffset;
10
- };
11
- export const getMillisecondsInUTCFromTimestamp = (timestamp, timeZone) => {
12
- const utcDate = getTimestampAsUTCDateMini(timestamp);
13
- const timeZoneOffset = getValidatedTimeZoneOffset(timeZone, utcDate);
14
- return utcDate.getTime() - timeZoneOffset;
15
- };
16
- export const getMillisecondsInUTCFromDate = (date, timeZone) => {
17
- const utcDate = getDateAsUTCDateMini(date);
18
- const timeZoneOffset = getValidatedTimeZoneOffset(timeZone, utcDate);
19
- return utcDate.getTime() - timeZoneOffset;
20
- };
1
+ import { toZonedTime } from 'date-fns-tz';
21
2
  /**
22
3
  * @param timeZone For a list of valid time zones run
23
4
  * `Intl.supportedValuesOf('timeZone')` on your environment.
package/dist/sDate.d.ts CHANGED
@@ -90,6 +90,16 @@ export declare const getDateFromDate: (date: string | SDate) => number;
90
90
  * in the YYYY-MM-DD format.
91
91
  */
92
92
  export declare const getWeekdayFromDate: (date: string | SDate) => number;
93
+ /**
94
+ * Returns the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC)
95
+ * for the given date in the specified time zone.
96
+ *
97
+ * @param date The date to convert to UTC milliseconds. It can be an SDate or a string
98
+ * in the YYYY-MM-DD format.
99
+ * @param timeZone The time zone to use when converting the date. See
100
+ * `Intl.supportedValuesOf('timeZone')` for a list of valid time zones.
101
+ */
102
+ export declare const getUTCMillisecondsFromDate: (date: string | SDate, timeZone: string) => number;
93
103
  /**
94
104
  * Returns a native Date adjusted so that the local time of that date matches
95
105
  * the local time at the specified time zone.
package/dist/sDate.js CHANGED
@@ -1,9 +1,10 @@
1
+ import { getTimezoneOffset } from 'date-fns-tz';
1
2
  import { SDate } from './internal/SDate.js';
2
3
  import { DayToWeekday, DaysInWeek, MillisecondsInDay, } from './internal/constants.js';
3
4
  import { getDateAsUTCDateMini, getISODateFromISODate, getISODateFromZonedDate, getISOMonthFromISODate, getISOYearFromISODate, } from './internal/date.js';
4
5
  import { getAtIndex } from './internal/utils.js';
5
6
  import { getIndexForWeekday } from './internal/weekdays.js';
6
- import { getMillisecondsInUTCFromDate, getTimeZonedDate, } from './internal/zoned.js';
7
+ import { getTimeZonedDate } from './internal/zoned.js';
7
8
  /**
8
9
  * --- Factory ---
9
10
  */
@@ -142,6 +143,24 @@ export const getWeekdayFromDate = (date) => {
142
143
  const nativeDate = getDateAsUTCDateMini(sDateValue);
143
144
  return getAtIndex(DayToWeekday, nativeDate.getDay());
144
145
  };
146
+ /**
147
+ * Returns the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC)
148
+ * for the given date in the specified time zone.
149
+ *
150
+ * @param date The date to convert to UTC milliseconds. It can be an SDate or a string
151
+ * in the YYYY-MM-DD format.
152
+ * @param timeZone The time zone to use when converting the date. See
153
+ * `Intl.supportedValuesOf('timeZone')` for a list of valid time zones.
154
+ */
155
+ export const getUTCMillisecondsFromDate = (date, timeZone) => {
156
+ const sDateValue = sDate(date);
157
+ const utcDate = getDateAsUTCDateMini(sDateValue);
158
+ const timeZoneOffset = getTimezoneOffset(timeZone, utcDate);
159
+ if (isNaN(timeZoneOffset)) {
160
+ throw new Error(`Invalid time zone. Time zone: '${timeZone}'`);
161
+ }
162
+ return utcDate.getTime() - timeZoneOffset;
163
+ };
145
164
  /**
146
165
  * Returns a native Date adjusted so that the local time of that date matches
147
166
  * the local time at the specified time zone.
@@ -153,7 +172,7 @@ export const getWeekdayFromDate = (date) => {
153
172
  */
154
173
  export const getTimeZonedDateFromDate = (date, timeZone) => {
155
174
  const sDateValue = sDate(date);
156
- const milliseconds = getMillisecondsInUTCFromDate(sDateValue, timeZone);
175
+ const milliseconds = getUTCMillisecondsFromDate(sDateValue, timeZone);
157
176
  const zonedTime = getTimeZonedDate(milliseconds, timeZone);
158
177
  return zonedTime;
159
178
  };
@@ -49,6 +49,16 @@ export declare const getTimestampFromDateAndTime: (date: string | SDate, time: s
49
49
  /**
50
50
  * --- Getters ---
51
51
  */
52
+ /**
53
+ * Returns the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC)
54
+ * for the given timestamp in the specified time zone.
55
+ *
56
+ * @param timestamp The timestamp to convert to UTC milliseconds. It can be an STimestamp
57
+ * or a string in the YYYY-MM-DDTHH:MM format.
58
+ * @param timeZone The time zone to use when converting the timestamp. See
59
+ * `Intl.supportedValuesOf('timeZone')` for a list of valid time zones.
60
+ */
61
+ export declare const getUTCMillisecondsFromTimestamp: (timestamp: string | STimestamp, timeZone: string) => number;
52
62
  /**
53
63
  * Returns a native Date adjusted so that the local time of that date matches
54
64
  * the local timestamp at the specified time zone.
@@ -197,10 +207,10 @@ export declare const addDaysToTimestamp: (timestamp: string | STimestamp, days:
197
207
  *
198
208
  * Time is converted from the given time zone to
199
209
  * UTC before the minutes are added, and then converted back to the specified
200
- * time zone. This results in the resulting time being adjusted for daylight saving time
201
- * changes. (e.g. Adding 60 minutes to 2024-03-10T01:59 in America/New_York will
202
- * result in 2024-03-10T03:59 as time move forward one hour for daylight saving
203
- * time at 2024-03-10T02:00.)
210
+ * time zone. This results in the resulting time being adjusted for daylight
211
+ * saving time changes. (e.g. Adding 60 minutes to 2024-03-10T01:59 in
212
+ * America/New_York will result in 2024-03-10T03:59 as time move forward one
213
+ * hour for daylight saving time at 2024-03-10T02:00.)
204
214
  *
205
215
  * For example, adding one minute to 2024-03-10T01:59 will result in
206
216
  * 2024-03-10T03:00 as expected. However, trying to add one minute to
@@ -1,7 +1,8 @@
1
+ import { getTimezoneOffset } from 'date-fns-tz';
1
2
  import { STimestamp } from './internal/STimestamp.js';
2
3
  import { MillisecondsInMinute, MillisecondsInSecond, } from './internal/constants.js';
3
4
  import { getISODateFromISOTimestamp, getISOTimeFromISOTimestamp, getISOTimestampFromZonedDate, getTimestampAsUTCDateMini, } from './internal/timestamp.js';
4
- import { getMillisecondsInUTCFromTimestamp, getTimeZonedDate, } from './internal/zoned.js';
5
+ import { getTimeZonedDate } from './internal/zoned.js';
5
6
  import { getShortDateString, sDate } from './sDate.js';
6
7
  import { get12HourTimeString, sTime } from './sTime.js';
7
8
  /**
@@ -62,6 +63,24 @@ export const getTimestampFromDateAndTime = (date, time) => {
62
63
  /**
63
64
  * --- Getters ---
64
65
  */
66
+ /**
67
+ * Returns the number of milliseconds since the Unix epoch (January 1, 1970, 00:00:00 UTC)
68
+ * for the given timestamp in the specified time zone.
69
+ *
70
+ * @param timestamp The timestamp to convert to UTC milliseconds. It can be an STimestamp
71
+ * or a string in the YYYY-MM-DDTHH:MM format.
72
+ * @param timeZone The time zone to use when converting the timestamp. See
73
+ * `Intl.supportedValuesOf('timeZone')` for a list of valid time zones.
74
+ */
75
+ export const getUTCMillisecondsFromTimestamp = (timestamp, timeZone) => {
76
+ const sTimestampValue = sTimestamp(timestamp);
77
+ const utcDate = getTimestampAsUTCDateMini(sTimestampValue);
78
+ const timeZoneOffset = getTimezoneOffset(timeZone, utcDate);
79
+ if (isNaN(timeZoneOffset)) {
80
+ throw new Error(`Invalid time zone. Time zone: '${timeZone}'`);
81
+ }
82
+ return utcDate.getTime() - timeZoneOffset;
83
+ };
65
84
  /**
66
85
  * Returns a native Date adjusted so that the local time of that date matches
67
86
  * the local timestamp at the specified time zone.
@@ -73,7 +92,7 @@ export const getTimestampFromDateAndTime = (date, time) => {
73
92
  */
74
93
  export const getTimeZonedDateFromTimestamp = (timestamp, timeZone) => {
75
94
  const sTimestampValue = sTimestamp(timestamp);
76
- const dateInUTCMilliseconds = getMillisecondsInUTCFromTimestamp(sTimestampValue, timeZone);
95
+ const dateInUTCMilliseconds = getUTCMillisecondsFromTimestamp(sTimestampValue, timeZone);
77
96
  return getTimeZonedDate(dateInUTCMilliseconds, timeZone);
78
97
  };
79
98
  /**
@@ -130,7 +149,7 @@ export const getTimeZonedDateFromTimestamp = (timestamp, timeZone) => {
130
149
  export const getSecondsToTimestamp = (timestamp, timeZone) => {
131
150
  const sTimestampValue = sTimestamp(timestamp);
132
151
  const millisecondsNow = Date.now();
133
- const millisecondsAtTimestamp = getMillisecondsInUTCFromTimestamp(sTimestampValue, timeZone);
152
+ const millisecondsAtTimestamp = getUTCMillisecondsFromTimestamp(sTimestampValue, timeZone);
134
153
  return Math.floor((millisecondsAtTimestamp - millisecondsNow) / MillisecondsInSecond);
135
154
  };
136
155
  /**
@@ -240,10 +259,10 @@ export const addDaysToTimestamp = (timestamp, days) => {
240
259
  *
241
260
  * Time is converted from the given time zone to
242
261
  * UTC before the minutes are added, and then converted back to the specified
243
- * time zone. This results in the resulting time being adjusted for daylight saving time
244
- * changes. (e.g. Adding 60 minutes to 2024-03-10T01:59 in America/New_York will
245
- * result in 2024-03-10T03:59 as time move forward one hour for daylight saving
246
- * time at 2024-03-10T02:00.)
262
+ * time zone. This results in the resulting time being adjusted for daylight
263
+ * saving time changes. (e.g. Adding 60 minutes to 2024-03-10T01:59 in
264
+ * America/New_York will result in 2024-03-10T03:59 as time move forward one
265
+ * hour for daylight saving time at 2024-03-10T02:00.)
247
266
  *
248
267
  * For example, adding one minute to 2024-03-10T01:59 will result in
249
268
  * 2024-03-10T03:00 as expected. However, trying to add one minute to
@@ -278,7 +297,7 @@ export const addDaysToTimestamp = (timestamp, days) => {
278
297
  */
279
298
  export const addMinutesToTimestamp = (timestamp, minutes, timeZone) => {
280
299
  const sTimestampValue = sTimestamp(timestamp);
281
- const newMillisecondsInUTC = getMillisecondsInUTCFromTimestamp(sTimestampValue, timeZone) +
300
+ const newMillisecondsInUTC = getUTCMillisecondsFromTimestamp(sTimestampValue, timeZone) +
282
301
  minutes * MillisecondsInMinute;
283
302
  const newTimestamp = getTimestampFromUTCMilliseconds(newMillisecondsInUTC, timeZone);
284
303
  return newTimestamp;
package/dist/sWeekdays.js CHANGED
@@ -62,7 +62,7 @@ export const sWeekdays = (weekdays) => {
62
62
  * ```
63
63
  */
64
64
  export const getWeekdaysFromWeekdayFlags = (weekdays) => {
65
- const newWeekdays = [...AllWeekdaysIncludedMask];
65
+ const newWeekdays = Array.from(AllWeekdaysIncludedMask);
66
66
  for (let i = 0; i < DayToWeekday.length; i++) {
67
67
  const weekday = getAtIndex(DayToWeekday, i);
68
68
  if (!hasFlag(weekdays, weekday)) {
@@ -102,7 +102,7 @@ export const getWeekdaysWithNoneIncluded = () => {
102
102
  */
103
103
  export const shiftWeekdaysForward = (weekdays) => {
104
104
  const sWeekdaysInstance = sWeekdays(weekdays);
105
- const after = [...NoWeekdaysIncluded];
105
+ const after = Array.from(NoWeekdaysIncluded);
106
106
  const DayShift = 1;
107
107
  for (let i = 0; i < WeekdaysCount; i++) {
108
108
  const prevDayIndex = (WeekdaysCount - DayShift + i) % WeekdaysCount;
@@ -163,7 +163,7 @@ export const filterWeekdaysForDates = (weekdays, fromDate, toDate) => {
163
163
  */
164
164
  export const addWeekdayToWeekdays = (weekdays, weekdayToAdd) => {
165
165
  const sWeekdaysInstance = sWeekdays(weekdays);
166
- const newWeekdays = [...sWeekdaysInstance.weekdays];
166
+ const newWeekdays = Array.from(sWeekdaysInstance.weekdays);
167
167
  const weekdayIndex = getIndexForWeekday(weekdayToAdd);
168
168
  newWeekdays[weekdayIndex] = getAtIndex(AllWeekdaysIncludedMask, weekdayIndex);
169
169
  return sWeekdays(newWeekdays.join(''));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scdate",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./dist/index.js"
@@ -23,7 +23,6 @@
23
23
  "test:watch": "vitest",
24
24
  "test:utc:watch": "TZ=Etc/Universal yarn test:watch",
25
25
  "smoke": "yarn build && yarn lint && yarn test:utc",
26
- "docs": "typedoc && prettier --ignore-unknown --write docs/",
27
26
  "-- PRE-COMMIT HOOKS --": "",
28
27
  "localAfterInstall": "is-ci || husky || true",
29
28
  "prepublishOnly": "pinst --disable",
@@ -32,24 +31,21 @@
32
31
  "dependencies": {
33
32
  "@date-fns/utc": "^2.1.0",
34
33
  "date-fns": "^4.1.0",
35
- "date-fns-tz": "^3.1.3"
34
+ "date-fns-tz": "^3.2.0"
36
35
  },
37
36
  "devDependencies": {
38
- "@eslint/js": "^9.10.0",
37
+ "@eslint/js": "^9.25.0",
39
38
  "@tsconfig/strictest": "^2.0.5",
40
- "@types/node": "^22.5.5",
41
- "eslint": "^9.10.0",
42
- "husky": "^9.1.6",
43
- "is-ci": "^3.0.1",
44
- "lint-staged": "^15.2.10",
39
+ "@types/node": "^22.14.1",
40
+ "eslint": "^9.25.0",
41
+ "husky": "^9.1.7",
42
+ "lint-staged": "^15.5.1",
45
43
  "pinst": "^3.0.0",
46
- "prettier": "^3.3.3",
44
+ "prettier": "^3.5.3",
47
45
  "rimraf": "^6.0.1",
48
- "typedoc": "^0.26.7",
49
- "typedoc-plugin-markdown": "^4.2.7",
50
- "typescript": "^5.6.2",
51
- "typescript-eslint": "^8.6.0",
52
- "vitest": "^2.1.1"
46
+ "typescript": "^5.8.3",
47
+ "typescript-eslint": "^8.30.1",
48
+ "vitest": "^3.1.1"
53
49
  },
54
50
  "prettier": {
55
51
  "tabWidth": 2,
@@ -74,5 +70,5 @@
74
70
  "*.{ts,tsx,mjs}": "eslint --cache",
75
71
  "*": "prettier --ignore-unknown --write"
76
72
  },
77
- "packageManager": "yarn@4.3.0"
73
+ "packageManager": "yarn@4.9.1"
78
74
  }