@cj-tech-master/excelts 1.4.1 → 1.4.3

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * @cj-tech-master/excelts v1.4.1
2
+ * @cj-tech-master/excelts v1.4.3
3
3
  * TypeScript Excel Workbook Manager - Read and Write xlsx and csv Files.
4
4
  * (c) 2025 cjnoname
5
5
  * Released under the MIT License
@@ -5876,7 +5876,7 @@ var ExcelTS = (function(exports) {
5876
5876
  if (isUndefined$2(ctx.colors)) ctx.colors = false;
5877
5877
  if (isUndefined$2(ctx.customInspect)) ctx.customInspect = true;
5878
5878
  if (ctx.colors) ctx.stylize = stylizeWithColor;
5879
- return formatValue(ctx, obj, ctx.depth);
5879
+ return formatValue$1(ctx, obj, ctx.depth);
5880
5880
  }
5881
5881
  exports.inspect = inspect$1;
5882
5882
  inspect$1.colors = {
@@ -5919,10 +5919,10 @@ var ExcelTS = (function(exports) {
5919
5919
  });
5920
5920
  return hash$4;
5921
5921
  }
5922
- function formatValue(ctx, value, recurseTimes) {
5922
+ function formatValue$1(ctx, value, recurseTimes) {
5923
5923
  if (ctx.customInspect && value && isFunction$4(value.inspect) && value.inspect !== exports.inspect && !(value.constructor && value.constructor.prototype === value)) {
5924
5924
  var ret = value.inspect(recurseTimes, ctx);
5925
- if (!isString$1(ret)) ret = formatValue(ctx, ret, recurseTimes);
5925
+ if (!isString$1(ret)) ret = formatValue$1(ctx, ret, recurseTimes);
5926
5926
  return ret;
5927
5927
  }
5928
5928
  var primitive = formatPrimitive(ctx, value);
@@ -5990,8 +5990,8 @@ var ExcelTS = (function(exports) {
5990
5990
  else if (desc$1.set) str = ctx.stylize("[Setter]", "special");
5991
5991
  if (!hasOwnProperty$3(visibleKeys, key$1)) name = "[" + key$1 + "]";
5992
5992
  if (!str) if (ctx.seen.indexOf(desc$1.value) < 0) {
5993
- if (isNull$1(recurseTimes)) str = formatValue(ctx, desc$1.value, null);
5994
- else str = formatValue(ctx, desc$1.value, recurseTimes - 1);
5993
+ if (isNull$1(recurseTimes)) str = formatValue$1(ctx, desc$1.value, null);
5994
+ else str = formatValue$1(ctx, desc$1.value, recurseTimes - 1);
5995
5995
  if (str.indexOf("\n") > -1) if (array) str = str.split("\n").map(function(line) {
5996
5996
  return " " + line;
5997
5997
  }).join("\n").slice(2);
@@ -45096,7 +45096,7 @@ ${XMLNS_NAMESPACE}.`);
45096
45096
  /**
45097
45097
  * Check if format is a date format
45098
45098
  */
45099
- function isDateFormat(fmt) {
45099
+ function isDateFormat$1(fmt) {
45100
45100
  const cleaned = fmt.replace(/\[[^\]]*\]/g, "");
45101
45101
  return /[ymdhs]/i.test(cleaned) && !/^[#0.,E%$\s()\-+]+$/i.test(cleaned);
45102
45102
  }
@@ -45166,16 +45166,16 @@ ${XMLNS_NAMESPACE}.`);
45166
45166
  * @param fmt Format string
45167
45167
  */
45168
45168
  function formatDate(serial, fmt) {
45169
+ const timeOfDay = Math.round(serial * 86400) % 86400;
45170
+ const hours = Math.floor(timeOfDay / 3600);
45171
+ const minutes = Math.floor(timeOfDay % 3600 / 60);
45172
+ const seconds = timeOfDay % 60;
45169
45173
  const date = excelToDate(serial, false);
45170
- const year = date.getFullYear();
45171
- const month = date.getMonth();
45172
- const day = date.getDate();
45173
- const hours = date.getHours();
45174
- const minutes = date.getMinutes();
45175
- const seconds = date.getSeconds();
45176
- const dayOfWeek = date.getDay();
45177
- const totalSeconds = serial * 86400;
45178
- const fractionalSeconds = totalSeconds - Math.floor(totalSeconds);
45174
+ const year = date.getUTCFullYear();
45175
+ const month = date.getUTCMonth();
45176
+ const day = date.getUTCDate();
45177
+ const dayOfWeek = date.getUTCDay();
45178
+ const fractionalSeconds = serial * 86400 - Math.floor(serial * 86400);
45179
45179
  const hasAmPm = /AM\/PM|A\/P/i.test(fmt);
45180
45180
  const isPm = hours >= 12;
45181
45181
  const hours12 = hours % 12 || 12;
@@ -45510,7 +45510,7 @@ ${XMLNS_NAMESPACE}.`);
45510
45510
  cleanFmt = processPlaceholders(cleanFmt);
45511
45511
  cleanFmt = processQuotedText(cleanFmt);
45512
45512
  if (/\[[hms]+\]/i.test(cleanFmt)) return formatElapsedTime(numVal, cleanFmt);
45513
- if (isDateFormat(cleanFmt)) return formatDate(numVal, cleanFmt);
45513
+ if (isDateFormat$1(cleanFmt)) return formatDate(numVal, cleanFmt);
45514
45514
  if (cleanFmt.includes("%")) return formatPercentage(numVal, cleanFmt);
45515
45515
  if (/E[+-]?/i.test(cleanFmt)) return formatScientific(numVal, cleanFmt);
45516
45516
  if (/\?+\s*\/\s*[\d?]+/.test(cleanFmt)) return formatFraction(numVal, cleanFmt);
@@ -45542,16 +45542,78 @@ ${XMLNS_NAMESPACE}.`);
45542
45542
  * Provides convenient helper functions for common spreadsheet operations
45543
45543
  */
45544
45544
  /**
45545
+ * Convert a Date object back to Excel serial number without timezone issues.
45546
+ * This reverses the excelToDate conversion exactly.
45547
+ * excelToDate uses: new Date(Math.round((v - 25569) * 24 * 3600 * 1000))
45548
+ * So we reverse it: (date.getTime() / (24 * 3600 * 1000)) + 25569
45549
+ */
45550
+ function dateToExcelSerial(d) {
45551
+ return d.getTime() / (24 * 3600 * 1e3) + 25569;
45552
+ }
45553
+ /**
45554
+ * Check if format is a pure time format (no date components like y, m for month, d)
45555
+ * Time formats only contain: h, m (minutes in time context), s, AM/PM
45556
+ * Excludes elapsed time formats like [h]:mm:ss which should keep full serial number
45557
+ */
45558
+ function isTimeOnlyFormat(fmt) {
45559
+ const cleaned = fmt.replace(/"[^"]*"/g, "");
45560
+ if (/\[[hms]\]/i.test(cleaned)) return false;
45561
+ const withoutBrackets = cleaned.replace(/\[[^\]]*\]/g, "");
45562
+ const hasTimeComponents = /[hs]/i.test(withoutBrackets) || /AM\/PM|A\/P/i.test(withoutBrackets);
45563
+ if (/[yd]/i.test(withoutBrackets)) return false;
45564
+ if (/m/i.test(withoutBrackets) && !hasTimeComponents) return false;
45565
+ return hasTimeComponents;
45566
+ }
45567
+ /**
45568
+ * Check if format is a date format (contains y, d, or month-m)
45569
+ * Used to determine if dateFormat override should be applied
45570
+ */
45571
+ function isDateFormat(fmt) {
45572
+ const cleaned = fmt.replace(/"[^"]*"/g, "");
45573
+ if (/\[[hms]\]/i.test(cleaned)) return false;
45574
+ const withoutBrackets = cleaned.replace(/\[[^\]]*\]/g, "");
45575
+ if (/[yd]/i.test(withoutBrackets)) return true;
45576
+ if (/m/i.test(withoutBrackets)) {
45577
+ if (!(/[hs]/i.test(withoutBrackets) || /AM\/PM|A\/P/i.test(withoutBrackets))) return true;
45578
+ }
45579
+ return false;
45580
+ }
45581
+ /**
45582
+ * Format a value (Date, number, boolean, string) according to the given format
45583
+ * Handles timezone-independent conversion for Date objects
45584
+ * @param value - The value to format
45585
+ * @param fmt - The format string to use
45586
+ * @param dateFormat - Optional override format for date values (not applied to time or elapsed time formats)
45587
+ */
45588
+ function formatValue(value, fmt, dateFormat) {
45589
+ if (value instanceof Date) {
45590
+ let serial = dateToExcelSerial(value);
45591
+ if (isTimeOnlyFormat(fmt)) {
45592
+ serial = serial % 1;
45593
+ if (serial < 0) serial += 1;
45594
+ return format(fmt, serial);
45595
+ }
45596
+ return format(dateFormat && isDateFormat(fmt) ? dateFormat : fmt, serial);
45597
+ }
45598
+ return format(fmt, value);
45599
+ }
45600
+ /**
45545
45601
  * Get formatted display text for a cell value
45546
45602
  * Returns the value formatted according to the cell's numFmt
45547
- * This matches Excel's display exactly
45603
+ * This matches Excel's display exactly (timezone-independent)
45604
+ * @param cell - The cell to get display text for
45605
+ * @param dateFormat - Optional override format for date values
45548
45606
  */
45549
- function getCellDisplayText(cell) {
45607
+ function getCellDisplayText(cell, dateFormat) {
45550
45608
  const value = cell.value;
45551
45609
  const fmt = cell.numFmt || "General";
45552
45610
  if (value == null) return "";
45553
- if (value instanceof Date) return format(fmt, dateToExcel(value, false));
45554
- if (typeof value === "number" || typeof value === "boolean" || typeof value === "string") return format(fmt, value);
45611
+ if (value instanceof Date || typeof value === "number" || typeof value === "boolean" || typeof value === "string") return formatValue(value, fmt, dateFormat);
45612
+ if (typeof value === "object" && "formula" in value) {
45613
+ const result = value.result;
45614
+ if (result == null) return "";
45615
+ if (result instanceof Date || typeof result === "number" || typeof result === "boolean" || typeof result === "string") return formatValue(result, fmt, dateFormat);
45616
+ }
45555
45617
  return cell.text;
45556
45618
  }
45557
45619
  /**
@@ -45741,7 +45803,7 @@ ${XMLNS_NAMESPACE}.`);
45741
45803
  let isEmpty = true;
45742
45804
  for (let col = startCol; col <= endCol; col++) {
45743
45805
  const cell = worksheet.getCell(row, col);
45744
- const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
45806
+ const val = o.raw === false ? getCellDisplayText(cell, o.dateFormat).trim() : cell.value;
45745
45807
  if (val != null && val !== "") {
45746
45808
  rowData[col - startCol] = val;
45747
45809
  isEmpty = false;
@@ -45760,7 +45822,7 @@ ${XMLNS_NAMESPACE}.`);
45760
45822
  let isEmpty = true;
45761
45823
  for (let col = startCol; col <= endCol; col++) {
45762
45824
  const cell = worksheet.getCell(row, col);
45763
- const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
45825
+ const val = o.raw === false ? getCellDisplayText(cell, o.dateFormat).trim() : cell.value;
45764
45826
  const key$1 = encodeCol(col - 1);
45765
45827
  if (val != null && val !== "") {
45766
45828
  rowData[key$1] = val;
@@ -45781,7 +45843,7 @@ ${XMLNS_NAMESPACE}.`);
45781
45843
  const colIdx = col - startCol;
45782
45844
  const key$1 = headerOpt[colIdx] ?? `__EMPTY_${colIdx}`;
45783
45845
  const cell = worksheet.getCell(row, col);
45784
- const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
45846
+ const val = o.raw === false ? getCellDisplayText(cell, o.dateFormat).trim() : cell.value;
45785
45847
  if (val != null && val !== "") {
45786
45848
  rowData[key$1] = val;
45787
45849
  isEmpty = false;
@@ -45810,7 +45872,7 @@ ${XMLNS_NAMESPACE}.`);
45810
45872
  let isEmpty = true;
45811
45873
  for (let col = startCol; col <= endCol; col++) {
45812
45874
  const cell = worksheet.getCell(row, col);
45813
- const val = o.raw === false ? getCellDisplayText(cell).trim() : cell.value;
45875
+ const val = o.raw === false ? getCellDisplayText(cell, o.dateFormat).trim() : cell.value;
45814
45876
  const key$1 = headers[col - startCol];
45815
45877
  if (val != null && val !== "") {
45816
45878
  rowData[key$1] = val;