C# Excel Interop Charts with multi series - X axis as DateTime - c#

I have an excel addin implemented in C#. This connects to a server and obtains <key, value1, value2, value3..> pairs, where key is DateTime.
After data is fetched, this is populated in Excel worksheet. This data is used to plot multi-series line graph.
I am using ChartWizard and on the Chart object I add multiple series using .NewSeries option.
What is the best way to specify that my X axis is DateTime. I see the behaviour differs when I use ScatterLines or XLLines. I am unable to find an approach where I can say to the chart that my X axis is DateTime and specify a dateformat to same
Any help will be appreciated.
Vikron
Microsoft.Office.Tools.Excel.Chart chart = worksheet.Controls.AddChart(0, 0, xx, yy, "Trend");
chart.ChartWizard(Type.Missing,
Microsoft.Office.Interop.Excel.XlChartType.xlXYScatterLines,
Type.Missing,
XlRowCol.xlColumns,
Type.Missing,
Type.Missing,
true,
"Trend",
"Time stamp",
Type.Missing,
Type.Missing);
chart.AutoScaling = false;
chart.ChartStyle = 34;
chart.Legend.Position = XlLegendPosition.xlLegendPositionBottom;
chart.HasTitle = true;
chart.ChartType = XlChartType.xlXYScatterLines;
chart.ChartTitle.Text = "Trend";
foreach (series)
{
Excel.Series xlSeries = (Excel.Series)((Excel.SeriesCollection)chart.SeriesCollection()).NewSeries();
Microsoft.Office.Interop.Excel.Range seriesRange = worksheet.get_Range(series.seriesBeginRange,
worksheet.get_Range(series.seriesBeginRange).get_End(XlDirection.xlDown));
xlSeries.Name = series.seriesName;
xlSeries.XValues = timeSeriesRange; //This has datetime
xlSeries.ChartType = Microsoft.Office.Interop.Excel.XlChartType.xlXYScatterLines;
xlSeries.Values = seriesRange;
}
cell.NumberFormat = "MM/dd/yy HH:mm";
cell.Value = ts;

Found, if not best, something that works for me. When I was populating with DateTime formatted to the desired date time display pattern, the Cell type was getting set to "General" and of-course the value was treated as "String", with this xlLines did worked perfectly. Then the problem with this is that user will not be able to modify the DateTime format into a different display pattern as the cells were updated as "String".
Now, I populate the Excel cell with C# DateTime object. I set the format as
cell.NumberFormat = "m/d/yy h:mm;#";
To obtain the exact NumberFormat to Format Axis=>Number=>Category=>Format Code properties in Excel. This will let Excel treat the Type as Time and user can modify the date time format. Then, I modified to xlXLScatterLines, modified Tickspaces as below:
Axis xAxis = (Excel.Axis)chart.Axes(Excel.XlAxisType.xlCategory);
TickLabels ticks = xAxis.TickLabels;
xAxis.MinimumScale = timeSeriesRange.Value2[1, 1];
xAxis.MaximumScale = timeSeriesRange.Value2[timeSeriesRange.Count, 1];
xAxis.MajorTickMark = XlTickMark.xlTickMarkCross;
xAxis.MinorTickMark = XlTickMark.xlTickMarkInside;
xAxis.MajorUnit = 0.005;
xAxis.HasMinorGridlines = true;
xAxis.HasMajorGridlines = true;
ticks.Orientation = XlTickLabelOrientation.xlTickLabelOrientationUpward;
chart.PlotArea.Select();
chart.PlotArea.Height = 300;

Related

C# DateTime from Excel turns into float number

I have an excel file in the first column which contains dates in the format dd.MM.yyyy hh:mm:ss. I'm trying to display data from an excel table in datagridview, but the date is displayed as a float number.
I tried to convert the date to the desired format in this way, but it does not work:
worksheet.Cells[2, 1, endCell.Row, 1].Style.Numberformat.Format = "dd.MM.yyyy hh:mm:ss";
The full code of my method:
public static DataTable readTableFromExcel(FileInfo file)
{
DataTable table = new DataTable();
Console.WriteLine(file.Exists);
using (ExcelPackage package= new ExcelPackage(file))
{
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
ExcelCellAddress startCell = worksheet.Dimension.Start;
ExcelCellAddress endCell = worksheet.Dimension.End;
ExcelRange range = worksheet.Cells[startCell.Row, startCell.Column, endCell.Row, endCell.Column];
ExcelTable excelTable = worksheet.Tables.Add(range, "table");
Console.WriteLine(worksheet.Cells[2, 1].Value.ToString());
table = excelTable.ToDataTable();
}
return table;
}
String with Console.Writeline outputs 44912,0912268519 instead of 17.12.2022 2:11:22.
Then I output the data to datagridview: tableView.DataSource = table;
And it looks like: https://i.stack.imgur.com/aXx6V.png
File used: https://drive.google.com/drive/folders/1hXKmKs_F7EyO5GdVU3HVATxDLlFWO4jk?usp=share_link
How can I display the datetime correctly?
In Excel, dates and times are stored as a floating point number representing the number of days since the epoch date of January 1, 1970. This means that when you read a date or time value from an Excel file into a C# DateTime object, you will need to convert the floating point value to a DateTime object.
// Assume that the Excel date value is stored in a variable called "excelDate"
// Convert the Excel date value to a DateTime object
DateTime dateTime = DateTime.FromOADate(excelDate);
system.datetime.fromoadate

range.set_Value formatting for dates in Excel VSTO

The following code puts date values into excel, but for some reason they are not automatically formatted as date. If I enter these dates manually – they get formatted automatically. Excel is running on Windows with European locale setting. How do I make Excel format the dates automatically? I can't explicitly apply formatting as the range I'm putting into excel may contain columns of different data types and the whole range has to be inserted in one shot for performance reasons.
string[,] arr = new string [2, 2];
arr[0, 0] = "Date";
arr[0, 1] = "DateTime";
arr[1, 0] = "21/12/2018";
arr[1, 1] = "26/12/2019";
Range rng = Globals.ThisAddIn.Application.ActiveSheet.Range["A1:B2"];
rng.set_Value(XlRangeValueDataType.xlRangeValueDefault, arr);
UPDATE:
I've actually narrowed it down to the following:
string dt = DateTime.Now.ToString(System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat);
worksheet.Range["A1"].Value = dt;
It's bizarre, the string is formatted according to the user's locale setting, but when I insert it into excel in the second line – Excel for some reason converts it to US format. So with european date format setup in Windows, if the string is "11/03/2019", what I see in Excel after I run the code is "03/11/2019".

How to make format mask in DataGridView cell?

I need to make a format/mask in a cell that prevents the user from entering data that isn't relevant.
The column cell contains date values like "MM/YYYY" without a day value.
I tried the following to make this definition but without success:
dataGridView1.Columns[0].DefaultCellStyle.Format = "##/####" // || dd/yyyy
Also, I tried to go to the properties of DataGridView and define Format from there.
The method you're using for formatting is a valid approach. There are a few issues that may be happening here. Please ensure:
The underlying data is of type DateTime and not type string. Type string will not apply the format as expected. (See columns 1 and 2 in example below.)
The individual DataGridViewTextBoxCell.Style.Format isn't being set to something different than your desired format. This would override the column formatting. (See column 3 in example below.)
EXAMPLE
this.dataGridView1.ColumnCount = 4;
this.dataGridView1.RowCount = 1;
this.dataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
DateTime date = DateTime.Now;
this.dataGridView1[0, 0].Value = date;
this.dataGridView1[1, 0].Value = date.ToString();
this.dataGridView1[2, 0].Value = date.ToString("MM/yyyy");
this.dataGridView1[3, 0].Value = date;
this.dataGridView1[3, 0].Style.Format = "MM/yyyy";
this.dataGridView1.Columns[0].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[1].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[2].DefaultCellStyle.Format = "dd/yyyy";
this.dataGridView1.Columns[3].DefaultCellStyle.Format = "dd/yyyy";
As you can see from the output:
Columns[0] contains a DateTime and correctly formats as "dd/yyyy".
Columns[1] contains a string and cannot be reformatted to "dd/yyyy".
Columns[2] contains a formatted string and cannot be reformatted to "dd/yyyy".
Columns[3] contains a DateTime and formatting is overridden by the cell format "MM/yyyy".
To correct these issues, just set your cell value using the DateTime object and not any string representation.
In the case where you are getting this data from some outside source and it's already of type string, you can Parse it, but note that the missing portions of the DateTime object will be defaulted and there's really nothing you can do about that without having the original full data:
DateTime date = DateTime.Parse("10/2016");
Console.WriteLine("Output: {0}", date.ToString());
// Output: 10/1/2016 12:00:00 AM
Validation
If validating user input (and losing formatting on edits) is your main concern, consider the following method for validation to cancel an invalid edit:
private void DataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
DateTime parsed;
if (!DateTime.TryParse(e.FormattedValue.ToString(), out parsed))
{
this.dataGridView1.CancelEdit();
}
}
Coupled with this answer for reapplying your format using the DataGridView.CellFormatting event handler. (Note that this also negates the need to ensure your data types are not string, but is more costly due to the event being triggered often.)

Writing a TimeSpan to a cell using OpenXml without using CellValues.Date DataType

I'm creating a graph in Excel using OpenXml. The graph shows a TimeSpan of elapsed time between two DateTimes.
I'm writing my elapsed time to a cell in the following way
new Cell {DataType = new EnumValue<CellValues>(CellValues.Date), StyleIndex = 4, CellValue = new CellValue(ElapsedTime.ToString())}
where StyleIndex = 4 corresponds to
cellFormats.AppendChild(new CellFormat {NumberFormatId = 21, ApplyNumberFormat = true, FontId = 2, ApplyFont = true});
however this is causing some problems with Excel 2007 as it doesn't support date time.
The best solution I've found for this so far is to convert it to the double equivalent of the DateTime and write that to the cell but that seems ugly and I'd rather maintain my hours/minutes format.
I managed to solve this with the following code (the cellStringValue should be like 14:45):
TimeSpan TsValue = new TimeSpan();
TimeSpan.TryParse(cellStringValue, out TsValue);
double ms = TsValue.TotalSeconds;
double ms1 = (ms / 86400);
myCell.CellValue = new CellValue(ms1.ToString(CultureInfo.InvariantCulture));
Excel saves time in seconds divided by maximum seconds of a day.
Using no datatype or datatype CellValues.Number - the result is the same.
The cell should have a StyleIndex pointing to a CellFormat with for instance 20 what is "hh:mm" and where StyleIndex is the position in CellFormats listing.
My beginner problem was assuming, that a newly created workbook was having all the cellformats built in. That was wrong. You need to add them manually. At least one empty, one for date and one for time.
I managed to work around this by writing the cell as a number cell as the number cell type can be used to write dates to. Although it didn't seem to support TimeSpans, I worked around this by representing my TimeSpan as a DateTime and adding my TimeSpan to the MinValue of DateTime:
new Cell {DataType = new EnumValue<CellValues>(CellValues.Number), StyleIndex = 4, CellValue = new CellValue(DateTime.MinValue.Add(platformOccupancyRow.ElapsedTime).ToOADate().ToString(CultureInfo.CurrentCulture))}

I am not able to filter date to Month, Year, Date with generated excel using epplus

I have a view, from which I filter data and show the search results, I changed the Date format to
convert(varchar(11),getdate(),113)
This is the format in view
After downloading in excel, it is just giving all dates. No grouping is available.
I tried several formatting to change the date format in Excel as well as code like
ews.Column(i).Style.Numberformat.Format = "d-mmm-yy";
but no use.
My View returns date like 19 Mar 2014
I want grouping of date with format as 19-Mar-2014
Please suggest me a working answer.
Don't do any conversion in the view, e.g. just have it return getdate() and set the format in EPPlus code. I use this for one of my projects and it will allow selection / format correctly in Excel going this route.
I agree with Jordan in that you should not format the date within the database, but return it to your .NET code as a SQL DATETIME, C# DateTime. If you do that, you have more control over how you can write it into the spreadsheet.
var file = new FileInfo(#"C:\Temp\ExcelDemo.xlsx");
using (var package = new ExcelPackage(file))
{
var worksheet = package.Workbook.Worksheets.Add("Demo");
var date = DateTime.Now;
worksheet.Cells[1, 1].Value = #"Date Raw";
worksheet.Cells[1, 2].Value = #"Date Raw with Style.Numberformat.Format = ""D-MMM-YY""";
worksheet.Cells[1, 3].Value = #".ToString()";
worksheet.Cells[1, 4].Value = #".ToString(dd MMM yy)";
worksheet.Cells[1, 5].Value = #".ToString(yyyy-MM-ddTHH\:mm\:ss.fffffffzzz)";
worksheet.Column(2).Style.Numberformat.Format = "D-MMM-YY";
worksheet.Cells[2, 1].Value = date;
worksheet.Cells[2, 2].Value = date;
worksheet.Cells[2, 3].Value = date.ToString();
worksheet.Cells[2, 4].Value = date.ToString(#"dd MMM yy");
worksheet.Cells[2, 5].Value = date.ToString(#"yyyy-MM-ddTHH\:mm\:ss.fffffffzzz");
package.Save();
}
select replace(convert(varchar(11),getdate(),113),' ','-')

Categories

Resources