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 int _index = -1;
|
||||||
private string _xName;
|
private string _xName;
|
||||||
|
|
||||||
|
internal int FormatId { get; set; } = -1;
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public string[] Aliases { get; set; }
|
public string[] Aliases { get; set; }
|
||||||
@ -52,6 +54,7 @@ namespace MiniExcelLibs.Attributes
|
|||||||
public class DynamicExcelColumn : ExcelColumnAttribute
|
public class DynamicExcelColumn : ExcelColumnAttribute
|
||||||
{
|
{
|
||||||
public string Key { get; set; }
|
public string Key { get; set; }
|
||||||
|
|
||||||
public DynamicExcelColumn(string key)
|
public DynamicExcelColumn(string key)
|
||||||
{
|
{
|
||||||
Key = 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
|
namespace MiniExcelLibs.OpenXml.Constants
|
||||||
{
|
{
|
||||||
@ -52,10 +57,21 @@ namespace MiniExcelLibs.OpenXml.Constants
|
|||||||
</x:cellXfs>
|
</x:cellXfs>
|
||||||
</x:styleSheet>";
|
</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:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||||
<x:numFmts count=""1"">
|
<x:numFmts count=""{NumFmtsCountToken}"">
|
||||||
<x:numFmt numFmtId=""0"" formatCode="""" />
|
<x:numFmt numFmtId=""0"" formatCode="""" />
|
||||||
|
{NumFmtsToken}
|
||||||
</x:numFmts>
|
</x:numFmts>
|
||||||
<x:fonts count=""2"">
|
<x:fonts count=""2"">
|
||||||
<x:font>
|
<x:font>
|
||||||
@ -133,7 +149,7 @@ namespace MiniExcelLibs.OpenXml.Constants
|
|||||||
<x:protection locked=""1"" hidden=""0"" />
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
</x:xf>
|
</x:xf>
|
||||||
</x:cellStyleXfs>
|
</x:cellStyleXfs>
|
||||||
<x:cellXfs count=""4"">
|
<x:cellXfs count=""{cellXfsCountToken}"">
|
||||||
<x:xf></x:xf>
|
<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: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"" />
|
<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:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyBorder=""1"" applyAlignment=""1"">
|
||||||
<x:alignment horizontal=""fill""/>
|
<x:alignment horizontal=""fill""/>
|
||||||
</x:xf>
|
</x:xf>
|
||||||
|
{cellXfsToken}
|
||||||
</x:cellXfs>
|
</x:cellXfs>
|
||||||
<x:cellStyles count=""1"">
|
<x:cellStyles count=""1"">
|
||||||
<x:cellStyle name=""Normal"" xfId=""0"" builtinId=""0"" />
|
<x:cellStyle name=""Normal"" xfId=""0"" builtinId=""0"" />
|
||||||
</x:cellStyles>
|
</x:cellStyles>
|
||||||
</x:styleSheet>";
|
</x:styleSheet>";
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
internal static readonly string DefaultWorkbookXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
internal static readonly string DefaultWorkbookXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
<x:workbook xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""
|
<x:workbook xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""
|
||||||
xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
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)
|
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}"" />";
|
=> $@"<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.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels, cancellationToken);
|
||||||
await CreateZipEntryAsync(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString, cancellationToken);
|
await CreateZipEntryAsync(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString, cancellationToken);
|
||||||
|
await GenerateStylesXmlAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CreateSheetXmlAsync(object value, string sheetPath, CancellationToken cancellationToken)
|
private async Task CreateSheetXmlAsync(object value, string sheetPath, CancellationToken cancellationToken)
|
||||||
@ -47,27 +48,27 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
await WriteEmptySheetAsync(writer);
|
await WriteEmptySheetAsync(writer);
|
||||||
goto End; //for re-using code
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
//DapperRow
|
|
||||||
|
|
||||||
switch (value)
|
|
||||||
{
|
{
|
||||||
case IDataReader dataReader:
|
//DapperRow
|
||||||
await GenerateSheetByIDataReaderAsync(writer, dataReader);
|
|
||||||
break;
|
switch (value)
|
||||||
case IEnumerable enumerable:
|
{
|
||||||
await GenerateSheetByEnumerableAsync(writer, enumerable);
|
case IDataReader dataReader:
|
||||||
break;
|
await GenerateSheetByIDataReaderAsync(writer, dataReader);
|
||||||
case DataTable dataTable:
|
break;
|
||||||
await GenerateSheetByDataTableAsync(writer, dataTable);
|
case IEnumerable enumerable:
|
||||||
break;
|
await GenerateSheetByEnumerableAsync(writer, enumerable);
|
||||||
default:
|
break;
|
||||||
throw new NotImplementedException($"Type {value.GetType().FullName} is not implemented. Please open an issue.");
|
case DataTable dataTable:
|
||||||
|
await GenerateSheetByDataTableAsync(writer, dataTable);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
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));
|
_zipDictionary.Add(sheetPath, new ZipPackageInfo(entry, ExcelContentTypes.Worksheet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,8 +456,6 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
{
|
{
|
||||||
await AddFilesToZipAsync(cancellationToken);
|
await AddFilesToZipAsync(cancellationToken);
|
||||||
|
|
||||||
await GenerateStylesXmlAsync(cancellationToken);
|
|
||||||
|
|
||||||
await GenerateDrawinRelXmlAsync(cancellationToken);
|
await GenerateDrawinRelXmlAsync(cancellationToken);
|
||||||
|
|
||||||
await GenerateDrawingXmlAsync(cancellationToken);
|
await GenerateDrawingXmlAsync(cancellationToken);
|
||||||
@ -479,7 +478,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken)
|
private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var styleXml = GetStylesXml();
|
var styleXml = GetStylesXml(_configuration.DynamicColumns);
|
||||||
|
|
||||||
await CreateZipEntryAsync(
|
await CreateZipEntryAsync(
|
||||||
ExcelFileNames.Styles,
|
ExcelFileNames.Styles,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MiniExcelLibs.OpenXml.Constants;
|
using MiniExcelLibs.Attributes;
|
||||||
|
using MiniExcelLibs.OpenXml.Constants;
|
||||||
using MiniExcelLibs.OpenXml.Models;
|
using MiniExcelLibs.OpenXml.Models;
|
||||||
using MiniExcelLibs.Utils;
|
using MiniExcelLibs.Utils;
|
||||||
using MiniExcelLibs.Zip;
|
using MiniExcelLibs.Zip;
|
||||||
@ -108,6 +109,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
if (dynamicColumn.Format != null)
|
if (dynamicColumn.Format != null)
|
||||||
{
|
{
|
||||||
prop.ExcelFormat = dynamicColumn.Format;
|
prop.ExcelFormat = dynamicColumn.Format;
|
||||||
|
prop.ExcelFormatId = dynamicColumn.FormatId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamicColumn.Aliases != null)
|
if (dynamicColumn.Aliases != null)
|
||||||
@ -158,14 +160,26 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(str));
|
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);
|
var formattedStr = formattableValue.ToString(columnInfo.ExcelFormat, _configuration.Culture);
|
||||||
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(formattedStr));
|
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)
|
if (type.IsEnum)
|
||||||
{
|
{
|
||||||
var description = CustomPropertyHelper.DescriptionAttr(type, value);
|
var description = CustomPropertyHelper.DescriptionAttr(type, value);
|
||||||
@ -193,33 +207,6 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
return Tuple.Create("4", "str", ExcelOpenXmlUtils.EncodeXML(base64));
|
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()));
|
return Tuple.Create("2", "str", ExcelOpenXmlUtils.EncodeXML(value.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,24 +312,21 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
return base64;
|
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)
|
if (_configuration.Culture != CultureInfo.InvariantCulture)
|
||||||
{
|
{
|
||||||
var cellValue = ((DateTime)value).ToString(_configuration.Culture);
|
cellValue = (value).ToString(_configuration.Culture);
|
||||||
return Tuple.Create("2", "str", cellValue);
|
return Tuple.Create("2", "str", cellValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oaDate = CorrectDateTimeValue(value);
|
||||||
|
cellValue = oaDate.ToString(CultureInfo.InvariantCulture);
|
||||||
if (columnInfo == null || columnInfo.ExcelFormat == null)
|
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);
|
return Tuple.Create<string, string, string>("3", null, cellValue);
|
||||||
}
|
else
|
||||||
|
return Tuple.Create(columnInfo.ExcelFormatId.ToString(), (string)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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double CorrectDateTimeValue(DateTime value)
|
private static double CorrectDateTimeValue(DateTime value)
|
||||||
@ -375,14 +359,14 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
return dimensionRef;
|
return dimensionRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetStylesXml()
|
private string GetStylesXml(ICollection<ExcelColumnAttribute> columns)
|
||||||
{
|
{
|
||||||
switch (_configuration.TableStyles)
|
switch (_configuration.TableStyles)
|
||||||
{
|
{
|
||||||
case TableStyles.None:
|
case TableStyles.None:
|
||||||
return ExcelXml.NoneStylesXml;
|
return ExcelXml.SetupStyleXml(ExcelXml.NoneStylesXml, columns);
|
||||||
case TableStyles.Default:
|
case TableStyles.Default:
|
||||||
return ExcelXml.DefaultStylesXml;
|
return ExcelXml.SetupStyleXml(ExcelXml.DefaultStylesXml, columns);
|
||||||
default:
|
default:
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using MiniExcelLibs.OpenXml.Constants;
|
using MiniExcelLibs.Attributes;
|
||||||
|
using MiniExcelLibs.OpenXml.Constants;
|
||||||
using MiniExcelLibs.OpenXml.Models;
|
using MiniExcelLibs.OpenXml.Models;
|
||||||
using MiniExcelLibs.Utils;
|
using MiniExcelLibs.Utils;
|
||||||
using MiniExcelLibs.Zip;
|
using MiniExcelLibs.Zip;
|
||||||
@ -68,6 +69,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
{
|
{
|
||||||
CreateZipEntry(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels);
|
CreateZipEntry(ExcelFileNames.Rels, ExcelContentTypes.Relationships, ExcelXml.DefaultRels);
|
||||||
CreateZipEntry(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString);
|
CreateZipEntry(ExcelFileNames.SharedStrings, ExcelContentTypes.SharedStrings, ExcelXml.DefaultSharedString);
|
||||||
|
GenerateStylesXml();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSheetXml(object value, string sheetPath)
|
private void CreateSheetXml(object value, string sheetPath)
|
||||||
@ -79,29 +81,29 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
WriteEmptySheet(writer);
|
WriteEmptySheet(writer);
|
||||||
goto End; //for re-using code
|
|
||||||
}
|
|
||||||
|
|
||||||
//DapperRow
|
|
||||||
|
|
||||||
if (value is IDataReader)
|
|
||||||
{
|
|
||||||
GenerateSheetByIDataReader(writer, value as IDataReader);
|
|
||||||
}
|
|
||||||
else if (value is IEnumerable)
|
|
||||||
{
|
|
||||||
GenerateSheetByEnumerable(writer, value as IEnumerable);
|
|
||||||
}
|
|
||||||
else if (value is DataTable)
|
|
||||||
{
|
|
||||||
GenerateSheetByDataTable(writer, value as DataTable);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new NotImplementedException($"Type {value.GetType().FullName} is not implemented. Please open an issue.");
|
//DapperRow
|
||||||
|
|
||||||
|
if (value is IDataReader)
|
||||||
|
{
|
||||||
|
GenerateSheetByIDataReader(writer, value as IDataReader);
|
||||||
|
}
|
||||||
|
else if (value is IEnumerable)
|
||||||
|
{
|
||||||
|
GenerateSheetByEnumerable(writer, value as IEnumerable);
|
||||||
|
}
|
||||||
|
else if (value is DataTable)
|
||||||
|
{
|
||||||
|
GenerateSheetByDataTable(writer, value as DataTable);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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));
|
_zipDictionary.Add(sheetPath, new ZipPackageInfo(entry, ExcelContentTypes.Worksheet));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +153,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
for (int i = 0; i < fieldCount; i++)
|
for (int i = 0; i < fieldCount; i++)
|
||||||
{
|
{
|
||||||
var cellValue = reader.GetValue(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++;
|
xIndex++;
|
||||||
}
|
}
|
||||||
writer.Write(WorksheetXml.EndRow);
|
writer.Write(WorksheetXml.EndRow);
|
||||||
@ -356,7 +358,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
for (int j = 0; j < value.Columns.Count; j++)
|
for (int j = 0; j < value.Columns.Count; j++)
|
||||||
{
|
{
|
||||||
var cellValue = value.Rows[i][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++;
|
xIndex++;
|
||||||
}
|
}
|
||||||
writer.Write(WorksheetXml.EndRow);
|
writer.Write(WorksheetXml.EndRow);
|
||||||
@ -454,7 +456,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
|
|
||||||
return yIndex - 1;
|
return yIndex - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteCell(MiniExcelStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo columnInfo)
|
private void WriteCell(MiniExcelStreamWriter writer, int rowIndex, int cellIndex, object value, ExcelColumnInfo columnInfo)
|
||||||
{
|
{
|
||||||
var columnReference = ExcelOpenXmlUtils.ConvertXyToCell(cellIndex, rowIndex);
|
var columnReference = ExcelOpenXmlUtils.ConvertXyToCell(cellIndex, rowIndex);
|
||||||
@ -484,8 +486,6 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
{
|
{
|
||||||
AddFilesToZip();
|
AddFilesToZip();
|
||||||
|
|
||||||
GenerateStylesXml();
|
|
||||||
|
|
||||||
GenerateDrawinRelXml();
|
GenerateDrawinRelXml();
|
||||||
|
|
||||||
GenerateDrawingXml();
|
GenerateDrawingXml();
|
||||||
@ -508,7 +508,7 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void GenerateStylesXml()
|
private void GenerateStylesXml()
|
||||||
{
|
{
|
||||||
var styleXml = GetStylesXml();
|
var styleXml = GetStylesXml(_configuration.DynamicColumns);
|
||||||
CreateZipEntry(ExcelFileNames.Styles, ExcelContentTypes.Styles, styleXml);
|
CreateZipEntry(ExcelFileNames.Styles, ExcelContentTypes.Styles, styleXml);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,4 +600,4 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
public double? ExcelColumnWidth { get; internal set; }
|
public double? ExcelColumnWidth { get; internal set; }
|
||||||
public string ExcelIndexName { get; internal set; }
|
public string ExcelIndexName { get; internal set; }
|
||||||
public bool ExcelIgnore { get; internal set; }
|
public bool ExcelIgnore { get; internal set; }
|
||||||
|
public int ExcelFormatId { get; internal set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ExcellSheetInfo
|
internal class ExcellSheetInfo
|
||||||
@ -205,6 +206,7 @@
|
|||||||
ExcelIndexName = p.GetAttribute<ExcelColumnIndexAttribute>()?.ExcelXName ?? excelColumn?.IndexName,
|
ExcelIndexName = p.GetAttribute<ExcelColumnIndexAttribute>()?.ExcelXName ?? excelColumn?.IndexName,
|
||||||
ExcelColumnWidth = p.GetAttribute<ExcelColumnWidthAttribute>()?.ExcelColumnWidth ?? excelColumn?.Width,
|
ExcelColumnWidth = p.GetAttribute<ExcelColumnWidthAttribute>()?.ExcelColumnWidth ?? excelColumn?.Width,
|
||||||
ExcelFormat = excelFormat ?? excelColumn?.Format,
|
ExcelFormat = excelFormat ?? excelColumn?.Format,
|
||||||
|
ExcelFormatId = excelColumn?.FormatId ?? -1
|
||||||
};
|
};
|
||||||
}).Where(_ => _ != null);
|
}).Where(_ => _ != null);
|
||||||
}
|
}
|
||||||
@ -292,7 +294,10 @@
|
|||||||
p.Nullable = true;
|
p.Nullable = true;
|
||||||
//p.ExcludeNullableType = item2[key]?.GetType();
|
//p.ExcludeNullableType = item2[key]?.GetType();
|
||||||
if (dynamicColumn.Format != null)
|
if (dynamicColumn.Format != null)
|
||||||
|
{
|
||||||
p.ExcelFormat = dynamicColumn.Format;
|
p.ExcelFormat = dynamicColumn.Format;
|
||||||
|
p.ExcelFormatId = dynamicColumn.FormatId;
|
||||||
|
}
|
||||||
if (dynamicColumn.Aliases != null)
|
if (dynamicColumn.Aliases != null)
|
||||||
p.ExcelColumnAliases = dynamicColumn.Aliases;
|
p.ExcelColumnAliases = dynamicColumn.Aliases;
|
||||||
if (dynamicColumn.IndexName != null)
|
if (dynamicColumn.IndexName != null)
|
||||||
|
@ -309,7 +309,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
|
|
||||||
var rows = MiniExcel.Query(path, false).ToList();
|
var rows = MiniExcel.Query(path, false).ToList();
|
||||||
Assert.Equal("createdate", rows[0].A);
|
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("name", rows[0].B);
|
||||||
Assert.Equal("Jack", rows[1].B);
|
Assert.Equal("Jack", rows[1].B);
|
||||||
Assert.Equal("Account Point", rows[0].C);
|
Assert.Equal("Account Point", rows[0].C);
|
||||||
@ -334,7 +334,7 @@ namespace MiniExcelLibs.Tests
|
|||||||
|
|
||||||
var rows = MiniExcel.Query(path, false).ToList();
|
var rows = MiniExcel.Query(path, false).ToList();
|
||||||
Assert.Equal("createdate", rows[0].A);
|
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("name", rows[0].B);
|
||||||
Assert.Equal("Jack", rows[1].B);
|
Assert.Equal("Jack", rows[1].B);
|
||||||
Assert.Equal("Account Point", rows[0].C);
|
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()
|
public void DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingIDataReader()
|
||||||
{
|
{
|
||||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
var dateTime = DateTime.Now;
|
||||||
|
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||||
var table = new DataTable();
|
var table = new DataTable();
|
||||||
{
|
{
|
||||||
table.Columns.Add("Column1", typeof(string));
|
table.Columns.Add("Column1", typeof(string));
|
||||||
table.Columns.Add("Column2", typeof(int));
|
table.Columns.Add("Column2", typeof(int));
|
||||||
table.Rows.Add("MiniExcel", 1);
|
table.Columns.Add("Column3", typeof(DateTime));
|
||||||
table.Rows.Add("Github", 2);
|
table.Columns.Add("Column4", typeof(DateOnly));
|
||||||
|
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||||
|
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
var configuration = new OpenXmlConfiguration
|
var configuration = new OpenXmlConfiguration
|
||||||
@ -1240,7 +1244,15 @@ namespace MiniExcelLibs.Tests
|
|||||||
Name = "Its value",
|
Name = "Its value",
|
||||||
Index = 1,
|
Index = 1,
|
||||||
Width = 150
|
Width = 150
|
||||||
|
},
|
||||||
|
new DynamicExcelColumn("Column3")
|
||||||
|
{
|
||||||
|
Name = "Its Date",
|
||||||
|
Index = 2,
|
||||||
|
Width = 150,
|
||||||
|
Format = "dd.mm.yyyy hh:mm:ss",
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var reader = table.CreateDataReader();
|
var reader = table.CreateDataReader();
|
||||||
@ -1255,13 +1267,21 @@ namespace MiniExcelLibs.Tests
|
|||||||
|
|
||||||
Assert.Contains("Name of something", rows[0]);
|
Assert.Contains("Name of something", rows[0]);
|
||||||
Assert.Contains("Its value", 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("Name of something", rows[1]);
|
||||||
Assert.Contains("Its value", 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("MiniExcel", rows[0]["Name of something"]);
|
||||||
Assert.Equal(1D, rows[0]["Its value"]);
|
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("Github", rows[1]["Name of something"]);
|
||||||
Assert.Equal(2D, rows[1]["Its value"]);
|
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()
|
public void DynamicColumnsConfigurationIsUsedWhenCreatingExcelUsingDataTable()
|
||||||
{
|
{
|
||||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid()}.xlsx");
|
||||||
|
var dateTime = DateTime.Now;
|
||||||
|
var onlyDate = DateOnly.FromDateTime(dateTime);
|
||||||
var table = new DataTable();
|
var table = new DataTable();
|
||||||
{
|
{
|
||||||
table.Columns.Add("Column1", typeof(string));
|
table.Columns.Add("Column1", typeof(string));
|
||||||
table.Columns.Add("Column2", typeof(int));
|
table.Columns.Add("Column2", typeof(int));
|
||||||
table.Rows.Add("MiniExcel", 1);
|
table.Columns.Add("Column3", typeof(DateTime));
|
||||||
table.Rows.Add("Github", 2);
|
table.Columns.Add("Column4", typeof(DateOnly));
|
||||||
|
table.Rows.Add("MiniExcel", 1, dateTime, onlyDate);
|
||||||
|
table.Rows.Add("Github", 2, dateTime, onlyDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
var configuration = new OpenXmlConfiguration
|
var configuration = new OpenXmlConfiguration
|
||||||
@ -1292,6 +1316,13 @@ namespace MiniExcelLibs.Tests
|
|||||||
Name = "Its value",
|
Name = "Its value",
|
||||||
Index = 1,
|
Index = 1,
|
||||||
Width = 150
|
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("Name of something", rows[0]);
|
||||||
Assert.Contains("Its value", 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("Name of something", rows[1]);
|
||||||
Assert.Contains("Its value", 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("MiniExcel", rows[0]["Name of something"]);
|
||||||
Assert.Equal(1D, rows[0]["Its value"]);
|
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("Github", rows[1]["Name of something"]);
|
||||||
Assert.Equal(2D, rows[1]["Its value"]);
|
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