我是一名初级程序员,刚刚开始。我被赋予了一项任务,确定当前是否正在发生事件(每年都会发生一次又一次)。事件存储在数据库中,格式为月/日开始日期到月/日结束日期,但没有年份。为了使事情变得更加复杂,事件不会超过正常日历年,它们发生在一年的7月1日到明年的6月30日之间的财政年度。似乎没有办法让DateTime对象没有一年,而且我真的不想使用任意年份的方法,因为我认为从长远来看这不会有用。据我了解,我们的项目将会越来越多,根据一年中的月份和日期显示信息(或不显示信息)。鉴于当前日期,以及我知道以月/日格式表示开始日期和结束日期的事件,如何判断事件当前是否正在发生?请记住,这可能会跨越日历年的变化。如果我可以将这个功能构建到一个linq查询中,那么我甚至不会从数据库中提取我不关心的事件,那将是非常棒的,但我将采取我能做的工作。我们使用的语言是C#。感谢
很抱歉我的帖子的结构,我没有多少使用堆栈溢出 数据库中的数据结构如下:
StartDate | EndDate
-------------|----------
3/21 | 4/15
4/25 | 5/6
11/30 | 3/7
是的,它存储为varchar。
答案 0 :(得分:3)
我强烈建议您重构数据库以便更易于查询 - 您不希望在每个查询中解析每行的字符串值。此外,您可以添加一个额外的字段来指示该事件是跨年度的,即" start"按照你的最后一个例子,在"结束"之后。所以你有类似的东西:
StartDay StartMonth EndDay EndMonth CrossYear
21 3 15 4 False
25 4 6 5 False
30 11 7 3 True
此时,您可以轻松地编写合理的查询。例如:
DateTime date = ...; // Wherever you get this from
var activeEvents = db.Events.Where
(e =>
// Regular case
(e.CrossYear == false &&
(date.Month > e.StartMonth || (date.Month == e.StartMonth && date.Day >= e.StartDay)) &&
(date.Month < e.EndMonth || (date.Month == e.EndMonth && date.Day <= e.EndDay))) ||
// Cross-year case, basically, just invert start and end... conditions
(e.CrossYear == true &&
(date.Month < e.StartMonth || (date.Month == e.StartMonth && date.Day <= e.StartDay)) &&
(date.Month > e.EndMonth || (date.Month == e.EndMonth && date.Day >= e.EndDay))));
您可以通过使用乘法将月/日转换为单个数字来表达相同的结果简单地,例如
int pseudoDayOfYear = date.Month * 100 + date.Day;
var activeEvents = db.Events.Where
(e =>
// Regular case
(e.CrossYear == false &&
pseudoDayOfYear >= e.StartMonth * 100 + e.StartDay &&
pseudoDayOfYear <= e.EndMonth * 100 + e.EndDay) ||
// Cross-year case
(e.CrossYear == true &&
pseudoDayOfYear <= e.StartMonth * 100 + e.StartDay &&
pseudoDayOfYear >= e.EndMonth * 100 + e.EndDay));
这是有效的,因为从来没有超过100天的月份,但它有点丑陋的IMO。
答案 1 :(得分:0)
我想你可以修复数据库结构,正如许多人所说的那样。话虽如此,你 是一名初级程序员,你可能对这件事没有多少发言权。
我从你的问题中注意到的一些事情:
您显然拥有一个包含部分日期片段的事件表,以varchar格式存储。没有年份信息。
您有一个会计年度的概念,从7月1日到6月30日 - 例如2016年7月1日 - 2017年6月30日。
基于以上两点,我认为您指的是一个包含每年重复事件的表(即每个列出的行项每年发生一次)。
现在,重新解释一下您的问题:如果当前日期,以上参数,您如何判断事件即将到来,是否正在发生现在,还是已经过去了?
DateTime.TryParse
方法从事件表中的日期片段重建日期。只需获取片段,然后将当前年添加到片段中。因此,对于您的示例3/21
和4/15
,您可以将这些字符串扩展为3/21/2016
和4/15/2016
。 AddYears(1)
)。如果他们都落后,那么你知道他们是今年。现在,时髦的部分是如果开始和结束跨越FY边界。示例:5月1日开始,7月1日结束。根据FY规则,年份从7月开始,所以我们谈论的是2017年5月1日开始和2017年7月1日结束。你需要弄清楚逻辑,我希望你理解我的观点。DateTime.Today
,则意味着该事件要么 a)已启动或已完成; b)如果没有,那么事件就在将来的某个地方。如果 b)的情况属实,那么您必须根据DateTime.Today
评估结束日期。如果等于或小于,则事件已完成(或将在今天完成)。如果更大,那么事件仍在进行中。对于超级冗长的帖子感到抱歉,但我只是想让您高效地了解如何仍然可以合理有效地满足您的要求,而无需触发表重新设计。
我常常因为一些原因而重新设计现有的桌子。其中一个主要问题是,我可能不知道该表的项目依赖关系的完整地图。例如,某些生产报告可能针对该表运行。或者Excel插件可能正在查询该表并为某个用户生成一些输出。最重要的是,如果看起来有点腥,在你再次进行重新设计之前,试着弄清楚为什么它的设计是这样的。有时,鱼腥设计的基本原理是引人注目的,有时它只是一个孤立的坏思维产品(因此可以重新设计,风险最小)。