Skip to content

Commit d3d5dd7

Browse files
authored
Fixes issue 1523 (#1525)
* Fixes issue #1523 * Fixed handling of cultures in Text property * Removed using
1 parent 87a382a commit d3d5dd7

File tree

6 files changed

+92
-11
lines changed

6 files changed

+92
-11
lines changed

src/EPPlus/ExcelWorkbook.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,9 @@ internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManage
215215
TopNode = WorkbookXml.DocumentElement;
216216
SchemaNodeOrder = new string[] { "fileVersion", "fileSharing", "workbookPr", "workbookProtection", "bookViews", "sheets", "functionGroups", "functionPrototypes", "externalReferences", "definedNames", "calcPr", "oleSize", "customWorkbookViews", "pivotCaches", "smartTagPr", "smartTagTypes", "webPublishing", "fileRecoveryPr", "webPublishObjects", "extLst" };
217217
FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates.
218-
GetSharedStrings();
218+
FullPrecision = GetXmlNodeBool("d:calcPr/@fullPrecision", false);
219+
220+
GetSharedStrings();
219221
}
220222

221223
/// <summary>
@@ -1152,8 +1154,16 @@ public ExcelCalcMode CalcMode
11521154
}
11531155
#endregion
11541156
}
1155-
1156-
private const string FULL_CALC_ON_LOAD_PATH = "d:calcPr/@fullCalcOnLoad";
1157+
/// <summary>
1158+
/// If false, EPPlus will round cell values to the number of decimals as displayed in the cell by using the cells number format when calculating the workbook.
1159+
/// If true, full precision will be used on calculation.
1160+
/// </summary>
1161+
public bool FullPrecision
1162+
{
1163+
get;
1164+
set;
1165+
}
1166+
private const string FULL_CALC_ON_LOAD_PATH = "d:calcPr/@fullCalcOnLoad";
11571167
/// <summary>
11581168
/// Should Excel do a full calculation after the workbook has been loaded?
11591169
/// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks>
@@ -1222,7 +1232,9 @@ internal void Save() // Workbook Save
12221232

12231233
DeleteCalcChain();
12241234

1225-
if (_vba == null && !_package.ZipPackage.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)))
1235+
SetXmlNodeBool("d:calcPr/@fullPrecision", FullPrecision, false);
1236+
1237+
if (_vba == null && !_package.ZipPackage.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)))
12261238
{
12271239
if (Part.ContentType != ContentTypes.contentTypeWorkbookDefault &&
12281240
Part.ContentType != ContentTypes.contentTypeWorkbookMacroEnabled)

src/EPPlus/Style/XmlAccess/ExcelFormatTranslator.cs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@ internal ExcelFormatTranslator(string format, int numFmtID)
6161
DataType = eFormatType.DateTime;
6262
f.SpecialDateFormat = eSystemDateFormat.SystemShortDate;
6363
}
64-
else if (format.Equals("general", StringComparison.OrdinalIgnoreCase))
64+
else if (ContainsGeneral(ref format))
6565
{
66-
f.NetFormat = f.NetFormatForWidth = "G10";
66+
f.NetFormat = f.NetFormatForWidth = format;
6767
DataType = eFormatType.Number;
6868
f.SpecialDateFormat = eSystemDateFormat.General;
6969
}
@@ -74,6 +74,42 @@ internal ExcelFormatTranslator(string format, int numFmtID)
7474
}
7575
}
7676

77+
private bool ContainsGeneral(ref string format)
78+
{
79+
if(format.IndexOf("general", StringComparison.OrdinalIgnoreCase) < 0) return false;
80+
var ret = false;
81+
var sb = new StringBuilder();
82+
bool inString = false;
83+
char pc='\0';
84+
for (int i= 0;i<format.Length;i++)
85+
{
86+
var c = format[i];
87+
if (c=='\"' && pc!='\\')
88+
{
89+
inString=!inString;
90+
continue;
91+
}
92+
else if (i+1 < format.Length && c=='\\' && format[i+1]!='\\')
93+
{
94+
continue;
95+
}
96+
else if(inString == false)
97+
{
98+
if(i+7 <= format.Length && (c=='g' || c == 'G') && format.Substring(i,7).Equals("general", StringComparison.InvariantCultureIgnoreCase))
99+
{
100+
ret = true;
101+
sb.Append("{0}");
102+
i += 6;
103+
continue;
104+
}
105+
}
106+
pc = c;
107+
sb.Append(c);
108+
}
109+
format=sb.ToString();
110+
return ret;
111+
}
112+
77113
// escape ('\') before these characters will be retained
78114
private static char[] _escapeChars = new char[] { '.', ',', '\'' };
79115

@@ -577,8 +613,12 @@ internal FormatPart GetFormatPart(object value)
577613
else if (Formats[0].SpecialDateFormat==eSystemDateFormat.General)
578614
{
579615
var d = ConvertUtil.GetValueDouble(value);
580-
Formats[0].NetFormat = Formats[0].NetFormatForWidth = GetGeneralFormatFromDoubleValue(d);
581-
616+
var fmt = GetGeneralFormatFromDoubleValue(d);
617+
foreach(var f in Formats)
618+
{
619+
f.NetFormat = string.Format(f.NetFormat, "{0:" + fmt + "}");
620+
f.NetFormatForWidth = string.Format(f.NetFormatForWidth, "{0:" + fmt + "}");
621+
}
582622
}
583623

584624
return Formats[0];

src/EPPlus/Utils/ValueToTextHandler.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,15 @@ internal static string FormatValue(object v, bool forWidthCalc, ExcelFormatTrans
8686
if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number)
8787
{
8888
if (string.IsNullOrEmpty(f.FractionFormat))
89-
{
90-
return FormatNumber(d, format, overrideCultureInfo ?? nf.Culture);
89+
{
90+
if (f.SpecialDateFormat == ExcelFormatTranslator.eSystemDateFormat.General)
91+
{
92+
return string.Format(overrideCultureInfo ?? nf.Culture, f.NetFormat, d);
93+
}
94+
else
95+
{
96+
return FormatNumber(d, format, overrideCultureInfo ?? nf.Culture);
97+
}
9198
}
9299
else
93100
{

src/EPPlusTest/Export/JsonExport/TableExporterTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public void ValidateJsonExport()
3232
[TestMethod]
3333
public async Task ValidateJsonExportRange()
3434
{
35+
SwitchToCulture();
3536
using (var p = new ExcelPackage())
3637
{
3738
var ws = p.Workbook.Worksheets.Add($"Sheet1");
@@ -66,6 +67,7 @@ public async Task ValidateJsonExportRange()
6667
Assert.AreEqual("{\"range\":{\"columns\":[{\"name\":\"SEK\",\"dt\":\"number\"},{\"name\":\"EUR\",\"dt\":\"number\"},{\"name\":\"USD\",\"dt\":\"number\"}],\"rows\":[{\"cells\":[{\"v\":\"1\",\"t\":\"1\"},{\"v\":\"10.35\",\"t\":\"10,35\"},{\"v\":\"9.51\",\"t\":\"9,51\"}]},{\"cells\":[{\"v\":\"1\",\"t\":\"1\"},{\"v\":\"10.48\",\"t\":\"10,48\"},{\"v\":\"9.59\",\"t\":\"9,59\"}]}]}}",
6768
json);
6869
}
70+
SwitchBackToCurrentCulture();
6971
}
7072
[TestMethod]
7173
public void ValidateJsonEncoding()

src/EPPlusTest/Issues/StylingIssues.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,23 @@ public void Issue1493()
195195

196196
SwitchBackToCurrentCulture();
197197
}
198+
[TestMethod]
199+
public void i1523()
200+
{
201+
using (var package = new ExcelPackage())
202+
{
203+
SwitchToCulture();
204+
var sheet = package.Workbook.Worksheets.Add("Sheet1");
205+
sheet.Cells["A1"].Value = 123;
206+
sheet.Cells["A1"].Style.Numberformat.Format = "General\\ \"mm\"";
207+
Assert.AreEqual("123 mm", sheet.Cells[1, 1].Text);
208+
209+
sheet.Cells["A2"].Value = 123456789.1234;
210+
sheet.Cells["A2"].Style.Numberformat.Format = "General\\ \"mm\"";
211+
Assert.AreEqual("123456789.1 mm", sheet.Cells[2, 1].Text);
212+
SwitchBackToCurrentCulture();
213+
}
214+
}
198215
public string TextHandler(NumberFormatToTextArgs options)
199216
{
200217
switch(options.NumberFormat.NumFmtId)

src/EPPlusTest/Table/PivotTable/Calculation/PivotTableCalculationDemoTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ public static void Init(TestContext context)
2222
[ClassCleanup]
2323
public static void Cleanup()
2424
{
25-
_package.Dispose();
25+
if (_package != null)
26+
{
27+
_package.Dispose();
28+
}
2629
}
2730
[TestMethod]
2831
public void DemoTest()

0 commit comments

Comments
 (0)