Copy last value to other cells till we see a filled cell - c#

I have a list like below :
2016-10-05 00:00:00.000
NULL
NULL
NULL
2016-08-12 07:46:00.000
NULL
NULL
Which I need to convert to
2016-10-05 00:00:00.000
2016-10-05 00:00:00.000
2016-10-05 00:00:00.000
2016-10-05 00:00:00.000
2016-08-12 07:46:00.000
2016-08-12 07:46:00.000
2016-08-12 07:46:00.000
Basically, I need to capture the last occurrence date and copy it to next rows till i see a filled row.
Here is how I see it working now
foreach (var date in dates)
{
var lastValue = null;
if(date != null)
{
lastValue = date;
}
if(date == null)
{
date = lastValue;
}
else
{
lastValue = date;
}
}

I would use a simple for-loop for this
List<DateTime?> dates = new List<DateTime?>()
{
new DateTime( 2016,10,05,00,00,00),
null,
null,
null,
new DateTime( 2016, 08, 12 ,07,46,00),
null,
null
};
DateTime? latest = null;
for (int i = 0; i < dates.Count; i++)
{
if (dates[i].HasValue)
{
latest = dates[i];
}
else
{
dates[i] = latest;
}
}
https://dotnetfiddle.net/qqDaMf

//input
List<DateTime?> dates = new List<DateTime?> { DateTime.Now, null, DateTime.Parse("2019-10-01"), null };
DateTime? lastPresentDate = dates.FirstOrDefault();
if (lastPresentDate.HasValue)
{
dates = dates.Select(d => d.HasValue ? lastPresentDate = d : lastPresentDate).ToList();
}
//output
7/23/2019 7:15:48 AM
7/23/2019 7:15:48 AM
10/1/2019 12:00:00 AM
10/1/2019 12:00:00 AM
This will only correct the dates if the first date is present and otherwise leave the list as is.

Assuming you actually have a class (let's say Product) with some other properties:
DateTime? lastDate = null;
var result = products.Select(
p =>
new {
Id = p.Id,
CreateDate = (p.CreateDate.HasValue ? (lastDate = p.CreateDate) : lastDate)
//Other properties..
}
);
If not and you have just the dates:
DateTime? lastDate = null;
var result = dates.Select(d => (d.HasValue ? (lastDate = d.Value) : lastDate));
You can add .ToList() if you like or not.

Change String class for whatever class u are using.
String lastValue = null;
foreach(var value in ValuesList){
if(value == null)
value = lastValue;
else
lastValue = value;
}

Related

pairing and calculating the hours of checkTypes

Continuing from here, I have a table named Attendancelogs which has all the sorted logs CHeckTypes In and Out accordingly. (Thanks to #StephenMuecke the previous question was pretty much resolved) However, what I am trying to achieve next is to make a pairList of all the In and Out in a particular period (StartDate and EndDate) and then calculate the total hours of the employee.
Different Cases, already been taken care of in the previous question
I have two method, one called getSingleDevicePairs(int EnrollNumber, DateTime StartDate, DateTime EndDate) which creates the pairList and the second method getTimeSpentEachDay(List<Pair> pairList) which calculates the total hours of each day.
Pair.cs
public class Pair {
public int id { get; set; }
public int RegisterationId { get; set; }
public int EmpID { get; set; }
public DateTime InnDateTime { get; set; }
public DateTime OutDateTime { get; set; }
}
public List<Pair> getSingleDevicePairs(int EnrollNumber, DateTime StartDate, DateTime EndDate) {
DateTime today = DateTime.Now;
List<Pair> pairList = new List<Pair>();
var logs = db.AttendanceLogs.Where(x => x.RegisterationId == EnrollNumber && x.Date >= StartDate &&
x.Date <= EndDate && x.isIgnore != true && (x.CheckType == "In" || x.CheckType == "Out")).Distinct().ToList();
int loopEnd = 0;
bool oddLogs = false;
if (logs.Count % 2 == 0) {
loopEnd = logs.Count;
} else {
loopEnd = logs.Count - 1;
oddLogs = true;
}
bool inn = true;
if (loopEnd > 1) {
Pair pair = new Pair();
for (int v = 0; v < loopEnd; v++) {
if (inn) {
pair.InnDateTime = logs[v].DateTime;
inn = false;
} else {
pair.OutDateTime = logs[v].DateTime;
inn = true;
pairList.Add(pair);
pair = new Pair();
}
}
}
Bogus bogus = new Bogus();
DateTime bogusDate = new DateTime();
if (oddLogs) {
bogus.MachineNum = logs[logs.Count - 1].DeviceID;
bogus.RegisterationId = logs[logs.Count - 1].RegisterationId;
bogus.DateTime = logs[logs.Count - 1].DateTime;
bogusDate = logs[logs.Count - 1].DateTime;
}
return pairList;
}
^I changed the above method with different approach, since the above approach would mess up with Case 1 shown in the link above.
public List<Pair> getSingleDevicePairs(int EnrollNumber, DateTime StartDate, DateTime EndDate) {
DateTime today = DateTime.Now;
List<Pair> pairList = new List<Pair>();
var logs = db.AttendanceLogs.Where(x => x.RegisterationId == EnrollNumber && x.Date >= StartDate &&
x.Date <= EndDate && x.isIgnore != true && (x.CheckType == "In" || x.CheckType == "Out")).Distinct().ToList();
bool isCheck = false;
Pair pair = new Pair();
DateTime previous = logs.FirstOrDefault().DateTime;
foreach (var log in logs) {
if (!isCheck) {
pair.InnDateTime = log.DateTime;
isCheck = true;
} else {
pair.OutDateTime = log.DateTime;
isCheck = false;
}
pairList.Add(pair);
pair = new Pair();
}
return pairList;
}
^This approach again will fail at Case 1 as it is sequentially adding In and Out in the pairList.
public List<DateAndTime> getTimeSpentEachDay(List<Pair> pairList) {
List<DateAndTime> list = new List<DateAndTime>();
if (pairList.Count > 0) {
for (int i = 0; i < pairList.Count; i++) {
TimeSpan span = TimeSpan.Zero;
// bool flag = false;
int result = -1;
do {
span = span + (pairList[i].OutDateTime - pairList[i].InnDateTime);
result = -1;
if (i < pairList.Count - 1) {
DateTime p = (DateTime)pairList[i].InnDateTime;
DateTime q = (DateTime)pairList[i + 1].InnDateTime;
result = DateTime.Compare(p.Date, q.Date);
}
if (result == 0) {
i++;
// flag = true;
}
} while (result == 0);
//if (i == pairList.Count - 1)
//{
// span = span + (pairList[i].OutDateTime - pairList[i].InnDateTime) ?? TimeSpan.Zero;
//}
DateAndTime dnt = new DateAndTime();
dnt.date = ((DateTime)pairList[i].InnDateTime).ToString("yyyy-MM-dd");
dnt.Time = span;
list.Add(dnt);
}
}
return list.ToList();
}
I am trying to get total hours for each pair as well as a way to take the odd In's together which I can display on the calendar.
Below is an image of the calendar view for an employee which displays only the paired hours, I even want to show a In that would indicate the employee that he either forgot to check out or a missing entry was made.
*Lets say he had a checkin for 9th April of around 08:00 PM that had no Check out on that day and also in the NightersLimit (12 AM - 7 AM) then there should be a single line displayed on the calendar which can only happen if I bring the bogus record for a day from previous method.
There is nothing wrong with the getTimeSpentEachDay(); just a little changes in the getSingleDevicePairs(); method, your first approach fails since it eliminates the last entry of the logs in case of an odd number and your second approach fails since it is not taking account of the sequence the logs are stored in the table.
public List<Pair> getSingleDevicePairs(int EnrollNumber, DateTime StartDate, DateTime EndDate, int? missingEntry)
{
var logs = db.AttendanceLogs.Where(x => x.RegisterationId == EnrollNumber &&
x.Date >= StartDate && x.Date <= EndDate && x.isIgnore != true
&& (x.CheckType == "In" || x.CheckType == "Out")).Distinct().ToList();
if (logs.Count > 0)
{
bool isCheck = false;
Pair pair = new Pair();
DateTime previous = logs.FirstOrDefault().DateTime;
foreach (var log in logs)
{
if (!isCheck)
{
if (log.CheckType == "In")
{
pair.InnDateTime = log.DateTime;
isCheck = true;
}
}
else
{
if (log.CheckType == "Out")
{
pair.OutDateTime = log.DateTime;
isCheck = false;
pairList.Add(pair);
pair = new Pair();
}
if (pair.OutDateTime == DateTime.MinValue)
{
pair.InnDateTime = log.DateTime;
}
}
}
}
return pairList;
}
This completes the pair only when there is an Out for an In.

C# WinForm error import from excel to database

Hei. I need to understand why I receive an error like that :
C# windows form import from excel error
I can't separe the year from string (year time). Or, can I renounce at split and import directly the string as "date"? Sorry, I'm too beginner in c#, but I need this help, is a task for me.
Here is my code :
for (int i = 0; i < dvColumns.Count; i++)
{
string columnName = string.Empty;
string columnField = string.Empty;
if ((dvColumns[i]["Header"] != null) && (!Convert.IsDBNull(dvColumns[i]["Header"])))
{
columnName = dvColumns[i]["Header"].ToString();
}
if ((dvColumns[i]["Field"] != null) && (!Convert.IsDBNull(dvColumns[i]["Field"])))
{
columnField = dvColumns[i]["Field"].ToString();
}
rangeObject = cellsObject.GetType().InvokeMember("Item", BindingFlags.GetProperty, null, cellsObject, new object[] { row, i + 1 });
object valueObject = rangeObject.GetType().InvokeMember("Value", BindingFlags.GetProperty, null, rangeObject, null);
if (columnName == "FiscalCode" && columnField == "PartnerId")
{
string fiscalCode = Erp.Core.Utils.GetStringFromObject(valueObject);
partnerId = p.GetPartnerIdByFiscalCode(fiscalCode);
eventRow["PartnerId"] = partnerId;
}
else if (columnField == "StartDate" || columnField == "EndDate")
{
string date = Erp.Core.Utils.GetStringFromObject(valueObject);
DateTime columnDate = DateTime.Now;
string[] dateComponents = null;
int year = 0;
int month = 0;
int day = 0;
if (date.Contains("."))
{
dateComponents = date.Split('.');
}
if (date.Contains("/"))
{
dateComponents = date.Split('/');
}
if (date.Contains(":"))
{
dateComponents = date.Split(':');
}
if (dateComponents.Length > 1)
{
string s = dateComponents[0];
day = Erp.Core.Utils.GetIntFromObject(s);
s = dateComponents[1];
month = Erp.Core.Utils.GetIntFromObject(s);
s = dateComponents[2];
year = Erp.Core.Utils.GetIntFromObject(s);
columnDate = new DateTime(year, month, day, 9, 0, 0);
}
eventRow[columnField] = columnDate;
}
else if (columnField != "PartnerId" && columnField != "StartDate" && columnField != "EndDate")
{
eventRow[columnField] = valueObject;
}
}
I tried to keep in excel same format as in database table : 'yyyy/mm/dd hh:mm:ss.000'.
The line date = Erp.Core.Utils.GetStringFromObject(valueObject); get my date from first excel cell.
ds.Tables["Events"] is all time empty.
I know this line eventRow[columnField] = date; must add the dates in DB, really? After split, day is ok (receive an int by s[0]), month is ok (receive an int by s[1], but s[2] for year is something like 2017 19:06:22 .... year plus time). I tried to split again by space, but without results, to keep the number (2017) in year variable.
Best way is to use DateTime.ParseExact method. In your case, if original format is 'yyyy/mm/dd hh:mm:ss.000', you can convert it to DateTime like this:
//string date = Erp.Core.Utils.GetStringFromObject(valueObject);
string date = "2017/08/15 10:20:30.000";
DateTime columnDate = DateTime.ParseExact(date, "yyyy/MM/dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
This way you can skip parsing excel string.
In your example, usage will be like this:
//...snip...
else if (columnField == "StartDate" || columnField == "EndDate")
{
string date = Erp.Core.Utils.GetStringFromObject(valueObject);
//parsing date string
DateTime columnDate = DateTime.ParseExact(date, "yyyy/MM/dd HH:mm:ss.fff", CultureInfo.InvariantCulture);
eventRow[columnField] = columnDate;
}
else if (columnField != "PartnerId" && columnField != "StartDate" && columnField != "EndDate")
{
eventRow[columnField] = valueObject;
}
if hours are in 12-hour format, use lowercase hh, like this "yyyy/MM/dd hh:mm:ss.fff"

How to determine if the value of datetime is valid(full date) or it is in year only?

DATETIME Value 1980
I have this code to retrieve a DateTime from sql
string startDate = ed.IDAFrom != null ? Convert.ToDateTime(ed.IDAFrom).ToShortDateString() : "";
EDIT
Note: The Date here is Year Graduated (must be in full date)
I have a datepicker in my view(so the date is in full date right?).. What if the user forgot the date when he graduate so the user will be edit the datepicker to year only.
What I want to achieve here is if the user encode full date or year I want to get the value of YEAR if the user encode full date.
Hope it clears.
Thanks.
Code
foreach (var ed in exams)
{
int rowId = i;
string startDate = ed.IDAFrom != null ?Convert.ToDateTime(ed.IDAFrom).ToShortDateString() : "";
string endDate = ed.IDATo != null ? Convert.ToDateTime(ed.IDATo).ToShortDateString() : "";
string InclusiveDates = startDate + " - " + endDate;
rowsObj[i] = new { id = rowId, cell = new object[] { rowId, InclusiveDates } };
i++;
}
I want to display the year only if it is in full date.
DateTime value;
if(DateTime.TryParse(ed.IDAFrom, out value))
{
Int year = value.Year;
}
If you care about culture:
CultureInfo = CultureInfo.CreateSpecificCulture("en-US"); // Or whichever culture you need
if (DateTime.TryParse(ed.IDAFrom, culture, DateTimeStyles.None, out value))
{
int year = value.Year;
}
If the user has the option to either enter year only or a full date, use this method:
public static string GetDateTime(string value)
{
DateTime date;
string dateString = ""; // Empty by default
// If full date is given, this will succeed
if (DateTime.TryParse(value, out date))
{
dateString = date.ToShortDateString();
}
// If only year is given then this will succeed
else if (DateTime.TryParseExact(value,
"yyyy",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out date))
{
dateString = date.ToShortDateString();
}
return dateString;
}
EDIT
Now that you have added some more code to your question, here is how to do it using Linq:
int i = 0;
int j = 0;
var rows = list.Select(exam =>
{
string inclusiveDates = string.Format("{0} - {1}", GetDateTime(exam.IDAFrom), GetDateTime(exam.IDATo));
return new
{
Id = ++i,
Cell = new object[] { ++j, inclusiveDates }
};
})
.ToList();
And here is an example usage
class Program
{
public class Exam
{
public string IDAFrom { get; set; }
public string IDATo { get; set; }
}
public static string GetDateTime(string value)
{
DateTime date;
string dateString = ""; // Empty by default
// If full date is given, this will succeed
if (DateTime.TryParse(value, out date))
{
dateString = date.ToShortDateString();
}
// If only year is given then this will succeed
else if (DateTime.TryParseExact(value,
"yyyy",
CultureInfo.InvariantCulture,
DateTimeStyles.None,
out date))
{
dateString = date.ToShortDateString();
}
return dateString;
}
static void Main(string[] args)
{
var list = new List<Exam> { new Exam { IDAFrom = "1999", IDATo = null },
new Exam { IDAFrom = DateTime.Now.ToShortDateString(), IDATo = DateTime.Now.AddDays(5).ToShortDateString() } };
int i = 0;
int j = 0;
var rows = list.Select(exam =>
{
string inclusiveDates = string.Format("{0} - {1}", GetDateTime(exam.IDAFrom), GetDateTime(exam.IDATo));
return new
{
Id = ++i,
Cell = new object[] { ++j, inclusiveDates }
};
})
.ToList();
foreach (var item in rows)
{
Console.WriteLine("{0}\t{1}\t{2}", item.Id.ToString(), item.Cell[0], item.Cell[1]);
}
Console.Read();
}
}

How to set a default value to a DateTime parameter

In my MVC application I want to set default values to the DateTime parameter.
[HttpPost]
public ActionResult BudgetVSActualTabular(DateTime startDate)
{
var Odata = _db.sp_BudgetedVsActualTabular(startDate).ToList();
string[] monthName = new string[12];
for (int i = 0; i < 12;i++ )
{
DateTime date = startDate;
date = date.AddMonths(i);
monthName[i] = date.ToString("MMMM") + " " + date.Year.ToString();
}
ViewBag.startDate = new SelectList(_db.DaymonFinancialYears, "startDate", "DateRange");
var MonthName = monthName.ToList();
ViewBag.Bdata = Odata;
ViewBag.Cdata = MonthName;
return View();
}
You cannot set a null to a DateTime but you can use a Nullable DateTime parameter instead:
[HttpPost]
public ActionResult BudgetVSActualTabular(DateTime? startDate = null )
{
if (startDate == null)
{
startDate = new DateTime(2016, 06, 01);
}
//You should pass startDate.Value
var Odata = _db.sp_BudgetedVsActualTabular(startDate.Value).ToList();
}
You can use the default keyword with this syntax
public ActionResult BudgetVSActualTabular(DateTime startDate = default(DateTime))
This will make possible to call the method without passing any parameter and inside your method the startDate variable will be equal to DateTime.MinValue
If you need the default to be a specific date instead of DateTime.MinValue you could write a simple test
public ActionResult BudgetVSActualTabular(DateTime startDate = default(DateTime))
{
if(startDate == DateTime.MinValue)
startDate = new DateTime(2014,6,1);
// After the check for a missing parameter pass the startDate as before
var Odata = _db.sp_BudgetedVsActualTabular(startDate).ToList();
.....
}
Named and optional (default) parameters are available starting from C# 4.0. in case you're using an older version, you may overload your method like:
public ActionResult BudgetVSActualTabular()
{
return BudgetVSActualTabular(new DateTime(2014,6,1));
}
I would suggest setting the DateTime to be nullable public ActionResult BudgetVSActualTabular(DateTime? startDate).
Inside your controller you can use DateTime.HasValue to set a default if the DateTime is null.
var nonNullableDate = startDate.HasValue ? startDate.Value : new DateTime();
[HttpPost]
public ActionResult BudgetVSActualTabular(DateTime? startDate)
{
var nonNullableDate = startDate.HasValue ? startDate.Value : new DateTime();
var Odata = _db.sp_BudgetedVsActualTabular(nonNullableDate).ToList();
string[] monthName = new string[12];
for (int i = 0; i < 12;i++ )
{
DateTime date = nonNullableDate;
date = date.AddMonths(i);
monthName[i] = date.ToString("MMMM") + " " + date.Year.ToString();
}
ViewBag.startDate = new SelectList(_db.DaymonFinancialYears, "startDate", "DateRange");
var MonthName = monthName.ToList();
ViewBag.Bdata = Odata;
ViewBag.Cdata = MonthName;
return View();
}

How to Compare two date without timeline in C#

I want to compare two dates. In pseudo-code:
If the dueDate > now or dueDate = now
Then Fine Amount = something.
Else Fine Amount = 0
I wrote below code:
DateTime dueDate = Convert.ToDateTime(Reader1[3].ToString());
DateTime now = DateTime.Now;
int result = DateTime.Compare(dueDate, now);
if ((result < 0) || (result == 1))
{
row["Fine_Amount"] = Convert.ToDouble(Reader1[4].ToString());
}
else
{
row["Fine_Amount"] = 0;
}
This code gives wrong value, when
dueDate = 23-12-2011 AM 12:00:00
now = 23-12-2011 PM 05:26:54
I want to Compare:
dueDate = 23-12-2011
now = 23-12-2011
How do I remove the time in that?.
Adding below code is given result. But its to lengthy code.: -
DateTime dueDate = Convert.ToDateTime(Reader1[3].ToString());
DateTime now = DateTime.Now;
if (dueDate.Year < now.Year)
{
row["Fine_Amount"] = Convert.ToDouble(Reader1[4].ToString());
}
else if (dueDate.Year > now.Year)
{
row["Fine_Amount"] = 0;
}
else if (dueDate.Year == now.Year)
{
if (dueDate.Month < now.Month)
{
row["Fine_Amount"] = Convert.ToDouble(Reader1[4].ToString();
}
else if(dueDate.Month > now.Month)
{
row["Fine_Amount"] = 0;
}
else if(dueDate.Month == now.Month)
{
if(dueDate.Day < now.Day)
{
row["Fine_Amount"] = Convert.ToDouble(Reader1[4].ToString();
}
else
{
row["Fine_Amount"] = 0;
}
}
}
Is there any way to short this code?.
Answer For this Question is
if (dueDate.Date >= now.Date)
{
row["Fine_Amount"] = 0;
}
else
{
row["Fine_Amount"] = Convert.ToDouble(Reader1[4].ToString());
}
This datetime.date is gives
dueDate = 23-12-2011 AM 12:00:00 to 23-12-2011 AM 12:00:00
now = 23-12-2011 PM 05:26:54 to 23-12-2011 AM 12:00:00
You can use DateTime.Now.Date
According to docs, Date property returns: A new object with the same date as this instance, and the time value set to 12:00:00 midnight (00:00:00).
The DateTime class in C# supports comparison by simply using <, >, and == operators. Do it like your above written pseudo code.
dueDate.Date >= DateTime.Now.Date
Although you could use the .Date property of DateTime it is generally a good practice to compare a certain date to a date range:
startDate <= someDate && someDate < endDate
You can use the DateTime.Date Property to gets the date component of a DateTime value:
if (dueDate.Date >= DateTime.Now.Date)
use the Date property of DateTime object for comparison

Categories