Loading dates from a text file in EPPLUS - c#

I'm trying to create an Excel spreadsheet in my web application using a tab-delimited text file as the data source. The code that loads my data looks like this:
// Load the data into the cells
Int32 rowIdx = 1;
foreach (String line in tab.Lines)
{
String[] cellTexts = line.Split(TAB);
Int32 colIdx = 1;
foreach (String cellText in cellTexts)
{
sheet.Cells[rowIdx, colIdx].Value = cellText;
colIdx++;
}
rowIdx++;
}
That seems to work fine. Later, however, I add a NumberFormat of "mm/dd/yyyy" to the cells:
range.Style.Numberformat.Format = "mm/dd/yyyy";
However, this doesn't change the display of the data in the cells. (The dates look like 5/1/15 or 12/31/15 in the original text file, and remain that way after the format is applied.
I am pretty sure that this because I've put a text value into the cell. (While it looks like a date, it's still just a string of characters.) But from my reading, I need to put a double into the cell to meet Excel's expectation that dates are stored as a double. Because the cell contains a string and not a double, the format string isn't applied, leaving the original, unformatted text.
I want to add some code to
Check the type of data in each cell in the range to which I apply a
date format.
If it's not a double, attempt to convert it to a date.
If the date conversion is successful, then convert the .NET date to an OADate and put it back into the cell.
My question is: Is this the best (or at least a reasonable) approach, and if so, how do I do that?
This code doesn't work:
foreach (OfficeOpenXml.ExcelRangeBase oneCell in range)
{
if (typeof(oneCell.Value) == "System.String")
{
// date manipulations here
}
}
The red line appears under oneCell in the typeof(oneCell.Value) call with the message "The type or namespace 'oneCell' could not be found. (Are you missing a using directive or an assembly reference?)"
Note that I can't know in advance where the date fields will be because both the data and the cell formats are provided from an external source. (The external cell formats do indicate when the format being applied is for a date format as opposed to a regular number format or a string.)

As #mason suggested, I'm posting the code I used to get around this problem.
(I didn't get an answer to my original question, which is how to iterate cells in a range and check the data type of each cell's content, but with this solution, I no longer need to do that.)
Instead, I modified the loop that loads the data from the tab-delimited text file to use some TryParse() calls to detect dates, numbers, or regular text data, and then load the appropriately typed data into the cell. Note how it checks for a leading single quote character to suppress the data typing if the cell is actually text, but looks like a number or a date:
// Load the data into the cells
Int32 rowIdx = 1;
foreach (String line in tab.Lines)
{
String[] cellTexts = line.Split(TAB);
Int32 colIdx = 1;
foreach (String cellText in cellTexts)
{
DateTime dateValue;
Double doubleValue;
if(cellText.StartsWith("'"))
{
sheet.Cells[rowIdx, colIdx].Value = cellText.Substring(1);
}
else if(DateTime.TryParse(cellText,out dateValue))
{
sheet.Cells[rowIdx, colIdx].Value = dateValue;
}
else if (Double.TryParse(cellText, out doubleValue))
{
sheet.Cells[rowIdx, colIdx].Value = doubleValue;
}
else
{
sheet.Cells[rowIdx, colIdx].Value = cellText;
}
colIdx++;
}
rowIdx++;
}
With the data typed appropriately in the cells, the formats have the desired effect.

Related

C# - Excel, converting date to string

I want to convert date to string in excel, i have similiar problem to this :
Convert date field into text in Excel
But I need to implement this in C# project, any idea how to achieve that ?
I had numbers in format like this : "1-2".
I also get strange number like 40530 after formating whole excel file to text, I think that's the number of days from year 1900.
EDIT:
I didn't mention that I'm reading data from .xml file, then fill excel file with this data, I had some columns that I fill with text like "1-2", but when I open excel it's shows as 2 January (excel changes it to date automatically).
SOLUTION
Maybe someone will use it:
if (value != null)
{
if (value.Contains("-") && value.Length == 3) // cause my value = "1-2"
{
value = "'" + value; // addin ' to value
}
} //now value ="'1-2"
Where value is my cell that I'm writing to excel. The " ' " sign will guarantee that the value "1-2" will be displayed as text, not as date.

Format string value datagridview c#

I am looking to format a value in a datagridview.
These values are a string containing a decimal number. (Like "3000"
I want to display it with a thousand separator (space), like this: "3,000".
I know it can be done by assigning format of defaultcellstyle using format like "N2" for example, this works with decimal column type but
I'm using a string column type in my datagridview to handle some exception(displaying "-" instead of "0" to simplify users view)
I tried differents cell style format and nothing changed in the display.
do i need to change the column type of my datagridview or it can be done without too much code ?
Thanks for all reply,
Tristan
i just made it working as i expected. i did the commented things first and it just showed errors, so i tried the second way (simpliest) that is not commented.
string value = cell.Value.ToString();
//NumberFormatInfo nfi =(NumberFormatInfo)CultureInfo.InvariantCulture.NumberFormat.Clone();
//nfi.NumberGroupSeparator = " ";
//string formatted = double.Parse(value).ToString("n", nfi);
//cell.Value = formatted.Replace(".00","");// 12 345.00
string formatted = double.Parse(value).ToString("# ### ###");
cell.Value = formatted;

DataTable to CSV date format

I'm trying to export a DataTable to CSV, with a number of columns. I would like that the date_time column is exported to CSV while retaining the database date_time format (YYY-MM-DD HH:mm:ss), or something like that.
This is my code:
private void DataTableToCsv(string path, DataTable dt)
{
File.Delete(path);
StringBuilder sb = new StringBuilder();
string[] columnNames = dt.Columns.Cast<DataColumn>().
Select(column => column.ColumnName).
ToArray();
sb.AppendLine(string.Join(",", columnNames));
foreach (DataRow row in dt.Rows)
{
string[] fields = row.ItemArray.Select(field => field.ToString()).
ToArray();
sb.AppendLine(string.Join(",", fields));
}
File.WriteAllText(path, sb.ToString());
}
The dates are appearing in a different format, which is giving me errors when trying to pick up from MySQL.
I know there is an accepted answer already, but...
Actually there is a way to control the formatting of dates in a consistent manner, without specifying the format for every type of data: you can use IFormatProvider
First, the method object.ToString(); with no parameters is formatting your object using current CultureInfo set in your thread/application/system. This is problematic when you need consistent formatting, for example when you try to save values into database. It isn't only problematic for dates but also for numbers - there are languages out there that use comma as decimal separator or use thousand separator in a number, for example, and databases do not like that very much. Now imagine your program is run on the computer that has a different language set...
Having said that, many of those problems can be avoided by using object.ToString(CultureInfo.InvariantCulture); instead. It is associated with the English language. Then, the result for 31th October 2014will be: 10/31/2014 08:35:52
Obviously still not what you want.
You can further control your formatting by modifying the culture a little yourself:
CultureInfo format = (CultureInfo) CultureInfo.InvariantCulture.Clone();
// those are the formats used by ToString() mathod:
format.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
format.DateTimeFormat.ShortTimePattern = "HH:mm:ss";
Console.WriteLine(DateTime.Now.ToString(format));
double ddd=13.11;
Console.WriteLine(ddd.ToString(format));
string sss = "some string";
// although this may not be a good idea:
Console.WriteLine(sss.ToString(format));
result:
2014-10-31 08:39:53
13.11
some string
With DateTime values, you can control the output by calling
dateTimeField.ToString("yyyy-dd-MM");
Currently you're treating all fields equally, and using the default conversion:
field => field.ToString()
You can't specify a conversion as object.ToString() has no overloads to do so; you'd have to specify what conversion to use for each type separately, ie:
string[] fields = row.ItemArray.Select(field => ConvertToCsvValue(field)).ToArray();
and
static void ConvertToCsvValue(object value)
{
if (value is DateTime)
{
return ((DateTime)value).ToString("yyyy-dd-MM");
}
else
{
return value.ToString();
}
}
data in a database is not aware of any format; the behaviour you are experiencing is related to that and is correct.
when filling the csv your code is taking the default format for the env/os/locale and applying it to the values.
to solve the issue you have some possible solution:
you change the source sql code to produce a sql text field filled with formatted data (imho a bad choice)
you handle the format client side when preparing the csv; you have to modify your code to handle the fields one by one applying the correct format to date fields
you alter the datatable content applying the expected format to date fields (this may be possible or maybe not depending on datatype of the involved fields)
my preference goes to the second or third solution because i prefer to keep formatting on the client side but YMMV and in your post there is not enough information to make a proper choice.

What is the recommended way to insert current date in an Excel cell, as a constant?

I have been using the following code:
private void InsertDate(string dstCoordinates)
{
Range dstRange = worksheet.get_Range(dstCoordinates);
dstRange.Formula = "=TODAY()";
dstRange.Locked = true;
}
Which re-evaluates the date every time the spreadsheet file is opened.
But now I need the date to be evaluated once, when it is inserted in the cell. From that moment on, the value should remain constant.
That value seems to be stored internally as double.
Perhaps what I need is a function as follows:
string today = ExcelEvaluate("=TODAY()");
dstRange.value2 = today;
Is there such facility?
TIA
Like Corak wrote you can probably use ToOADate(). You need to set the cell format to date after it, so that it doesn't display as a double. The TODAY() function does that automatically.
Here's the code:
dstRange.Value2 = DateTime.Now.ToOADate();
dstRange.NumberFormat = "m/d/yyyy"

Export to Excel using OpenXML and C#, Integers and DateTime

I'm writing an application that's supposed to export data from a map application.
This application is using Silverlight, and to facilitate export to Excel I am using this library.
All of the data is represented in strings by default. When I write to the spreadsheet, I try to parse each string to see which type it is:
string str = kvp.Value;
int i = 0;
long l = 0;
decimal dec = 0;
DateTime dt;
if (int.TryParse(str, out i))
doc.Workbook.Sheets[0].Sheet.Rows[r].Cells[c].SetValue(i);
else if (decimal.TryParse(str, out dec))
doc.Workbook.Sheets[0].Sheet.Rows[r].Cells[c].SetValue(dec);
else if (long.TryParse(str, out l))
doc.Workbook.Sheets[0].Sheet.Rows[r].Cells[c].SetValue(l);
else if (DateTime.TryParse(str, out dt))
doc.Workbook.Sheets[0].Sheet.Rows[r].Cells[c].SetValue(dt);
else
doc.Workbook.Sheets[0].Sheet.Rows[r].Cells[c].SetValue(str);
This works great, except for DateTime and when I try to parse a social security number, which in my case is 12 characters long.
The social security number is parsed as a decimal number, and is displayed in scientific form in Excel. From what I've gathered through reading it seems like a limitation in Excel. If I mark the cell however, I see the correct number in the top bar where you can write formulas. I've solved this problem so far by simply putting this number as a string and letting the end user handle it for now, but I'd really like for it to be a number in the finished document. Is this possible?
What really boggles my mind though, is the DateTime. The format of the date comes like this from the application: 10/15/2013 1:10:00 AM.
It looks like this in the Excel file: 2455075.
I checked the source code for the date formatting but I don't seem to be adept enough to see if there is anything wrong in it. For anyone intresed, you can check it out here.
The SetValue-function is supposed to identify the following types automatically:
bool
DateTime
decimal
Exception
SharedStringDefinition
string
I apologize for the long post. It boils down to these questions:
Can I make Excel handle long numbers without scientific notation programatically?
Why is the DateTime being outputed to such a weird format?
To be set Cell Value in Date format you have to convert DateTime to OLE Automation Date. Also you can create more clear method for writing cell values. Somthing like this:
public bool UpdateValue(WorkbookPart wbPart, string sheetName, string addressName, string value,
UInt32Value styleIndex, CellValues dataType)
{
// Assume failure.
bool updated = false;
Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where(
(s) => s.Name == sheetName).FirstOrDefault();
if (sheet != null)
{
Worksheet ws = ((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
Cell cell = InsertCellInWorksheet(ws, addressName);
if (dataType == CellValues.SharedString)
{
// Either retrieve the index of an existing string,
// or insert the string into the shared string table
// and get the index of the new item.
int stringIndex = InsertSharedStringItem(wbPart, value);
cell.CellValue = new CellValue(stringIndex.ToString());
}
else
{
cell.CellValue = new CellValue(value);
}
cell.DataType = new EnumValue<CellValues>(dataType);
if (styleIndex > 0)
cell.StyleIndex = styleIndex;
// Save the worksheet.
ws.Save();
updated = true;
}
return updated;
}
Then call this method like this (first call is for String second is for DateTime):
UpdateValue(workbookPart, wsName, "D14", "Some text", 0, CellValues.String);
UpdateValue(workbookPart, wsName, "H13", DateTime.Parse("2013-11-01").ToOADate().ToString(CultureInfo.InvariantCulture), 0, CellValues.Date);

Categories