I am trying to find the biggest positive changes in the account transactions. It starts with opening balance and keep changing based on spending and deposits.
We need to find in which two dates the account contains the biggest or highest positive cash flow. I am not able to calculate and my code fails. I think my logic is wrong it gives a wrong output. Because between 8 Dec - 10 Dec account seen highest deposit or positive changes
12/11/2015 12:00:00 AM, 12/12/2015 12:00:00 AM, 23000
Instead
12/8/2015 12:00:00 AM, 12/10/2015 12:00:00 AM, 10000
dotnet fiddle
Below is the code
using System;
using System.Collections.Generic;
public class Test
{
public static void Main()
{
var transactions = new List<Transaction>()
{
new Transaction() {Date = new DateTime(2015, 12, 04), Balance = -4000}, // Open with negative 4000
new Transaction() {Date = new DateTime(2015, 12, 05), Balance = 2000}, // Settled 6000, so balance 2000
new Transaction() {Date = new DateTime(2015, 12, 06), Balance = 0}, // Spent 2000
new Transaction() {Date = new DateTime(2015, 12, 07), Balance = 2000}, // Deposited 2000
new Transaction() {Date = new DateTime(2015, 12, 08), Balance = -5000}, // Spent 7000
new Transaction() {Date = new DateTime(2015, 12, 09), Balance = 0}, // Deposited 5000
new Transaction() {Date = new DateTime(2015, 12, 10), Balance = 5000}, // Deposited 5000
new Transaction() {Date = new DateTime(2015, 12, 11), Balance = 1000}, // Spent 4000
new Transaction() {Date = new DateTime(2015, 12, 12), Balance = 6000}, // Deposited 5000
};
var (start, end, biggestAmountChangePositive) = GetBiggestBalanceChangeInPositive(transactions);
Console.WriteLine(start); //2015, 12, 08
Console.WriteLine(end); //2015, 12, 10
Console.WriteLine(biggestAmountChangePositive); //10000
}
public static (DateTime? start, DateTime? end, decimal biggestAmountChangePositive) GetBiggestBalanceChangeInPositive(List<Transaction> transactions)
{
decimal biggestAmountChangePositive = 0;
DateTime? startDate = null;
DateTime? endDate = null;
for (var i = 1; i < transactions.Count; i++)
{
if (transactions[i].Balance > transactions[i - 1].Balance)
{
var change = Math.Abs(transactions[i - 1].Balance - transactions[i].Balance);
biggestAmountChangePositive = biggestAmountChangePositive + change;
startDate = transactions[i - 1].Date;
endDate = transactions[i].Date;
}
}
return (startDate, endDate, biggestAmountChangePositive);
}
}
public class Transaction
{
public DateTime Date { get; set; }
public decimal Balance { get; set; }
}
I made what you asked.
I created one method and one class to remove some code.
public static (DateTime? start, DateTime? end, decimal highestPositiveBalanceChange) GetBiggestBalanceChangeInPositive(List<Transaction> transactions)
{
DateTime? startDate = null;
DateTime? endDate = null;
var highestPositiveBalanceChange = decimal.MinValue;
DateTime? tempStart = transactions[0].Date;
DateTime? tempEnd = transactions[0].Date;
var tempLast = transactions[0].Balance;
decimal tempHighestPositiveBalanceChange = 0;
for (var index = 1; index < transactions.Count; index++)
{
var transaction = transactions[index];
if (transaction.Balance >= tempLast)
{
tempHighestPositiveBalanceChange += transaction.Balance - tempLast;
tempLast = transaction.Balance;
tempEnd = transaction.Date;
}
else
{
if (tempHighestPositiveBalanceChange > highestPositiveBalanceChange)
{
highestPositiveBalanceChange = tempHighestPositiveBalanceChange;
startDate = tempStart;
endDate = tempEnd;
}
tempStart = transaction.Date;
tempEnd = transaction.Date;
tempLast = transaction.Balance;
tempHighestPositiveBalanceChange = 0;
}
}
if (tempHighestPositiveBalanceChange > highestPositiveBalanceChange)
{
highestPositiveBalanceChange = tempHighestPositiveBalanceChange;
startDate = tempStart;
endDate = tempEnd;
}
return highestPositiveBalanceChange == 0 ? (null, null, 0) : (startDate, endDate, highestPositiveBalanceChange);
}
With this, you will get the 10000 that you wanted
Related
I am trying to calculate the no of bank holidays in between two given dates for example 31/10/2019 10:00:00 and 01/11/2019 08:00:00 assuming 01/11/2019 is a bank holiday. I should get the bank holiday difference in minutes as 480 minutes in total. I am using the following code where if the one of given date falls on same date as bank holiday then my code is returning 1440 which is wrong, Can someone please suggest how to achieve this. Thanks
DateTime firstDay = new DateTime(2019, 10, 31, 10, 0, 0);
DateTime lastDay = new DateTime(2019, 11, 1, 8, 0, 0);
public static int CountOfBusinessClosures(DateTime firstDay, DateTime lastDay, IOrganizationService service)
{
// firstDay = firstDay.Date;
// lastDay = lastDay.Date;
var count = 0;
var businessClosuresdate = new DateTime(2019, 11, 1, 0, 0, 0);//GetBusinessClosureCalendarRules(service);
// Count the number of bank holidays in between the given dates
if (firstDay <= businessClosuresdate && businessClosuresdate <= lastDay)
{
count++;
}
return count;
}
OR
public static double CountOfBusinessClosures2(DateTime firstDay, DateTime lastDay, IOrganizationService service)
{
var firstDay1 = firstDay.Date;
var lastDay1 = lastDay.Date;
var count = 0;
double t = 0;
// var businessClosures = GetBusinessClosureCalendarRules(service);
// Count the number of bank holidays during the time interval
// foreach (var closure in businessClosures)
// {
var startDate = 01/11/2019 00:00:00 //(DateTime)closure["effectiveintervalstart"];
var endDate = 02/11/2019 00:00:00 // (DateTime)closure["effectiveintervalend"];
DateTime bh1 = startDate.Date;
if (firstDay1 <= bh1 && bh1 <= lastDay1)
{
// count++;
if (firstDay.Date < startDate.Date && startDate.Date != endDate.Date)
{
t += 1440; // 24h * 60 min
}
else
{
double difference;
difference = (endDate - startDate).TotalMinutes;
difference = difference - (firstDay - startDate).TotalMinutes;
t += difference;
}
}
// }
return t;
}
private static IEnumerable<Entity> GetBusinessClosureCalendarRules(IOrganizationService service)
{
// Get Organization Business Closure Calendar Id
var organization = service.Retrieve("organization", _orgId, new ColumnSet("businessclosurecalendarid"));
var query = new QueryExpression("calendar")
{
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression()
};
// Add condition to get Get Calander where CalanderId is equal to Organization's businessclosurecalendarid
query.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, organization["businessclosurecalendarid"].ToString()));
// Get Calendar
var businessClosureCalendar = service.RetrieveMultiple(query).Entities[0];
return businessClosureCalendar == null || businessClosureCalendar.GetAttributeValue<EntityCollection>("calendarrules") == null ? null : businessClosureCalendar.GetAttributeValue<EntityCollection>("calendarrules").Entities;
}
#Bellam Try this and see if it suits your needs:
// Unit Test Class
[TestClass]
public class UnitTest1
{
[TestMethod]
public void C58840237T01()
{
DateTime firstDay = new DateTime(2019, 10, 31, 0, 0, 0);
DateTime lastDay = new DateTime(2019, 11, 1, 0, 0, 0);
double totalMinutesBusinessIsClosed = C58840237.MinutesBusinessIsClosed(firstDay, lastDay);
Assert.IsTrue(totalMinutesBusinessIsClosed == 480);
}
}
// Sample Class
public class C58840237
{
public static double MinutesBusinessIsClosed(DateTime firstDay, DateTime lastDay)
{
double t = 0;
// Holiday 01
var h01Start = Convert.ToDateTime("11/01/2019 08:00:00");
var h01End = Convert.ToDateTime("11/01/2019 16:00:00");
// Holiday is in range
if (firstDay <= h01Start && h01Start >= lastDay)
{
return (h01End - h01Start).TotalMinutes;
}
return t;
}
}
EDIT: I realize our date time formats are different, but that's easily adjustable.
I want to generate a list of weekly business dates between two dates excluding weekends and holidays. I have managed to exclude the Weekends and created a routine for the holidays. Now I need to exclude the holidays. Below is my code.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SeriesTest
{
class Program
{
public class BusinessWeekDays
{
public DateTime Monday;
public DateTime Sunday;
}
private static List<DateTime> Holidays = new List<DateTime>()
{
new DateTime(1, 1, 1), //New Year Day
new DateTime(1, 5, 1), //Labour Day
new DateTime(1, 7, 4), //Independence Day
new DateTime(1, 3, 1), //Martin Luther King Jr. Day
new DateTime(1, 3, 2), //Presidents Day
new DateTime(1, 12, 25), //Christmas
new DateTime(1, 5, 5), //Memorial Day
new DateTime(1, 9, 1), //Labor Day
new DateTime(1, 10, 2), //Columbus Day
new DateTime(1, 11, 4), //Columbus Day
};
private static bool IsHoliday(DateTime value, List<DateTime> holidays = null)
{
if (null == holidays)
holidays = Holidays;
return (value.DayOfWeek == DayOfWeek.Sunday) ||
(value.DayOfWeek == DayOfWeek.Saturday) ||
holidays.Any(holiday => holiday.Day == value.Day &&
holiday.Month == value.Month);
}
public static int BusinessDays(DateTime fromDate, DateTime toDate, List<DateTime> holidays = null)
{
int result = 0;
for (var date = fromDate;
date < toDate.Date;
date = date.AddDays(1))
if (!IsHoliday(date, holidays))
result += 1;
return result;
}
static void Main(string[] args)
{
var StartDate = DateTime.Parse("02/12/2019");
var SeriesEndDate = DateTime.Parse("12/31/2025");
var holidays = new List<DateTime>();
var firstMonday = Enumerable.Range(0, 7)
.SkipWhile(x => StartDate.AddDays(x).DayOfWeek != DayOfWeek.Monday)
.Select(x => StartDate.AddDays(x))
.First();
var ts = (SeriesEndDate - firstMonday);
var dates = new List<BusinessWeekDays>();
for (var i = 0; i < ts.Days; i += 7)
{
//Remove holidays. Weekend already removed here
if (BusinessDays(StartDate, SeriesEndDate, holidays) != 0)
{
dates.Add(new BusinessWeekDays { Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 9) });
}
}
Console.WriteLine(dates);
}
}
}
It looks like you already have everything you need, but holidays is never set to your Holidays. Change the line below so that holidays is set to null. Then it will hit the null check in IsHoliday and be set properly.
var holidays = new List<DateTime>();
Should be:
var holidays = null;
I want to cluster the list of DateTimes in the groups.
Every times that are near each other in interval of 30 sec for ins.
12:00:05,
12:00:10,
12:00:15,
12:30:15,
12:30:25
I have a list of the times- MainBookmarksList
MainBookmarksList.Add(dt1);
MainBookmarksList.Add(dt2);
MainBookmarksList.Add(dt3);
MainBookmarksList.Add(dt4);
MainBookmarksList.Add(dt5);
now I expect to have a groups like this
12:00:05,
12:00:10,
12:00:15,
********
12:30:15,
12:30:25
I tried this :
TimeSpan interval = new TimeSpan(0, 0, 15);
var groupedTimes = from dt in MainBookmarksList
group dt by dt.Ticks / interval.Ticks
into g
select new { Begin = new DateTime(g.Key * interval.Ticks), Values = g.ToList() };
but it doesn't return the correct results.
One possible solution would be this:
static void Main(string[] args)
{
var MainBookmarksList = new List<DateTime>();
MainBookmarksList.Add(new DateTime(1900, 1, 1, 12, 0, 5));
MainBookmarksList.Add(new DateTime(1900, 1, 1, 12, 0, 10));
MainBookmarksList.Add(new DateTime(1900, 1, 1, 12, 0, 15));
MainBookmarksList.Add(new DateTime(1900, 1, 1, 12, 30, 15));
MainBookmarksList.Add(new DateTime(1900, 1, 1, 12, 30, 25));
var interval = new TimeSpan(0, 0, 15);
var groupedTimes = new List<TimeGroup>();
var currentTimeGroup = new TimeGroup(MainBookmarksList[0]);
groupedTimes.Add(currentTimeGroup);
for (var i = 1; i < MainBookmarksList.Count; i++)
{
var time = MainBookmarksList[i];
if (time-currentTimeGroup.Begin > interval)
{
currentTimeGroup = new TimeGroup(time);
groupedTimes.Add(currentTimeGroup);
}
else
{
currentTimeGroup.Values.Add(time);
}
}
}
class TimeGroup
{
public TimeGroup(DateTime dateTime)
{
Begin = dateTime;
Values = new List<DateTime>() { dateTime };
}
public DateTime Begin { get; }
public List<DateTime> Values { get; }
}
I'm trying to find the time duration between time range and convert it to hour, minutes and seconds. Hours should added should not get converted to 24 hour. if there is 50 hours 30 min and 30 seconds it should display as 50:30:30, If the minute duration exceeds 59 it should add to hours same in case of seconds.
Please see the complete code.Both methods are not giving the correct answer. Method GetSumOfDuration is considering 0.30 as 0.3 so its not giving the correct answer. method GetSumOfDurationFromSecond fails when there is more than 24 hours difference.
using System;
using System.Collections.Generic;
using System.Linq;
namespace TimeCalculationApp
{
public class ProcessDetail
{
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
public double? DurationInSeconds
{
get
{
if (StartTime != null && EndTime != null)
return (EndTime.Value - StartTime.Value).TotalSeconds;
return null;
}
}
public double? Duration
{
get
{
if (StartTime != null && EndTime != null)
return double.Parse(DateTimeHelper.GetTimeDuration(StartTime, EndTime));
return null;
}
}
}
class DateTimeHelper
{
public static string GetTimeDuration(DateTime? sDateTime, DateTime? eDateTime)
{
if (sDateTime != null && eDateTime != null)
{
if (sDateTime.Value <= eDateTime.Value)
{
var tsdiff = eDateTime.Value - sDateTime.Value;
var ts = TimeSpan.FromSeconds(tsdiff.TotalSeconds);
return string.Format("{0}.{1}", ts.Hours.ToString("0"), ts.Minutes.ToString("D2"));
}
return "0.00";
}
return "0.00";
}
public static string GetSumOfDuration(List<ProcessDetail> processDetails)
{
TimeSpan? sumDuration = null;
var totalhours = 0;
var totalminutes = 0;
foreach (var processDetail in processDetails)
{
if (processDetail.Duration != null)
{
var splitString = processDetail.Duration.ToString().Split('.');
var hour = splitString.Length > 0 ? splitString[0] : "0";
var minutes = splitString.Length > 1 ? splitString[1] : "0";
totalhours += int.Parse(hour);
totalminutes += int.Parse(minutes);
sumDuration = new TimeSpan(totalhours, totalminutes, 0);
}
}
return sumDuration == null
? null
: Math.Floor(sumDuration.Value.TotalHours).ToString("0") + ":" +
sumDuration.Value.Minutes.ToString("D2");
}
public static string GetSumOfDurationFromSecond(List<ProcessDetail> processDetails, bool includeSeconds = false)
{
var seconds = processDetails.Where(x => x.DurationInSeconds != null).Sum(x => x.DurationInSeconds);
if (seconds == null) return null;
var ts = TimeSpan.FromSeconds(seconds.Value);
return includeSeconds ? string.Format("{0}:{1}:{2}", ts.Hours.ToString("0"), ts.Minutes.ToString("D2"), ts.Seconds.ToString("D2")) :
string.Format("{0}:{1}", ts.Hours.ToString("0"), ts.Minutes.ToString("D2"));
}
}
class Program
{
static void Main(string[] args)
{
var processDetails = GetProcessDetails();
var duration = DateTimeHelper.GetSumOfDuration(processDetails);
var durationFromSeconds = DateTimeHelper.GetSumOfDurationFromSecond(processDetails);
Console.WriteLine(duration);
Console.WriteLine(durationFromSeconds);
processDetails = GetProcessDetailsTestData();
duration = DateTimeHelper.GetSumOfDuration(processDetails);
durationFromSeconds = DateTimeHelper.GetSumOfDurationFromSecond(processDetails);
Console.WriteLine(duration);
Console.WriteLine(durationFromSeconds);
Console.ReadKey();
}
private static List<ProcessDetail> GetProcessDetails()
{
return new List<ProcessDetail>
{
new ProcessDetail
{
StartTime = new DateTime(2017, 01, 01, 1, 0, 0),
EndTime = new DateTime(2017, 01, 01, 7, 59, 0)
},
new ProcessDetail
{
StartTime = new DateTime(2017, 01, 01, 1, 0, 0),
EndTime = new DateTime(2017, 01, 01, 17, 3, 45)
},
new ProcessDetail
{
StartTime = new DateTime(2017, 01, 01, 1, 0, 0),
EndTime = new DateTime(2017, 01, 01, 10, 0, 20)
},
new ProcessDetail
{
StartTime = new DateTime(2017, 01, 01, 1, 0, 0),
EndTime = new DateTime(2017, 01, 01, 15, 1, 12)
}
};
}
private static List<ProcessDetail> GetProcessDetailsTestData()
{
return new List<ProcessDetail>
{
new ProcessDetail
{
StartTime = DateTime.Parse("11/01/2017 06:36:28"),
EndTime = DateTime.Parse("11/01/2017 06:53:51")
},
new ProcessDetail
{
StartTime = DateTime.Parse("11/01/2017 09:12:46"),
EndTime = DateTime.Parse("11/01/2017 09:43:00")
},
new ProcessDetail
{
StartTime =DateTime.Parse("11/01/2017 15:29:25"),
EndTime = DateTime.Parse("11/01/2017 15:37:26")
},
new ProcessDetail
{
StartTime = DateTime.Parse("11/01/2017 15:19:19"),
EndTime = DateTime.Parse("11/01/2017 15:27:52")
},
new ProcessDetail
{
StartTime = DateTime.Parse("12/01/2017 01:05:43"),
EndTime = DateTime.Parse("12/01/2017 01:08:37")
}
};
}
}
}
This should give the total hours between the dates.
DateTime dt1 = new DateTime(2016, 1, 1);
DateTime dt2 = new DateTime(2016, 1, 5);
TimeSpan difference = dt2 - dt1;
int totalDaysToHours = difference.Days * 24;
Console.WriteLine((difference.Hours + totalDaysToHours) + " hours " + difference.Minutes + " Minutes " + difference.Seconds + " seconds" );
Console.ReadKey();
You can fix a time span of the difference by subtract actions.
TimeSpan time1 = TimeSpan.Parse(date1);
TimeSpan time2 = TimeSpan.Parse(date2);
TimeSpan difference = time1 - time2;
int hours = difference.Hours;
int minutes = difference.Minutes;
You can just substract the starttime from the endtime.
The result will be a Timespan object.
// Set startime example to one hour ten minutes and 30 seconds ago
DateTime startTime = DateTime.Now.AddSeconds(-4230);
DateTime endTime = DateTime.Now;
TimeSpan elapsedTime = endTime-startTime;
// Print out the elapsed time in hour:minutes:seconds to string
string result = elapsedTime.TotalHours + ":" + elapsedTime.Minutes + ":" + elapsedTime.Seconds
Be aware that TimeSpan provides Properties for e.g Hours and TotalHours. Hours can have a value between 0-23 (when the value would exceed 23 the property Days is increased instead) whereas TotalHours provides the total number of full hours
I agree with Thomas Voß that you should use Timespan. However TotalHours should be casted to int to get proper number of hours.
string result = (int)elapsedTime.TotalHours + ":" + elapsedTime.Minutes + ":" + elapsedTime.Seconds
If you can consider displaying the result in days format you could utilize TimeSpan Formatting :
elapsedTime.ToString("dd\.hh\:mm\:ss")
You can read more about custom TimeSpan Formatting here
I'm new in linq and read some stuff on the web about them.
Now, below is a query works fine which is to calculate the project 12-month running balance from the current date. Is it possible to translate this to linq?
It would help me understand the linq better.
var firstDayMonth = new DateTimeOffset(new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1));
var months = Enumerable.Range(0, 12)
.Select(m => firstDayMonth.AddMonths(m));
List<SomeDate> SomeDates = new List<SomeDate>()
{
new SomeDate { Id = 7, Month = firstDayMonth.AddMonths(0), Balance = 1m },
new SomeDate { Id = 7, Month = firstDayMonth.AddMonths(0), Balance = 3m },
new SomeDate { Id = 8, Month = firstDayMonth.AddMonths(1), Balance = 6m },
new SomeDate { Id = 8, Month = firstDayMonth.AddMonths(1), Balance = 5m },
new SomeDate { Id = 8, Month = firstDayMonth.AddMonths(1), Balance = 3m },
new SomeDate { Id = 9, Month = firstDayMonth.AddMonths(2), Balance = 5m },
new SomeDate { Id = 10, Month = firstDayMonth.AddMonths(3), Balance = 3m },
new SomeDate { Id = 12, Month = firstDayMonth.AddMonths(5), Balance = 15m },
new SomeDate { Id = 13, Month = firstDayMonth.AddMonths(6), Balance = 16m },
new SomeDate { Id = 13, Month = firstDayMonth.AddMonths(6), Balance = 12m },
};
var projected12MonthsBalance = new List<SomeDate>();
foreach(var month in months)
{
projected12MonthsBalance.Add(new SomeDate { Month = month, Balance = SomeDates.TakeWhile(s => s.Month <= month).Sum(s => s.Balance) });
}
Console.WriteLine(projected12MonthsBalance);
public class SomeDate
{
public int Id { get; set; }
public DateTimeOffset Month { get; set; }
public decimal Balance { get; set; }
}
Try this:
var projected12MonthsBalance = months.Select(x => new SomeDate
{
Month = x,
Balance = SomeDates.TakeWhile(s => s.Month <= x).Sum(s => s.Balance)
}).ToList();