2013-02-14 90 views
0

我正在爲事件進行資源分配。查找一天中的可用時間

一個資源我的事件表看起來是這樣的:

(Int)---(nvarchar(100)---(datetime)--(datetime) 

EventId --- Event --- StartTime ---    EndTime 

1 /  test / 2013-02-20 13:00:00 / 2013-02-20 15:00:00 

2 /  test2 / 2013-02-20 09:30:00/ 2013-02-20 11:00:00 

3 /  test3 / 2013-02-25 11:30:00/ 2013-02-25 14:30:00 

現在我想找到一個一天,這個資源的總可用性。

喜歡2013年2月20日我想從這個資源中刪除繁忙時間,並且只想顯示新事件的可用時間。

我使用php和sql server 2008 r2。

它工作正常,只有一天的記錄。現在我正在使用一個帶有計算的foreach循環。

我的代碼是:

$id = 6;  
$cdata = $test->getResourceEvents($id); 

$h = ""; 
$final= array(); 

foreach($cdata as $c) 
    { 

    $sh = $c['starttime']->Format('H'); // Starting hour 
    $eh = $c['endtime']->Format('H'); // End hour 

    $hh = $sh; 
    $final = array(); 
    $sdate = $c['starttime']->Format('Y-m-d'); 
    $edate = $c['endtime']->Format('Y-m-d'); 
    if($edate == $sdate) 
    { 

    $dh = $eh-$sh; // Duration 
     for($i=1;$i<=$dh;$i++) 
     { 
      $hh = $hh.",".($sh+$i); // Busy hours 
     }  
    $busyhrs[$sdate] = explode(",",$hh); 
     $final[$sdate] = $busyhrs; 
    } 
    else 
    { 
     echo "false"; 
    } 
} 

print_r($final); 

,我的結果是:

 
Array 
(
    [2013-02-20] => Array 
     (
      [2013-02-20] => Array 
       (
        [0] => 9 
        [1] => 10 
        [2] => 11 
       ) 

     ) 

    [2013-02-26] => Array 
     (
      [2013-02-26] => Array 
       (
        [0] => 11 
        [1] => 12 
        [2] => 13 
        [3] => 14 
       ) 

     ) 

) 

前兩條記錄有相同的日期。但這隻能計算第二排的小時數。不計算第一行的小時數爲13,14,15。

任何人都可以請告訴我如何匹配日期以及如何獲得一個日期的總忙時間?

+0

請向我們顯示您的代碼。 – anditpainsme 2013-02-14 01:22:45

+0

你想讓你的輸出看起來像什麼?一系列時間範圍?如果你從你想要的結果回來,你可能會回答你自己的問題。 – Jerry 2013-02-14 01:25:25

+0

是的,我想要一個可用時間的數組,如可用小時數。我正在忙於工作,然後從資源的總工作時間中刪除忙時間。但它工作正常,只有一個日期的記錄。就像前2條記錄一樣,它只記錄第2條記錄。它不包括繁忙時間10至13小時。在邏輯上某處我錯了。請告訴我該怎麼辦? – Mausami 2013-02-14 01:44:00

回答

0

我找到了解決辦法。 我改變了製作最終陣列的過程。 非常感謝所有幫助我的人。 我覺得它很簡單。 這是我的代碼。

可能會對某人有幫助。

 $id = 6;  
     $cdata = $test->getResourceEvents($id); 

     $h = ""; 
     $final= array(); 

     foreach($cdata as $c) 
     { 
      $sh = $c['starttime']->Format('H'); // Starting hour 

      $eh = $c['endtime']->Format('H'); // End hour 


      $hh = $sh; 
      $busyhrs = array(); 
      $sdate = $c['starttime']->Format('Y-m-d'); 
      $edate = $c['endtime']->Format('Y-m-d'); 
      if($edate == $sdate) 
      { 
       $dh = $eh-$sh; // Duration 
       for($i=1;$i<=$dh;$i++) 
       { 
        $hh = $hh.",".($sh+$i); // Busy hours 
       } 

       if($final != array() || $final != NULL) 
       { 
        foreach($final as $key=>$val) 
        { 
         if($key==$sdate) 
         { 
          $final[$key] = $val.",".$hh; 
         } 
         else 
         { 
          $final[$sdate] = $hh; 
         } 
        } 
       } 
       else 
       { 
        $final[$sdate] = $hh; 
       }       
      } 
      else 
      { 
       echo "false"; 
      } 
     } 

     echo "<pre>"; 
     print_r($final); 
0

我在Java中做了類似的事情。

我有一個包含日期範圍的表格,還有一個日期範圍,我必須從已存在的日期範圍中插入到覆蓋範圍中。

我基本上把我感興趣的日期範圍和「減去」所有現有的日期範圍。你會在下面的代碼中找到我的減法方法。

從DateRange_A中減去DateRange_B會導致DateRange_A在位置上被修改,如果DateRange_A被DateRange_B完全拆分,則該方法返回一個新的DateRange。

當然還有其他方法可以解決這個問題,在SQL SERVER中這樣的迭代,但是我已經在使用Java的思維模式,而且這個解決方案剛好發生了。


/* 
* Copyright (c) 2009, Ben Fortuna 
* (Modified by Alex Marunowski) 
* All rights reserved. 
* 
* Redistribution and use in source and binary forms, with or without 
* modification, are permitted provided that the following conditions 
* are met: 
* 
* o Redistributions of source code must retain the above copyright 
* notice, this list of conditions and the following disclaimer. 
* 
* o Redistributions in binary form must reproduce the above copyright 
* notice, this list of conditions and the following disclaimer in the 
* documentation and/or other materials provided with the distribution. 
* 
* o Neither the name of Ben Fortuna nor the names of any other contributors 
* may be used to endorse or promote products derived from this software 
* without specific prior written permission. 
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
*/ 

import java.io.Serializable; 
import java.util.Date; 

/** 
* @author fortuna 
* 
*/ 
public class DateRange implements Serializable { 

    private static final long serialVersionUID = -7303846680559287286L; 

    /** 
    * A flag indicating whether to include the start of the period in test functions. 
    */ 
    public static final int INCLUSIVE_START = 1; 

    /** 
    * A flag indicating whether to include the end of the period in test functions. 
    */ 
    public static final int INCLUSIVE_END = 2; 

    private Date rangeStart; 

    private Date rangeEnd; 

    /** 
    * @param start the start of the range 
    * @param end the end of the range 
    */ 
    public DateRange(Date start, Date end) { 
     if (start == null) { 
      throw new IllegalArgumentException("Range start is null"); 
     } 
     if (end == null) { 
      throw new IllegalArgumentException("Range end is null"); 
     } 
     if (end.before(start)) { 
      throw new IllegalArgumentException("Range start must be before range end"); 
     } 
     this.rangeStart = start; 
     this.rangeEnd = end; 
    } 

    /** 
    * @return the rangeStart 
    */ 
    public Date getStartDate() { 
     return rangeStart; 
    } 

    /** 
    * @return the rangeEnd 
    */ 
    public Date getEndDate() { 
     return rangeEnd; 
    } 

    public void setRangeStart(Date rangeStart) { 
     if(rangeStart.after(getEndDate())) 
      throw new IllegalArgumentException("The start of a date range cannot be after its end!"); 

     this.rangeStart = rangeStart; 
    } 

    public void setRangeEnd(Date rangeEnd) { 
     if(rangeStart.after(getEndDate())) 
      throw new IllegalArgumentException("The end of a date range cannot be after its start!"); 

     this.rangeEnd = rangeEnd; 
    } 

    /** 
    * Determines if the specified date occurs within this period (inclusive of 
    * period start and end). 
    * @param date a date to test for inclusion 
    * @return true if the specified date occurs within the current period 
    * 
    */ 
    public final boolean includes(final Date date) { 
     return includes(date, INCLUSIVE_START | INCLUSIVE_END); 
    } 

    /** 
    * Decides whether a date falls within this period. 
    * @param date the date to be tested 
    * @param inclusiveMask specifies whether period start and end are included 
    * in the calculation 
    * @return true if the date is in the period, false otherwise 
    * @see Period#INCLUSIVE_START 
    * @see Period#INCLUSIVE_END 
    */ 
    public final boolean includes(final Date date, final int inclusiveMask) { 
     boolean includes = true; 
     if ((inclusiveMask & INCLUSIVE_START) > 0) { 
      includes = includes && !rangeStart.after(date); 
     } 
     else { 
      includes = includes && rangeStart.before(date); 
     } 
     if ((inclusiveMask & INCLUSIVE_END) > 0) { 
      includes = includes && !rangeEnd.before(date); 
     } 
     else { 
      includes = includes && rangeEnd.after(date); 
     } 
     return includes; 
    } 

    /** 
    * Decides whether this period is completed before the given period starts. 
    * 
    * @param range 
    *   a period that may or may not start after this period ends 
    * @return true if the specified period starts after this periods ends, 
    *   otherwise false 
    */ 
    public final boolean before(final DateRange range) { 
     return (rangeEnd.before(range.getStartDate())); 
    } 

    /** 
    * Decides whether this period starts after the given period ends. 
    * 
    * @param range 
    *   a period that may or may not end before this period starts 
    * @return true if the specified period end before this periods starts, 
    *   otherwise false 
    */ 
    public final boolean after(final DateRange range) { 
     return (rangeStart.after(range.getEndDate())); 
    } 

    /** 
    * Decides whether this period intersects with another one. 
    * 
    * @param range 
    *   a possible intersecting period 
    * @return true if the specified period intersects this one, false 
    *   otherwise. 
    */ 
    public final boolean intersects(final DateRange range) { 
     boolean intersects = false; 
     // Test for our start date in period 
     // (Exclude if it is the end date of test range) 
     if (range.includes(rangeStart) && !range.getEndDate().equals(rangeStart)) { 
      intersects = true; 
     } 
     // Test for test range's start date in our range 
     // (Exclude if it is the end date of our range) 
     else if (includes(range.getStartDate()) 
       && !rangeEnd.equals(range.getStartDate())) { 
      intersects = true; 
     } 
     return intersects; 
    } 

    /** 
    * Decides whether these periods are serial without a gap. 
    * @param range a period to test for adjacency 
    * @return true if one period immediately follows the other, false otherwise 
    */ 
    public final boolean adjacent(final DateRange range) { 
     boolean adjacent = false; 
     if (rangeStart.equals(range.getEndDate())) { 
      adjacent = true; 
     } else if (rangeEnd.equals(range.getStartDate())) { 
      adjacent = true; 
     } 
     return adjacent; 
    } 

    /** 
    * Decides whether the given period is completely contained within this one. 
    * 
    * @param range 
    *   the period that may be contained by this one 
    * @return true if this period covers all the dates of the specified period, 
    *   otherwise false 
    */ 
    public final boolean contains(final DateRange range) { 
     // Test for period's start and end dates in our range 
     return (includes(range.getStartDate()) && includes(range.getEndDate())); 
    } 

    /** 
    * Decides whether the given period is completely contained within this one, taking into consideration whether date ranges with matching start or end dates 
    * are counted as being contained 
    * 
    * @param range 
    *   the period that may be contained by this one 
    * @param inclusiveMask 
    *    if this is set to 0, the start and end dates cannot be the same date and have it be considered to be contained within this date range. 
    *    this.contains(this, 1) returns true 
    *    this.contains(this, 0) returns false 
    * @return true if this period covers all the dates of the specified period, 
    *   otherwise false 
    */ 
    public final boolean contains(final DateRange range, int inclusiveMask) { 
     // Test for period's start and end dates in our range 
     return (includes(range.getStartDate(), inclusiveMask) && includes(range.getEndDate(), inclusiveMask)); 
    } 


    /** 
    * Exclude otherRange from the dates covered by this DateRange. Note: This will put the specified buffer around the range being subtracted from this date range. 
    * @param otherRange 
    * @return an additional date range if subtracting otherRange from this DateRange results in a part of this objects DateRange being separated from the rest of the range. 
    * i.e. if this.includes(otherRange, 0), then there will be two remaining portions of this daterange. 
    * If no dangling date range remains, then the method returns null. 
    * @author Alex Marunowski. 2012.10.31 
    */ 
    public DateRange subtract(DateRange otherRange, long buffer) throws DateRangeObliteratedException{ 

     Date bufferedStart = new Date(otherRange.getStartDate().getTime()-buffer); 
     Date bufferedEnd= new Date(otherRange.getEndDate().getTime()+buffer); 
     otherRange = new DateRange(bufferedStart, bufferedEnd); 

     // If the other range is entirely after this range, nothing happens 
     if(getEndDate().before(otherRange.getStartDate())) 
      return null; 

     // If the other range is entirely before this range, nothing happens 
     if(getStartDate().after(otherRange.getEndDate())) 
      return null; 

     if(otherRange.contains(this)) 
      throw new DateRangeObliteratedException(); 

     DateRange separatedTimeInterval = null; 
     if(this.contains(otherRange, 0)){ 

      // The trailing daterange is the time between the end date of the inner daterange, and the end date of the outer date range 
      separatedTimeInterval = new DateRange(otherRange.getEndDate(), getEndDate()); 

      // This date range now ends at the start time of the inner date range 
      this.setRangeEnd(otherRange.getStartDate()); 

      return separatedTimeInterval; 
     } 




     if(otherRange.getEndDate().before(getEndDate())){ 
      // This date range is now the time between the end of the otherRange plus the buffer time, and the end of this date range 
      long newRangeStart = otherRange.getEndDate().getTime(); 
      this.setRangeStart(new Date(newRangeStart)); 
      return null; 
     } 

     if(otherRange.getStartDate().after(getStartDate())){ 
      // This date range is now the time between this date range's start, and the other date ranges start minus the buffer time 
      long newRangeEnd = otherRange.getStartDate().getTime(); 
      this.setRangeEnd(new Date(newRangeEnd)); 
      return null; 
     } 

     // This will never happen, but the compiler doesn't know that 
     System.out.println("This should never have happened. No comparisons between the date ranges was discovered"); 
     return null; 



    } 

    public static class DateRangeObliteratedException extends Exception { 
     /** 
     * 
     */ 
     private static final long serialVersionUID = -5642891561498447972L; 

     public DateRangeObliteratedException() { 
      super("This date range no longer exists. It was entirely contained within the range you subtracted from it."); 
     } 
    } 
} 



         for(int rangeIndex = 0; rangeIndex less than rangesBusy.size(); rangeIndex++) { 
          DateRange busyRange = rangesBusy.get(rangeIndex); 
          try { 
           DateRange trailingRange = freeTimeBlock.subtract(busyRange, 0); 

           if(trailingRange != null) { 
            freeTimeRanges.add(trailingRange); 
           } 

          } catch (DateRangeObliteratedException e) { 
           freeTimeRanges.remove(rangeIndex); 
           rangeIndex--; 
          } 
         } 
+0

謝謝amarunowski爲您解答。我認爲這不是我想要的。我想從存儲的值中計算總忙時數。我也懂了。但我認爲問題出現在我的循環中,因爲如果有多個記錄的日期比只記錄最後一個記錄的小時數多。我想添加所有的時間。 – Mausami 2013-02-14 02:22:54

+0

所以你想知道資源每天會有多少小時忙? – amarunowski 2013-02-14 02:26:57

+0

雅我想知道資源每天會有多少小時忙?我怎麼能從SQL中做到這一點? – Mausami 2013-02-14 02:32:51

0

我想這就是你所期待的。關鍵是涉及$ all_finals和$ final的移動。我通常用Python語言編寫,不知道追加到PHP中的數組的最佳方式,所以我用這個http://php.net/manual/en/function.array-push.php

$id = 6;  
$cdata = $test->getResourceEvents($id); 

$h = ""; 
$all_finals = array(); 


foreach($cdata as $c) 
    { 
    $final= array(); 
    $sh = $c['starttime']->Format('H'); // Starting hour 
    $eh = $c['endtime']->Format('H'); // End hour 

    $hh = $sh; 
    $final = array(); 
    $sdate = $c['starttime']->Format('Y-m-d'); 
    $edate = $c['endtime']->Format('Y-m-d'); 
    if($edate == $sdate) 
    { 

    $dh = $eh-$sh; // Duration 
     for($i=1;$i<=$dh;$i++) 
     { 
      $hh = $hh.",".($sh+$i); // Busy hours 
     }  
    $busyhrs[$sdate] = explode(",",$hh); 
     $final[$sdate] = $busyhrs; 
    } 
    else 
    { 
     echo "false"; 
    } 
    array_push($all_finals, $final); 
} 

print_r($all_final); 
+0

對不起傑克。這all_final沒有工作。如果數組的日期相同,我想添加小時數。意思是我想每天獲得資源的總忙時。 – Mausami 2013-02-14 02:37:36