a2bei4-utils 1.0.3 → 1.0.4

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.
@@ -799,133 +799,222 @@ function randomDateInRange(date1, date2) {
799
799
  return new Date(v1 + Math.floor(Math.random() * (v2 - v1 + 1)));
800
800
  }
801
801
 
802
+ //#region 持续时间相关
803
+
804
+ /**
805
+ * 时间持续对象(完整版本,包含年月日时分秒毫秒)
806
+ * @typedef {Object} DurationObject
807
+ * @property {number} years - 年数
808
+ * @property {number} months - 月数(0-11)
809
+ * @property {number} days - 天数(0-29,取决于 monthDays)
810
+ * @property {number} hours - 小时数(0-23)
811
+ * @property {number} minutes - 分钟数(0-59)
812
+ * @property {number} seconds - 秒数(0-59)
813
+ * @property {number} milliseconds - 毫秒数(0-999)
814
+ */
815
+
802
816
  /**
803
- * 计算两个时间之间的剩余/已过时长(天-时-分-秒),返回带补零的展示对象。
817
+ * 时间持续对象(最大单位为天)
818
+ * @typedef {Object} DurationMaxDayObject
819
+ * @property {number} days - 天数
820
+ * @property {number} hours - 小时数(0-23)
821
+ * @property {number} minutes - 分钟数(0-59)
822
+ * @property {number} seconds - 秒数(0-59)
823
+ * @property {number} milliseconds - 毫秒数(0-999)
824
+ */
825
+
826
+ /**
827
+ * 时间持续对象(最大单位为小时)
828
+ * @typedef {Object} DurationMaxHourObject
829
+ * @property {number} hours - 小时数
830
+ * @property {number} minutes - 分钟数(0-59)
831
+ * @property {number} seconds - 秒数(0-59)
832
+ * @property {number} milliseconds - 毫秒数(0-999)
833
+ */
834
+
835
+ /**
836
+ * 将毫秒转换为时间持续对象。
804
837
  *
805
- * @param {string|number|Date} originalTime - 原始时间(可转 Date 的任意值)
806
- * @param {Date} [currentTime=new Date()] - 基准时间,默认当前
807
- * @returns {{days:number,hours:string,minutes:string,seconds:string}}
838
+ * @param {number} milliseconds - 毫秒数(非负整数)
839
+ * @param {Object} [options] - 选项对象。
840
+ * @param {number} [options.yearDays=365] - 一年的天数。
841
+ * @param {number} [options.monthDays=30] - 一月的天数。
842
+ * @returns {DurationObject} 时间持续对象
843
+ * @throws {TypeError} 当 milliseconds 不是有效数字
844
+ * @throws {RangeError} 当 milliseconds 为负数
845
+ * @throws {RangeError} 当 yearDays 或 monthDays 不是正整数
846
+ *
847
+ * @example
848
+ * // 基本用法
849
+ * millisecond2Duration(42070000500);
850
+ * // 返回: { years: 1, months: 4, days: 1, hours: 22, minutes: 6, seconds: 40, milliseconds: 500 }
808
851
  */
809
- function calcTimeDifference(originalTime, currentTime = new Date()) {
810
- // 计算时间差(毫秒)
811
- const diffMs = currentTime - new Date(originalTime);
812
-
813
- // 转换为天、小时、分钟、秒
814
- const diffSeconds = Math.floor(diffMs / 1000);
815
- const days = Math.floor(diffSeconds / (3600 * 24));
816
- const hours = Math.floor((diffSeconds % (3600 * 24)) / 3600);
817
- const minutes = Math.floor((diffSeconds % 3600) / 60);
852
+ function millisecond2Duration(milliseconds, options = { yearDays: 365, monthDays: 30 }) {
853
+ // 参数验证
854
+ if (typeof milliseconds !== "number" || isNaN(milliseconds)) {
855
+ throw new TypeError("milliseconds must be a valid number");
856
+ }
857
+ if (milliseconds < 0) {
858
+ throw new RangeError("milliseconds must be a non-negative number");
859
+ }
860
+
861
+ // 默认选项
862
+ const { yearDays = 365, monthDays = 30 } = options;
863
+
864
+ // 选项验证
865
+ if (!Number.isInteger(yearDays) || yearDays <= 0) {
866
+ throw new RangeError("yearDays must be a positive integer");
867
+ }
868
+ if (!Number.isInteger(monthDays) || monthDays <= 0) {
869
+ throw new RangeError("monthDays must be a positive integer");
870
+ }
871
+
872
+ const totalMilliseconds = Math.floor(milliseconds);
873
+ const ms = totalMilliseconds % 1000;
874
+ const diffSeconds = Math.floor(totalMilliseconds / 1000);
875
+
818
876
  const seconds = diffSeconds % 60;
877
+ const minutes = Math.floor(diffSeconds / 60) % 60;
878
+ const hours = Math.floor(diffSeconds / 3600) % 24;
819
879
 
820
- const padZero = (num) => String(num).padStart(2, "0");
880
+ // 计算年、月、日
881
+ const totalDays = Math.floor(diffSeconds / 3600 / 24);
882
+ const years = Math.floor(totalDays / yearDays);
883
+ const remainingDays = totalDays % yearDays;
884
+ const months = Math.floor(remainingDays / monthDays);
885
+ const days = remainingDays % monthDays;
821
886
 
822
- return {
823
- days,
824
- hours: padZero(hours),
825
- minutes: padZero(minutes),
826
- seconds: padZero(seconds)
827
- };
887
+ return { years, months, days, hours, minutes, seconds, milliseconds: ms };
828
888
  }
829
889
 
830
890
  /**
831
- * 将总秒数格式化成人类可读的时间段文本。
832
- * 固定进制:1 年=365 天,1 月=30 天。
833
- *
834
- * @param {number} totalSeconds - 非负总秒数
835
- * @param {object} [options] - 格式化选项
836
- * @param {Partial<{year:string,month:string,day:string,hour:string,minute:string,second:string}>} [options.labels] - 各单位的自定义文本
837
- * @param {('year'|'month'|'day'|'hour'|'minute'|'second')} [options.maxUnit] - 最大输出单位
838
- * @param {('year'|'month'|'day'|'hour'|'minute'|'second')} [options.minUnit] - 最小输出单位
839
- * @param {boolean} [options.showZero] - 是否强制显示 0 秒
840
- * @returns {string} 拼接后的时长文本,如“1天 02小时 30分钟”
841
- * @throws {TypeError} 当 totalSeconds 为非数字或负数时抛出
891
+ * 将毫秒转换为时间持续对象(最大单位为天)。
892
+ * @param {number} milliseconds - 毫秒数(非负整数)
893
+ * @returns {DurationMaxDayObject} 包含天、小时、分钟、秒、毫秒的时间持续对象
894
+ * @throws {TypeError} milliseconds 不是有效数字时抛出
895
+ * @throws {RangeError} milliseconds 为负数时抛出
896
+ * @example
897
+ * // 返回 { days: 486, hours: 22, minutes: 6, seconds: 40, milliseconds: 500 }
898
+ * millisecond2DurationMaxDay(42070000500);
842
899
  */
843
- function formatDuration(totalSeconds, options = {}) {
844
- if (typeof totalSeconds !== "number" || totalSeconds < 0 || !isFinite(totalSeconds)) {
845
- throw new TypeError("totalSeconds 必须是非负数字");
900
+ function millisecond2DurationMaxDay(milliseconds) {
901
+ if (typeof milliseconds !== "number" || isNaN(milliseconds)) {
902
+ throw new TypeError("milliseconds must be a valid number");
903
+ }
904
+ if (milliseconds < 0) {
905
+ throw new RangeError("milliseconds must be a non-negative number");
846
906
  }
847
907
 
848
- // 1. 默认中文单位
849
- const DEFAULT_LABELS = {
850
- year: "年",
851
- month: "月",
852
- day: "天",
853
- hour: "小时",
854
- minute: "分钟",
855
- second: "秒"
856
- };
908
+ const totalMilliseconds = Math.floor(milliseconds);
909
+ const ms = totalMilliseconds % 1000;
910
+ const diffSeconds = Math.floor(totalMilliseconds / 1000);
857
911
 
858
- // 2. 固定进制表(秒)
859
- const UNIT_TABLE = [
860
- { key: "year", seconds: 365 * 24 * 3600 },
861
- { key: "month", seconds: 30 * 24 * 3600 },
862
- { key: "day", seconds: 24 * 3600 },
863
- { key: "hour", seconds: 3600 },
864
- { key: "minute", seconds: 60 },
865
- { key: "second", seconds: 1 }
866
- ];
867
-
868
- // 3. 合并用户自定义文本
869
- const labels = Object.assign({}, DEFAULT_LABELS, options.labels);
870
-
871
- // 4. 根据 maxUnit / minUnit 截取
872
- let start = 0,
873
- end = UNIT_TABLE.length;
874
- if (options.maxUnit) {
875
- const idx = UNIT_TABLE.findIndex((u) => u.key === options.maxUnit);
876
- if (idx !== -1) start = idx;
877
- }
878
- if (options.minUnit) {
879
- const idx = UNIT_TABLE.findIndex((u) => u.key === options.minUnit);
880
- if (idx !== -1) end = idx + 1;
881
- }
882
- const units = UNIT_TABLE.slice(start, end);
883
- if (!units.length) units.push(UNIT_TABLE[UNIT_TABLE.length - 1]); // 保底秒
884
-
885
- // 5. 逐级计算
886
- let rest = Math.floor(totalSeconds);
887
- const parts = [];
888
-
889
- for (const { key, seconds } of units) {
890
- const val = Math.floor(rest / seconds);
891
- rest %= seconds;
892
-
893
- const shouldShow = val > 0 || (options.showZero && key === "second");
894
- if (shouldShow || (parts.length === 0 && rest === 0)) {
895
- parts.push(`${val}${labels[key]}`);
896
- }
897
- }
912
+ const seconds = diffSeconds % 60;
913
+ const minutes = Math.floor(diffSeconds / 60) % 60;
914
+ const hours = Math.floor(diffSeconds / 3600) % 24;
915
+ const days = Math.floor(diffSeconds / 3600 / 24);
916
+
917
+ return { days, hours, minutes, seconds, milliseconds: ms };
918
+ }
898
919
 
899
- // 6. 兜底
900
- if (parts.length === 0) {
901
- parts.push(`0${labels[units[units.length - 1].key]}`);
920
+ /**
921
+ * 将毫秒转换为时间持续对象(最大单位为小时)。
922
+ * @param {number} milliseconds - 毫秒数(非负整数)
923
+ * @returns {DurationMaxHourObject} 包含小时、分钟、秒、毫秒的时间持续对象
924
+ * @throws {TypeError} 当 milliseconds 不是有效数字时抛出
925
+ * @throws {RangeError} 当 milliseconds 为负数时抛出
926
+ * @example
927
+ * // 返回 { hours: 11686, minutes: 6, seconds: 40, milliseconds: 500 }
928
+ * millisecond2DurationMaxHour(42070000500);
929
+ */
930
+ function millisecond2DurationMaxHour(milliseconds) {
931
+ if (typeof milliseconds !== "number" || isNaN(milliseconds)) {
932
+ throw new TypeError("milliseconds must be a valid number");
902
933
  }
934
+ if (milliseconds < 0) {
935
+ throw new RangeError("milliseconds must be a non-negative number");
936
+ }
937
+
938
+ const totalMilliseconds = Math.floor(milliseconds);
939
+ const ms = totalMilliseconds % 1000;
940
+ const diffSeconds = Math.floor(totalMilliseconds / 1000);
903
941
 
904
- return parts.join("");
942
+ const seconds = diffSeconds % 60;
943
+ const minutes = Math.floor(diffSeconds / 60) % 60;
944
+ const hours = Math.floor(diffSeconds / 3600);
945
+
946
+ return { hours, minutes, seconds, milliseconds: ms };
905
947
  }
906
948
 
907
949
  /**
908
- * 快捷调用 {@link formatDuration},最大单位到“天”。
950
+ * 将秒转换为时间持续对象。
909
951
  *
910
- * @param {number} totalSeconds
911
- * @param {Omit<Parameters<typeof formatDuration>[1],'maxUnit'>} [options]
912
- * @returns {string}
952
+ * @param {number} seconds - 秒数(非负整数)
953
+ * @param {Object} [options] - 选项对象。
954
+ * @param {number} [options.yearDays=365] - 一年的天数。
955
+ * @param {number} [options.monthDays=30] - 一月的天数。
956
+ * @returns {DurationObject} 时间持续对象
957
+ * @throws {TypeError} 当 seconds 不是有效数字
958
+ * @throws {RangeError} 当 seconds 为负数
959
+ * @throws {RangeError} 当 yearDays 或 monthDays 不是正整数
960
+ *
961
+ * @example
962
+ * // 基本用法
963
+ * second2Duration(42070000.5);
964
+ * // 返回: { years: 1, months: 4, days: 1, hours: 22, minutes: 6, seconds: 40, milliseconds: 500 }
913
965
  */
914
- function formatDurationMaxDay(totalSeconds, options = {}) {
915
- return formatDuration(totalSeconds, { ...options, maxUnit: "day" });
966
+ function second2Duration(seconds, options = { yearDays: 365, monthDays: 30 }) {
967
+ if (typeof seconds !== "number" || isNaN(seconds)) {
968
+ throw new TypeError("seconds must be a valid number");
969
+ }
970
+ if (seconds < 0) {
971
+ throw new RangeError("seconds must be a non-negative number");
972
+ }
973
+ return millisecond2Duration(seconds * 1000, options);
916
974
  }
917
975
 
918
976
  /**
919
- * 快捷调用 {@link formatDuration},最大单位到“小时”。
920
- *
921
- * @param {number} totalSeconds
922
- * @param {Omit<Parameters<typeof formatDuration>[1],'maxUnit'>} [options]
923
- * @returns {string}
977
+ * 将秒转换为时间持续对象(最大单位为天)。
978
+ * @param {number} seconds - 秒数(非负整数)
979
+ * @returns {DurationMaxDayObject} 包含天、小时、分钟、秒、毫秒的时间持续对象
980
+ * @throws {TypeError} 当 seconds 不是有效数字时抛出
981
+ * @throws {RangeError} 当 seconds 为负数时抛出
982
+ * @example
983
+ * // 返回 { days: 486, hours: 22, minutes: 6, seconds: 40, milliseconds: 500 }
984
+ * second2DurationMaxDay(42070000.5);
985
+ */
986
+ function second2DurationMaxDay(seconds) {
987
+ if (typeof seconds !== "number" || isNaN(seconds)) {
988
+ throw new TypeError("seconds must be a valid number");
989
+ }
990
+ if (seconds < 0) {
991
+ throw new RangeError("seconds must be a non-negative number");
992
+ }
993
+ return millisecond2DurationMaxDay(seconds * 1000);
994
+ }
995
+
996
+ /**
997
+ * 将秒转换为时间持续对象(最大单位为小时)。
998
+ * @param {number} seconds - 秒数(非负整数)
999
+ * @returns {DurationMaxHourObject} 包含小时、分钟、秒、毫秒的时间持续对象
1000
+ * @throws {TypeError} 当 seconds 不是有效数字时抛出
1001
+ * @throws {RangeError} 当 seconds 为负数时抛出
1002
+ * @example
1003
+ * // 返回 { hours: 11686, minutes: 6, seconds: 40, milliseconds: 500 }
1004
+ * second2DurationMaxHour(42070000.5);
924
1005
  */
925
- function formatDurationMaxHour(totalSeconds, options = {}) {
926
- return formatDuration(totalSeconds, { ...options, maxUnit: "hour" });
1006
+ function second2DurationMaxHour(seconds) {
1007
+ if (typeof seconds !== "number" || isNaN(seconds)) {
1008
+ throw new TypeError("seconds must be a valid number");
1009
+ }
1010
+ if (seconds < 0) {
1011
+ throw new RangeError("seconds must be a non-negative number");
1012
+ }
1013
+ return millisecond2DurationMaxHour(seconds * 1000);
927
1014
  }
928
1015
 
1016
+ //#endregion
1017
+
929
1018
  /**
930
1019
  * 根据小时数返回对应的时间段名称。
931
1020
  *
@@ -2012,7 +2101,6 @@ exports.MyEvent_CrossPagePlugin = MyEvent_CrossPagePlugin;
2012
2101
  exports.MyId = MyId;
2013
2102
  exports.WebSocketManager = WebSocketManager;
2014
2103
  exports.assignExisting = assignExisting;
2015
- exports.calcTimeDifference = calcTimeDifference;
2016
2104
  exports.debounce = debounce;
2017
2105
  exports.deepCloneByJSON = deepCloneByJSON;
2018
2106
  exports.downloadByBlob = downloadByBlob;
@@ -2024,9 +2112,6 @@ exports.extractFullyCheckedKeys = extractFullyCheckedKeys;
2024
2112
  exports.fetchOrDownloadByUrl = fetchOrDownloadByUrl;
2025
2113
  exports.findObjAttrValueById = findObjAttrValueById;
2026
2114
  exports.flatCompleteTree2NestedTree = flatCompleteTree2NestedTree;
2027
- exports.formatDuration = formatDuration;
2028
- exports.formatDurationMaxDay = formatDurationMaxDay;
2029
- exports.formatDurationMaxHour = formatDurationMaxHour;
2030
2115
  exports.formatTimeForLocale = formatTimeForLocale;
2031
2116
  exports.getAllSearchParams = getAllSearchParams;
2032
2117
  exports.getDataType = getDataType;
@@ -2041,6 +2126,9 @@ exports.isFunction = isFunction;
2041
2126
  exports.isNonEmptyString = isNonEmptyString;
2042
2127
  exports.isPlainObject = isPlainObject;
2043
2128
  exports.isPromise = isPromise;
2129
+ exports.millisecond2Duration = millisecond2Duration;
2130
+ exports.millisecond2DurationMaxDay = millisecond2DurationMaxDay;
2131
+ exports.millisecond2DurationMaxHour = millisecond2DurationMaxHour;
2044
2132
  exports.moveItem = moveItem;
2045
2133
  exports.nestedTree2IdMap = nestedTree2IdMap;
2046
2134
  exports.pcmToWavBlob = pcmToWavBlob;
@@ -2050,6 +2138,9 @@ exports.randomHan = randomHan;
2050
2138
  exports.randomHanOrEn = randomHanOrEn;
2051
2139
  exports.randomIntInRange = randomIntInRange;
2052
2140
  exports.readBlobAsText = readBlobAsText;
2141
+ exports.second2Duration = second2Duration;
2142
+ exports.second2DurationMaxDay = second2DurationMaxDay;
2143
+ exports.second2DurationMaxHour = second2DurationMaxHour;
2053
2144
  exports.shuffle = shuffle;
2054
2145
  exports.throttle = throttle;
2055
2146
  exports.toDate = toDate;