I am developing a project at C#. I have a model named ExamResult which has a field named Date, which is defined as String.
I then define the following
var executionQuery = (from x in db.ExamResult
where x.Student.Equals(iStudent)
orderby x.Date
select *);
The Date gets values in the format <YEAR>-<MONTH>
like this
2014-01
2013-04
2013-09
What I want to do, is to create a table which gets the minimum value of all the dates returned, and creates a table which have the difference in months from that minimum date.
Example:
When we have results like above, I want to get the following table (if we get that the minimum value is 2013-04)
9
0
5
I tried to do the following but I get a System.NotSupported exception
var dates = executionQuery.Select(x => int.Parse(x.Date.Substring(0,
4)) * 12 + int.Parse(x.Date.Substring(5, 2)) -
int.Parse(minDate.Substring(0, 4)) * 12 -
int.Parse(minDate.Substring(5, 2)));
Do you know how I can do this?
I'd use a small Func<TIn, TOut> delegate to convert your string dates into DateTimes, then they can be sorted properly.
First, a simple method to convert the date string to a DateTime object:
// Split the string and instantiate new DateTime object to sort by later
Func<string, DateTime> getDate = s => {
int[] dateParts = s
.Split(new char[] {'-'})
.Select(dp => int.Parse(dp))
.ToArray();
// Let's use the new DateTime(int year, int month, int day) constructor overload
// dateParts[0] is the year and dateParts[1] is the month;
// the magic number 1 below is just a day to give to the DateTime constructor
return new DateTime(dateParts[0], dateParts[1], 1);
};
Your code might look something like this; I can't test your code so this will be up to you to make it work:
Note I separated your Linq query and am doing the ordering in C#; so you can get the stuff from the DB anyway you want, then order the items. I hope this works; otherwise, you have to call my getDate Func twice - once on orderby, and once on select; I didn't like that option.
// The select now builds an anonymous object; You can also create a new class, ExamResultWithDate,
// for example, that has all fields of ExamResult plus a DateTime field; OR you can just add that
// property to the partial class generated by EF or Linq-to-Sql or whatever right on the ExamResult
// entity.
var executionQuery = (from x in db.ExamResult
where x.Student.Equals(iStudent)
select new { Entity = x, ActualDate = getDate(x.Date) }); // note select * as in your OP doesn't compile :)
var orderedQuery = executionQuery
.OrderBy(eq => eq.ActualDate)
.Select(er => er.Entity); // gets you just the entities in this case and discards the dates
To get dates with difference, just do some simple calculations on your minimum date: Again this is pseudo code for your program;
// Let's get the minimum date and difference in months;
DateTime minDate = executionQuery
.ToList()
.Select(o => o.ActualDate)
.Min();
// I am just using the dates here but you can easily use your entire entity or whatever you need
Dictionary<DateTime, int> datesWithMonthDifference = executionQuery
.ToDictionary(
eq => eq.ActualDate
eq => ((eq.Year - minDate.Year) * 12) + eq.Month - minDate.Month // this formula calculates month difference as an integer
);
Here's a working program that does what you need: Note this is just an example that needs to be fit into your project.
using System;
using System.Collections.Generic;
using System.Linq;
namespace DateTimeFromString
{
class Program
{
static void Main(string[] args)
{
List<string> dates = new List<string>()
{
"2014-01",
"2013-04",
"2013-09"
};
// Split the string and instantiate new DateTime object to sort by later
Func<string, DateTime> getDate = s => {
int[] dateParts = s
.Split(new char[] {'-'})
.Select(dp => int.Parse(dp))
.ToArray();
// Let's use the new DateTime(int year, int month, int day) constructor overload
// dateParts[0] is the year and dateParts[1] is the month;
// the magic number 1 below is just a day to give to the DateTime constructor
return new DateTime(dateParts[0], dateParts[1], 1);
};
List<DateTime> sortedDates = dates
.Select(d => getDate(d))
.OrderBy(d => d)
.ToList();
Console.WriteLine(" Sorted Dates: ");
sortedDates.ForEach(d => Console.WriteLine(d.Year.ToString() + " - " + d.Month.ToString()));
// Let's get the minimum date and difference in months;
DateTime minDate = sortedDates.Min();
Dictionary<DateTime, int> datesWithMonthDifference = sortedDates
.ToDictionary(
sd => sd,
sd => ((sd.Year - minDate.Year) * 12) + sd.Month - minDate.Month
);
Console.WriteLine();
Console.WriteLine("Sorted dates with month difference:");
foreach (var key in datesWithMonthDifference.Keys)
{
Console.WriteLine("{0} has difference of {1}", key, datesWithMonthDifference[key]);
}
Console.ReadKey();
}
}
}
The result of my test program looks like this:

Converting your strings to actual 'DateTime' objects will make things simpler.
// Getting DateTime objects instead of strings
var dates = executionQuery.ToArray().Select(
x => DateTime.ParseExact(x.Date,"yyyy-MM", CultureInfo.InvariantCulture));
// calculating smallest date
var minDate = dates.Min(x => x);
// this will help you get a collection of integers
var diffDates = dates.Select(
x => ((x.Year - minDate.Year) * 12) + x.Month - minDate.Month);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With