我如何让闰年起作用?

时间:2014-04-26 08:08:00

标签: time tcl

我在TCL中有一些代码试图测量两个日期之间的时间。

这两个第一部作品,但正如你看到最后一部作品不起作用;它完全错了,因为一年只能有12个月,但这还不止于此。

无论如何,我认为闰年是问题所在,但我不确定。你能帮忙吗?

proc isTimeAgo {t1} {

  set t2 "1387524660"
  #set t2 [clock seconds]
  set cnt [expr {(($t2 - $t1) / 31536000)}]

  set cur [clock add $t1 $cnt years]

  set res {}

  foreach unit {years months weeks days hours minutes seconds} {
    while {$cur <= $t2} {
      set cur [clock add $cur 1 $unit]
      incr cnt
    }

    set cur [clock add $cur -1 $unit]
    incr cnt -1

    if {$cnt} {
      lappend res $cnt $unit
    }

    set cnt 0
  }

  return $res
}

puts "1: [isTimeAgo "1355988659"]"
puts "2: [isTimeAgo "1355988660"]"
puts "3: [isTimeAgo "1355988661"]"

proc days_per_month year {
  set leap [expr {($year%4)==0 && (!($year%400) || ($year%100))}]
  set days [list 31 [expr {$leap ? 29 : 28}] 31 30 31 30 31 31 30 31 30 31]
  return $days
}

结果是:

1: 1 years 1 seconds <- Correct
2: 1 years <- Correct
3: 11 months 4 weeks 1 days 23 hours 59 minutes 59 seconds <- Wrong

1 个答案:

答案 0 :(得分:2)

日期和时间算术令人惊讶地难以正确,因为人们的意思是如此彻底不确定。在一段时间内添加间隔时,您必须在月份之前添加年份(因为闰年),日期前几个月(因为月份长度不同),以及时间前几天(因为DST变化)。这非常棘手,我们有一个处理复杂性的命令:clock add(至少需要Tcl 8.5)。走向相反的方向?这是一个尝试每个单位的问题,直到你超越。

proc getInterval {from to} {
    set result {}
    foreach unit {year month week day hour minute second} {
        set n 0
        while 1 {
            set new [clock add $from 1 $unit]
            if {$new > $to} break
            set from $new
            incr n
        }
        lappend result $n $unit
    }
    return $result
}

让我们尝试一下:

% getInterval 1355988659 [clock seconds]
1 year 4 month 0 week 6 day 6 hour 52 minute 39 second

我想我们可以添加以确保fromto之前,并省略零项。我将这些留作练习。

请注意,您可能需要更改clock add使用的区域设置和时区以获得您期望的答案(分别使用-locale-timezone选项)。有关这可能会产生什么影响以及一些示例,请参见the documentation