2014-04-26 2 views
2

TCL에 두 날짜 사이의 시간을 측정하는 코드가 있습니다.윤년을 어떻게 작동합니까?

첫 번째 두 작품이지만 마지막 작품은 보이지 않습니다. 1 년에 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 
+0

나는 de-ja-vous했다. 비슷한 질문이 몇 시간 전에 나타 났습니까? –

+0

왜 잘못 됐습니까? 나는 상세한 계산을하지는 않았지만, 3 번째 줄에는 11 개월이 있고 나머지 부분은 1 개월 미만입니다. 11 월에는 30 일, 4 주 및 2 일이 있으며 결과 종류가 나에게 의미가 있습니다. – Jerry

+0

Jerry, 올바른 경우 다른 시각에서 볼 것입니다. 매월은 매월, 매주 n 주, 며칠 만에 계산됩니다. 메신저 출력은 "1 년 2 초" – Whiskey

답변

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 앞에 0이있는 항목을 생략 보장에 추가 할 수도있을 것 같군요. 나는 그것들을 운동으로 남겨 둘 것이다.

clock add 로케일과 시간대를 변경해야 예상 답변을 얻을 수 있습니다 (각각 -locale-timezone 옵션 사용). 이것이 영향을 줄 수있는 것과 정확히 몇 가지 예를 보려면 the documentation을 참조하십시오.

+0

Donal Fellows이게 어떻게 작동하는지 잘 모르지만 잘하면 내 고시를 볼 수있다. – Whiskey

+0

+1 첫 문장. 까다로운 이슈 중 하나는 "2013-01-31, 2013-01-29, 2013-01-29, 2013-01-28, 2012- 2012-01-29','2012-01-28'},'given_date + 1 month'는 어떤 날짜입니까? ". 1 월 말 날짜에 한 달 추가하는 것이 가장 간단한 경우입니다. 달의 28 일 이후에 적절한 날짜를 더한 날짜에는 문제가 있습니다. ISO SQL에서는 연 - 월 간격을 일 - 두 번째 간격과 함께 사용할 수 없습니다. Oracle SQL에서 MONTHS_BETWEEN 함수는 월말에 날짜 쌍에 대해 특이한 해답을 제공합니다. –

+0

@JonathanLeffler 바로 이것이 내가 '시계 추가'를 홍보하는 이유입니다.예를 들어''clock format [clock add [clock scan 2013-01-31] ​​1 month]'는''Thu Feb 28 00:00:00 GMT 2013'에 사람들이 한 달 추가 할 때 가장 좋은 근사치입니다. 그 시점에서 (2 월 말부터 1 월 말까지). '30 일 '을 추가하는 것은 달라질 것입니다. 물론'clock' 명령의 구현은 _scary_ code이지만, 당신은 그것을 기대할 수 있습니다. 그것은 또한 매우 무겁게 테스트 중입니다 ... –

관련 문제