I'm using OleDb to read data from an Excel file. The piece of code that reads the data is the following:
OleDbCommand oleDbCommand = new OleDbCommand(selectCommandText, oleDbConnection);
using (OleDbDataReader dr = oleDbCommand.ExecuteReader())
{
DataTable dt = new DataTable();
dt.Load(dr);
return dt;
}
The problem is that the data readed appears randomly as a string sometimes (for example "16.02.1995") or like a number - timestamp (41187), something like this convert Excel Date Serial Number to Regular Date.
Is there any way to solve this? I would like to read the data always as a format, don't matter if it's a number or a string.
Edit: I found that when I have the Excel file opened the date readed is in number format (date serial number) and when I don't have the file opened the date is in string format. Does somebody know why?
Edit2: The personalized format used in the date cell
To convert date number or date string to c# you need two different methods.
One to convert string and the other one to convert number to date format.
So, regarding converting string to date, there are TryParse method in c#, and regarding the number conversation to date there are already answer on that in SO.
Putting that together we can do some thing like:
public static DateTime? GetDateTime(object o)
{
DateTime? date;
try
{
date = FromStringToDate(o.ToString());
if (date == DateTime.MinValue)
{
date = FromExcelSerialDate((int)o);
}
}
catch (Exception e)
{
//log your exception
date = null;
}
return date;
}
private static DateTime FromExcelSerialDate(int serialDate)
{
if (serialDate > 59) serialDate -= 1; //Excel/Lotus 2/29/1900 bug
return new DateTime(1899, 12, 31).AddDays(serialDate);
}
private static DateTime FromStringToDate(string stringDate)
{
DateTime.TryParse(stringDate, out DateTime result);
return result;
}
To put that in use, in your main method for testing you can do some thing like:
List<object> excelData = new List<object>()
{
"16.02.1995",
41187,
13131.3242,
"",
null
};
foreach (object o in excelData)
{
var dateTime = GetDateTime(o);
if (dateTime != null)
{
Console.WriteLine(dateTime);
}
}
The output will be:
16-02-1995 00:00:00
05-10-2012 00:00:00
I have testing it i excel as well.
Note: This is just example, you might improve the methods, change the order, adding more protective lines so it does not break, for example if date is null, empty or wrong format in excel to fit you business logic.
Related
I have a page to display content of different tables upon user selection.
These tables have fields DateTime type, but time is not always relevant, specially when time is 00:00:00
These means that, sometimes the table to display might have a BirthDate column where time is irrelevant, others might have CreatedOn where time is necessary to be displayed in the view.
I am not able to specifically set a format for an specific column as the view can show any table, however in code behind (C#) I am able to identify if a column is DateTime type and set a format before displayng.
Using condition like:
DataTable dt0 = dsDataSet.Tables[0].Copy();
foreach (DataColumn column in dt0.Columns)
{
if (column.DataType == typeof(System.DateTime))
{
var printDateFormat = dtfi.ShortDatePattern;
:..
:..
}
}
The result will be dd-MM-yyyy for all DateTime columns, and will remove the time for columns even for those columns for which time is needed to be displayed.
An ideal solution should display the data as follow:
in DB -> DateTime |In Page View| in DB -> DateTime |In Page View |
===================|============|===================|===================|
BirthDate | |Created On | |
===================|============|===================|===================|
07/03/2014 00:00:00|07/03/2014 |05/03/2015 03:04:01|05/03/2015 03:04:01|
12/01/2014 00:00:00|12/01/2014 |03/01/2015 06:05:01|03/01/2015 06:05:01|
Thank you in advance.
I'm not sure how efficient this is, but this will strip the time when you need that done:
First Cast the Date as type DATE, then recast it as DATETIME
CAST(CAST(GETDATE() AS Date) AS Datetime)
However, if you're just formatting it in C#, just call ToShortDateString() on the DateTime field.
UPDATE
So, you just need to display the time if it has a non-zero time. In that case, you could:
Test the Hours, Minutes and Seconds to see if they are each 0.
var date = DateTime.Now;
var printDate = (date.Hour == 0 && date.Minute == 0 && date.Second == 0)
? date.ToShortDateString() : date.ToShortDateTimeString();
UPDATE 2
One other thing would be to get the time of day and then the total seconds. This will be zero at midnight.
var printDate2 = (date.TimeOfDay.TotalSeconds == 0)
? date.ToShortDateString() : date.ToShortDateTimeString();
You can create a new DataTable, replacing the DateTime column to a string column, specifying the desired format.
// DataTable with original data
// May contain DataTime with zero time.
var dt = new DataTable();
// DataTable with Date converted to string.
var dt2 = new DataTable();
var dateIndexes = new HashSet<int>();
// Create columns in dt2, changing DateTime with zero time to string type
foreach (DataColumn column in dt.Columns)
{
if (column.DataType == typeof(DateTime) &&
dt.Rows.Cast<DataRow>()
.Select(row => (DateTime)row[column])
.All(dateTime => dateTime.TimeOfDay.Ticks == 0))
{
// If all time is zero then create string type column.
dt2.Columns.Add(column.ColumnName, typeof(string));
// Remember the index of the column with zero time
dateIndexes.Add(column.Ordinal);
}
else
{
// Create column same type.
dt2.Columns.Add(column.ColumnName, column.DataType);
}
}
// Copy rows
foreach (DataRow row in dt.Rows)
{
var newRow = dt2.NewRow();
dt2.Rows.Add(newRow);
for (int i = 0; i < row.ItemArray.Length; i++)
{
if (dateIndexes.Contains(i))
{
// Column with zero time. Convert it to string.
newRow[i] = ((DateTime)row[i]).ToShortDateString();
}
else
{
// Copy as is.
newRow[i] = row[i];
}
}
}
One solution is to add a custom extension method to the DateTime class that returns your custom string format (this potentially saves a lot of duplicated code and provides a single place to change the format later if needed):
public static class Extensions
{
public static string GetCustomFormatString(this DateTime input,
bool excludeTimeIfZero = true)
{
return input.TimeOfDay == TimeSpan.Zero && excludeTimeIfZero
? input.ToString("MM/dd/yyyy")
: input.ToString("MM/dd/yyyy hh:mm:ss");
}
}
Example Usage
private static void Main()
{
// DateTime.Now includes a non-zero time (except at midnight)
Console.WriteLine(DateTime.Now.GetCustomFormatString());
// A new DateTime has a zero time value
Console.WriteLine(new DateTime().GetCustomFormatString());
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
Output
i have dgvData(datagridview), cmbPickRoom(combobox), numDay_In & numDay_Out(numericupdown) and code which like this
private void dgvData_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewRow row = this.dgvData.Rows[e.RowIndex];
cmbPickRoom.Text = row.Cells["Room"].Value.ToString();
numDay_In.Text = row.Cells["Day_In"].Value.ToString();
numDay_Out.Text = row.Cells["Day_Out"].Value.ToString();
}
}
while the data in mysql store date format(dd-mm-yyyy) for both "Day_In" and "Day_Out".
I want when i click dgvData, numDay_In and numDay_Out only take the day(dd)
If the database fields are of type DateTime, (Day_In and Day_Out) then you don't need to convert these values to string but to a DateTime variable, then getting the day is just a matter of reading a property
DateTime inDate = Convert.ToDateTime(row.Cells["Day_In"].Value);
numDay_In.Text = inDate.Day.ToString();
You can use DateTime.TryParse to convert the user entered string to date time format and then get the Day from it as I have done in the below code.
DateTime dt = new DateTime();
if(DateTime.TryParse(row.Cells["Day_In"].Value, out dt))
{
numDay_In.Text = dt.Day.ToString();
}
else
{
//Code to display error message
}
The added advantage of this code is that you can check if the user entered format is coorect, by checking the success of the TryParse in an if condition, If it fails, you can prompt the user to enter the Date in the correct format.
I am parsing a CSV file. One of it's columns represents a date. The thing is that the date can be in dd/MM/yyyy and MM/dd/yyyy.
I can't identify which format is correct when for example the date there is 06/04/2015 (April or June?)
My code is doing this to format the output (standarized csv) when I can tell the difference. Do you know if there is a better method to this and how to Identify correct format?
public static DateTime? ToValidDateTime(this string date)
{
if (string.IsNullOrEmpty(date))
return null;
try
{
var r = DateTime.Parse(date, CultureInfo.InvariantCulture);
return new DateTime(r.Year, r.Month, r.Day, r.Hour, r.Minute, r.Second);
}
catch (Exception exception)
{
var r = DateTime.Parse(date);
return new DateTime(r.Year, r.Month, r.Day, r.Hour, r.Minute, r.Second);
}
}
This is not an answer, but it needs too much formating to fit as a comment. This code is redundant:
var r = DateTime.Parse(date);
return new DateTime(r.Year, r.Month, r.Day, r.Hour, r.Minute, r.Second);
You're creating two datetime instances for no good reason. Just the first one is good enough. You can just do this instead:
return DateTime.Parse(date);
The same holds for the version with the InvariantCulture format specifier.
I am working on a reminder application. The applications stores the reminder Date, Time and DateLastShown (in different fields) in the database and pulls them out to performs checks.
All dates are in "d/MM/yyyy" format. My problem is that when i pull the dates from the DB and try to store back into DateTime format they are still being shown in "M/d/yyyy" format which is not how the app needs to be.
I essentially need to pull the values from the DB do some checks to determine if it's time to show the reminder and do so. It seems rather straight forward, maybe i am making some small error.
Below is my code with comments.
Any help really appreciated.
public void CheckReminders()
{
IQueryable<Reminder> reminders;
DateTime reminderDate;
DateTime reminderTime;
DateTime reminderLastShown;
DateTime todayDate;
DateTime timeNow;
while (true)
{
try
{
db = new StudioManagementEntities();
reminders = from r in db.Reminders
select r;
foreach (Reminder r in reminders)
{
if (r.Enabled == 1)
{
if (r.Recurring == 1)
{
// This is the code i was using before when the date was in "M/d/yyyy" format
// which seems to be default.
reminderTime = DateTime.Parse(r.Time);
timeNow = DateTime.Parse(DateTime.Now.ToLongTimeString());
if (r.DateLastShown != DateTime.Today.ToShortDateString() && timeNow >= reminderTime)
{
FrmReminder frmReminder = new FrmReminder(r.Id, true);
frmReminder.ShowDialog();
r.DateLastShown = DateTime.Today.ToShortDateString();
}
}
else
{
// Now i need to pass in "d/M/yyyy" format but the
// code seems to return in "M/d/yyyy" format.
reminderDate = DateTime.ParseExact(r.Date, "d/MM/yyyy", null);
// Even this returns in wrong format
reminderDate = DateTime.ParseExact("24/01/2013", "d/MM/yyyy", null);
// Have tried with CultureInfo.InvariantCulture too.
MessageBox.Show(reminderDate.ToString());
return;
if (
r.DateLastShown != DateTime.Today.Date.ToShortDateString() //&&
//r.Date == DateTime.ParseExact(DateTime.Today, "d/MM/yyyy", CultureInfo.InvariantCulture).ToString() //&&
//now.TimeOfDay.TotalSeconds >= reminderTime.TimeOfDay.TotalSeconds
)
{
FrmReminder frmReminder = new FrmReminder(r.Id, true);
frmReminder.ShowDialog();
r.DateLastShown = DateTime.Today.ToShortDateString();
}
}
}
}
db.SaveChanges();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
// Check every minute
Thread.Sleep(60000);
}
}
And the DB table.
If the parsing into the date object is not erroring out, you are just having a problem with your output when you call .ToString().
From the docs:
The ToString method returns the string representation of the date and
time in the calendar used by the current culture.
If you need something other than the user's current culture settings, you can specify that using a format string in the overloaded ToString() method:
var reminderDate = DateTime.ParseExact("24/01/2013", "d/MM/yyyy", null);
MessageBox.Show(reminderDate.ToString("d/MM/yyyy"));
Also, as others have stated in comments, if possible you should be using the date data type in your database instead of storing the values as strings.
My problem is to delete data from given date to current date,
My code works fine for deleting the data by the date given in the DateTimePicker.
i want to delete the data from given date in DateTimePicker to CurrentDate.
For example:
In subfolder123 the data is available from 20100131 to 20110531 (Date Format yyyyMMdd).
I want to delete the date from 20100215 to 20110531.
Hope you understood my Question and problem.
Is there any suggestions?
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
string todaysDate = dateTimePicker1.Text;
int FinalDate4 = 0;
string Destinationnsefx = "C:\\folder\\subfolder\\subfolder123";
int xyz = 0;
string SecSym = (9722).ToString();
MWriterClass writerdelete1 = new MWriterClass();
try
{
writerdelete1.OpenDirectory(Destinationnsefx);
writerdelete1.OpenSecurityBySymbol(SecSym);
FinalDate4 = int.Parse(todaysDate);
if (writerdelete1.get_bDateExists(FinalDate4))
{
try
{
writerdelete1.DeleteIntradaySecRecordEx(FinalDate4, 080000, 240000);
}
catch
{
}
}
writerdelete1.CloseSecurity();
writerdelete1.CloseDirectory();
}
catch
{
}
}
Thanks in advance.
It sounds like you get a date from your DateTime picker and you need to work from that start date to your end date, correct?
In that case, look at the AddDays method for a DateTime object.
For example, this snippet of code will start at 4/1/2011 and print every date from then until today, in the format you specified.
var workingDate = new DateTime(2011, 4, 1);
while (workingDate < DateTime.Today)
{
workingDate = workingDate.AddDays(1);
Console.WriteLine(string.Format("{0:yyyyMMdd}", workingDate));
}