#

如果你想要知道100天以後是星期幾,請問你會怎麼做? 拿計算機按? 翻100頁的日曆? 還是查日曆軟體? 其實,這些的方法都可以讓你找到答案,不過更好的方法是寫一行Tcl的程式。使用程式來計算日期及時間,你就不用擔心大小月、跨月及跨年的問題,這是一種快速又準確的方法,雖然你也可以問別人來取得答案...但應該不會比執行一行Tcl的命令來的快才對。另外,如果你想要寫計帳、行事曆一類的軟體,如果不會計算日期時間的話,似乎是行不通的。這一個章節簡單的介紹Tcl處理日期及時間的方法。

13.1 取得目前的時間

Tcl可以用許多方法取得目前的時間,現在讓我們先來看比較簡單的一種:

clock seconds

clock seconds會以整數的法式回傳由1970年到目前為止經過的秒數。例如:



程式輸出:

1239882031

如果你要輸出比較適合人看的格式可以用下面的方法:



程式輸出:

2009-04-16 19:46:47

clock format是用來格式化時間輸出的命令,它可以幫你把clock seconds取得的時間轉換成各種格式輸出。後面的章節會比較詳細的介紹clock format,目前請先不要在意它。想想看,如果你要知道10000秒後是幾年幾月幾日該怎麼做? 其實很簡單:



注意程式的第1行,只要直接把目前得到的時間加上10000秒,就可以計算出來了。程式的輸出如下,原來只是幾個小時後而已。

2009-04-16 22:40:17

又如果你想要知道27天後的日期,該怎麼做?



請看第1行的一堆乘法的那邊,它是在計算27天的總秒數:一天24小時,1小時60分,1分60秒。所以程式的輸出是:

2009-05-13 20:01:56

除了clock seconds可以取得目前的時間之外,你還可以使用下面的方法:

clock milliseconds

clock milliseconds會以整數的法式回傳由1970年到目前為止經過的毫秒數。

clock microseconds

clock microseconds會以整數的法式回傳由1970年到目前為止經過的微秒數。 這兩個命令提供了更精準的時間資訊,但它們並不適合拿來給clock format使用,一般的情形下,我只會在程式需要計時功能的時候才會用到它們。

程式範例:



請比較它們的輸出:

1239883841
1239883841907
1239883841907456

13.2 格式化時間輸出

上面的內容我們已經有看到clock format是用來格式化時間的命令,只要給予一個整數的值,它會把這個值當成是1970年初到現在的時間偏移量,然後輸出你指定的日期時間格式,以下是clock format的語法:

clock format timeVal ?-option value...?

timeVal是由1970年第1秒算起的時間。clock format可以接的選項如下:

-format format format是格式化字串,預設值是:%a %b %d %H:%M:%S %z %Y 。
-gmt boolean 如果boolean指定為true表示要把timeVal當成是UTC時間處理,若是false的話就當成是本地時間來處理。它的預設值是false。
-locale localeName localeName可以用來指定本地化的文字輸出。例如:指定zh_tw輸出的時候會用中文的「星期五」代替英文的「Fri」。
-timezone zoneName zoneName用來指定timeVal的值屬於哪個時區,例如:「:America/New_York」。

clock format命令最重要的地方應該是如何寫出正確的「格式化字串」,所謂的格式化字串指的就是「一般字元加上格式化字元」,例如:

"現在的時間是%Y年%m月%d日"

上面「%」符號後面的英文字母,就是格式化字元,而不屬於格式化字元的就都是一般的字元。每個格式化字元都有特別的意思,它們會用來表示真正的年、月、日、時、分、秒或星期...等。clock format命令在執行時,會解析格式化字串,然後把格式化字元都換成真正的值,而一般字元則照實輸出。例如:



程式的輸出是:

現在的時間是2009年04月17日

從上面的例子可以看到格式化字元都被換成真正的數值了。以下我們介紹幾個常用的格式化字元。

%a 以縮寫表示星期幾。例如:Mon、Tues...。
%A 以完整的方式表示星期幾。例如:Monday、Tuesday...。
%b 以縮寫表示月份。例如:Jan、Feb
%B 以完整的方式表示月份。例如:January、February
%d 以兩位數表示一個月中的第幾日(01~31)。
%e 以一位數表示一個月中的第幾日(1~31)。如果是一位數,前面會補一個空白。
%H 以兩位數表示一個天中的第幾小時(00~23),24小時制。
%I 以兩位數表示一個天中的第幾小時(12~11),12小時制。
%j 以三位數表示一年中的第幾日(001~366),12小時制。
%k 以一位數表示一個天中的第幾小時(0~23),24小時制。如果是一位數,前面會補一個空白。
%l 以一位數表示一個天中的第幾小時(12~11),12小時制。如果是一位數,前面會補一個空白。
%m 以兩位數表示月份(01~12)。
%M 以兩位數表示小時裡的幾分(00~59)。
%N 以一位數表示月份(1~12)。如果是一位數,前面會補一個空白。
%p 表示為AM或PM。
%P 表示為am或pm。
%S 以兩位數表示分裡的秒(00~59)。
%u 以數值表示一周裡的星期幾(1→星期一, 7→星期日)。
%U 以兩位數表示一年裡的第幾週(00-53),用星期日表示為一週的第一天。
%u 以數值表示一周裡的星期幾(0→星期日, 6→星期六)。
%U 以兩位數表示一年裡的第幾週(00-53),用星期一表示為一週的第一天。
%y 以二位數表示年份。例如:77、09...。
%Y 以四位數表示年份。例如:1977、2009...。
%z (+hhmm)或(-hhmm)的方式表示時區。例如:+0800。
%z 以名字表示時區。例如:CST。
%% 表示為一個「%」字元。

範例一:



程式輸出:

哈囉!! 現在是2009年04月17日 下午 04點30分36秒 星期五

範例二:




程式輸出:

2009-04-17 16:33:40

13.3 解析時間字串

上面介紹的clock format可以說是「秒數」轉換「時間字串」的功能,那解析時間串字剛就是反向的操作。想想看:現在有一個字串「2009-04-17」你想要把它轉回秒數然後做一些計算,該怎麼做? 其實這時候就是使用解析時間字串的好時機。Tcl使用clock scan命令來解析帶有時間資訊的字串,它的語法如下:

clock scan inputString ?-option value...?

inputString是帶有時間資訊的字串,這個命令可以使用的選項和clock format是一樣的,但多了一個選項:

-base time 如果沒有指定-format時,inputString可以使用一種相對時間的方式來解析時間。例如:「1 days」表示要掃出基準時間加上一天的時間值,而基準時間就由這個選項決定,它的預設值是現在的時間。

clock scan同樣可以使用clock format大部份的格式化字元,我們用例子來看看它的用法:

假設你現在有一個「2009年12月25日」字串,你想要把它轉回時間值:



它的輸出是:

1261670400

這個例子會回傳2009年12月25日0時0分0秒的時間值。注意!! 這裡最重要的事就是要如何寫出-format後面的字串,其實這項工作不會太困難,你可用下面的兩個步驟輕鬆的完成:

  1. 先複製inputString字串到-format後面。像這樣「-format "2009年12月25日"」
  2. 然後你知道2009是4位數的年所以用「%Y」,12是2位數的月用「%m」,25是2位數的日用「%d」。然後就變成「-format "%Y年%m月%d日"」。

ok!讓我們再試一個例子,現在我有一個字串「2009/11/15 13:34:01」,要怎麼把它轉回時間值?



它的輸出是:

1258263241

13.4 計算時間

在之前的例子裡,我們知道使用加減時間值可以正確的計算時間,其實除了這個方式之外,Tcl還提供了更方便的方法讓你來計算時間,它就是clock add命令,請看它的語法:

clock add timeVal ?count unit...? ?-option value?

timeVal是時間的基準值,簡單的說就是被加數,count加數,而unit是count的單位。可以用的單位有: seconds、minutes、hours、days、weeks、months及years。可以使用的選項是clock format裡的-gmt、-locale及-timezone,它們的意義是一樣的。

例如,想知道現在開始3天又4秒後的時間值,可以這麼做:



想知道現在15天前現在的時間值,可以這麼做:



想知道3年又4天又4小時後的時間值,可以這麼做:



最後一點!! 上面這些計算時間所回傳的值,你都可以用clock format轉換為比較適合人閱讀的格式。所以你會用一行程式算出100天後是星期幾了嗎?



真的只要一行~~~沒說大話吧!!

40 個意見

嘟豆把子 | 2009年11月26日 下午3:33

dear Dai:
不知道可不可以麻煩你教我怎麼樣可以寫一段顯示時鐘的程式就是秒數會一直更新
可以秀一段簡單的程式讓我學習一下嗎?
謝謝

Dai | 2009年11月26日 下午4:17

一個簡單的方法像這樣:

proc tt {} {
puts [clock seconds]
after 1000 tt
}

tt

嘟豆把子 | 2009年11月26日 下午8:01

我將它複製去試run了一下結果只有一個空的wish框ㄟ

嘟豆把子 | 2009年11月26日 下午8:10

喔!對不起是我沒存到檔。
請教您 after 1000的1000是1000毫秒的意思嗎?

Dai | 2009年11月26日 下午10:24

是的,忘記在哪一章的教學裡有提到的樣子。

JIN | 2009年12月10日 下午5:18

請問
如何將1970後的 microseconds 轉成 Calendar format
1102937697520229 >> 20041213 113457.520

dai | 2009年12月10日 下午6:11

像這樣:

set s1 [expr 1102937697520229/1000000]
set s2 [expr 1102937697520229%1000000]
puts [clock format $s1 -format "%Y%m%d %H%M%S"].$s2

輸出:

20041213 193457.520229

JIN | 2009年12月10日 下午8:52

厲害...目前正在試著寫 資料轉換程式...有問題在跟您請教....感謝你囉

dai | 2009年12月10日 下午10:28

不用客氣,歡迎常來~

如果是要寫像轉Blog之類含有XML的檔案,可以參考tdom

匿名 | 2011年3月14日 上午9:50

有2個地方寫了clock clock microseconds
實際上應該為clock microseconds
原文多了一個clock

dai | 2011年3月15日 上午10:42

修正了 謝謝哦!!

匿名 | 2011年3月31日 下午12:46

請問

我要寫的程式,是需要記錄下每一次收到資料的時間(Timestamp)
要如何顯示至毫秒呢?

dai | 2011年4月2日 上午8:44

Hi 匿名的朋友,

用 clock milliseconds 可以得到1970年到現在的毫秒數,這個命令回傳值的後3位是你要的答案嗎?

匿名 | 2011年4月6日 下午4:01

dai你好,謝謝你的回答

但我還是有些問題想請教,
我的code如下
# 取得一個時間戳記
set now [clock seconds]
set s2 [clock click -milliseconds]
puts $now
puts $s2

輸出結果:
1302076589
701499298

請問為何這兩個時間會差這麼多?
我將set s2 [clock click -milliseconds]
修改為set s2 [clock milliseconds]就無法執行

匿名 | 2011年4月6日 下午5:53

我找出原因了
原來是我的tclkit的版本太舊,不支援上面的指令

anyway, thanks you, dai

匿名 | 2011年7月1日 上午11:10

13.2的表格裡面重複了兩次%j喔
%j 以三位數表示一年中的第幾日(001~366),12小時制。
%j 以三位數表示一年中的第幾日(001~366),12小時制。

dai | 2011年7月18日 下午10:17

收到!! 謝謝你。

匿名 | 2011年12月4日 下午3:36

時間系統程式碼我怎麼跑不動呢?
使用了你的程式碼: puts [clock add [clock seconds] 3 days 4 seconds] <==add沒有變顏色,似乎不是

Error in startup script: bad option "add": must be clicks, format, scan, or seconds
while executing
"clock add [clock seconds] 3 days 4 seconds"
invoked from within
"puts [clock add [clock seconds] 3 days 4 seconds]"



另外:puts [clock scan "2009年12月25日" -format "%Y年%m月%d日"] <==scan有變顏色,但還是跑不動
出現:
Error in startup script: bad switch "-format": must be -base or -gmt
while executing
"clock scan "2009年12月25日" -format "%Y年%m月%d日""
invoked from within
"puts [clock scan "2009年12月25日" -format "%Y年%m月%d日"]"

dai | 2011年12月5日 下午5:16

這應該是版本問題哦~下載新版的Tcl應該就可以了!!

匿名 | 2011年12月5日 下午6:46

我linux系統的
已經下載了新的TCL8.6
還是無法。
是不是我原先的TCL無法刪除?該怎樣更替系統??能指導一下嗎?

洪書凱 | 2013年6月26日 下午2:45

%H %Y那些是什麼形式輸出的阿

如何拿它做比較 EX: %H > 08

洪書凱 | 2013年6月26日 下午2:59

沒事了 他是以字串做比較 知道了

匿名 | 2013年10月22日 下午5:45

求助呀,我想知道一个单一的时间型字串,例如“08:08:08”,想转换成秒为单位的整数值,该如何做呢?

dai | 2013年10月22日 下午8:02

set t "08:08:08"
lassign [split $t ":"] h m s
puts [expr [string trimleft $h "0"]*60*60 + [string trimleft $m "0"]*60 + [string trimleft $s "0"]]

dai

dai | 2013年10月22日 下午8:03

set t "08:08:08"
lassign [split $t ":"] h m s
puts [expr [string trimleft $h "0"]*60*60 + [string trimleft $m "0"]*60 + [string trimleft $s "0"]]

dai

匿名 | 2013年10月31日 下午5:50

哈囉Dai大大
從前面一路看過來真的是學到不少
不過小弟有個疑問
就是我也想像一樓那樣寫一個自動秒數更新的時間
但我想要獨立視窗出來
但我用lable或者是entry他都只能顯示第一次後就會出現error
不知道是否可不可以讓他刷新label或entry的資料而讓他一直更新下去

匿名 | 2013年11月1日 上午11:46

您好Dai大大
在我研究過後我把原本的lable改成文字變數就解決了
有您這個網站真的很感激您!!
另外我想要請教的是我們可以在tcl程式裡直接預設視窗是on top的嗎??遠永在最上層的意思

dai | 2013年11月1日 下午4:59

請參考:

wm attributes . -topmost 1


dai

匿名 | 2013年11月5日 上午9:20

Dai大您好
所以他這個wm attributes . -topmost l是不是只支援8.5以上?

匿名 | 2014年2月13日 上午2:19

Dai 你好
想請問如何記錄每一次的時間戳記共跑了多少時間
舉例:
2014-02-13 02:10:11 -> 第一次時間戳記
2014-02-14 06:15:16 -> 第二次時間戳記
= 5:05:05 (Total Record Time)
謝謝

dai | 2014年2月13日 上午10:56

像這樣:
set t0 [clock scan "1970-01-01 00:00:00" -format "%Y-%m-%d %H:%M:%S"]
set t1 [clock scan "2014-02-13 02:10:11" -format "%Y-%m-%d %H:%M:%S"]
set t2 [clock scan "2014-02-14 06:15:16" -format "%Y-%m-%d %H:%M:%S"]
puts [clock format [expr $t0+$t2-$t1] -format "%H:%M:%S"]

匿名 | 2014年2月13日 下午2:03

Hi, Dai
謝謝你提供的建議,但似乎無法正確執行...
set t0 [clock scan "1970-01-01 00:00:00" -format "%Y-%m-%d %H:%M:%S"]
Error: bad switch "-format": must be -base or -gmt
Use error_info for more info. (CMD-013)
set t0 [clock scan "1970-01-01 00:00:00" -format "%Y-%m-%d %H:%M:%S"]
Error: bad switch "-format": must be -base or -gmt
Use error_info for more info. (CMD-013)

匿名 | 2014年2月13日 下午2:05

補充:
set t0 [clock scan "1970-01-01 00:00:00" -base "%Y-%m-%d %H:%M:%S"]
Error: expected integer but got "%Y-%m-%d %H:%M:%S"
Use error_info for more info. (CMD-013)

dai | 2014年2月13日 下午2:33

應該是tcl版本的問題,我用8.6

匿名 | 2014年2月13日 下午4:12

Dear Dai

I use "tclsh -version 2013.4_26.18" workaround as follows:

[step 1. Before Timing]
set t1 [clock seconds]
1392276230
puts [clock format $t1 -format "%Y-%m-%d %H:%M:%S"]
2014-02-13 15:23:50

[step 2. After Timing]
set t2 [clock seconds]
1392276234
puts [clock format $t2 -format "%Y-%m-%d %H:%M:%S"]
2014-02-13 15:23:54

[step 3. 每一次計算都會多出8小時]
puts [clock format [expr $t2-$t1] -format "%H:%M:%S"]
08:00:04

[step 4. Default產生的8小時]
puts [clock format 0 -format "%H:%M:%S"]
08:00:00

[step 5. 格林威治時間]
puts [clock format 0 -format "%Y-%m-%d %H:%M:%S"]
1970-01-01 08:00:00

[step 6. 每一次計算都"減去"格林威治時間所產生的8小時得到剩餘的執行時間]
puts [clock format [expr $t2-$t1-28800] -format "%H:%M:%S"]
00:00:04

dai | 2014年2月13日 下午8:10

謝謝回饋 你測試的結果 ~

Jacky | 2014年8月18日 下午7:19

你好:

請問tcl可以輸出有顏色嗎?
類似 c shell 讓輸出的文字上色,

tcl puts可以包色碼讓他上色嗎?
目前google找不太到相對得用法,感謝!

dai | 2014年8月19日 下午10:58

這個....沒用過哦!!

Albert Yi | 2016年1月26日 下午3:28

我想請問一下,如果我自定義輸入兩串時間字串,然後將兩時間進行相減求時間間隔,怎麼寫?
Example:
timediff "14:34:20" "14:34:10" 會回傳 10s
timediff "14:33:50" "14:34:10" 會回傳 30s


匿名 | 2016年2月23日 下午2:39

proc timediff {one two} {
set listone [split $one :]; foreach {h m s} $listone break
set onesec [expr $h*60*60+$m*60+$s]
set listtwo [split $two :]; foreach {h m s} $listtwo break
set twosec [expr $h*60*60+$m*60+$s]
return [expr abs($onesec-$twosec)]
}

puts [timediff "14:33:50" "14:34:10"]
puts [timediff "14:34:20" "14:34:10"]

留下您的意見

Theme Design by devolux.org. Converted by Wordpress To Blogger for WP Blogger Themes. Sponsored by iBlogtoBlog
This template is brought to you by : allblogtools.com | Blogger Templates