2014-02-02 3 views
3

Я разрабатываю проект на C#. У меня есть модель с именем ExamResult, которая имеет поле с именем Date, которое определено как String.C# получить разницу в месяцах?

Я тогда определить следующее

 var executionQuery = (from x in db.ExamResult 
        where x.Student.Equals(iStudent) 
        orderby x.Date 
        select *); 

Дата получает значения в формате <YEAR>-<MONTH> как этого

2014-01 
2013-04 
2013-09 

То, что я хочу сделать, это создать таблицу, которая получает минимальное значение всех возвращенных дат и создает таблицу, которая имеет разницу в месяцах с этой минимальной даты.

Пример:

Когда мы имеем результаты, как выше, я хочу, чтобы получить следующую таблицу (если мы получим, что минимальное значение 2013-04)

9 
0 
5 

Я попытался сделать следующее но я получаю исключение System.NotSupported

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))); 

вы знаете, как я могу это сделать?

+1

Почему бы не использовать DateTime для в вашей схеме ваших дат? –

+0

@DavidKhaykin Большое спасибо Дэвиду. Это было бы наиболее логично. Однако база данных не моя :) Моя система должна взаимодействовать с этой базой данных, но у нас нет прав владельца. Есть ли у вас какие-либо предложения в коде? – user2327751

+0

Конечно, см. Мой ответ :) –

ответ

3

Преобразование строк в объекты 'DateTime' упростит работу.

// 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); 
+0

Большое спасибо Anri за ваш ответ. Мне бы очень хотелось попробовать, но я получаю сообщение об ошибке «Нет перегрузки для метода« ParseExact »принимает два аргумента« 'в строке' var date = query.Select (x => DateTime.ParseExact (x .Date + "-01", "yyyy-MM-dd")); '. Я делаю что-то неправильно? – user2327751

+0

@ user2327751 исправлен метод вызова «ParseExact», попробуйте сейчас – Anri

+0

На самом деле, добавление «-01» к строке даты необязательно, так как вы можете просто указать формат как «yyyy-mm». – Georg

3

Я хотел бы использовать небольшой Func<TIn, TOut> делегат преобразовать строку даты в DateTimes, то они могут быть отсортированы правильно.

Во-первых, простой способ, чтобы преобразовать строку даты в DateTime объекта:

// 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); 
}; 

Ваш код может выглядеть следующим образом; Я не могу проверить ваш код, так что это будет зависеть от вас, чтобы он работал:

Примечание. Я отделил ваш запрос Linq и делаю заказ на C#; так что вы можете получить материал из базы данных так или иначе, как хотите, а затем заказать элементы. Я надеюсь, что это сработает; в противном случае вы должны позвонить мне getDateFunc дважды - один раз на orderby и один раз на select; Мне не понравился этот вариант.

// 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 

Чтобы получить даты с разницей, просто сделать несколько простых вычислений на вашей минимальной даты: Опять же, это псевдо-код для вашей программы;

// 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 
    ); 

Вот рабочая программа, которая делает то, что вам нужно: Примечание это только пример, который должен быть установлен в вашем проекте.

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(); 
     } 
    } 
} 

Результат моей тестовой программы выглядит следующим образом:

enter image description here

Смежные вопросы