我正在为一个事件进行资源分配。
我的一个资源的事件表如下所示:
(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);
我的结果是:
大堆(〔2013-02-20〕=>阵列(〔2013-02-20〕=>阵列([0]=>9[1] =>10[2] =>11))〔2013-02-26〕=>阵列(〔2013-02-26〕=>阵列([0]=>11[1] =>12[2] =>13[3] =>14)))
前两条记录的日期相同。但这只计算第二行的小时数。不计算第一行的13、14、15小时。
有人能告诉我如何匹配日期以及如何获得一次约会的总繁忙时间吗?
我认为这符合您的期望。关键行是那些涉及$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);
我在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--;
}
}
我找到了解决方案。我改变了制作最终阵列的过程。非常感谢所有帮助我的人。我认为这很简单。这是我的密码。
也许它会对某人有所帮助。
$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);