超越 MySQL 的 TIME 值限制 838:59:59

问题描述 投票:0回答:7

标题可能有点令人困惑,所以请允许我解释一下。我正在使用一个表格来记录我的工作日志。每天我都会创建一个条目,说明我从什么时间到什么时间工作,并且我会添加一条评论来描述我所做的事情。

然后,我使用查询来比较时间戳,以准确计算出我当天工作了多少小时和分钟。此外,我使用查询来计算我全年工作的小时数和分钟数的总和。这就是我遇到问题的地方。我的查询如下。

SELECT TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(entry_end_time, entry_start_time)))), '%H:%i') 
AS total FROM entry 
WHERE entry_date BETWEEN '2012-01-01' AND '2012-12-31' AND user_id = 3

默认情况下,MySQL TIME 字段允许的时间范围为“-838:59:59”到“838:59:59”。不过,我今年已经记录了超过 900 小时的工作时间,我希望查询结果能够反映这一点。相反,结果是 838:59:59,这是有道理的,因为这是极限。

有没有办法解决这个问题,以便查询结果可以超过 839 小时,或者我是否必须使用 PHP 之类的东西来遍历整个表并将其全部加起来?如果可能的话,我想避免这种情况。

mysql time sum
7个回答
8
投票

看看timestampdiff,它没有时间限制。 IE。像(未经测试):

SELECT CONCAT(
        TIMESTAMPDIFF(HOUR, entry_end_time, entry_start_time), 
        ":",
        MOD(TIMESTAMPDIFF(MINUTE, entry_end_time, entry_start_time),60)
      )
AS total FROM entry 
WHERE entry_date BETWEEN '2012-01-01' AND '2012-12-31' AND user_id = 3

concat
并不理想——我相信会有一个更优雅的解决方案。


6
投票

我只是检索工作的总秒数,并根据应用程序表示层的要求转换为小时/分钟(毕竟,这是除以 60 的简单情况):

<?
  $dbh = new PDO("mysql:dbname=$dbname", $username, $password);
  $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);

  $qry = $dbh->prepare('
    SELECT SUM(TIME_TO_SEC(entry_end_time)-TIME_TO_SEC(entry_start_time))
    FROM   entry 
    WHERE  entry_date BETWEEN :start_date AND :end_date
       AND user_id = :user_id
  ');

  $qry->execute([
    ':start_date' => '2012-01-01',
    ':end_date'   => '2012-12-31',
    ':user_id'    => 3
  ]);

  list ($totalMins, $remngSecs) = gmp_div_qr($qry->fetchColumn(), 60);
  list ($totalHour, $remngMins) = gmp_div_qr($totalMins, 60);

  echo "Worked a total of $totalHour:$remngMins:$remngSecs.";
?>

3
投票

一些简单的数学就可以解决这个问题,我硬编码了随机的秒数(10000000)

SELECT CONCAT(FLOOR(10000000/3600),':',FLOOR((10000000%3600)/60),':',(10000000%3600)%60)

小提琴

2777:46:40

0
投票

分开算日子就够了。
这是我使用的串联。

我用一个完全复制/粘贴的示例来说明,以方便理解我们所达到的限制(TIME 格式的最大值)
捆绑免费独角兽,简化逗号管理

SELECT 'pq7~' AS unicorn
#######################
##  Expected result  ##
#######################
## Total, formatted as days:hh:mm:ss ##
  ,CONCAT(
    FLOOR(TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24') / 86400)
    , ':'
    , SEC_TO_TIME(TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24') % 86400)
  ) AS Real_expected_result

#########################
## Calculation details ##
#########################
## Extracted days from diff ##
  ,FLOOR(TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24') / 86400) AS Real_days
## Extracted Hours/minutes/seconds from diff ##
  ,SEC_TO_TIME(TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24') % 86400) AS Real_hours_minutes_seconds

###################################
## Demo of wrong values returned ##
###################################
  ,TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24') AS Real_seconds_diff

## WRONG value returned. 5.64M is truncated to 3.02 ! ##
  ,TIME_TO_SEC(SEC_TO_TIME(5644119)) AS WRONG_result

## Result is effectively limited to 838h59m59s ##
  ,SEC_TO_TIME(TIMESTAMPDIFF(SECOND, '2017-01-01 09:17:45', '2017-03-07 17:06:24')) AS Limit_hit

## Lights on said limit ##
  ,SEC_TO_TIME( 3020398) AS Limit_value_check1
  ,SEC_TO_TIME( 3020400) AS Limit_value_check2

0
投票

看看这些函数。学分:( https://gist.github.com/NaWer/8333736 )

DROP FUNCTION IF EXISTS BIG_SEC_TO_TIME;
DELIMITER $$
CREATE FUNCTION BIG_SEC_TO_TIME(SECS BIGINT)
RETURNS TEXT
READS SQL DATA
DETERMINISTIC
BEGIN
    DECLARE HEURES TEXT;
    DECLARE MINUTES CHAR(5);
    DECLARE SECONDES CHAR(5);

    IF (SECS IS NULL) THEN RETURN NULL; END IF;

    SET HEURES = FLOOR(SECS / 3600);

    SET MINUTES = FLOOR((SECS - (HEURES*3600)) / 60);

    SET SECONDES = MOD(SECS, 60);

    IF MINUTES < 10 THEN SET MINUTES = CONCAT( "0", MINUTES); END IF;
    IF SECONDES < 10 THEN SET SECONDES = CONCAT( "0", SECONDES); END IF;

    RETURN CONCAT(HEURES, ":", MINUTES, ":", SECONDES);
END;
$$
DELIMITER ;

DROP FUNCTION IF EXISTS BIG_TIME_TO_SEC;
DELIMITER $$
CREATE FUNCTION BIG_TIME_TO_SEC(TIME TEXT)
    RETURNS BIGINT
    DETERMINISTIC
    READS SQL DATA
BEGIN
    DECLARE HEURES TEXT;
    DECLARE MINUTES CHAR(5);
    DECLARE SECONDES CHAR(5);

    IF (TIME IS NULL) THEN RETURN NULL; END IF;

    SET HEURES = SUBSTRING_INDEX(TIME, ":", 1);

    SET MINUTES = SUBSTRING(TIME FROM -5 FOR 2);

    SET SECONDES = SUBSTRING(TIME FROM -2 FOR 2);

    RETURN CAST(HEURES AS  UNSIGNED INTEGER)*3600 + CAST(MINUTES AS  UNSIGNED INTEGER)*60 + CAST(SECONDES AS  UNSIGNED INTEGER);
END;
$$
DELIMITER ;

-1
投票
select  concat(truncate(sum(time_to_sec(TIMEDIFF(hora_fim, hora_ini)))/3600,0), ':', 
TIME_FORMAT(sec_to_time(sum(time_to_sec(TIMEDIFF(hora_fim, hora_ini))) - truncate(sum(time_to_sec(TIMEDIFF(hora_fim, hora_ini)))/3600,0)*3600), '%i:%s'))
as hms from  tb_XXXXXX

-1
投票

首先计算天数差异,然后乘以 24*60*60 将其转换为秒,然后添加到 time_to_sec 值结果

DATEDIFF(start_date,end_date)*24*60*60 + TIME_TO_SEC(TIMEDIFF(TIME(start_date),TIME(end_date))) 
AS sec_diff

有关更多详细信息,请检查 codebucket-超越 time_to_sec() 函数最大限制

© www.soinside.com 2019 - 2024. All rights reserved.