mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Custom DateTime format (#616)
* - goto/jumpmark * + generate numberformats * + `FormatId` * ~ first working shot * ~ assign responsibilities correctly * ~ fix last test issues * + extend tests * ~ clean up * ~ simplify `DateOnly` handling * + `DateOnly` to Tests * Update ExcelOpenXmlSheetWriter.cs Update GenerateSheetByIDataReader * + datetime format for async part --------- Co-authored-by: Gary Jia <35099424+jiaguangli@users.noreply.github.com>
This commit is contained in:
parent
12bb1c0028
commit
00a445c6bd
@ -9,6 +9,8 @@ namespace MiniExcelLibs.Attributes
|
||||
private int _index = -1;
|
||||
private string _xName;
|
||||
|
||||
internal int FormatId { get; set; } = -1;
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public string[] Aliases { get; set; }
|
||||
@ -52,6 +54,7 @@ namespace MiniExcelLibs.Attributes
|
||||
public class DynamicExcelColumn : ExcelColumnAttribute
|
||||
{
|
||||
public string Key { get; set; }
|
||||
|
||||
public DynamicExcelColumn(string key)
|
||||
{
|
||||
Key = key;
|
||||
|
@ -1,4 +1,9 @@
|
||||
using MiniExcelLibs.OpenXml.Models;
|
||||
using MiniExcelLibs.Attributes;
|
||||
using MiniExcelLibs.OpenXml.Models;
|
||||
using MiniExcelLibs.Utils;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MiniExcelLibs.OpenXml.Constants
|
||||
{
|
||||
@ -52,10 +57,21 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
</x:cellXfs>
|
||||
</x:styleSheet>";
|
||||
|
||||
internal static readonly string DefaultStylesXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
#region StyleSheet
|
||||
|
||||
private const int startUpNumFmts = 1;
|
||||
private const string NumFmtsToken = "{{numFmts}}";
|
||||
private const string NumFmtsCountToken = "{{numFmtCount}}";
|
||||
|
||||
private const int startUpCellXfs = 5;
|
||||
private const string cellXfsToken = "{{cellXfs}}";
|
||||
private const string cellXfsCountToken = "{{cellXfsCount}}";
|
||||
|
||||
internal static readonly string DefaultStylesXml = $@"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<x:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||
<x:numFmts count=""1"">
|
||||
<x:numFmts count=""{NumFmtsCountToken}"">
|
||||
<x:numFmt numFmtId=""0"" formatCode="""" />
|
||||
{NumFmtsToken}
|
||||
</x:numFmts>
|
||||
<x:fonts count=""2"">
|
||||
<x:font>
|
||||
@ -133,7 +149,7 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
<x:protection locked=""1"" hidden=""0"" />
|
||||
</x:xf>
|
||||
</x:cellStyleXfs>
|
||||
<x:cellXfs count=""4"">
|
||||
<x:cellXfs count=""{cellXfsCountToken}"">
|
||||
<x:xf></x:xf>
|
||||
<x:xf numFmtId=""0"" fontId=""1"" fillId=""2"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""0"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||
<x:alignment horizontal=""left"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||
@ -150,12 +166,15 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyBorder=""1"" applyAlignment=""1"">
|
||||
<x:alignment horizontal=""fill""/>
|
||||
</x:xf>
|
||||
{cellXfsToken}
|
||||
</x:cellXfs>
|
||||
<x:cellStyles count=""1"">
|
||||
<x:cellStyle name=""Normal"" xfId=""0"" builtinId=""0"" />
|
||||
</x:cellStyles>
|
||||
</x:styleSheet>";
|
||||
|
||||
#endregion
|
||||
|
||||
internal static readonly string DefaultWorkbookXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||
<x:workbook xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""
|
||||
xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||
@ -231,5 +250,52 @@ namespace MiniExcelLibs.OpenXml.Constants
|
||||
|
||||
internal static string Sheet(SheetDto sheetDto, int sheetId)
|
||||
=> $@"<x:sheet name=""{ExcelOpenXmlUtils.EncodeXML(sheetDto.Name)}"" sheetId=""{sheetId}""{(string.IsNullOrWhiteSpace(sheetDto.State) ? string.Empty : $" state=\"{sheetDto.State}\"")} r:id=""{sheetDto.ID}"" />";
|
||||
|
||||
internal static string SetupStyleXml(string styleXml, ICollection<ExcelColumnAttribute> columns)
|
||||
{
|
||||
const int numFmtIndex = 166;
|
||||
|
||||
var sb = new StringBuilder(styleXml);
|
||||
var columnsToApply = GenerateStyleIds(columns);
|
||||
|
||||
var numFmts = columnsToApply.Select((x, i) =>
|
||||
{
|
||||
return new
|
||||
{
|
||||
numFmt =
|
||||
$@"<x:numFmt numFmtId=""{numFmtIndex + i}"" formatCode=""{x.Format}"" />",
|
||||
|
||||
cellXfs =
|
||||
$@"<x:xf numFmtId=""{numFmtIndex + i}"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||
<x:protection locked=""1"" hidden=""0"" />
|
||||
</x:xf>"
|
||||
};
|
||||
}).ToArray();
|
||||
|
||||
sb.Replace(NumFmtsToken, string.Join(string.Empty, numFmts.Select(x => x.numFmt)));
|
||||
sb.Replace(NumFmtsCountToken, (startUpNumFmts + numFmts.Length).ToString());
|
||||
|
||||
sb.Replace(cellXfsToken, string.Join(string.Empty, numFmts.Select(x => x.cellXfs)));
|
||||
sb.Replace(cellXfsCountToken, (5 + numFmts.Length).ToString());
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static IEnumerable<ExcelColumnAttribute> GenerateStyleIds(ICollection<ExcelColumnAttribute> dynamicColumns)
|
||||
{
|
||||
if (dynamicColumns == null)
|
||||
yield break;
|
||||
|
||||
int index = 0;
|
||||
foreach (var g in dynamicColumns?.Where(x => !string.IsNullOrWhiteSpace(x.Format) && new ExcelNumberFormat(x.Format).IsValid).GroupBy(x => x.Format))
|
||||
{
|
||||
foreach (var col in g)
|
||||
col.FormatId = startUpCellXfs + index;
|
||||
|
||||
yield return g.First();
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
await CreateZipEntryAsync(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken);
|
||||
await CreateZipEntryAsync(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString, cancellationToken);
|
||||
await GenerateStylesXmlAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private async Task CreateSheetXmlAsync(object value, string sheetPath, CancellationToken cancellationToken)
|
||||
@ -47,9 +48,9 @@ namespace MiniExcelLibs.OpenXml
|
||||
if (value == null)
|
||||
{
|
||||
await WriteEmptySheetAsync(writer);
|
||||
goto End; //for re-using code
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//DapperRow
|
||||
|
||||
switch (value)
|
||||
@ -67,7 +68,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
throw new NotImplementedException($"Type {value.GetType().FullName} is not implemented. Please open an issue.");
|
||||
}
|
||||
}
|
||||
End: //for re-using code
|
||||
}
|
||||
_zipDictionary.Add(sheetPath, new ZipPackageInfo(entry, ExcelContentTypes.Worksheet));
|
||||
}
|
||||
|
||||
@ -455,8 +456,6 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
await AddFilesToZipAsync(cancellationToken);
|
||||
|
||||
await GenerateStylesXmlAsync(cancellationToken);
|
||||
|
||||
await GenerateDrawinRelXmlAsync(cancellationToken);
|
||||
|
||||
await GenerateDrawingXmlAsync(cancellationToken);
|
||||
@ -479,7 +478,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
/// </summary>
|
||||
private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var styleXml = GetStylesXml();
|
||||
var styleXml = GetStylesXml(_configuration.DynamicColumns);
|
||||
|
||||
await CreateZipEntryAsync(
|
||||
ExcelFileNames.Styles,
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.Attributes;
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.OpenXml.Models;
|
||||
using MiniExcelLibs.Utils;
|
||||
using MiniExcelLibs.Zip;
|
||||
@ -108,6 +109,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
if (dynamicColumn.Format != null)
|
||||
{
|
||||
prop.ExcelFormat = dynamicColumn.Format;
|
||||
prop.ExcelFormatId = dynamicColumn.FormatId;
|
||||
}
|
||||
|
||||
if (dynamicColumn.Aliases != null)
|
||||
@ -158,14 +160,26 @@ namespace MiniExcelLibs.OpenXml
|
||||
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(str));
|
||||
}
|
||||
|
||||
if (columnInfo?.ExcelFormat != null && value is IFormattable formattableValue)
|
||||
var type = GetValueType(value, columnInfo);
|
||||
|
||||
|
||||
if (columnInfo?.ExcelFormat != null && columnInfo?.ExcelFormatId == -1 && value is IFormattable formattableValue)
|
||||
{
|
||||
var formattedStr = formattableValue.ToString(columnInfo.ExcelFormat, _configuration.Culture);
|
||||
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(formattedStr));
|
||||
}
|
||||
|
||||
var type = GetValueType(value, columnInfo);
|
||||
if (type == typeof(DateTime))
|
||||
{
|
||||
return GetDateTimeValue((DateTime)value, columnInfo);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
if (type == typeof(DateOnly))
|
||||
{
|
||||
return GetDateTimeValue(((DateOnly)value).ToDateTime(new TimeOnly()), columnInfo);
|
||||
}
|
||||
#endif
|
||||
if (type.IsEnum)
|
||||
{
|
||||
var description = CustomPropertyHelper.DescriptionAttr(type, value);
|
||||
@ -193,33 +207,6 @@ namespace MiniExcelLibs.OpenXml
|
||||
return Tuple.Create("4", "str", ExcelOpenXmlUtils.EncodeXML(base64));
|
||||
}
|
||||
|
||||
if (type == typeof(DateTime))
|
||||
{
|
||||
return GetDateTimeValue(value, columnInfo);
|
||||
}
|
||||
|
||||
#if NET6_0_OR_GREATER
|
||||
if (type == typeof(DateOnly))
|
||||
{
|
||||
if (_configuration.Culture != CultureInfo.InvariantCulture)
|
||||
{
|
||||
var cellValue = ((DateOnly)value).ToString(_configuration.Culture);
|
||||
return Tuple.Create("2", "str", cellValue);
|
||||
}
|
||||
|
||||
if (columnInfo == null || columnInfo.ExcelFormat == null)
|
||||
{
|
||||
var oaDate = CorrectDateTimeValue((DateTime)value);
|
||||
var cellValue = oaDate.ToString(CultureInfo.InvariantCulture);
|
||||
return Tuple.Create<string, string, string>("3", null, cellValue);
|
||||
}
|
||||
|
||||
// TODO: now it'll lose date type information
|
||||
var formattedCellValue = ((DateOnly)value).ToString(columnInfo.ExcelFormat, _configuration.Culture);
|
||||
return Tuple.Create("2", "str", formattedCellValue);
|
||||
}
|
||||
#endif
|
||||
|
||||
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(value.ToString()));
|
||||
}
|
||||
|
||||
@ -325,24 +312,21 @@ namespace MiniExcelLibs.OpenXml
|
||||
return base64;
|
||||
}
|
||||
|
||||
private Tuple<string, string, string> GetDateTimeValue(object value, ExcelColumnInfo columnInfo)
|
||||
private Tuple<string, string, string> GetDateTimeValue(DateTime value, ExcelColumnInfo columnInfo)
|
||||
{
|
||||
string cellValue = null;
|
||||
if (_configuration.Culture != CultureInfo.InvariantCulture)
|
||||
{
|
||||
var cellValue = ((DateTime)value).ToString(_configuration.Culture);
|
||||
cellValue = (value).ToString(_configuration.Culture);
|
||||
return Tuple.Create("2", "str", cellValue);
|
||||
}
|
||||
|
||||
var oaDate = CorrectDateTimeValue(value);
|
||||
cellValue = oaDate.ToString(CultureInfo.InvariantCulture);
|
||||
if (columnInfo == null || columnInfo.ExcelFormat == null)
|
||||
{
|
||||
var oaDate = CorrectDateTimeValue((DateTime)value);
|
||||
var cellValue = oaDate.ToString(CultureInfo.InvariantCulture);
|
||||
return Tuple.Create<string, string, string>("3", null, cellValue);
|
||||
}
|
||||
|
||||
// TODO: now it'll lose date type information
|
||||
var formattedCellValue = ((DateTime)value).ToString(columnInfo.ExcelFormat, _configuration.Culture);
|
||||
return Tuple.Create("2", "str", formattedCellValue);
|
||||
else
|
||||
return Tuple.Create(columnInfo.ExcelFormatId.ToString(), (string)null, cellValue);
|
||||
}
|
||||
|
||||
private static double CorrectDateTimeValue(DateTime value)
|
||||
@ -375,14 +359,14 @@ namespace MiniExcelLibs.OpenXml
|
||||
return dimensionRef;
|
||||
}
|
||||
|
||||
private string GetStylesXml()
|
||||
private string GetStylesXml(ICollection<ExcelColumnAttribute> columns)
|
||||
{
|
||||
switch (_configuration.TableStyles)
|
||||
{
|
||||
case TableStyles.None:
|
||||
return ExcelXml.NoneStylesXml;
|
||||
return ExcelXml.SetupStyleXml(ExcelXml.NoneStylesXml, columns);
|
||||
case TableStyles.Default:
|
||||
return ExcelXml.DefaultStylesXml;
|
||||
return ExcelXml.SetupStyleXml(ExcelXml.DefaultStylesXml, columns);
|
||||
default:
|
||||
return string.Empty;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.Attributes;
|
||||
using MiniExcelLibs.OpenXml.Constants;
|
||||
using MiniExcelLibs.OpenXml.Models;
|
||||
using MiniExcelLibs.Utils;
|
||||
using MiniExcelLibs.Zip;
|
||||
@ -68,6 +69,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
CreateZipEntry(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels);
|
||||
CreateZipEntry(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString);
|
||||
GenerateStylesXml();
|
||||
}
|
||||
|
||||
private void CreateSheetXml(object value, string sheetPath)
|
||||
@ -79,9 +81,9 @@ namespace MiniExcelLibs.OpenXml
|
||||
if (value == null)
|
||||
{
|
||||
WriteEmptySheet(writer);
|
||||
goto End; //for re-using code
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
//DapperRow
|
||||
|
||||
if (value is IDataReader)
|
||||
@ -101,7 +103,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
throw new NotImplementedException($"Type {value.GetType().FullName} is not implemented. Please open an issue.");
|
||||
}
|
||||
}
|
||||
End: //for re-using code
|
||||
}
|
||||
_zipDictionary.Add(sheetPath, new ZipPackageInfo(entry, ExcelContentTypes.Worksheet));
|
||||
}
|
||||
|
||||
@ -151,7 +153,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
for (int i = 0; i < fieldCount; i++)
|
||||
{
|
||||
var cellValue = reader.GetValue(i);
|
||||
WriteCell(writer, yIndex, xIndex, cellValue, columnInfo: null);
|
||||
WriteCell(writer, yIndex, xIndex, cellValue, columnInfo: props?.FirstOrDefault(x => x?.ExcelColumnIndex == xIndex - 1));
|
||||
xIndex++;
|
||||
}
|
||||
writer.Write(WorksheetXml.EndRow);
|
||||
@ -356,7 +358,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
for (int j = 0; j < value.Columns.Count; j++)
|
||||
{
|
||||
var cellValue = value.Rows[i][j];
|
||||
WriteCell(writer, yIndex, xIndex, cellValue, columnInfo: null);
|
||||
WriteCell(writer, yIndex, xIndex, cellValue, columnInfo: props?.FirstOrDefault(x => x?.ExcelColumnIndex == xIndex - 1));
|
||||
xIndex++;
|
||||
}
|
||||
writer.Write(WorksheetXml.EndRow);
|
||||
@ -484,8 +486,6 @@ namespace MiniExcelLibs.OpenXml
|
||||
{
|
||||
AddFilesToZip();
|
||||
|
||||
GenerateStylesXml();
|
||||
|
||||
GenerateDrawinRelXml();
|
||||
|
||||
GenerateDrawingXml();
|
||||
@ -508,7 +508,7 @@ namespace MiniExcelLibs.OpenXml
|
||||
/// </summary>
|
||||
private void GenerateStylesXml()
|
||||
{
|
||||
var styleXml = GetStylesXml();
|
||||
var styleXml = GetStylesXml(_configuration.DynamicColumns);
|
||||
CreateZipEntry(ExcelFileNames.Styles, ExcelContentTypes.Styles, styleXml);
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
public double? ExcelColumnWidth { get; internal set; }
|
||||
public string ExcelIndexName { get; internal set; }
|
||||
public bool ExcelIgnore { get; internal set; }
|
||||
public int ExcelFormatId { get; internal set; }
|
||||
}
|
||||
|
||||
internal class ExcellSheetInfo
|
||||
@ -205,6 +206,7 @@
|
||||
ExcelIndexName = p.GetAttribute<ExcelColumnIndexAttribute>()?.ExcelXName ?? excelColumn?.IndexName,
|
||||
ExcelColumnWidth = p.GetAttribute<ExcelColumnWidthAttribute>()?.ExcelColumnWidth ?? excelColumn?.Width,
|
||||
ExcelFormat = excelFormat ?? excelColumn?.Format,
|
||||
ExcelFormatId = excelColumn?.FormatId ?? -1
|
||||
};
|
||||
}).Where(_ => _ != null);
|
||||
}
|
||||
@ -292,7 +294,10 @@
|
||||
p.Nullable = true;
|
||||
//p.ExcludeNullableType = item2[key]?.GetType();
|
||||
if (dynamicColumn.Format != null)
|
||||
{
|
||||
p.ExcelFormat = dynamicColumn.Format;
|
||||
p.ExcelFormatId = dynamicColumn.FormatId;
|
||||
}
|
||||
if (dynamicColumn.Aliases != null)
|
||||
p.ExcelColumnAliases = dynamicColumn.Aliases;
|
||||
if (dynamicColumn.IndexName != null)
|
||||
|
@ -309,7 +309,7 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
var rows = MiniExcel.Query(path, false).ToList();
|
||||
Assert.Equal("createdate", rows[0].A);
|
||||
Assert.Equal("2022-04-12", rows[1].A);
|
||||
Assert.Equal(new DateTime(2022, 04, 12), rows[1].A);
|
||||
Assert.Equal("name", rows[0].B);
|
||||
Assert.Equal("Jack", rows[1].B);
|
||||
Assert.Equal("Account Point", rows[0].C);
|
||||
@ -334,7 +334,7 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
var rows = MiniExcel.Query(path, false).ToList();
|
||||
Assert.Equal("createdate", rows[0].A);
|
||||
Assert.Equal("2022-04-12", rows[1].A);
|
||||
Assert.Equal(new DateTime(2022, 04, 12), rows[1].A);
|
||||
Assert.Equal("name", rows[0].B);
|
||||
Assert.Equal("Jack", rows[1].B);
|
||||
Assert.Equal("Account Point", rows[0].C);
|
||||
|
@ -1281,5 +1281,150 @@ namespace MiniExcelLibs.Tests
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingIDataReader()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
var dateTime = DateTime.Now;
|
||||
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||
var table = new DataTable();
|
||||
{
|
||||
table.Columns.Add("Column1", typeof(string));
|
||||
table.Columns.Add("Column2", typeof(int));
|
||||
table.Columns.Add("Column3", typeof(DateTime));
|
||||
table.Columns.Add("Column4", typeof(DateOnly));
|
||||
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||
}
|
||||
|
||||
var configuration = new OpenXmlConfiguration
|
||||
{
|
||||
DynamicColumns = new[]
|
||||
{
|
||||
new DynamicExcelColumn("Column1")
|
||||
{
|
||||
Name = "Name of something",
|
||||
Index = 0,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column2")
|
||||
{
|
||||
Name = "Its value",
|
||||
Index = 1,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column3")
|
||||
{
|
||||
Name = "Its Date",
|
||||
Index = 2,
|
||||
Width = 150,
|
||||
Format = "dd.mm.yyyy hh:mm:ss",
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
var reader = table.CreateDataReader();
|
||||
|
||||
await MiniExcel.SaveAsAsync(path, reader, configuration: configuration);
|
||||
|
||||
using (var stream = File.OpenRead(path))
|
||||
{
|
||||
var rows = stream.Query(useHeaderRow: true)
|
||||
.Select(x => (IDictionary<string, object>)x)
|
||||
.ToList();
|
||||
|
||||
Assert.Contains("Name of something", rows[0]);
|
||||
Assert.Contains("Its value", rows[0]);
|
||||
Assert.Contains("Its Date", rows[0]);
|
||||
Assert.Contains("Column4", rows[0]);
|
||||
Assert.Contains("Name of something", rows[1]);
|
||||
Assert.Contains("Its value", rows[1]);
|
||||
Assert.Contains("Its Date", rows[1]);
|
||||
Assert.Contains("Column4", rows[1]);
|
||||
|
||||
Assert.Equal("MiniExcel", rows[0]["Name of something"]);
|
||||
Assert.Equal(1D, rows[0]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[0]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[0]["Column4"]);
|
||||
Assert.Equal("Github", rows[1]["Name of something"]);
|
||||
Assert.Equal(2D, rows[1]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[1]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[1]["Column4"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTable()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
var dateTime = DateTime.Now;
|
||||
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||
var table = new DataTable();
|
||||
{
|
||||
table.Columns.Add("Column1", typeof(string));
|
||||
table.Columns.Add("Column2", typeof(int));
|
||||
table.Columns.Add("Column3", typeof(DateTime));
|
||||
table.Columns.Add("Column4", typeof(DateOnly));
|
||||
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||
}
|
||||
|
||||
var configuration = new OpenXmlConfiguration
|
||||
{
|
||||
DynamicColumns = new[]
|
||||
{
|
||||
new DynamicExcelColumn("Column1")
|
||||
{
|
||||
Name = "Name of something",
|
||||
Index = 0,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column2")
|
||||
{
|
||||
Name = "Its value",
|
||||
Index = 1,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column3")
|
||||
{
|
||||
Name = "Its Date",
|
||||
Index = 2,
|
||||
Width = 150,
|
||||
Format = "dd.mm.yyyy hh:mm:ss"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await MiniExcel.SaveAsAsync(path, table, configuration: configuration);
|
||||
|
||||
using (var stream = File.OpenRead(path))
|
||||
{
|
||||
var rows = stream.Query(useHeaderRow: true)
|
||||
.Select(x => (IDictionary<string, object>)x)
|
||||
.Select(x => (IDictionary<string, object>)x)
|
||||
.ToList();
|
||||
|
||||
Assert.Contains("Name of something", rows[0]);
|
||||
Assert.Contains("Its value", rows[0]);
|
||||
Assert.Contains("Its Date", rows[0]);
|
||||
Assert.Contains("Column4", rows[0]);
|
||||
Assert.Contains("Name of something", rows[1]);
|
||||
Assert.Contains("Its value", rows[1]);
|
||||
Assert.Contains("Its Date", rows[1]);
|
||||
Assert.Contains("Column4", rows[1]);
|
||||
|
||||
|
||||
Assert.Equal("MiniExcel", rows[0]["Name of something"]);
|
||||
Assert.Equal(1D, rows[0]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[0]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[0]["Column4"]);
|
||||
Assert.Equal("Github", rows[1]["Name of something"]);
|
||||
Assert.Equal(2D, rows[1]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[1]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[1]["Column4"]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1217,12 +1217,16 @@ namespace MiniExcelLibs.Tests
|
||||
public void DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingIDataReader()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
var dateTime = DateTime.Now;
|
||||
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||
var table = new DataTable();
|
||||
{
|
||||
table.Columns.Add("Column1", typeof(string));
|
||||
table.Columns.Add("Column2", typeof(int));
|
||||
table.Rows.Add("MiniExcel", 1);
|
||||
table.Rows.Add("Github", 2);
|
||||
table.Columns.Add("Column3", typeof(DateTime));
|
||||
table.Columns.Add("Column4", typeof(DateOnly));
|
||||
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||
}
|
||||
|
||||
var configuration = new OpenXmlConfiguration
|
||||
@ -1240,7 +1244,15 @@ namespace MiniExcelLibs.Tests
|
||||
Name = "Its value",
|
||||
Index = 1,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column3")
|
||||
{
|
||||
Name = "Its Date",
|
||||
Index = 2,
|
||||
Width = 150,
|
||||
Format = "dd.mm.yyyy hh:mm:ss",
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
var reader = table.CreateDataReader();
|
||||
@ -1255,13 +1267,21 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
Assert.Contains("Name of something", rows[0]);
|
||||
Assert.Contains("Its value", rows[0]);
|
||||
Assert.Contains("Its Date", rows[0]);
|
||||
Assert.Contains("Column4", rows[0]);
|
||||
Assert.Contains("Name of something", rows[1]);
|
||||
Assert.Contains("Its value", rows[1]);
|
||||
Assert.Contains("Its Date", rows[1]);
|
||||
Assert.Contains("Column4", rows[1]);
|
||||
|
||||
Assert.Equal("MiniExcel", rows[0]["Name of something"]);
|
||||
Assert.Equal(1D, rows[0]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[0]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[0]["Column4"]);
|
||||
Assert.Equal("Github", rows[1]["Name of something"]);
|
||||
Assert.Equal(2D, rows[1]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[1]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[1]["Column4"]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1269,12 +1289,16 @@ namespace MiniExcelLibs.Tests
|
||||
public void DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTable()
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||
var dateTime = DateTime.Now;
|
||||
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||
var table = new DataTable();
|
||||
{
|
||||
table.Columns.Add("Column1", typeof(string));
|
||||
table.Columns.Add("Column2", typeof(int));
|
||||
table.Rows.Add("MiniExcel", 1);
|
||||
table.Rows.Add("Github", 2);
|
||||
table.Columns.Add("Column3", typeof(DateTime));
|
||||
table.Columns.Add("Column4", typeof(DateOnly));
|
||||
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||
}
|
||||
|
||||
var configuration = new OpenXmlConfiguration
|
||||
@ -1292,6 +1316,13 @@ namespace MiniExcelLibs.Tests
|
||||
Name = "Its value",
|
||||
Index = 1,
|
||||
Width = 150
|
||||
},
|
||||
new DynamicExcelColumn("Column3")
|
||||
{
|
||||
Name = "Its Date",
|
||||
Index = 2,
|
||||
Width = 150,
|
||||
Format = "dd.mm.yyyy hh:mm:ss"
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1307,14 +1338,22 @@ namespace MiniExcelLibs.Tests
|
||||
|
||||
Assert.Contains("Name of something", rows[0]);
|
||||
Assert.Contains("Its value", rows[0]);
|
||||
Assert.Contains("Its Date", rows[0]);
|
||||
Assert.Contains("Column4", rows[0]);
|
||||
Assert.Contains("Name of something", rows[1]);
|
||||
Assert.Contains("Its value", rows[1]);
|
||||
Assert.Contains("Its Date", rows[1]);
|
||||
Assert.Contains("Column4", rows[1]);
|
||||
|
||||
|
||||
Assert.Equal("MiniExcel", rows[0]["Name of something"]);
|
||||
Assert.Equal(1D, rows[0]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[0]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[0]["Column4"]);
|
||||
Assert.Equal("Github", rows[1]["Name of something"]);
|
||||
Assert.Equal(2D, rows[1]["Its value"]);
|
||||
Assert.Equal(dateTime, (DateTime)rows[1]["Its Date"], TimeSpan.FromMilliseconds(10d));
|
||||
Assert.Equal(onlyDate.ToDateTime(TimeOnly.MinValue), (DateTime)rows[1]["Column4"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user