From 19f7ff2a46e80dd1da00b1fc5495e61233091822 Mon Sep 17 00:00:00 2001 From: Pedro Rossato Date: Fri, 30 Oct 2026 16:39:12 -0300 Subject: [PATCH] Read built-in number format 17 (mmm-yy) as DateTime The built-in number format 17 was declared with typeof(TimeSpan). ConvertValueByStyleFormat only handles DateTime? and TimeSpan?, so cells using it were returned as the raw OADate serial. Declare it as typeof(DateTime?), like the other built-in date formats (14, 15, 16 and 22). Fixes #1034 --- src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs | 2 +- .../Issues/MiniExcelGithubIssuesTests.cs | 33 +++++++++++++++++++ .../Utils/SheetHelper.cs | 15 +++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs b/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs index 40a268fb..29bf6aa1 100644 --- a/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs +++ b/src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs @@ -213,7 +213,7 @@ internal static async Task CreateAsync(OpenXmlZip zip, Cancellati { 14, new NumberFormatString("d/m/yyyy", typeof(DateTime?)) }, { 15, new NumberFormatString("d-mmm-yy", typeof(DateTime?)) }, { 16, new NumberFormatString("d-mmm", typeof(DateTime?)) }, - { 17, new NumberFormatString("mmm-yy", typeof(TimeSpan)) }, + { 17, new NumberFormatString("mmm-yy", typeof(DateTime?)) }, { 18, new NumberFormatString("h:mm AM/PM", typeof(TimeSpan?)) }, { 19, new NumberFormatString("h:mm:ss AM/PM", typeof(TimeSpan?)) }, { 20, new NumberFormatString("h:mm", typeof(TimeSpan?)) }, diff --git a/tests/MiniExcel.OpenXml.Tests/Issues/MiniExcelGithubIssuesTests.cs b/tests/MiniExcel.OpenXml.Tests/Issues/MiniExcelGithubIssuesTests.cs index ad646ad3..7eb559ac 100644 --- a/tests/MiniExcel.OpenXml.Tests/Issues/MiniExcelGithubIssuesTests.cs +++ b/tests/MiniExcel.OpenXml.Tests/Issues/MiniExcelGithubIssuesTests.cs @@ -3284,4 +3284,37 @@ public void TestIssue863_MergeSameCells() Assert.Equal("C3:C4", mergedCells[1]); Assert.Equal("A7:A8", mergedCells[2]); } + + // https://github.com/mini-software/MiniExcel/issues/1034 + [Theory] + [InlineData(14)] + [InlineData(15)] + [InlineData(16)] + [InlineData(17)] + [InlineData(22)] + public void QueryReadsBuiltInDateFormatsAsDateTime(int numFmtId) + { + using var path = AutoDeletingPath.Create(); + _excelExporter.Export(path.FilePath, new[] { new { Value = "control" } }); + SheetHelper.ReplaceStylesXml(path.FilePath, $""" + + + + + + + + """); + SheetHelper.ReplaceFirstSheetXml(path.FilePath, """ + + + + 46327 + + """); + + var row = _excelImporter.Query(path.FilePath).Single(); + + Assert.Equal(new DateTime(2026, 11, 1), (object)row.A); + } } diff --git a/tests/MiniExcel.OpenXml.Tests/Utils/SheetHelper.cs b/tests/MiniExcel.OpenXml.Tests/Utils/SheetHelper.cs index 43780704..28c77c21 100644 --- a/tests/MiniExcel.OpenXml.Tests/Utils/SheetHelper.cs +++ b/tests/MiniExcel.OpenXml.Tests/Utils/SheetHelper.cs @@ -88,6 +88,21 @@ internal static void ReplaceFirstSheetXml(string path, string worksheetXml) writer.Write(worksheetXml); } + internal static void ReplaceStylesXml(string path, string stylesXml) + { + using var stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite); + using var archive = new ZipArchive(stream, ZipArchiveMode.Update, false, Encoding.UTF8); + var styles = archive.Entries.Single(w => + w.FullName.Equals("xl/styles.xml", StringComparison.OrdinalIgnoreCase) || + w.FullName.Equals("/xl/styles.xml", StringComparison.OrdinalIgnoreCase)); + var entryName = styles.FullName; + styles.Delete(); + + var replacement = archive.CreateEntry(entryName); + using var writer = new StreamWriter(replacement.Open(), new UTF8Encoding(false)); + writer.Write(stylesXml); + } + internal static string? GetFirstSheetDimensionRefValue(string path) { var ns = new XmlNamespaceManager(new NameTable());