C# 根据“查找实际日期”;DayOfWeek,日/月“; 背景:

C# 根据“查找实际日期”;DayOfWeek,日/月“; 背景:,c#,datetime,C#,Datetime,在一个奇怪的Csv导入中,我们有一些未格式化的日期,需要进行一些搜索。Csv无法修复,无法对其进行控制,我们必须导入它 在Csv行中: “食品名称;Mer 30/05;Kbr5 08h00-13h00(-00h10)Kbr5 13h15-16h55;e 07h59 S 13h00 e 13h12 S 16h02;08h00-13h00 13h15-16h55;6:30;6:30;;” 我们有一个奇怪格式的日期:它看起来像一个手写的R/R格式,被切割成12个字符,就像是一个dd/MM/yyyy “

在一个奇怪的Csv导入中,我们有一些未格式化的日期,需要进行一些搜索。Csv无法修复,无法对其进行控制,我们必须导入它

在Csv行中:

“食品名称;Mer 30/05;Kbr5 08h00-13h00(-00h10)Kbr5 13h15-16h55;e 07h59 S 13h00 e 13h12 S 16h02;08h00-13h00 13h15-16h55;6:30;6:30;;”

我们有一个奇怪格式的日期:它看起来像一个手写的R/R格式,被切割成12个字符,就像是一个
dd/MM/yyyy

“ddd dd/MM”

我知道最后一次约会是最近的。并已订购

样本日期:

new string[] {
"Mer 15/06","Jeu 16/06","Ven 17/06","Sam 18/06","Dim 19/06","Lun 20/06","Mar 21/06",
"Jeu 23/06","Ven 24/06","Sam 25/06","Dim 26/06","Lun 27/06","Mar 28/06","Mer 29/06",
"Jeu 30/06","Ven 01/07","Sam 02/07","Dim 03/07","Lun 04/07","Mar 05/07","Mer 06/07"
}
如何将“ddd dd/MM”这样的字符串转换为
列表
? 现在,为了找到可以给出这个输出的日期,我计算了一个范围内的所有日期,并将它们与上述格式进行比较

CultureInfo fr = new CultureInfo("fr-FR");

var endDate = DateTime.Now;
var startDate = new DateTime(DateTime.Now.Year-15,1,1);

var allDates = Enumerable.Range(0, 1 + endDate.Subtract(startDate).Days)
                  .Select(x => startDate.AddDays(x))
                  .Select(x => new { key = x, strDay = x.ToString("ddd"), strOther = x.ToString(" dd/MM", fr) })
                  // French format for ddd has a dot at the end. Let's remove it.               
                  .Select(x =>new { key = x.key, str = x.strDay.Remove(x.strDay.Length - 1) + x.strOther})
                  .ToArray();

foreach (var wDate in datesToFind)
{
    var results = dates.Where(x => x.str == wDate);

    // etc..
}

datetime中的年份会发生什么变化?您是否有任何特定的年份,或者您是否尝试查找例如“哪一年的7月1日是星期日”?如果后一种情况不可靠,例如7月1日是2018年、2012年等的星期日,您可以这样做:

    var dateStrings = new string[] {
    "Mer 15/06","Jeu 16/06","Ven 17/06","Sam 18/06","Dim 19/06","Lun 20/06","Mar 21/06",
    "Jeu 23/06","Ven 24/06","Sam 25/06","Dim 26/06","Lun 27/06","Mar 28/06","Mer 29/06",
    "Jeu 30/06","Ven 01/07","Sam 02/07","Dim 03/07","Lun 04/07","Mar 05/07","Mer 06/07"
    };
var year = GetYear(dateStrings[0]);
var listDates = dateStrings
    .Select(x => {
        var input = x.Split(' ')[1].Split('/');

        return new DateTime(year, Convert.ToInt32(input[1]), Convert.ToInt32(input[0])); 
    }).ToList();
从技术上讲,您只需要一天就可以得到年份(如果您知道日期列表来自同一年):


我希望这会有所帮助

我以一种与Svetoslav Petrov非常相似的方式进行这项工作,但我没有假设所有给定的日期都在同一年内,而是以相反的顺序处理日期字符串集,并在循环的每次迭代中确定最近的一年(a)等于或早于最近转换日期的年份和(b)一周中给定日期有效的日期。只要序列中的任意两个连续日期之间,或者序列中的最后一个日期与当前日期之间没有多年的间隔,这种方法就应该有效

void Test()
{
    var dateStrings = new string[] {
        "Mer 15/06","Jeu 16/06","Ven 17/06","Sam 18/06","Dim 19/06","Lun 20/06","Mar 21/06",
        "Jeu 23/06","Ven 24/06","Sam 25/06","Dim 26/06","Lun 27/06","Mar 28/06","Mer 29/06",
        "Jeu 30/06","Ven 01/07","Sam 02/07","Dim 03/07","Lun 04/07","Mar 05/07","Mer 06/07"
        };

    var parsedDates = ParseDateStrings(dateStrings);
    foreach (var date in parsedDates)
        Console.WriteLine(date);
}

// Takes a set of date strings in the format described by the question and returns
// the analogous set of DateTime objects. This method assumes that the supplied
// dates are in chronological order.
List<DateTime> ParseDateStrings(IEnumerable<string> dateStrings)
{
    var year = DateTime.Today.Year;
    var parsedDates = new List<DateTime>();

    // Since we can't know at first how many years are represented in the given
    // data set, we can't really make any assumptions about the year in which the
    // data begins. Instead we assume that the most recent date occurs in either
    // the current year or the latest previous year in which that date was valid,
    // and work through the set backwards.
    foreach (var dateString in dateStrings.Reverse())
    {
        var dayOfWeek = GetDayOfWeek(dateString.Substring(0, 3));
        var day = int.Parse(dateString.Substring(4, 2));
        var month = int.Parse(dateString.Substring(7, 2));
        year = GetMostRecentValidYear(year, month, day, dayOfWeek);
        parsedDates.Add(new DateTime(year, month, day));
    }

    // Reversing our output again at this point puts the results back into the
    // same order as the inputs.
    parsedDates.Reverse();
    return parsedDates;
}

// Gets the appropriate DayOfWeek value for the given three-character abbreviation.
DayOfWeek GetDayOfWeek(string abbreviation)
{
    switch (abbreviation.ToLower())
    {
        case "dim": return DayOfWeek.Sunday;
        case "lun": return DayOfWeek.Monday;
        case "mar": return DayOfWeek.Tuesday;
        case "mer": return DayOfWeek.Wednesday;
        case "jeu": return DayOfWeek.Thursday;
        case "ven": return DayOfWeek.Friday;
        case "sam": return DayOfWeek.Saturday;
        default: throw new ArgumentException();
    }
}

// Gets the latest year that is equal to or earlier than the given year, and in
// which the given day of the given month fell on the given day of the week.
int GetMostRecentValidYear(int year, int month, int day, DayOfWeek dayOfWeek)
{
    while (!YearIsValid(year, month, day, dayOfWeek))
        --year;

    return year;
}

// Returns a flag indicating whether the given day of the given month fell on the
// given day of the week in the given year.
bool YearIsValid(int year, int month, int day, DayOfWeek dayOfWeek) =>
    (month != 2 || day != 29 || IsLeapYear(year)) &&
    new DateTime(year, month, day).DayOfWeek == dayOfWeek;

// Returns a flag indicating whether the given year was a leap year.
bool IsLeapYear(int year) =>
    (year % 4 == 0) && (year % 100 != 0 || year % 400 == 0);

编辑:我又看了一遍,在我最初的
YearIsValid
实现中发现了一个bug:试图为非闰年的2月29日构造一个
DateTime
,将导致构造函数抛出。我添加了闰年测试来解决这个问题
YearIsValid
如果您给它的输入在任何一年都无效,比如2月30日,它仍然会抛出,但在这种情况下,一个异常是预期的行为。

首先,看起来您需要处理“一年中的一天”(在法国文化中本地化)的概念。“一年中的某一天”的概念与年份无关,应该能够产生每一个可能的有效日期时间(从起始年份开始?)

你可以想出类似的方法来实现这个概念:

sealed class FrenchDayInYear
{
    private readonly string _dayOfYear;
    private readonly DateTimeFormatInfo _fr;
    public FrenchDayInYear(string dayOfYear)
    {
        _dayOfYear = dayOfYear;
        _fr = new CultureInfo("fr-FR").DateTimeFormat;
        _fr.AbbreviatedDayNames = new[] { "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim" };
    }
    public IReadOnlyList<DateTime> PossibleDates(int startYear)
    {
        return Enumerable.Range(startYear, DateTime.Now.Year - startYear)
                         .Select(WithYear)
                         .OfType<DateTime>()
                         .ToList();
    }
    private DateTime? WithYear(int year)
    {
        if (DateTime.TryParseExact(_dayOfYear + year, "ddd dd/MMyyyy", _fr, DateTimeStyles.None, out var result))
        {
            return result;
        }
        else
        {
            return null;
        }
    }
}

上面的代码将给出2004年和2010年的日期,2000年到现在(2018年)这两个可能的年份,在这两个年份中,
DayInYear
是可能的。

我不想这么说,但是
GIGO
@RichardSchneider,这是你学会珍惜的真正财富。作为来自过去的人工制品,这将带来怀旧。注意,在过去的一个小时里,我检查了过去24年中120多名员工工厂每周5个日期的员工,仍然没有错误。这是可以解决的,但答案不是日期时间,而是日期时间列表。我还没有看到一个选择规则。如果没有额外的信息或规则,“过去24年”是无法解决的。@bommelding,来自问题“进入列表”。没错!选择的过程超出了问题的范围,但是如果你想要更多的细节,我可以给你:基本上所有的数据都来自轮班约会。并通过rs232电缆上的设备发送给每一个使用过它的员工。这些信息然后存储在csv文件中。我知道雇员什么时候离开,所以他最后一点应该是离开日期。如果你按相反的顺序预约,那么之前的每一点都必须接近上一点。旧的徽章和考勤系统可能会很有趣。尤其是当你试图从他们那里获取信息时。我不知道是谁想出了这样一个主意,使用串行端口rs232从每个徽章站按创建顺序收集每个员工的信息,然后将其发送到“大脑”。是的,这是关于如何找到日期时间,其中“7月1日是星期日”
2016-06-15 00:00:00
2016-06-16 00:00:00
2016-06-17 00:00:00
2016-06-18 00:00:00
2016-06-19 00:00:00
2016-06-20 00:00:00
2016-06-21 00:00:00
2016-06-23 00:00:00
2016-06-24 00:00:00
2016-06-25 00:00:00
2016-06-26 00:00:00
2016-06-27 00:00:00
2016-06-28 00:00:00
2016-06-29 00:00:00
2016-06-30 00:00:00
2016-07-01 00:00:00
2016-07-02 00:00:00
2016-07-03 00:00:00
2016-07-04 00:00:00
2016-07-05 00:00:00
2016-07-06 00:00:00
sealed class FrenchDayInYear
{
    private readonly string _dayOfYear;
    private readonly DateTimeFormatInfo _fr;
    public FrenchDayInYear(string dayOfYear)
    {
        _dayOfYear = dayOfYear;
        _fr = new CultureInfo("fr-FR").DateTimeFormat;
        _fr.AbbreviatedDayNames = new[] { "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam", "Dim" };
    }
    public IReadOnlyList<DateTime> PossibleDates(int startYear)
    {
        return Enumerable.Range(startYear, DateTime.Now.Year - startYear)
                         .Select(WithYear)
                         .OfType<DateTime>()
                         .ToList();
    }
    private DateTime? WithYear(int year)
    {
        if (DateTime.TryParseExact(_dayOfYear + year, "ddd dd/MMyyyy", _fr, DateTimeStyles.None, out var result))
        {
            return result;
        }
        else
        {
            return null;
        }
    }
}
        var inputs = new string[]
        {
            "Mer 15/06","Jeu 16/06","Ven 17/06","Sam 18/06","Dim 19/06","Lun 20/06","Mar 21/06",
            "Jeu 23/06","Ven 24/06","Sam 25/06","Dim 26/06","Lun 27/06","Mar 28/06","Mer 29/06",
            "Jeu 30/06","Ven 01/07","Sam 02/07","Dim 03/07","Lun 04/07","Mar 05/07","Mer 06/07"
        };
        var output = inputs.ToDictionary(input => input, input => new FrenchDayInYear(input).PossibleDates(2000));
        foreach (var kv in output)
        {
            Console.WriteLine("{0}=[{1}]", kv.Key, string.Join(",", kv.Value));
        }