C# 如何获取月份差异?

3

我正在开发一个C#项目。我有一个名为ExamResult的模型,其中有一个名为Date的字段,它被定义为String

然后我定义了以下内容:

        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来表示日期? - Dmitriy Khaykin
@DavidKhaykin 非常感谢您,David。这是最合乎逻辑的做法。但是数据库不是我的 :) 我的系统需要与该数据库交互,但我们没有任何所有者权限。您对代码有什么建议吗? - user2327751
当然,看我的回答 :) - Dmitriy Khaykin
2个回答

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

非常感谢你的回答,Anri。我很想尝试一下,但是在这行代码 var dates = query.Select(x => DateTime.ParseExact(x.Date + "-01", "yyyy-MM-dd")); 中,我遇到了一个错误,它说“没有重载方法'ParseExact'接受两个参数”。我做错了什么吗? - user2327751
@user2327751 修复了“ParseExact”方法的调用,请现在尝试。 - Anri
实际上,在日期字符串后添加“-01”是不必要的,因为您可以简单地指定格式为“yyyy-mm”。 - Georg
@Georg 不确定会用第一天,但是没错,谢谢。 - Anri
我尝试过了,Anrie,但是我遇到了这个异常System.Data.Entity.dll,但在用户代码中未处理。额外信息:LINQ to Entities不识别方法'System.DateTime ParseExact(System.String, System.String, System.IFormatProvider)'方法,而且此方法无法转换为存储表达式。 - Jim Blum
@JimBlum在C#中加载数据后添加了ToArray()调用来解析。现在应该可以工作了。 - Anri

3

我建议使用一个小的 Func<TIn, TOut> 委托来将你的字符串日期转换成 DateTime,然后它们就可以被正确地排序了。

首先,将日期字符串转换为 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#中进行排序;这样你就可以按照任何想要的方式从数据库中获取数据,然后对项目进行排序。我希望这能够正常工作;否则,你必须两次调用我的 getDate Func -- 一次在 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


这句话意思是,某人在测试他的程序时得到了一个类似于图片的结果。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接