I have an Excel sheet generated with Epplus, I am experiencing some pain points and I wish to be directed by someone who have solved a similar challenge.
I need to apply number formatting to a double value and I want to present it in Excel like this.
8 → 8.0
12 → 12.0
14.54 → 14.5
0 → 0.0
Here is my code
ws.Cells[row, col].Style.Numberformat.Format = "##0.0";
The final Excel file always append E+0 to the end of this format and therefore presents the final values like this instead.
8 → 8.0E+0
12 → 12.0E+0
14.54 → 14.5E+0
0 → 000.0E+0
When I check in the format cells of the generated Excel sheet, I see that my format appears as ##0.0E+2 instead of ##0.0 that I applied.
What may be wrong?
Here are some number format options for EPPlus:
//integer (not really needed unless you need to round numbers, Excel will use default cell properties)
ws.Cells["A1:A25"].Style.Numberformat.Format = "0";
//integer without displaying the number 0 in the cell
ws.Cells["A1:A25"].Style.Numberformat.Format = "#";
//number with 1 decimal place
ws.Cells["A1:A25"].Style.Numberformat.Format = "0.0";
//number with 2 decimal places
ws.Cells["A1:A25"].Style.Numberformat.Format = "0.00";
//number with 2 decimal places and thousand separator
ws.Cells["A1:A25"].Style.Numberformat.Format = "#,##0.00";
//number with 2 decimal places and thousand separator and money symbol
ws.Cells["A1:A25"].Style.Numberformat.Format = "€#,##0.00";
//percentage (1 = 100%, 0.01 = 1%)
ws.Cells["A1:A25"].Style.Numberformat.Format = "0%";
//accounting number format
ws.Cells["A1:A25"].Style.Numberformat.Format = "_-$* #,##0.00_-;-$* #,##0.00_-;_-$* \"-\"??_-;_-#_-";
Don't change the decimal and thousand separators to your own
localization. Excel will do that for you.
By request some DateTime formatting options.
//default DateTime pattern
worksheet.Cells["A1:A25"].Style.Numberformat.Format = DateTimeFormatInfo.CurrentInfo.ShortDatePattern;
//custom DateTime pattern
worksheet.Cells["A1:A25"].Style.Numberformat.Format = "dd-MM-yyyy HH:mm";
Addition to Accepted Answer, because value Accept Object you must pass Number to Value For Example if your input is in string :
var input = "5";
ws.Cells["A1:A25"].Value = double.Parse(input);
Another addition to the accepted answer: you can use nullable values and the formatting all looks good BUT it ends up being a string in Excel and you can't SUM, AVG etc.
So make sure you use the actual Value of the nullable.
And if you want to format a specific column like column "B" to number format you can do it this way-
using (var package = new ExcelPackage())
{
var worksheet = package.Workbook.Worksheets.Add("SHEET1");
worksheet.Cells["A1"].LoadFromDataTable(dataTable, PrintHeaders: true);
for (var col = 1; col < dataTable.Columns.Count + 1; col++)
{
if (col == 2)//col number 2 is equivalent to column B
{
worksheet.Column(col).Style.Numberformat.Format = "#";//apply the number formatting you need
}
worksheet.Column(col).AutoFit();
}
return File(package.GetAsByteArray(), XlsxContentType, "report.xlsx");//downloads file
}
I solved it as follows, so I just load the model and change as per my model if it is int ordatetime
var li = typeof(Model)
.GetProperties()
.ToArray();
using (var package = new ExcelPackage(stream))
{
var workSheet = package.Workbook.Worksheets.Add("Sheet1");
var i = 0;
foreach (var c in li)
{
i++;
if(c.PropertyType.Name == typeof(DateTime).Name || c.PropertyType.Name == typeof(DateTime?).Name)
workSheet.Column(i).Style.Numberformat.Format = DateTimeFormatInfo.CurrentInfo.ShortDatePattern; ;
if (c.PropertyType.Name == typeof(int).Name || c.PropertyType.Name == typeof(int?).Name)
workSheet.Column(i).Style.Numberformat.Format = "0";
}
}
Related
I built a service to read csv files of trade data from my new prime broker. The files show this format for negative numbers.
This is the code to read the file and process (only showing the part where I check for duplicate symbols since I am storing in Azure Table and cannot have duplicate symbols since the symbol is the row key)
for (var i = 0; i < records.Count - 1; i++)
{
//check if symbol is a duplicate
if (i>0 && records[i].Symbol == records[i - 1].Symbol)
{ //sum the columns in records[i] and records[i-1]
//change ent for symbol to new values
entities[i - (1 + dupeRecords)].CommissionPl = Convert.ToDouble(records[i].CommissionPl) + Convert.ToDouble(records[i - 1].CommissionPl).ToString(CultureInfo.InvariantCulture);
entities[i - (1 + dupeRecords)].PositionPl = Convert.ToDouble(records[i].PositionPl) + Convert.ToDouble(records[i - 1].PositionPl).ToString(CultureInfo.InvariantCulture);
entities[i - (1 + dupeRecords)].TransactionPl = Convert.ToDouble(records[i].TransactionPl) + Convert.ToDouble(records[i - 1].TransactionPl).ToString(CultureInfo.InvariantCulture);
entities[i - (1 + dupeRecords)].TotalPl = Convert.ToDouble(records[i].TotalPl) + Convert.ToDouble(records[i - 1].TotalPl).ToString(CultureInfo.InvariantCulture);
// do not create new ent for this record
//count the dupe entries for the entities index to match up
dupeRecords++;
}
The problem lies in the fact that these entries (i.e. records[i - 1].TotalPl, et al) when negative, despite showing -100 (for example) in the file show as (100) when you hover over them during processing. The Convert.ToDouble function can't process them when they are in parentheses format.
I can't figure out an EASY way to reformat the string value while iterating the records. I could check for parentheses and then strip them and multiply by -1 but I'm probably not seeing an easier solution.
Instead of using Convert.ToDouble, use double.Parse and specify the formats you allow:
NumberStyles styles = NumberStyles.AllowParentheses | NumberStyles.AllowTrailingSign | NumberStyles.Float | NumberStyles.AllowThousands;
entities[i - (1 + dupeRecords)].CommissionPl = double.Parse(records[i].CommissionPl, styles) ...
I am having some Cell values printed as Taxt (String) and i want them to be printed as Number, as this values are used in a Sum Formula.
The values came from an operation that i do with a library (OSISoft AF SDK) and are printed in my Excel as Strings.
ExcelRange cell = excelSheet.Cells[startRow, startCol + i + y];
cell.Value = valueAsString;
Just in case someone is using AF SDK as me getting data from PI Systems my code is actually something like this...
//point is a PIPoint.
cell.Value = point.RecordedValue(startDate.LocalTime.AddHours(i), OSIsoft.AF.Data.AFRetrievalMode.AtOrBefore);
Just parsing the value to double (or int) will be okey.
cell.Value = Double.Parse(cell.Value.ToString());
You can also set a Format to the number, but it is not necessary:
cell.Style.Numberformat.Format = "0.00";
All formats available:
https://stackoverflow.com/a/40214134/6574873
I am trying to format strings by whitespaces.
All strings normally look like
01. Anton 30p
02. Cinderella 20p
03. Thomas 18p
04. Anastacia-Laura 16p
I want to format each string, that the points start at the same column.
There I wrote:
s = stringUpToName;
int addSpacing = 37 - s.Length;
for (int i = 0; i < addSpacing; i += 1) s += " ";
s += points;
It gets closer this way, but it's still not perfectly formatted.
I want it to look like this:
01. Anton 30p
02. Cinderella 20p
03. Thomas 18p
04. Anastacia-Laura 16p
Use "0" custom specifier as zero-placeholder symbol to format index/number of record. 0:00 will give you 01 for value 1.
Also keep in mind that item format syntax is { index[,alignment][:formatString]} where alignment indicates preferred formatted field width. So, adding alignment to second item format {1,20} gives you right-aligned field width of 20 characters. With negative alignment field will be left-aligned.
Total format string will look like "{0:00}. {1,-20}{2}p"
You can use it with String.Format or StringBuilder.AppendFormat if you are build string, or Console.WriteLine if you are writing it to console.
int index = 1;
string name = "Anton";
int points = 30;
var result = String.Format("{0:00}. {1,-20}{2}p", index, name, points)
// "01. Anton 30p"
String.Format and Composite Formatting using the Alignment functionality
string[] names = new string[]
{
"1. Anton 30p",
"2. Cinderella 20p",
"3. Thomas 18p",
"4. Anastacia-Laura 16p"
};
foreach(string s in names)
{
int lastSpace = s.LastIndexOf(' ');
int firstSpace = s.IndexOf(' ');
string result = string.Format("{0,-4}{1,-37}{2,4}", s.Substring(0, firstSpace), s.Substring(firstSpace + 1, lastSpace), s.Substring(lastSpace+1));
Console.WriteLine(result);
}
Keep in mind that to see the output exactly aligned in columns you need to use a Fixed Width font like Lucida Console or Courier, because fonts with variable width use less pixel to print an I than to print a W.
Try right-align the numbers using
String.Format("{0} {1} {2,4}p",
Num,
Name,
Point);
How to format a decimal in C# with at least one digit after the decimal point, but not a fixed upper limit if specified more than 1 digit after the decimal point:
5 -> "5.0"
5.1 -> "5.1"
5.122 -> "5.122"
10.235544545 -> "10.235544545"
Use ToString("0.0###########################").
Some notes:,
There are 27 #s in there, as the decimal structure can accommodate precision up to 28 decimal places.
The 0 custom specifier will cause a digit to always be displayed, even if the value is 0.
The # custom specifier only displays a value if the digit is zero and all of the digits to the right/left of that digit (depending on what side of the decimal point you are on) are zero.
You will need to insert as many # after the first 0 to the right of the decimal point to accommodate the length of all the values you will pass to ToString, if you will only have precision to 10 decimal places, then you need nine # (since you have the first decimal place to the right handled by 0)
For more information, see the section of MSDN titled "Custom Numeric Format Strings".
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var a = 5m;
var b = 5.1m;
var c = 5.122m;
var d = 10.235544545m;
var ar = DecToStr.Work(a);
var br = DecToStr.Work(b);
var cr = DecToStr.Work(c);
var dr = DecToStr.Work(d);
Assert.AreEqual(ar, "5.0");
Assert.AreEqual(br, "5.1");
Assert.AreEqual(cr, "5.122");
Assert.AreEqual(dr, "10.235544545");
}
}
public class DecToStr
{
public static string Work(decimal val)
{
if (val * 10 % 10 == 0)
return val.ToString("0.0");
else
return val.ToString();
}
}
Func<decimal, string> FormatDecimal = d => (
d.ToString().Length <= 3 ||
!d.ToString().Contains(".")) ? d.ToString("#.0") : d.ToString()
);
I have a double and I want to format it with the following rules:
If there are no decimal places show just the number (see 100 example below)
If there are any decimal places show 2 decimal places
So, as a few examples:
100 --> 100
99.958443534 --> 99.96
99.1 -> 99.10
You could check if its a whole number, the use the type of formatting based on that:
string res = string.Format(((number % 1) == 0) ? "{0:0}" : "{0:0.00}", number);
What about:
var a = 100;
var b = 99.95844354;
var aAnswer = a.ToString("0.##"); //aAnswer is "100"
var bAnswer = b.ToString("0.##"); //bAnswer is "99.96"
You can use:
decimal a = 99.949999999M;
Math.Round(a, 2); // Returns 99.95