首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将时间范围分割成若干个部分

将时间范围分割成若干个部分
EN

Stack Overflow用户
提问于 2010-05-07 22:24:53
回答 5查看 2K关注 0票数 20

第一个问题。请温柔些。

我正在开发跟踪技术人员在任务上花费的时间的软件。该软件需要加强,以识别不同的收费率乘数根据一周的一天和时间的一天。(例如,“工作日下午5点半之后的时间”)

使用该软件的技术人员只需要记录日期、开始时间和停止时间(以小时和分钟为单位)。该软件预计将打破时间进入部分边界时,速率乘数变化。单次输入不允许跨越多天。

下面是税率表的部分示例。很明显,第一级数组键是一周中的几天。二级数组键表示一天中新的乘法器启动时的时间,并一直运行到数组中的下一个顺序条目。数组值是该时间范围的乘数。

代码语言:javascript
运行
复制
[rateTable] => Array
    (
        [Monday] => Array
            (
                [00:00:00] => 1.5
                [08:00:00] => 1
                [17:00:00] => 1.5
                [23:59:59] => 1
            )

        [Tuesday] => Array
            (
                [00:00:00] => 1.5
                [08:00:00] => 1
                [17:00:00] => 1.5
                [23:59:59] => 1
            )
        ...
    )

在通俗易懂的英语中,这是指从午夜到上午8点半的时间,从晚上8点到下午5点半,从下午5点到11点59分的时间半。这些中断发生的时间对第二天来说可能是任意的,而且每天都有任意数量的中断。(这种格式完全是可协商的,但我的目标是使它尽可能容易被人类阅读。)

例如:周一15:00(下午3点)至21:00 (9 PM)记录的时间条目将包括2小时的1倍计费和4小时1.5倍的计费。一个时间条目也有可能跨越多个中断。使用上面的示例rateTable,从上午6点到下午9点的时间条目将有3个子范围,分别是6-8 AM @1.5 x、8-5 PM @ 1x和5-9 PM @1.5 x。相反,时间条目可能只在08:15:00到08:30:00之间,并且完全包含在一个乘法器的范围内。

我真的需要一些帮助来编写一些PHP代码(或者至少设计一个算法),它可以花费一天的时间、一个开始时间和一个停止时间,然后解析成所需的子部分。理想的做法是,输出是一个数组,其中包含一个(开始、停止、乘法器)三重奏的多个条目。对于上面的例子,输出将是:

代码语言:javascript
运行
复制
[output] => Array
    (
        [0] => Array
            (
                [start] => 15:00:00
                [stop] => 17:00:00
                [multiplier] => 1
            )

        [1] => Array
            (
                [start] => 17:00:00
                [stop] => 21:00:00
                [multiplier] => 1.5
            )
    )

我很清楚,我无法理解将单个(开始、停止)划分为(潜在)多个子部分的逻辑。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-05-11 20:04:59

伊内基破解了算法。在我的尝试中缺少的部分是让start、在每个乘子范围内可用的停止时间。我对原始rateTable中的数据密度进行了评估,因此我使用Eineki的转化器()例程来接收存储在config中的表并在其中添加停止时间。我的代码已经自动创建(或填写)了一个最小速率表,确保其余代码不会阻塞或抛出警告/错误,因此我将其包括在内。我还将bill()和map_shift()合并在一起,因为在我看来,这两者没有任何有用的目的。

代码语言:javascript
运行
复制
<?php

//-----------------------------------------------------------------------
function CompactSliceData($start, $stop, $multiplier)
// Used by the VerifyRateTable() to change the format of the multiplier table.
{
    return compact('start', 'stop','multiplier');
}

//-----------------------------------------------------------------------
function VerifyAndConvertRateTable($configRateTable)
// The rate table must contain keyed elements for all 7 days of the week. 
// Each subarray must contain at LEAST a single entry for '00:00:00' => 
// 1 and '23:59:59' => 1. If the first entry does not start at midnight, 
// a new element will be added to the array to represent this. If given 
// an empty array, this function will auto-vivicate a "default" rate 
// table where all time is billed at 1.0x.
{
    $weekDays = array('Monday', 'Tuesday', 'Wednesday', 
            'Thursday', 'Friday', 'Saturday', 
            'Sunday',);  // Not very i18n friendly?     

    $newTable = array();
    foreach($weekDays as $day)
    {
        if( !array_key_exists($day, $configRateTable) 
            || !is_array($configRateTable[$day]) 
            || !array_key_exists('00:00:00', $configRateTable[$day]) )
        {
            $configRateTable[$day]['00:00:00'] = 1;
        }

        if( !array_key_exists($day, $configRateTable) 
            || !is_array($configRateTable[$day]) 
            || !array_key_exists('23:59:59', $configRateTable[$day]) )
        {
            $configRateTable[$day]['23:59:59'] = 1;
        }

        // Convert the provided table format to something we can work with internally.
        // Ref: http://stackoverflow.com/questions/2792048/slicing-a-time-range-into-parts
        $newTable[$day] = array_slice(
                array_map(
                   'CompactSliceData',
                   array_keys($configRateTable[$day]),
                   array_keys(array_slice($configRateTable[$day],1)),
                   $configRateTable[$day]),
                0,-1);
    }
    return $newTable;
}

//-----------------------------------------------------------------------
function SliceTimeEntry($dayTable, $start, $stop)
// Iterate through a day's table of rate slices and split the $start/$stop
// into parts along the boundaries.
// Ref: http://stackoverflow.com/questions/2792048/slicing-a-time-range-into-parts
{
    $report = array();
    foreach($dayTable as $slice) 
    {
        if ($start < $slice['stop'] && $stop > $slice['start'])
        {
           $report[] = array(
                    'start'=> max($start, $slice['start']),
                    'stop' => min($stop, $slice['stop']),
                    'multiplier' => $slice['multiplier']
                );
        }
    }
    return $report;
}


/* examples */
$rateTable = array(
    'Monday' => array('00:00:00' => 1.5, '08:00:00' => 1, '17:00:00' => 1.5),
    'Tuesday' => array('00:00:00' => 1.5, '08:00:00' => 1, '17:00:00' => 1.5),
    'Wednesday' => array('00:00:00' => 1.5, '08:00:00' => 1, '17:00:00' => 1.5),
    'Thursday' => array('00:00:00' => 1.5, '08:00:00' => 1, '17:00:00' => 1.5),
    'Friday' => array('00:00:00' => 1.5, '08:00:00' => 1, '17:00:00' => 1.5),
    'Saturday' => array('00:00:00' => 1.5, '15:00:00' => 2),
    'Sunday' => array('00:00:00' => 1.5, '15:00:00' => 2),
);

$rateTable = VerifyAndConvertRateTable($rateTable);

print_r(SliceTimeEntry($rateTable['Monday'],'08:05:00','18:05:00'));
print_r(SliceTimeEntry($rateTable['Monday'],'08:05:00','12:00:00'));
print_r(SliceTimeEntry($rateTable['Tuesday'],'07:15:00','19:30:00'));
print_r(SliceTimeEntry($rateTable['Tuesday'],'07:15:00','17:00:00'));

?>

谢谢大家,尤其是伊内基。

票数 0
EN

Stack Overflow用户

发布于 2010-05-08 01:58:42

我将使用一种不同的方法,并将根据几个考虑因素更改rateTable表示。

definition);

  • The描述间隔,为什么不正确地对它们进行编码呢?在边界上发生了什么(在我的例子中,使用两种不同的方法来处理边界,representation.

  • 23:59:59=>结果是类似的,但使用不同的representation.

  • 23:59:59=>对我来说似乎是一种攻击。我现在无法解释,但我的后脑勺有个铃在响,叫我小心。--

最后但并非最不重要的一点是,我个人的经验是,如果你不能全神贯注于一种算法,那么你的同事可能会遇到同样的困难(即使你成功并解决了问题),而代码将是bug的主要来源。如果你找到一个简单有效的解决方案,那将是一次时间、金钱和头痛的收获。即使解决方案效率不高,它也可能是一种收获。

代码语言:javascript
运行
复制
$rateTable = array(
    'Monday' => array (
        array('start'=>'00:00:00','stop'=>'07:59:59','multiplier'=>1.5),
        array('start'=>'08:00:00','stop'=>'16:59:59','multiplier'=>1),
        array('start'=>'17:00:00','stop'=>'23:59:59','multiplier'=>1.5)
    ),
    'Tuesday'=> array (
        array('start'=>'00:00:00','stop'=>'08:00:00','multiplier'=>1.5),
        array('start'=>'08:00:00','stop'=>'17:00:00','multiplier'=>1),
        array('start'=>'17:00:00','stop'=>'23:59:59','multiplier'=>1.5)
    )
);

function map_shift($shift, $startTime, $stopTime)
{
    if ($startTime >= $shift['stop'] or $stopTime <= $shift['start']) {
        return;
    }
    return array(
        'start'=> max($startTime, $shift['start']),
        'stop' => min($stopTime, $shift['stop']),
        'multiplier' => $shift['multiplier']
    );
}

function bill($day, $start, $stop)
{
    $report = array();
    foreach($day as $slice) {
        $result = map_shift($slice, $start, $stop);
        if ($result) {
           array_push($report,$result);
        }
    }
    return $report;
}



/* examples */
var_dump(bill($rateTable['Monday'],'08:05:00','18:05:00'));
var_dump(bill($rateTable['Monday'],'08:05:00','12:00:00'));
var_dump(bill($rateTable['Tuesday'],'07:15:00','19:30:00'));
var_dump(bill($rateTable['Tuesday'],'07:15:00','17:00:00'));

至少,您需要一个函数来将原始格式转换为新格式。

代码语言:javascript
运行
复制
$oldMonday = array (
   '00:00:00'=>1.5,
   '08:00:00'=>1,
   '17:00:00'=>1.5,
   '23:59:59'=>1
);

function convert($array) 
{
    return array_slice(
        array_map(
           function($start,$stop, $multiplier) 
           {
               return compact('start', 'stop','multiplier');
           },
           array_keys($array),
           array_keys(array_slice($array,1)),
           $array),
        0,
        -1);
}

var_dump(convert($oldMonday));

是的,你可以通过

代码语言:javascript
运行
复制
bill(convert($oldRateTable['Tuesday']),'07:15:00','17:00:00');

但如果你在乎一些表演..。

票数 3
EN

Stack Overflow用户

发布于 2010-05-08 01:31:59

这是我的方法

我把每件事都转换成了秒,这样就容易多了。

这是以秒为索引的比率表。星期一只有三个时隙

代码语言:javascript
运行
复制
// 0-28800 (12am-8am) = 1.5
// 28800-61200 (8am-5pm) = 1
// 61200-86399 (5pm-11:50pm) = 1.5

$rate_table = array(
    'monday' => array (
        '28800' => 1.5,
        '61200' => 1,
        '86399' => 1.5
    )
);

它使用此函数将hh:mm:ss转换为秒。

代码语言:javascript
运行
复制
function time2seconds( $time ){
    list($h,$m,$s) = explode(':', $time);
    return ((int)$h*3600)+((int)$m*60)+(int)$s;
}

这是返回一个比率表的函数。

代码语言:javascript
运行
复制
function get_rates( $start, $end, $rate_table ) {

    $day = strtolower( date( 'l', strtotime( $start ) ) );

    // these should probably be pulled out and the function
    // should accept integers and not time strings
    $start_time = time2seconds( end( explode( 'T', $start ) ) );
    $end_time = time2seconds( end( explode( 'T', $end ) ) );

    $current_time = $start_time;

    foreach( $rate_table[$day] as $seconds => $multiplier ) {

        // loop until we get to the first slot
        if ( $start_time < $seconds ) {
            //$rate[ $seconds ] = ( $seconds < $end_time ? $seconds : $end_time ) - $current_time;

            $rate[] = array (

                'start' => $current_time,
                'stop' => $seconds < $end_time ? $seconds : $end_time,
                'duration' => ( $seconds < $end_time ? $seconds : $end_time ) - $current_time,
                'multiplier' => $multiplier

            );

            $current_time=$seconds;
            // quit the loop if the next time block is after clock out time
            if ( $current_time > $end_time ) break;
        }

    }

    return $rate;
}

这是你怎么用的

代码语言:javascript
运行
复制
$start = '2010-05-03T07:00:00';
$end = '2010-05-03T21:00:00';

print_r( get_rates( $start, $end, $rate_table ) );

返回

代码语言:javascript
运行
复制
Array
(
    [0] => Array
        (
            [start] => 25200
            [stop] => 28800
            [duration] => 3600
            [multiplier] => 1.5
        )

    [1] => Array
        (
            [start] => 28800
            [stop] => 61200
            [duration] => 32400
            [multiplier] => 1
        )

    [2] => Array
        (
            [start] => 61200
            [stop] => 75600
            [duration] => 14400
            [multiplier] => 1.5
        )

)

基本上,代码在速率表上循环,并从给定的时隙中查找出属于每个速率的秒数。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2792048

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档