C# 根据“查找实际日期”;DayOfWeek,日/月“; 背景:
在一个奇怪的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个字符,就像是一个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 “
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));
}