How to find the closest date in c#? - c#

I am trying to display the values of ApmaksasApmers (which is a Reference Value) which are closest to DateToCompare in comparison to GivenDate
For example:
DateToCompare =01.01.2022 and 01.01.2021
and GivenDate = 01.03.2022
I am trying to get the values which come from date 01.01.2022
Here is my code:
vm.ApmaksasApmērs.LookupSource = _nolasītMaksājumusQuery.Nolasīt()
.OrderBy(x => x.DateToCompare.Value > vm.GivenDate.Value ? vm.GivenDate.Value - x.DateToCompare.Value : x.DateToCompare.Value - vm.GivenDate.Value)
.Select(x => new KeyValuePair<Guid?, string>(x.Id, x.ApmaksasApmērs +" (" + x.PersonasLīdzmaksājumsProcentos + "%)".ToString())) ;
Here I am geting an error of Name:[ApmaksasApmērs],Type:[ReferenceValue],Message:[Don't currently support idents of type TimeSpan]
Is there a better way of doing this? Thanks in advance

Hi if DateToCompare is an array then we compare the absolute value of difference between each el with the given date and when the value is lowest that's the closest date
Here is how
//adding some data
DateTime[] DateToCompare = {
new DateTime(2001, 05,05),
new DateTime(2022,01,01),
new DateTime(2021,01,01)
};
DateTime GivenDate = new DateTime(2022, 05, 02);
//Get the absolute value of diference between first el and given date
TimeSpan span = abs(DateToCompare[0] - GivenDate);
DateTime closestDate = DateToCompare[0];
//new we check each el if the dif is lower
for (int i = 1; i < DateToCompare.Length; i++)
{
if (abs(GivenDate - DateToCompare[i]) < span)
{
span = abs(GivenDate - DateToCompare[i]);
closestDate = DateToCompare[i];
}
}
//get absolute value
TimeSpan abs(TimeSpan t)
{
return (t.TotalSeconds >= 0) ? t : -t;
}
Console.WriteLine(closestDate.ToShortDateString());

Here is what I did :
Create a list for all of the elements:
var saraksts = _nolasītMaksājumusQuery.Nolasīt().Where(x => x.DateToCompare <= vm.GivenDate).ToList();
Find the max value from the list:
var maxDate = list.Max(x=>x.DateToCompare)
Find all of the elements where MaxDate == DateToCompare:
vm.ApmaksasApmērs.LookupSource = list.Where(x => x.DateToCompare== maxDate).Select(x => new KeyValuePair<Guid?, string>(x.Id, x.ApmaksasApmērs +" (" + x.PersonasLīdzmaksājumsProcentos + "%)".ToString()));

Related

EF core 3 problem by string to npgsqlTime

Hey guys im using Npgsql and need to pass parameters to my PostgreSQL stored procedure
my stored procedure expecting Date for my first two parameters:
SELECT wpv.avail_pro_failedbattry_error_powerconv(
<date>,
<date>,
<character varying>,
<character varying>,
<character varying>
);
so i need to pass date parameters :
NpgsqlDateTime DateFrom = NpgsqlDateTime.Parse(dtFrom);
NpgsqlDateTime DateTo = NpgsqlDateTime.Parse(dtTo);
NpgsqlParameter p0 = new NpgsqlParameter("#drfrom", dtFrom);
NpgsqlParameter p1 = new NpgsqlParameter("#dtto",dtTo);
NpgsqlParameter p2 = new NpgsqlParameter("#regionalmanager", regionalManager);
NpgsqlParameter p3 = new NpgsqlParameter("#serviceunder", service_under);
NpgsqlParameter p4 = new NpgsqlParameter("#supervisor", supervisor);
var x = _db.dataInGlance.FromSqlRaw(#"SELECT * from wpv.avail_pro_failedbattry_error_powerconv(#drfrom,#dtto,#regionalmanager,#serviceunder,#supervisor)
res (o_availability double precision, o_production double precision,o_numberofturbines integer, o_errors_disabled integer,o_failed_battery integer,o_power integer,o_crew_present text)",p0,p1,p2,p3,p4
).ToList();
dtfrom and dtto are string date format which is:
dtFrom="2020/07/03"
dtTo="2020/07/07"
but it gives me an error on the line
NpgsqlDateTime DateFrom = NpgsqlDateTime.Parse(dtFrom);
that the format is not correct!any help?
Looking at the source:
NpgsqlDateTime
which calls NpgsqlDate
along with Timespan.Parse() which seems mandatory.
Since you are not using a time, you could use NpgsqlDate.Parse() instead.
The source seems to be expecting the following format for date parsing: yyyy-MM-dd
So if you meant the 3rd of July
dtFrom="2020-07-03"
but if you meant the 7th of March
dtFrom="2020-03-07"
Source code:
try {
var idx = str.IndexOf('-');
if (idx == -1) {
throw new FormatException();
}
var year = int.Parse(str.Substring(0, idx));
var idxLast = idx + 1;
if ((idx = str.IndexOf('-', idxLast)) == -1) {
throw new FormatException();
}
var month = int.Parse(str.Substring(idxLast, idx - idxLast));
idxLast = idx + 1;
if ((idx = str.IndexOf(' ', idxLast)) == -1) {
idx = str.Length;
}
var day = int.Parse(str.Substring(idxLast, idx - idxLast));
if (str.Contains("BC")) {
year = -year;
}
return new NpgsqlDate(year, month, day);
} catch (OverflowException) {
throw;
} catch (Exception) {
throw new FormatException();
}
Additionally if NpgsqlDate.Parse is not accepted, you could use NpgsqlDateTime.Parse with the time part set to zero.
NpgsqlDateTime.Parse("2020-07-03 00:00")

Finding the month between a range

I have a datasource that returns dates and I have to find where the months falls within the month and day range buckets. The months and day range buckets are predefined so I put it in a Dictionary (not sure if that is even a good idea). I am using linq to find the min and Max dates and extracting the month from them. I need to find month from the dictionary where that month extracted falls within the range. For Example
Dictionary<int, int> MonthDayBuckets = new Dictionary<int, int>() { { 3,31 }, { 6,30 }, { 9,30 }, { 12,31 } };
var MinyDate = _dataSource.Min(x => x.values[0]);
var MaxDate = _dataSource.Max(x => x.values[0]);
var startMonth = Convert.ToDateTime(MinyDate).ToString("MM");
var endMonth = Convert.ToDateTime(MaxDate).ToString("MM");
Say startmonth return Jan so I want to be able to go to the dictionary and return only march (03.31) and if I get 10 for the Max (October) I am trying to return (12,31) December
If my understanding is correct, your MonthDayBuckets variable is meant to represent date ranges:
3/31 - 6/30
6/30 - 9/30
9/30 - 12/31
12/31 - 3/31
...and given a month, you're wanting to see what the end date is of the interval that the first of that month falls between? Like you gave the example of October returning 12/31.
This problem can be simplified since you'll get the same result saying "what's the next occurring date after this given date?" The next occurring date for 10/01 would be 12/31. So here's how you could rearrange your data:
var availableDates = new List<string> { "03/31", "06/30", "09/30", "12/31" };
Now you'll be able to find a match by finding the index of the first one that's greater than your given date. Note how I made the month/day combos lexicographical orderable.
var startMonth = Convert.ToDateTime(MinyDate).ToString("MM");
var startDate = startMonth + "/01";
var endMonth = Convert.ToDateTime(MaxDate).ToString("MM");
var endDate = endMonth + "/01";
// Wrap around to the first date if this falls after the end
var nextStartDate = availableDates.FirstOrDefault(d => d.CompareTo(startDate) >= 1) ?? availableDates[0];
var nextEndDate = availableDates.FirstOrDefault(d => d.CompareTo(endDate) >= 1) ?? availableDates[0];
You could use Linq for the purpose. For example,
var nearestKey = MonthDayBuckets.Keys.Where(x => x >= endMonth.Month).Min();
var nearestDate = new DateTime(DateTime.Now.Year,nearestKey,MonthDayBuckets[nearestKey]); // or whatever the year it needs to be represent
Though above query would get you the result, I would suggest you define a structure to store the Range itself, rather than using Dictionary
For example,
public class Range
{
public MonthDate StartRange{get;set;}
public MonthDate EndRange{get;set;}
public Range(MonthDate startRange,MonthDate endRange)
{
StartRange = startRange;
EndRange = endRange;
}
}
public class MonthDate
{
public MonthDate(int month,int date)
{
Month = month;
Date = date;
}
public int Month{get;set;}
public int Date{get;set;}
//Depending on if your Ranges are inclusive or not,you need to decide how to compare
public static bool operator >=(MonthDate source, MonthDate comparer)
{
return source.Month>= comparer.Month && source.Date>=comparer.Date;
}
public static bool operator <=(MonthDate source, MonthDate comparer)
{
return source.Month<= comparer.Month && source.Date<=comparer.Date;
}
}
Now you could define ranges as
var dateRanges = new Range[]
{
new Range(new MonthDate(12,31),new MonthDate(3,31)),
new Range(new MonthDate(3,31),new MonthDate(6,30)),
new Range(new MonthDate(6,30),new MonthDate(12,31)),
};
var result = dateRanges.First(x=>x.StartRange <= new MonthDate(endMonth.Month,endMonth.Day) && x.EndRange >= new MonthDate(endMonth.Month,endMonth.Day));

c# get next execution datetime

I have the following code:
Dictionary<DayOfWeek, List<TimeSpan>> Daily = new Dictionary<DayOfWeek, List<TimeSpan>>();
The idea is that i can add a day with a time to the Daily dictionary. But a job can execute on the same day more than once.
so Daily can look like this:
{ "Monday" : [{"Hour":10, "Minute": 15}, {"Hour": 8, "Minute":5}] }
Now i would like to get the next execution datetime.
private void UpdateNextExecutionTime()
{
TimeSpan t = new TimeSpan(15, 15, 0);
DayOfWeek current = DateTime.Now.DayOfWeek;
DayOfWeek tmp = current;
TimeSpan time = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);
int cur = (int)current;
for(int i = 0; i < 7; i++) {
if(Daily.ContainsKey((DayOfWeek)cur)) {
tmp = (DayOfWeek)cur;
/* stuck */
continue;
}
cur++;
if (cur >= 7)
cur = 0;
}
}
I managed to get the first upcoming day (including today) in the Daily dictionary but i'm stuck on the getting the time.
How would i be able to do this?
Assuming t is the time you're using as the point at which you'd like to find the next execution time, put this where you have 'stuck' (edit; just realized you changed to using TimeSpan in your list):
var execTimes = Daily[tmp];
if (execTimes != null) {
var nextTime = execTimes.OrderBy(x => x).FirstOrDefault(x => x > t);
if (nextTime != default(TimeSpan)) {
// do something...
}
}
You can also have the day in the TimeSpan,
Here is a simple example the finds the next date:
var schedule = new List<TimeSpan>{
new TimeSpan(0,16,30,0),
new TimeSpan(1,16,30,0),
new TimeSpan(5,16,30,0)
};
var monday = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek + 1);
var fromMonday = DateTime.Now - monday;
var next = schedule.OrderBy(t => t).FirstOrDefault(t => t > fromMonday);
Console.Write(monday + next - DateTime.Now);

List to return values in intervals for a specific field

I am implementing Telerik Chart with a huge data. The labels on x-axis of the chart are overlapping. I have overcome this problem but it is not reliable for long run.
These are the fields List have:
FieldName DataType
Date DATETIME
DateString STRING
Unit DOUBLE
Price DOUBLE
X-Axis label value comes from DateString field
Solution I implemented
The MIN and MAX Date DateString field will always return.
For the rest, return those values where weekday is 'Monday'
Here is code-
// Get min and max Date
DateTime minDate = DateTime.Now;
DateTime maxDate = DateTime.Now;
if (dtGas.Rows.Count > 0)
{
minDate = Convert.ToDateTime(dtGas.Compute("MIN([Date])", ""));
maxDate = Convert.ToDateTime(dtGas.Compute("MAX([Date])", ""));
}
// Group by 'Date' and 'DateString' | 'SUM' of Unit and 'Price'
var qGas = from x in dtGas.AsEnumerable()
group x by new
{
Date = x.Field<DateTime>("Date"),
DateString = x.Field<string>("DateString")
} into egroup
let isOne = egroup.Key.Date.DayOfWeek.ToString() == "Monday"
select new
{
Date = egroup.Key.Date,
DateString = minDate == egroup.Key.Date ?
(
egroup.Key.DateString
) :
(
maxDate == egroup.Key.Date ?
(
egroup.Key.DateString
) :
(
(isOne) ?
(
egroup.Key.DateString
) :
(" ")
)
),
Unit = egroup.Sum(r => r.Field<double>("Unit")),
Price = egroup.Sum(r => r.Field<double>("Price")),
};
This solution helps to return not all values but some of them. Hence avoiding overlapping. But in future as data grows, even this solution will fail.
Solution I need to implement
An idea that I was thinking but don't know how to implement is-
The MIN and MAX Date DateString field will always return. [Same as what I am doing right now]
Return 8 values in intervals from MIN and MAX date regardless of total count of List Item.
2.a. But if List count is less than or equals to 8 then return all values.
So, for example, if in List I have 32 values. It should return me total 10 values in DateString field and rest will be empty string.
I'd suggest something like this:
public static IList<Stock> GetSome(this IList<Stock> input)
{
var result = new List<Stock>();
if (input.Count < 8)
{
return input;
}
else
{
var i = 0;
for (; i < input.Count; ++i)
{
if (i % 8 == 0)
{
result.Add(input[i]);
}
}
if (i % 8 != 0)
{
result.Add(input.Last());
}
}
return result;
}
If the Stocks are not in chronological order, I'd call .Sort() by date on them.
You'll probably like to add null and empty collection checking in your code.

How can I get a collection of months between two Dates?

Below is my code. I am only getting the difference between two dates, but I want the name of that month which comes between the from and to dates.
public static int GetMonthsBetween(DateTime from, DateTime to)
{
if (from > to) return GetMonthsBetween(to, from);
var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));
if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
{
return monthDiff - 1;
}
else
{
return monthDiff;
}
}
Based on your code you could substract the month difference from the "to" DateTime to get DateTime difference from your input.
public static List<DateTime> GetMonthsBetween(DateTime from, DateTime to)
{
if (from > to) return GetMonthsBetween(to, from);
var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));
if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
{
monthDiff -= 1;
}
List<DateTime> results = new List<DateTime>();
for (int i = monthDiff; i >= 1; i--)
{
results.Add(to.AddMonths(-i));
}
return results;
}
To get the name of the month just format the DateTime to "MMM".
var dts = GetMonthsBetween(DateTime.Today, DateTime.Today.AddMonths(5));
foreach (var dateTime in dts)
{
Console.WriteLine(dateTime.ToString("MMM"));
}
If you want the names of all months between two dates, use something like this:
var d1 = new DateTime(2015,6,1);
var d2 = new DateTime(2015,9,1);
var monthlist = new List<string>();
string format = d1.Year == d2.Year ? "MMMM" : "MMMM yyyy";
for (var d = d1; d <= d2; d = d.AddMonths(1))
{
monthlist.Add(d.ToString(format));
}
The full list is now in monthlist - you will want to return that from your method.
Assuming you're using Java and JodaTime there are several flaws in your code.
You cant use from > to to evaluate if a date is after an other. Use from.isAfter(to) instead.
JodaTime already supplies a method to calculate the amount of whole months between two given Dates Months.monthsBetween(start,end).
With the calculated month difference you can instantiate a new DateTime object that holds a date in your desired month and output its name via yourNewDateTimeObject.month().getAsText().
edit: Just found out you're using C# so ignore my text above this. Below here I will try to answer your question in C#.
Why dont you just subtract the from from the to date and obtain your difference?
The resulting TimeSpan can be used to determine the amount of whole months between your two given dates.
To obtain the resulting month name you could use yourDateTime.ToString("MMMM");

Categories