21

2 つの DateTime 間の期間を分単位で決定する必要があります。

ただし、少しひねりがあります。

  • 週末を除く
  • 午前 7 時から午後 7 時までの分のみをカウントします。例えば: [09/30/2010 6:39:00 PM] - [09/30/2010 7:39:00 PM] = 21 Minutes

私はそれを行うためのまともな方法を思い付くのに苦労しているだけで、誰かが何かを提案していただければ幸いです.

ありがとう。


編集:

私はdtbのソリューションに行き着きました。注意が必要な特殊なケースが 1 つだけあります。終了時刻が午後 7 時以降の場合は、午前 7 時から実際の終了時刻までの分数を数えます。

これは私がそれを修正した方法です:

var minutes = from day in start.DaysInRangeUntil(end)
                where !day.IsWeekendDay()
                let st = Helpers.Max(day.AddHours(7), start)
                let en = (day.DayOfYear == end.DayOfYear ? 
                            end :
                            Helpers.Min(day.AddHours(19), end)
                            )
                select (en - st).TotalMinutes;

繰り返しますが、助けてくれてありがとう。

4

9 に答える 9

23

もちろん、LINQ を使用することもできます。

DateTime a = new DateTime(2010, 10, 30, 21, 58, 29);
DateTime b = a + new TimeSpan(12, 5, 54, 24, 623);

var minutes = from day in a.DaysInRangeUntil(b)
              where !day.IsWeekendDay()
              let start = Max(day.AddHours( 7), a)
              let end   = Min(day.AddHours(19), b)
              select (end - start).TotalMinutes;

var result = minutes.Sum();

// result == 6292.89

(注: おそらく、私が完全に無視した多くの特殊なケースを確認する必要があります。)

ヘルパー メソッド:

static IEnumerable<DateTime> DaysInRangeUntil(this DateTime start, DateTime end)
{
    return Enumerable.Range(0, 1 + (int)(end.Date - start.Date).TotalDays)
                     .Select(dt => start.Date.AddDays(dt));
}

static bool IsWeekendDay(this DateTime dt)
{
    return dt.DayOfWeek == DayOfWeek.Saturday
        || dt.DayOfWeek == DayOfWeek.Sunday;
}

static DateTime Max(DateTime a, DateTime b)
{
    return new DateTime(Math.Max(a.Ticks, b.Ticks));
}

static DateTime Min(DateTime a, DateTime b)
{
    return new DateTime(Math.Min(a.Ticks, b.Ticks));
}
于 2010-09-30T21:58:29.587 に答える
5

開始時刻を取り、その日の終わり (つまり午後 7 時) までの分数を取得します。

翌日の午前7時から最終日までの日数を数えます(最終日までの時間を除く)。

(ある場合) 週末が何回過ぎたかを計算します。(週末ごとに、日数を 2 減らします)。

そこから簡単な計算を行って、日数の合計分数を取得します。

最終日の延長戦と開始日の延長戦を加算します。

于 2010-09-30T21:57:43.293 に答える
4

次の DiffRange 関数を試してください。

public static DateTime DayStart(DateTime date)
{
    return date.Date.AddHours(7);
}

public static DateTime DayEnd(DateTime date)
{
    return date.Date.AddHours(19);
}

public static TimeSpan DiffSingleDay(DateTime start, DateTime end)
{
    if ( start.Date != end.Date ) {
        throw new ArgumentException();
    }

    if (start.DayOfWeek == DayOfWeek.Saturday || start.DayOfWeek == DayOfWeek.Sunday )
    {
        return TimeSpan.Zero;
    }

    start = start >= DayStart(start) ? start : DayStart(start);
    end = end <= DayEnd(end) ? end : DayEnd(end);
    return end - start;
}

public static TimeSpan DiffRange(DateTime start, DateTime end)
{
    if (start.Date == end.Date)
    {
        return DiffSingleDay(start, end);
    }

    var firstDay = DiffSingleDay(start, DayEnd(start));
    var lastDay = DiffSingleDay(DayStart(end), end);

    var middle = TimeSpan.Zero;
    var current = start.AddDays(1);
    while (current.Date != end.Date)
    {
        middle = middle + DiffSingleDay(current.Date, DayEnd(current.Date));
        current = current.AddDays(1);
    }

    return firstDay + lastDay + middle;
}
于 2010-09-30T22:01:47.563 に答える
1
static int WorkPeriodMinuteDifference(DateTime start, DateTime end)
{
    //easier to only have to work in one direction.
    if(start > end)
        return WorkPeriodMinuteDifference(end, start);
    //if weekend, move to start of next Monday.
    while((int)start.DayOfWeek % 6 == 0)
        start = start.Add(new TimeSpan(1, 0, 0, 0)).Date;
    while((int)end.DayOfWeek % 6 == 0)
        end = end.Add(new TimeSpan(1, 0, 0, 0)).Date;
    //Move up to 07:00 or down to 19:00
    if(start.TimeOfDay.Hours < 7)
        start = new DateTime(start.Year, start.Month, start.Day, 7, 0, 0);
    else if(start.TimeOfDay.Hours > 19)
        start = new DateTime(start.Year, start.Month, start.Day, 19, 0, 0);
    if(end.TimeOfDay.Hours < 7)
        end = new DateTime(end.Year, end.Month, end.Day, 7, 0, 0);
    else if(end.TimeOfDay.Hours > 19)
        end = new DateTime(end.Year, end.Month, end.Day, 19, 0, 0);

    TimeSpan difference = end - start;

    int weeks = difference.Days / 7;
    int weekDays = difference.Days % 7;
    if(end.DayOfWeek < start.DayOfWeek)
        weekDays -= 2;

    return (weeks * 5 * 12 * 60) + (weekDays * 12 * 60) + difference.Hours * 60 + difference.Minutes
}
于 2010-09-30T22:22:03.553 に答える
1

私の実装:)アイデアは、合計週をすばやく計算し、残りの週を毎日歩くことです...

public TimeSpan Compute(DateTime start, DateTime end)
{
    // constant start / end times per day
    TimeSpan sevenAM = TimeSpan.FromHours(7);
    TimeSpan sevenPM = TimeSpan.FromHours(19);

    if( start >= end )
    {
        throw new Exception("invalid date range");
    }

    // total # of weeks
    int completeWeeks = ((int)(end - start).TotalDays) / 7;

    // starting total
    TimeSpan total = TimeSpan.FromHours(completeWeeks * 12 * 5);

    // adjust the start date to be exactly "completeWeeks" past its original start
    start = start.AddDays(completeWeeks * 7);

    // walk days from the adjusted start to end (at most 7), accumulating time as we can...
    for(
        // start at midnight
        DateTime dt = start.Date;

        // continue while there is time left
        dt < end;

        // increment 1 day at a time
        dt = dt.AddDays(1)
    )
    {
        // ignore weekend
        if( (dt.DayOfWeek == DayOfWeek.Saturday) ||
             (dt.DayOfWeek == DayOfWeek.Sunday) )
        {
            continue;
        }

        // get the start/end time for each day...
        // typically 7am / 7pm unless we are at the start / end date
        TimeSpan dtStartTime = ((dt == start.Date) && (start.TimeOfDay > sevenAM)) ?
            start.TimeOfDay : sevenAM;
        TimeSpan dtEndTime = ((dt == end.Date) && (end.TimeOfDay < sevenPM)) ?
            end.TimeOfDay : sevenPM;

        if( dtStartTime < dtEndTime )
        {
            total = total.Add(dtEndTime - dtStartTime);
        }
    }

    return total;
}
于 2010-09-30T22:22:56.397 に答える
1

かなり難しい質問でした。基本的な簡単なアプローチとして、以下のコードを作成しました。

DateTime start = new DateTime(2010, 01, 01, 21, 00, 00);
DateTime end = new DateTime(2010, 10, 01, 14, 00, 00);

// Shift start date's hour to 7 and same for end date
// These will be added after doing calculation:
double startAdjustmentMinutes = (start - start.Date.AddHours(7)).TotalMinutes;
double endAdjustmentMinutes = (end - end.Date.AddHours(7)).TotalMinutes;

// We can do some basic
// mathematical calculation to find weekdays count:
// divide by 7 multiply by 5 gives complete weeks weekdays
// and adding remainder gives the all weekdays:
int weekdaysCount = (((int)((end.Date - start.Date).Days / 7) * 5) 
          + ((end.Date - start.Date).Days % 7));
// so we can multiply it by minutes between 7am to 7 pm
int minutes = weekdaysCount * (12 * 60);

// after adding adjustment we have the result:
int result = minutes + startAdjustmentMinutes + endAdjustmentMinutes;

私はこれがプログラム的に美しいとは思えないことを知っていますが、開始から終了まで何日も何時間も繰り返すのが良いかどうかはわかりません。

于 2010-09-30T22:13:33.680 に答える
1

私が逃したものがあると確信しています。

  TimeSpan CalcBusinessTime(DateTime a, DateTime b)
  {
     if (a > b)
     {
        DateTime tmp = a;
        a = b;
        b = tmp;
     }

     if (a.TimeOfDay < new TimeSpan(7, 0, 0))
        a = new DateTime(a.Year, a.Month, a.Day, 7, 0, 0);
     if (b.TimeOfDay > new TimeSpan(19, 0, 0))
        b = new DateTime(b.Year, b.Month, b.Day, 19, 0, 0);

     TimeSpan sum = new TimeSpan();
     TimeSpan fullDay = new TimeSpan(12, 0, 0);
     while (a < b)
     {
        if (a.DayOfWeek != DayOfWeek.Saturday && a.DayOfWeek != DayOfWeek.Sunday)
        {
           sum += (b - a < fullDay) ? b - a : fullDay;
        }
        a = a.AddDays(1);
     }

     return sum;
  } 
于 2010-09-30T22:11:23.273 に答える
1

TimeSpan.TotalMinutes を使用して、非営業日を減算し、余分な時間を減算します。

于 2010-10-04T18:37:58.733 に答える
0

コードは書きませんが、DateTime を使用すると曜日がわかるため、範囲内に週末がいくつあるかがわかるため、週末が何分かがわかります。

それほど難しいことではありません...もちろん、最適な1行のソリューションが必要です...しかし、これでうまくいくと思います。

言い忘れましたが、あなたは午後 7 時から午前 7 時までの分数も知っているので、取得した時差から適切な分数を差し引くだけで済みます。

于 2010-09-30T22:39:52.680 に答える