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