【问题标题】:How to find the EndDate from a set of given inputs如何从一组给定的输入中找到 EndDate
【发布时间】:2021-04-18 07:26:05
【问题描述】:

我正在努力解决一个日期时间问题,我得到了一组输入,我需要使用这些输入找到 EndDate。我正在尽我最大的努力解决这个问题,但由于时间不多了,所以我来到了这里。因此,可能已经面临此问题的人或有解决方案的人可以告诉我。

问题说明:

概念是直播课程流应用程序的每周时间表。老师从特定的开始日期安排了每周的课程。

假设开课日期是 2021 年 4 月 18 日,老师每周选择 3 天(周一、周二和周三),每天都有不同的课时(我的意思是持续时间,我们有那个课的开始时间日期和课程长度(以小时和分钟为单位)。

  • 开始日期:2021 年 4 月 18 日
  • 每周总天数:3
  • 日期:周一、周二、周三
  • 每天总时长:3 小时 30 分钟
  • 每周总时长:10 小时 30 分钟(合计 = 周一 + 周二 + 周三)
  • 用户不能超过的最长持续时间:50 小时

好的!现在我们将重复地将 TDPD(3 小时 30 分钟)添加到开始日期,直到达到 50 小时,然后找到它到达的日期(结束日期)。

到目前为止我尝试了什么?

int totalWeeks = 0;
int totalHoursPerWeek = 3;
int totalHoursAdded = 0;
int maxHours = 50;
for(int i = totalHoursPerWeek; i <= maxHours; i += totalHoursPerWeek)
{
    totalHoursAdded += i;
    totalWeeks++;
}

一旦循环结束,我就有了总周值。

DateTime endDate;
if(totalHoursAdded == maxHours)
{
    //My problem is solved, as there is no remaining time pending
    endDate = currentDate.AddDays(totalWeeks * 7);
}
else
{
    // I have some pending hours
    int pendingHours = maxHours - totalHoursAdded;

    //How do I proceed with this pendingHours? how to add this to the 
    //specific days per week and find the end date? I am stuck here...
}

【问题讨论】:

  • @Sweeper。是的,你是对的!我只是将其发布为示例。反正我现在就改正

标签: c# datetime logic


【解决方案1】:

我相信这可以通过一些经过深思熟虑的日期数学来完成,但是下面可能被称为懒惰的出路。这种方法只需要开始日期,一周中上课的日期列表,即星期一,星期二等......,以小时和分钟为单位的课程持续时间,最后是所需的最大总小时和分钟.

根据我的理解,鉴于上述信息,我们想知道,鉴于开课日期和班级开会的星期几……

满足最大总小时数的 LAST 课程将在什么日期。

为了简化这一点,可以派上用场的一件事就是知道......

“需要多少类才能满足 MAX 要求”。

换句话说,如果我们知道需要多少个类来满足最大要求,那么这应该会使事情变得更容易。

计算满足最大要求所需的班级总数,可以通过将最大要求除以班级持续时间来计算。如果除法产生余数,则这意味着需要一 (1) 个额外的类来满足最大要求。

因此,如果我们将类持续时间和最大持续时间变量都作为Timespan 对象,那么我们可以通过它们各自的Tick 属性划分TimeSpan 对象,并返回需要多少类才能满足最大值要求。这种方法可能看起来像……

private int GetTotalNumberOfClassesNeeded(TimeSpan classDuration, TimeSpan totalDuration) {
  double td = totalDuration.Ticks / (double)classDuration.Ticks;
  int totalClasses = (int)Math.Truncate(td); // <- get the whole portion
  if (Math.Floor(td) != td) {
    totalClasses++;  // <- there is a fractional part - 1 more class needed
  }
  return totalClasses;
}

接下来,我们需要将日期的DayOfWeek 与班级的DayOfWeek 进行比较。因此,我们可以做的是创建一个List&lt;DayOfWeek&gt; ... 一个类在会话中的DayOfWeek 对象列表。我们将使用此列表来检查特定日期的星期几是否在该列表中。因此,在此示例中,班级在一周中的哪几天见面是一个简单的逗号分隔 string。鉴于此string,代码将解析出日期并返回要与之比较的DayOfWeek 对象的正确列表。这种方法可能看起来像……

private List<DayOfWeek> GetDaysOfWeekForClasses(string daysOfWeek) {
  List<DayOfWeek> classesDOW = new List<DayOfWeek>();
  string[] splitArray = daysOfWeek.Split(',');
  DayOfWeek dow;
  for (int i = 0; i < splitArray.Length; i++) {
    switch (splitArray[i].Trim()) {
      case "Monday":
        dow = DayOfWeek.Monday;
        break;
      case "Tuesday":
        dow = DayOfWeek.Tuesday;
        break;
      case "Wednesday":
        dow = DayOfWeek.Wednesday;
        break;
      case "Thursday":
        dow = DayOfWeek.Thursday;
        break;
      case "Friday":
        dow = DayOfWeek.Friday;
        break;
      case "Saturday":
        dow = DayOfWeek.Saturday;
        break;
      default:
        dow = DayOfWeek.Sunday;
        break;
    }
    classesDOW.Add(dow);
  }
  return classesDOW;
}

这几乎就是我们所需要的。总体思路是……我们首先将int 变量curClassCount 设置为零(0)。此外,我们将创建一个DateTime 对象tempDate,它使用开始日期进行初始化。最后,我们将创建一个DateTime 对象列表scheduledClasses,其中将填充课程的日期。我们将启动一个while 循环,只要curClassCount 小于所需的类总数,就会继续。

在循环的每次迭代中,都会检查tempDateDayOfWeek 是否是类的DayOfWeek. 之一……如果是,那么我们将该日期添加到scheduledClasses 列表中并增加curClassCount。最后将tempDate 增加一 (1) 天,然后重新开始循环。最终,curClassCount 将等于所需的类数。这段代码可能看起来像……

while (curClassCount < totalNumberOfClassesNeeded) {
  if (ClassDaysOfWeek.Contains(tempDate.DayOfWeek)) {
    scheduledClasses.Add(tempDate.Date);
    curClassCount++;
  }
  tempDate = tempDate.AddDays(1);
}

通过将DateTimePicker, four (4) TextBoxes、Button 和多行TextBox 放到新的Winforms .Net 上,将所有这些放在一起,Form 可能看起来像……

使用下面的代码应该可以完成示例。

private void Form1_Load(object sender, EventArgs e) {
  dateTimePicker1.Value = new DateTime(2021, 4, 18);
  TextBoxTotDaysPerWeek.Text = "3";
  textBoxClassDays.Text = "Monday, Tuesday, Wednesday";
  textBoxClassDuration.Text = "00:03:00:00";
  textBoxMaxDuation.Text = "02:02:00:00";
}

private void btnCalculate_Click(object sender, EventArgs e) {
  DateTime StartDate = dateTimePicker1.Value;
  TimeSpan.TryParse(textBoxClassDuration.Text.Trim(), out TimeSpan ClassDuration);
  TimeSpan.TryParse(textBoxMaxDuation.Text.Trim(), out TimeSpan MaxDuration);
  int totalNumberOfClassesNeeded = GetTotalNumberOfClassesNeeded(ClassDuration, MaxDuration);
  List<DayOfWeek> ClassDaysOfWeek = GetDaysOfWeekForClasses(textBoxClassDays.Text.Trim());
  List<DateTime> scheduledClasses = new List<DateTime>();
  int curClassCount = 0;
  DateTime tempDate = StartDate.Date;
  while (curClassCount < totalNumberOfClassesNeeded) {
    if (ClassDaysOfWeek.Contains(tempDate.DayOfWeek)) {
      scheduledClasses.Add(tempDate.Date);
      curClassCount++;
    }
    tempDate = tempDate.AddDays(1);
  }
  txtBoxResults.Text = "";
  txtBoxResults.Text = "Start Date: " + StartDate.ToShortDateString() +Environment.NewLine;
  for (int i = 0; i < scheduledClasses.Count; i++) {
    txtBoxResults.Text += "Class # " + (i + 1) + " of " + totalNumberOfClassesNeeded +
                          " Date: " + scheduledClasses[i].ToShortDateString() + Environment.NewLine;
  }
} 

注意,关于最长持续时间……因为 TimeSpan 只允许小时

【讨论】:

  • 这是一个很棒的。我也需要测试一下。与我的部分视图中的条件数量相比,您输出的类列表及其日期对我来说似乎更容易一些。感谢您花时间写这个答案...
  • 因为你的答案比我要求的解释更高级,而且我发现这更干净、更容易、更有效地避免了条件复杂性。我将采用这种方法。谢谢你的回答..
  • 其实我忘了告诉你,不同天的课时长不一样!这是不一样的。星期一可能有一些价值,可能与星期二或星期三不同。我需要自己解决这个问题。任何帮助将不胜感激..
【解决方案2】:

这是两个选项(使用For和使用While循环),应该可以解决问题:

using System;

namespace SO.DtProblem
{
    class Program
    {
        static void Main(string[] args)
        {
            ClaculationOption1(); //Using For loop
            ClaculationOption2(); //Using While loop
        }

        private static void ClaculationOption1()
        {
            var totalWeeks = 0;
            var totalHoursPerWeek = 3;
            var durationPerDay = 3;
            var maxHours = 50;
            var courseStartDate = new DateTime(2021, 4, 12); //Which is a Monday day

            totalWeeks = maxHours / totalHoursPerWeek;

            var expectedEndDate = courseStartDate.AddDays(totalWeeks * 7);

            var pendingHours = maxHours % totalHoursPerWeek;

            for (var day = 1; day <= 6; day++)
            {
                if (pendingHours > 0)
                {
                    expectedEndDate = expectedEndDate.AddDays(1);

                    if ((expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Monday)
                    || (expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Tuesday)
                    || (expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Wednesday))
                    {
                        if (pendingHours - durationPerDay >= 0)
                        {
                            pendingHours = pendingHours - durationPerDay;
                        }
                        else
                        {
                            pendingHours = 0;
                            break;
                        }
                    }

                }
            }
            Console.Clear();
            Console.WriteLine("Option 1 Results");
            Console.WriteLine($"Course Start Date : {courseStartDate}");
            Console.WriteLine($"Course Start Date Day Name: {courseStartDate.DayOfWeek}");
            Console.WriteLine($"Expected End Date : {expectedEndDate}");
            Console.WriteLine($"Expected End Date Day Name: {expectedEndDate.DayOfWeek}");
            Console.WriteLine("===========================================================");

        }

        private static void ClaculationOption2()
        {
            var totalWeeks = 0;
            var totalHoursPerWeek = 3;
            var durationPerDay = 3;
            var maxHours = 50;
            var courseStartDate = new DateTime(2021, 4, 12); //Which is a Monday day

            totalWeeks = maxHours / totalHoursPerWeek;

            var expectedEndDate = courseStartDate.AddDays(totalWeeks * 7);

            var pendingHours = maxHours % totalHoursPerWeek;

            while (pendingHours > 0)
            {
                expectedEndDate = expectedEndDate.AddDays(1);

                if ((expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Monday)
                || (expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Tuesday)
                || (expectedEndDate.AddDays(1).DayOfWeek == DayOfWeek.Wednesday))
                {
                    if (pendingHours - durationPerDay >= 0)
                    {
                        pendingHours = pendingHours - durationPerDay;
                    }
                    else
                    {
                        pendingHours = 0;
                        break;
                    }
                }
            }

            Console.WriteLine("Option 2 Results");
            Console.WriteLine($"Course Start Date : {courseStartDate}");
            Console.WriteLine($"Course Start Date Day Name: {courseStartDate.DayOfWeek}");
            Console.WriteLine($"Expected End Date : {expectedEndDate}");
            Console.WriteLine($"Expected End Date Day Name: {expectedEndDate.DayOfWeek}");
            Console.ReadKey();

        }
    }
}

【讨论】:

  • 嗨@Thameem,代码已更新(控制台语句更正)
  • 感谢@Useme Alehosaini 的回答,我会检查并回来
  • 我想我可能遗漏了一些东西,但是,当我运行您发布的代码时,它给出的最终结果是“08/03/2021”? ……这不可能是正确的。如果课程每周开三(天)(周一、周二、周三),并且每节课时长 3 小时,那么这将是每周九 (9) 小时。如果最大值是 50 小时,那么,这将是 5.555 周。因此,四舍五入到六 (6) 周以达到最长小时数。假设开始日期是“2021 年 4 月 12 日”,那么该日期之后的六周将是“2021 年 5 月 XX 日”的某个时间。
  • 如果三小时的会议日只有一周一天,那么它将在八 (8) 月的某个时间结束,但您的代码似乎正在检查周一、周二和周三?我猜这条线……var totalHoursPerWeek = 3;……应该是……var totalHoursPerWeek = 9;因为每周有三 (3) 节课,每节课时长三 (3) 小时。再说一次,我可能遗漏了一些东西。
  • @UsemeAlehosaini 感谢您花时间写这个答案。虽然这可能会回答我原来的问题。我将继续使用 OP,因为这与我当前的系统架构相比是一种差异方法..
【解决方案3】:

最后,我根据@John 的回答得到了自己的解决方案。此答案专门针对可变小时和分钟。

private static void CalculateClassDates()
{
    DateTime courseStartDateTime = DateTime.Today;
    int courseDurationInHours = 60;
    int courseDurationInMinutes = 0;

    TimeSpan courseMaxDuration = new TimeSpan(courseDurationInHours, courseDurationInMinutes, 0);
    List<CourseScheduleDates> courseScheduleDates = new List<CourseScheduleDates>();

    List<DaysOfWeek> daysOfWeeks = new List<DaysOfWeek>()
            {
                new DaysOfWeek(){ DayOfWeek = DayOfWeek.Monday, StartTime = DateTime.Today.AddHours(10).TimeOfDay , TotalHours = 1, TotalMinutes = 15},
                new DaysOfWeek(){ DayOfWeek = DayOfWeek.Tuesday, StartTime = DateTime.Today.AddHours(10).TimeOfDay , TotalHours = 1, TotalMinutes = 15},
                new DaysOfWeek(){ DayOfWeek = DayOfWeek.Wednesday, StartTime = DateTime.Today.AddHours(10).TimeOfDay , TotalHours = 1, TotalMinutes = 30}
            };

    int daysToAdd = 0;
    TimeSpan singleDuration = new TimeSpan(daysOfWeeks[0].TotalHours, daysOfWeeks[0].TotalMinutes, 0);

    TimeSpan additionallyAddedTime = TimeSpan.Zero;
    List<DayOfWeek> days = daysOfWeeks.Select(x => x.DayOfWeek).ToList();
    while (singleDuration.Ticks <= courseMaxDuration.Ticks)
    {
        if (days.Contains(courseStartDateTime.AddDays(daysToAdd).DayOfWeek))
        {
            var dayOfWeek = daysOfWeeks.Where(x => x.DayOfWeek == courseStartDateTime.AddDays(daysToAdd).DayOfWeek).First();
            courseScheduleDates.Add(new CourseScheduleDates()
            {
                ScheduleDate = courseStartDateTime.AddDays(daysToAdd),
                StartTime = dayOfWeek.StartTime,
                TotalHours = dayOfWeek.TotalHours,
                TotalMinutes = dayOfWeek.TotalMinutes
            });

            additionallyAddedTime = new TimeSpan(dayOfWeek.TotalHours, dayOfWeek.TotalMinutes, 0);
            singleDuration = singleDuration.Add(additionallyAddedTime);
        }

        daysToAdd++;
    }

    singleDuration = singleDuration.Subtract(additionallyAddedTime);
    if (singleDuration.Ticks != courseMaxDuration.Ticks)
    {
        var timeSpanToAdd = new TimeSpan(courseMaxDuration.Ticks - singleDuration.Ticks);
        bool shouldContinue = true;
        while (shouldContinue)
        {
            var currentDate = courseStartDateTime.AddDays(daysToAdd);
            if (days.Contains(currentDate.DayOfWeek))
            {
                var dayOfWeek = daysOfWeeks.Where(x => x.DayOfWeek == courseStartDateTime.DayOfWeek).First();
                courseScheduleDates.Add(new CourseScheduleDates()
                {
                    ScheduleDate = courseStartDateTime.AddDays(daysToAdd),
                    StartTime = dayOfWeek.StartTime,
                    TotalHours = timeSpanToAdd.Hours,
                    TotalMinutes = timeSpanToAdd.Minutes
                });

                shouldContinue = false;
            }
        }
    }

    Console.WriteLine("Course Start Date " + courseStartDateTime.ToString("dd MMM, yyyy"));

    int classCount = 1;
    foreach (var item in courseScheduleDates)
    {
        DateTime dateTime = new DateTime(item.StartTime.Ticks);
        Console.WriteLine("Class " + classCount + " will commence on " + item.ScheduleDate.ToString("dd MMM, yyyy") +
            " " + dateTime.ToString("hh:mm tt") + " and will last for " + item.TotalHours + " hrs " + item.TotalMinutes + " mins");
        classCount++;
    }
    Console.ReadLine();
}

还有模特

public class DaysOfWeek
{
    public DayOfWeek DayOfWeek { get; set; }
    public TimeSpan StartTime { get; set; }
    public int TotalHours { get; set; }
    public int TotalMinutes { get; set; }
}

public class CourseScheduleDates
{
    public DateTime ScheduleDate { get; set; }
    public TimeSpan StartTime { get; set; }
    public int TotalHours { get; set; }
    public int TotalMinutes { get; set; }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-18
    • 1970-01-01
    • 2013-02-03
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 2013-04-14
    相关资源
    最近更新 更多