I have converted a very large csv file to a datatable and now I am parsing each column. I have run into a problem where the data in a specific column is not correct. It is suppose to be a date, ie 1/19/2020, but it has 1/1/0001 so it is crashing my attempt to parse. What I am attempting to do is to remove rows in the table before I write it back out.
DateTime checkDate = new DateTime(2018, 01, 01, 0, 0, 0);
for(int i = dt.Rows.Count-1; i >= 0; i--)
{
DataRow row = dt.Rows[i];
DateTime AccountInformationDate = DateTime.Parse(row["AccountInformationDate"].ToString());
if (DateTime.Compare(checkDate, AccountInformationDate) > 0)
{
row.Delete();
counter_skipped++;
}
}
dt.AcceptChanges();
I get an exception when it tries to parse the date.
Use DateTime.TryParse to check if the input is valid. This solution assumes that you only want to keep the rows with valid DateTime that is later than checkDate; adjust it to your needs as necessary.
DateTime checkDate = new DateTime(2018, 01, 01, 0, 0, 0);
for(int i = dt.Rows.Count-1; i >= 0; i--)
{
DataRow row = dt.Rows[i];
DateTime AccountInformationDate;
bool dateIsValid = DateTime.TryParse(row["AccountInformationDate"].ToString(), out AccountInformationDate);
if (!dateIsValid || (dateIsValid && DateTime.Compare(checkDate, AccountInformationDate) > 0))
{
row.Delete();
counter_skipped++;
}
}
dt.AcceptChanges();
You can use DateTime.TryParse to check whether the date string is correct.
Related
I've try to loop and from the below code, The problem is when it loop back to “IEnumerable selectedRows =”. The value of DateStart and DateEnd remain the same “9/1/2003 2:00:00” and “9/1/2003 2:59:00” respectively as its initial value. Why the “IEnumerable selectedRows =” do not update the DateTime value? Please help and thank you.
IEnumerable<DataRow> selectedRows =
dtData
.AsEnumerable()
.Where(row =>
row.Field<DateTime>("Date") >= DateStart
&& row.Field<DateTime>("Date") <= DateEnd);
foreach (DataRow row in selectedRows)
{
//Do some stuffs
}
//store the result in DataTable
DataRow dtDataRowResult = dtDataResult.NewRow();
dtDataRowResult[0] = DateStart;
dtDataRowResult[1] = result1;
dtDataRowResult[2] = result2;
dtDataResult.Rows.Add(dtDataRowResult);
//when code go this line below,
//it should be added one hour from the previous hour,
//so now it is “9/1/2003 3:00:00”
DateStart = DateStart.AddHours(1);
//and the DateEnd should be added to “9/1/2003 3:59:00”
DateEnd = DateStart + TimeSpan.FromMinutes(59);
//The problem is when it loop back to
//“IEnumerable<DataRow> selectedRows =”.
//The value of DateStart and DateEnd remain the same
//“9/1/2003 2:00:00” and “9/1/2003 2:59:00” respectively
//as the initial value. Why the
//“IEnumerable<DataRow> selectedRows =” not updated the
//DateTime value? Please help and thank you.
The below is the screenshot image of the example code
Let me see if I've produced a [mcve] that demonstrates your problem:
DateTime dateTime = new DateTime(2023, 1, 9, 2, 0, 0);
DataTable dataTable = new DataTable();
dataTable.Columns.Add("Date", typeof(DateTime));
DataRow dataRow = dataTable.NewRow();
dataRow[0] = dateTime;
dataTable.Rows.Add(dataRow);
Console.WriteLine($"{dateTime} == {(DateTime)dataTable.Rows[0][0]}");
dateTime += TimeSpan.FromMinutes(59.0);
Console.WriteLine($"{dateTime} != {(DateTime)dataTable.Rows[0][0]}");
When I run that I get this output:
2023/01/09 02:00:00 == 2023/01/09 02:00:00
2023/01/09 02:59:00 != 2023/01/09 02:00:00
The value in the DataTable does not update when I update the dateTime variable.
This is because when dateTime += TimeSpan.FromMinutes(59.0); is called the value in the variable dateTime is updated, but the variable stored in the DataTable is a copy of the original dateTime value. It's not linked in any way.
To make it update you would need to run this code:
dataTable.Rows[0][0] = dateTime;
Now we can see it is the same with this:
Console.WriteLine($"{dateTime} == {(DateTime)dataTable.Rows[0][0]}");
That produces:
2023/01/09 02:59:00 == 2023/01/09 02:59:00
i have a table in SqlServer which contain's: (ID, item_name, date_time_added)
i want to create a C# code to first: view (ID,item_name, date_time_added) column in datagridview then calculate (date_time_NOW - date_time_added) and view the result in a new column(named: expire's in:) in same datagridview...
Note: result would count day's remaining before expiring
what i've tried so far:
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("Expire's in:", typeof(int)));
int countrow = dataGridView1.RowCount;
for (int i = 0; i < countrow; i++)
{
string dateAsString = dataGridView1.Rows[dataGridView1.SelectedRows[0].Index].Cells[3].Value.ToString();
DateTime.TryParseExact(dateAsString , "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeLocal, out DateTime dateAsString);
dateTimePicker3.Text = dateAsString;
DateTime expire_date = dateTimePicker3.Value;
TimeSpan span = expire_date - DateTime.Now;
int days = span.Days;
dataGridView1.Rows[dataGridView1.SelectedRows[0].Index].Cells[4].Value = days;
}
Note:Code Updated...
Any help will be greatly appreciated..
I will assume the “ExpireDate” field returned from the sql query is a DateTime object. If this is the case then it would appear that converting the “date” to a string is unnecessary. Example, given a “future” date, then the difference between todays date and the “future” date can be accomplished as…
TimeSpan dif = futureDate.Subtract(DateTime.Now);
Using a DataTable proffers the ability to use an Expression column, however, I do not think this will work with dates and times. Fortunately, this should not be difficult to implement if the grids DataSource is a DataTable. Using a “Class” would be another option. This example uses a DataTable as a DataSource to the grid.
Given this, to make things simple it would appear that a method that takes a DataRow from the data table and adds this TimeSpan difference may come in handy. It may look something like below…
private void SetDifCol(DataRow row) {
TimeSpan dif = ((DateTime)row["ExpireDate"]).Subtract(DateTime.Now);
row["TimeToExpire"] = dif.Days + " days " + dif.Hours + " hours " + dif.Minutes + " minutes";
}
Given that the DataTable has already been filled with the data… the code is going to have to “ADD” this difference column, then loop through each row and calculate the difference between the dates. Therefore, a small method that simply adds this column may look something like below…
private void AddDifferenceColumn(DataTable dt) {
dt.Columns.Add("TimeToExpire", typeof(string));
}
Next is the loop through all the rows in the DataTable and simply call the SetDifCol method on each row.
private void CalculateDateDif(DataTable dt) {
foreach (DataRow row in dt.Rows) {
SetDifCol(row);
}
}
This will work as expected when the data is loaded, however, what if the user “changes” one of the “ExpireDate” values in the grid? In this case, we would need to wire up one of the grids cell change events. Specifically the grids CellValueChanged event. This event will call the SetDifCol method if the “ExpireDate” value changes in that row…
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "ExpireDate") {
if (e.RowIndex >= 0 && dataGridView1.Rows[e.RowIndex].Cells["ExpireDate"].Value != null) {
DataRowView row = (DataRowView)dataGridView1.Rows[e.RowIndex].DataBoundItem;
SetDifCol(row.Row);
}
}
}
Putting this all together may look something like below…
DataTable GridTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
GridTable = GetTable();
FillTable(GridTable);
AddDifferenceColumn(GridTable);
CalculateDateDif(GridTable);
dataGridView1.DataSource = GridTable;
dataGridView1.Columns[3].Width = 180;
}
private DataTable GetTable() {
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("ExpireDate", typeof(DateTime));
return dt;
}
private void AddDifferenceColumn(DataTable dt) {
dt.Columns.Add("TimeToExpire", typeof(string));
}
private void FillTable(DataTable dt) {
dt.Rows.Add("ID1", "Name1", new DateTime(2019, 12, 31));
dt.Rows.Add("ID2", "Name2", new DateTime(2019, 8, 31));
dt.Rows.Add("ID3", "Name3", new DateTime(2019, 4, 30));
dt.Rows.Add("ID4", "Name4", new DateTime(2019, 1, 31));
dt.Rows.Add("ID5", "Name5", new DateTime(2019, 4, 12, 21, 38, 00));
}
private void CalculateDateDif(DataTable dt) {
foreach (DataRow row in dt.Rows) {
SetDifCol(row);
}
}
private void SetDifCol(DataRow row) {
TimeSpan dif = ((DateTime)row["ExpireDate"]).Subtract(DateTime.Now);
row["TimeToExpire"] = dif.Days + " days " + dif.Hours + " hours " + dif.Minutes + " minutes";
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "ExpireDate") {
if (e.RowIndex >= 0 && dataGridView1.Rows[e.RowIndex].Cells["ExpireDate"].Value != null) {
DataRowView row = (DataRowView)dataGridView1.Rows[e.RowIndex].DataBoundItem;
SetDifCol(row.Row);
}
}
}
I hope this helps.
EDIT:
to change column type from string to int to sort numerically.
In reference to the extra question you posted, you commented that ”i want to calculate according to what is inside my db Table” … There is no code in this question or the other question that shows a data base. How are you getting the data to begin with?
It appears in this question that there IS a NEW DataTable dt and a column is added to it, however, it is NEVER used. The loop in the code simply adds the difference column to the “GRID” NOT the DataTable. My answer “adds” the diffence column to the DataTable (which you should do). I recommend you show how you are getting the data from the data base.
In reference to sorting the column, you have already noticed that strings that are numbers will not sort properly numerically. This is because they are string… solution… make them ints. Using my answer, two changes are need for this. First the creation of the column needs to be an int type…
private void AddDifferenceColumn(DataTable dt) {
dt.Columns.Add("TimeToExpire", typeof(int));
}
Second a change is needed in the SetDifCol method. Since you only want the days difference and any values less than zero should show as zero (0), then the following changes should accommodate this requirement.
private void SetDifCol(DataRow row) {
TimeSpan dif = ((DateTime)row["ExpireDate"]).Subtract(DateTime.Now);
if (dif.Days >= 0) {
row["TimeToExpire"] = dif.Days;
}
else {
row["TimeToExpire"] = 0;
}
}
These two changes should sort the column numerically as expected.
Lastly, it should be clear, that IF you want this “difference” column to be reflected in the database… then YOU will have to add the difference column to the database table, THEN, you will need to issue an update command to the database table.
From what I see you try to put a string into the DateTime value here:
DateTime str;
str=dataGridView1.Rows[dataGridView1.SelectedRows[0].Index].Cells[3].Value.ToString();
If you want to parse string to DateTime the code should look like this:
string dateAsString = dataGridView1.Rows[dataGridView1.SelectedRows[0].Index].Cells[3].Value.ToString();
DateTime.TryParseExact(dateAsString, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeLocal, out DateTime dateAsDateTime);
Then you can substract that date from DateTime.Now:
TimeSpan span = dateAsDateTime - DateTime.Now;
And finally extract the days from the span:
int days = span.Days;
OR just do it all in one line:
int days = (DateTime.Now - dataGridView1.Rows[dataGridView1.SelectedRows[0].Index].Cells[3].Value).Days;
I'm struggling with the following. I have a DataTable with dates in it. Dates that can contain several time rows. Now I want to click on a date on the calender and it will put the times records from that day in a listbox so I can then select the time.
I'm stuck and googled around but I'm blind at this point.
The datatable output in gridview:
Datum
-----------------
22-09-14 13:05:00
22-09-14 13:05:18
23-09-14 13:05:36
23-09-14 13:05:54
23-09-14 13:06:12
21-09-14 14:00:01
21-09-14 15:00:01
21-09-14 16:00:01
21-09-14 17:00:01
The code in the calander SelectionChanged event:
// Create datatable
DataTable dt = new DataTable();
string FileName = "C:\\ProjectName\\data\\data.dat";
var lines = File.ReadAllLines(FileName);
// Make date column
dt.Columns.Add("Datum", typeof(DateTime));
// add rows
for (int i = 2; i < lines.Count(); i++)
{
DataRow dr = dt.NewRow();
string[] values = lines[i].Split(new char[] { ',' }).Select(x => x.Replace("\"", "")).ToArray();
for (int j = 0; j < values.Count() && j < 1; j++)
dr[j] = values[j];
dt.Rows.Add(dr);
}
// Convert selected date
string currentDate = e.SelectedDates.Count - 1 >= 0 ? e.SelectedDates[e.SelectedDates.Count - 1].Date.ToString("dd-MM-yyyy") : "none";
// Print selected date to see format
Label1.Text = currentDate;
// Create dataview and apply filter
DataView dv = new DataView(dt);
dv.RowFilter = "Datum = #" + currentDate + "#";
dv.RowStateFilter = DataViewRowState.ModifiedCurrent;
dv.Sort = "Datum DESC";
// dataview to listbox
lbSource.DataSource = dv;
lbSource.DataTextFormatString = "{0:dd-MM-yyyy HH:mm}";
lbSource.DataTextField = "Datum";
lbSource.DataValueField = "Datum";
lbSource.DataBind();
The dv filter gives me:
String was not recognized as a valid DateTime.
Debugging stops with the following line and gives the "String was not recognized as a valid DateTime.":
dv.RowFilter = "Datum = #" + currentDate + "#";
currentdate comes with the correct date: 22-09-2014 (dd-MM-yyyy)
If someone could help me out, thanks a lot :)
Basically the .rowfilter compare takes the date as Mm/dd/yyyy as comparison. It will see 20/10/2018 as an invalid date. It will work for day being lower than 12.
So in your datatable, the date is stored as dd/mm/yyyy.
Unless you change the date storage format to mm/dd/yyyy, I don't think you can rowsfilter.
I am trying to parse out a RadCalendar Date and disable the dates prior to our Start Date of an event.
We get our StartDateTime from a database and I would like to disable the dates from our Future StartDateTime all the way back to the beginning of the current (this) month.
EDIT: More specific
Example: My StartDateTime is in November 2014 but I want to disable all dates from that future date until back to the beginning of this current month (this month is August 2014).
Below is the code we currently have, but it is only looking back i < 31. This is why I would like to the DateTime get the number of days as an int all the way back to the beginning (the 1st) of the current month.
if (nextAvailableTime != null && nextAvailableTime.StartDateTime > DateTime.Today)
{
//DISABLE dates prior to next available date
DateTime dt = nextAvailableTime.StartDateTime.AddDays(-1);
for (var i = 0; i < 31; i++) //Would like to change this to beginning of current month.
{
tkCalendar.SpecialDays.Add(new RadCalendarDay(tkCalendar) { Date = dt.Date.AddDays(i * -1), IsDisabled = true, IsSelectable = false });
}
}
Why not subtract the 2 dates and get the difference in days? I used my own variable because I was unclear what your variables were. My loop is disabling going forward instead of multiplying by -1. You may need to edit the loop to be <= or start from 1 depending on if you want the first and last date to be included.
if (nextAvailableTime != null && nextAvailableTime.StartDateTime > DateTime.Today)
{
//DISABLE dates prior to next available date
DateTime currentDate = DateTime.Now;
DateTime futureDate = DateTime.Now.AddMonths(3);
int daysBetween = (futureDate - currentDate).Days;
for (var i = 0; i < daysBetween; i++)
{
tkCalendar.SpecialDays.Add(new RadCalendarDay(tkCalendar) { Date = currentDate.AddDays(i), IsDisabled = true, IsSelectable = false });
}
}
The answer we came up with was to get the next available date and then the beginning date of the current month and get the difference using DayOfYear.
Solution is below:
if (nextAvailableTime != null && nextAvailableTime.StartDateTime > DateTime.Today)
{
//DISABLE dates prior to next available date
DateTime dt = nextAvailableTime.StartDateTime.AddDays(-1);
DateTime nextDate = nextAvailableTime.StartDateTime;
//Gate the calendar to just go get the product's next available date and then get block out everything until the beginning of the current month.
var now = DateTime.Now;
var startOfMonth = new DateTime(now.Year, now.Month, 1);
TimeSpan daysBetween = (futureDate - startOfMonth);
// for (var i = 0; i < 31; i++)//Original from 31 days from next available.
for (var i = 0; i < daysBetween.Days; i++) //Get difference between next available and beginning of current month.
{
tkCalendar.SpecialDays.Add(new RadCalendarDay(tkCalendar) { Date = dt.Date.AddDays(i * -1), IsDisabled = true, IsSelectable = false });
}
}
I'm trying to learn how to schedule pictures depending on what time a user has selected.
Here is code with questions:
private void startjob()
{
string theDate = DateTimePicker1.Value.ToString();
DateTime dt = Convert.ToDateTime(date);
{
DateTime start = new DateTime(2009, 12, 9, 10, 0, 0); //How Do I make this to read the string that is converted from DateTimePicker instead of this?
DateTime end = new DateTime(2009, 12, 10, 12, 0, 0); //How Do I make this to read the string that is converted from DateTimePicker instead of this?
DateTime now = DateTime.Now;
if ((now > start) && (now < end))
{
//match found
}
}
}
DateTimePicker.Value returns the DateTime object. You're trying to convert to and from a string type unnecessarily.
DateTime start = DateTimePickerStart.Value;
DateTime end = DateTimePickerEnd.Value;
Supposing your controls are named as DateTimePicker1 and DateTimePicker2:
private void startjob()
{
DateTime start = DateTimePicker1.Value;
DateTime end = DateTimePicker2.Value;
DateTime now = DateTime.Now;
if ((now > start) && (now < end))
{
//match found
}
}
DateTimePicker.Value property is a DateTime object itself, hence your code can be simplified, no need to convert to string.