@dereekb/date 13.0.5 → 13.0.7

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.
Files changed (3) hide show
  1. package/index.cjs.js +32 -20
  2. package/index.esm.js +33 -21
  3. package/package.json +4 -4
package/index.cjs.js CHANGED
@@ -1097,8 +1097,10 @@ function isSameDateTimezoneConversionConfig(a, b) {
1097
1097
  * @returns
1098
1098
  */
1099
1099
  function getCurrentSystemOffsetInMs(date) {
1100
- const systemTimezone = requireCurrentTimezone();
1101
- return calculateTimezoneOffset(systemTimezone, date);
1100
+ // Use native getTimezoneOffset() instead of calculateTimezoneOffset() to avoid
1101
+ // a DST edge case where toZonedTime() creates an epoch that lands on the system's
1102
+ // DST transition boundary, causing formatDate to return the wrong hour.
1103
+ return -date.getTimezoneOffset() * util.MS_IN_MINUTE;
1102
1104
  }
1103
1105
  /**
1104
1106
  * Returns the current system time offset in hours.
@@ -1133,24 +1135,32 @@ function getCurrentSystemOffsetInMinutes(date) {
1133
1135
  * @returns
1134
1136
  */
1135
1137
  function calculateTimezoneOffset(timezone, date) {
1136
- /*
1137
- // BUG: There is a bug with getTimezoneOffset where the offset is not calculated properly for the first 2 hours after the DST change.
1138
- // https://github.com/marnusw/date-fns-tz/issues/227
1138
+ let tzOffset;
1139
+ // UTC always has zero offset; skip toZonedTime which can produce wrong results
1140
+ // when the shifted epoch lands on the system's DST transition boundary.
1141
+ if (util.isConsideredUtcTimezoneString(timezone)) {
1142
+ tzOffset = 0;
1143
+ }
1144
+ else {
1145
+ /*
1146
+ // BUG: There is a bug with getTimezoneOffset where the offset is not calculated properly for the first 2 hours after the DST change.
1147
+ // https://github.com/marnusw/date-fns-tz/issues/227
1139
1148
 
1140
- const tzOffset = getTimezoneOffset(timezone, date);
1141
- */
1142
- /*
1143
- * WORKAROUND: This is the current workaround. Performance hit seems negligible for all UI use cases.
1144
- */
1145
- // inputTimeDate.setSeconds(0); // NOTE: setting seconds/milliseconds during the daylight savings epoch will also remove an hour
1146
- // inputTimeDate.setMilliseconds(0); // do not clear seconds in this way.
1147
- const inputTimeUnrounded = date.getTime();
1148
- const secondsAndMs = inputTimeUnrounded % util.MS_IN_MINUTE; // determine the number of seconds and milliseconds (prepare to round to nearest minute)
1149
- const inputTime = inputTimeUnrounded - secondsAndMs; // remove seconds and ms as it will throw off the final tzOffset
1150
- const zoneDate = dateFnsTz.toZonedTime(inputTime, timezone);
1151
- const zoneDateStr = dateFnsTz.format(zoneDate, 'yyyy-MM-dd HH:mm'); // ignore seconds, etc.
1152
- const zoneDateTime = new Date(zoneDateStr + 'Z').getTime();
1153
- const tzOffset = zoneDateTime - inputTime;
1149
+ const tzOffset = getTimezoneOffset(timezone, date);
1150
+ */
1151
+ /*
1152
+ * WORKAROUND: This is the current workaround. Performance hit seems negligible for all UI use cases.
1153
+ */
1154
+ // inputTimeDate.setSeconds(0); // NOTE: setting seconds/milliseconds during the daylight savings epoch will also remove an hour
1155
+ // inputTimeDate.setMilliseconds(0); // do not clear seconds in this way.
1156
+ const inputTimeUnrounded = date.getTime();
1157
+ const secondsAndMs = inputTimeUnrounded % util.MS_IN_MINUTE; // determine the number of seconds and milliseconds (prepare to round to nearest minute)
1158
+ const inputTime = inputTimeUnrounded - secondsAndMs; // remove seconds and ms as it will throw off the final tzOffset
1159
+ const zoneDate = dateFnsTz.toZonedTime(inputTime, timezone);
1160
+ const zoneDateStr = dateFnsTz.format(zoneDate, 'yyyy-MM-dd HH:mm'); // ignore seconds, etc.
1161
+ const zoneDateTime = new Date(zoneDateStr + 'Z').getTime();
1162
+ tzOffset = zoneDateTime - inputTime;
1163
+ }
1154
1164
  return tzOffset;
1155
1165
  }
1156
1166
  function calculateAllConversions(date, converter, map = ((x) => x)) {
@@ -2303,7 +2313,9 @@ function dateCellTimingEventRange(timing) {
2303
2313
  * @returns
2304
2314
  */
2305
2315
  function getDateCellTimingFirstEventDateRange(timing) {
2306
- return fitDateRangeToDayPeriod({ start: timing.startsAt, end: timing.end }, timing.timezone);
2316
+ const duration = calculateExpectedDateCellTimingDuration(timing);
2317
+ const end = dateFns.addMinutes(timing.startsAt, duration);
2318
+ return { start: timing.startsAt, end };
2307
2319
  }
2308
2320
  /**
2309
2321
  * Returns the number of hours in a DateCellTiming's duration.
package/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { MS_IN_HOUR, MS_IN_MINUTE, MINUTES_IN_DAY, isISO8601DateString, filterMaybeArrayValues, asArray, dayOfWeek, sortNumbersAscendingFunction, MS_IN_SECOND, SORT_VALUE_LESS_THAN, SORT_VALUE_GREATER_THAN, SORT_VALUE_EQUAL, copyArray, compareFnOrder, MS_IN_DAY, daysOfWeekArray, groupValues, minutesToFractionalHours, safeCompareEquality, DATE_NOW_VALUE, mapIdentityFunction, UTC_TIMEZONE_STRING, cachedGetter, parseISO8601DayStringToUTCDate, isSameNonNullValue, isConsideredUtcTimezoneString, replaceStringsFunction, repeatString, isEqualDate, startOfDayForUTCDateInUTC, range, pushArrayItemsIntoArray, sumOfIntegersBetween, makeValuesGroupMap, lastValue, sortAscendingIndexNumberRefFunction, indexRangeCheckFunction, asGetter, mergeFilterFunctions, isDate as isDate$2, HOURS_IN_DAY, getNextDay, iterablesAreSetEquivalent, daysOfWeekFromEnabledDays, forEachInIterable, enabledDaysFromDaysOfWeek, addToSet, invertFilter, firstValueFromIterable, HashSet, roundNumberUpToStep, protectedFactory, TimeAM, isLogicalDateStringCode as isLogicalDateStringCode$1, dateFromLogicalDate as dateFromLogicalDate$1, flattenArray, splitJoinRemainder } from '@dereekb/util';
1
+ import { MS_IN_HOUR, MS_IN_MINUTE, MINUTES_IN_DAY, isISO8601DateString, filterMaybeArrayValues, asArray, dayOfWeek, sortNumbersAscendingFunction, MS_IN_SECOND, SORT_VALUE_LESS_THAN, SORT_VALUE_GREATER_THAN, SORT_VALUE_EQUAL, copyArray, compareFnOrder, MS_IN_DAY, daysOfWeekArray, groupValues, minutesToFractionalHours, safeCompareEquality, DATE_NOW_VALUE, mapIdentityFunction, UTC_TIMEZONE_STRING, cachedGetter, parseISO8601DayStringToUTCDate, isConsideredUtcTimezoneString, isSameNonNullValue, replaceStringsFunction, repeatString, isEqualDate, startOfDayForUTCDateInUTC, range, pushArrayItemsIntoArray, sumOfIntegersBetween, makeValuesGroupMap, lastValue, sortAscendingIndexNumberRefFunction, indexRangeCheckFunction, asGetter, mergeFilterFunctions, isDate as isDate$2, HOURS_IN_DAY, getNextDay, iterablesAreSetEquivalent, daysOfWeekFromEnabledDays, forEachInIterable, enabledDaysFromDaysOfWeek, addToSet, invertFilter, firstValueFromIterable, HashSet, roundNumberUpToStep, protectedFactory, TimeAM, isLogicalDateStringCode as isLogicalDateStringCode$1, dateFromLogicalDate as dateFromLogicalDate$1, flattenArray, splitJoinRemainder } from '@dereekb/util';
2
2
  export { dateFromDateOrTimeMillisecondsNumber, unixDateTimeSecondsNumberForNow, unixDateTimeSecondsNumberFromDate, unixDateTimeSecondsNumberFromDateOrTimeNumber, unixDateTimeSecondsNumberToDate } from '@dereekb/util';
3
3
  import { isEqual, isSameDay, isDate as isDate$1, startOfMinute, isValid, parseISO, min, max, isAfter as isAfter$1, isBefore as isBefore$1, set, addMilliseconds, startOfMonth, endOfWeek, startOfWeek, endOfMonth, addDays, addHours, addMinutes, differenceInDays, startOfDay, addMonths, addWeeks, endOfDay, endOfHour, startOfHour, endOfMinute, differenceInMinutes, differenceInHours, millisecondsToHours, millisecondsToMinutes, formatDistanceStrict, formatDistance, formatDistanceToNow, format as format$1, parse, getMinutes, getSeconds, getMilliseconds, differenceInMilliseconds, setWeek, getWeek, getYear, getDay, isPast, addSeconds } from 'date-fns';
4
4
  import { Expose, Type, Exclude } from 'class-transformer';
@@ -1096,8 +1096,10 @@ function isSameDateTimezoneConversionConfig(a, b) {
1096
1096
  * @returns
1097
1097
  */
1098
1098
  function getCurrentSystemOffsetInMs(date) {
1099
- const systemTimezone = requireCurrentTimezone();
1100
- return calculateTimezoneOffset(systemTimezone, date);
1099
+ // Use native getTimezoneOffset() instead of calculateTimezoneOffset() to avoid
1100
+ // a DST edge case where toZonedTime() creates an epoch that lands on the system's
1101
+ // DST transition boundary, causing formatDate to return the wrong hour.
1102
+ return -date.getTimezoneOffset() * MS_IN_MINUTE;
1101
1103
  }
1102
1104
  /**
1103
1105
  * Returns the current system time offset in hours.
@@ -1132,24 +1134,32 @@ function getCurrentSystemOffsetInMinutes(date) {
1132
1134
  * @returns
1133
1135
  */
1134
1136
  function calculateTimezoneOffset(timezone, date) {
1135
- /*
1136
- // BUG: There is a bug with getTimezoneOffset where the offset is not calculated properly for the first 2 hours after the DST change.
1137
- // https://github.com/marnusw/date-fns-tz/issues/227
1137
+ let tzOffset;
1138
+ // UTC always has zero offset; skip toZonedTime which can produce wrong results
1139
+ // when the shifted epoch lands on the system's DST transition boundary.
1140
+ if (isConsideredUtcTimezoneString(timezone)) {
1141
+ tzOffset = 0;
1142
+ }
1143
+ else {
1144
+ /*
1145
+ // BUG: There is a bug with getTimezoneOffset where the offset is not calculated properly for the first 2 hours after the DST change.
1146
+ // https://github.com/marnusw/date-fns-tz/issues/227
1138
1147
 
1139
- const tzOffset = getTimezoneOffset(timezone, date);
1140
- */
1141
- /*
1142
- * WORKAROUND: This is the current workaround. Performance hit seems negligible for all UI use cases.
1143
- */
1144
- // inputTimeDate.setSeconds(0); // NOTE: setting seconds/milliseconds during the daylight savings epoch will also remove an hour
1145
- // inputTimeDate.setMilliseconds(0); // do not clear seconds in this way.
1146
- const inputTimeUnrounded = date.getTime();
1147
- const secondsAndMs = inputTimeUnrounded % MS_IN_MINUTE; // determine the number of seconds and milliseconds (prepare to round to nearest minute)
1148
- const inputTime = inputTimeUnrounded - secondsAndMs; // remove seconds and ms as it will throw off the final tzOffset
1149
- const zoneDate = toZonedTime(inputTime, timezone);
1150
- const zoneDateStr = format(zoneDate, 'yyyy-MM-dd HH:mm'); // ignore seconds, etc.
1151
- const zoneDateTime = new Date(zoneDateStr + 'Z').getTime();
1152
- const tzOffset = zoneDateTime - inputTime;
1148
+ const tzOffset = getTimezoneOffset(timezone, date);
1149
+ */
1150
+ /*
1151
+ * WORKAROUND: This is the current workaround. Performance hit seems negligible for all UI use cases.
1152
+ */
1153
+ // inputTimeDate.setSeconds(0); // NOTE: setting seconds/milliseconds during the daylight savings epoch will also remove an hour
1154
+ // inputTimeDate.setMilliseconds(0); // do not clear seconds in this way.
1155
+ const inputTimeUnrounded = date.getTime();
1156
+ const secondsAndMs = inputTimeUnrounded % MS_IN_MINUTE; // determine the number of seconds and milliseconds (prepare to round to nearest minute)
1157
+ const inputTime = inputTimeUnrounded - secondsAndMs; // remove seconds and ms as it will throw off the final tzOffset
1158
+ const zoneDate = toZonedTime(inputTime, timezone);
1159
+ const zoneDateStr = format(zoneDate, 'yyyy-MM-dd HH:mm'); // ignore seconds, etc.
1160
+ const zoneDateTime = new Date(zoneDateStr + 'Z').getTime();
1161
+ tzOffset = zoneDateTime - inputTime;
1162
+ }
1153
1163
  return tzOffset;
1154
1164
  }
1155
1165
  function calculateAllConversions(date, converter, map = ((x) => x)) {
@@ -2302,7 +2312,9 @@ function dateCellTimingEventRange(timing) {
2302
2312
  * @returns
2303
2313
  */
2304
2314
  function getDateCellTimingFirstEventDateRange(timing) {
2305
- return fitDateRangeToDayPeriod({ start: timing.startsAt, end: timing.end }, timing.timezone);
2315
+ const duration = calculateExpectedDateCellTimingDuration(timing);
2316
+ const end = addMinutes(timing.startsAt, duration);
2317
+ return { start: timing.startsAt, end };
2306
2318
  }
2307
2319
  /**
2308
2320
  * Returns the number of hours in a DateCellTiming's duration.
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@dereekb/date",
3
- "version": "13.0.5",
3
+ "version": "13.0.7",
4
4
  "peerDependencies": {
5
- "@dereekb/rxjs": "13.0.5",
6
- "@dereekb/util": "13.0.5",
5
+ "@dereekb/rxjs": "13.0.7",
6
+ "@dereekb/util": "13.0.7",
7
7
  "@vvo/tzdb": "^6.0.0",
8
8
  "class-transformer": "^0.5.1",
9
9
  "class-validator": "^0.15.1",
@@ -14,7 +14,7 @@
14
14
  },
15
15
  "dependencies": {},
16
16
  "devDependencies": {
17
- "@dereekb/rxjs": "13.0.5"
17
+ "@dereekb/rxjs": "13.0.7"
18
18
  },
19
19
  "exports": {
20
20
  "./package.json": "./package.json",