時間計算機

一小時是六十分,而這一頁把進位過程寫給你看。

本機處理

從某個時刻起算,過了幾小時幾分鐘之後(或之前)是幾點?

09:00 往後 2:45 是 11:45(同一天)

11:45

這個答案是怎麼算出來的

  1. 先把時數換成分鐘 —— 十進位計算機錯的就是這一步2 h 45 min = 2 × 60 + 45 = 165 min
  2. 再把起始時刻換成「午夜之後第幾分鐘」09:00 = 9 × 60 + 0 = 540 min
  3. 加上去540 + 165 = 705 min
  4. 換回時刻寫法 —— 逢 60 進位,不是逢 100705 min = 11:45
  • 落在哪一天同一天
  • 這段時數的十進位寫法2.75 小時
  • 這段時數共幾分鐘165

這一頁只做時鐘算術。它不套用時區,也不處理日光節約時間 —— 跨越時鐘調整那一天的班別,實際長度真的會比這裡的數字多一小時或少一小時。它同樣不知道你的零頭進位與休息扣除規則:那些來自雇主、契約或當地勞動法規,不是來自算術。把這個數字寫進出勤紀錄或請款單之前,請先對照你自己的規定。

完全在你的瀏覽器裡執行 —— 打開開發者工具的 Network 分頁就能驗證

從一個時刻往後或往前推幾小時幾分、量兩個時刻之間隔了多久、把一個班扣掉休息之後換成工時,或者在 7:30 與 7.5 之間互換。時鐘是逢六十進位,而你桌上其他每一個工具都是逢十進位 —— 這就是為什麼時間的算術特別容易錯,而且錯了之後特別難發現。這裡每一個答案都會把進位的那一步寫出來。

時鐘逢六十進位,你手上其他每一個工具都逢十進位

一整天會用到的計數方式,幾乎全部是逢十進位:試算表是、手機上的計算機是、薪資單最下面那個數字也是。只有時鐘不是 —— 分鐘那一欄從 0 數到 59 就把小時往前推一格。時間的算術會出錯,原因就只有這一個差別;而它出錯的方式很安靜,因為它吐回來的是一個外觀完全正常的數,而不是一句錯誤訊息。

把 7:45 加 6:30 打進一般計算機,它會把冒號當成小數點、用逢十進位算,然後給你 13.75。同樣兩個數字讀成幾時幾分,答案是 14:15,往後多了整整四十分鐘。這兩個數字單獨看都不像是錯的。一份月報表這樣加二十次,總數就已經差掉超過一個工作天。

可靠的做法是盡早離開六十進位這種寫法:先把兩段時數都換成單純的分鐘,在那裡完成加減(因為每一欄又都逢十進位了),最後一步才換回幾時幾分。這一頁的每一個答案都是這樣算的,而且每一步都印出來 —— 進位發生在哪裡是你可以自己看的東西,不是要你相信的東西。

午夜是一個模數,不是一條邊界

一個時刻是「1440 分鐘這個循環裡的某個位置」,不是時間軸上的一個點。所以 23:30 加兩小時得到的是 01:30 而不是 25:30;也所以那個答案本身是不完整的 —— 01:30 沒有告訴你它屬於哪一天。任何真的要照著做的事情(一個班、一班飛機、一段維護時間)都必須把日期跟時間一起帶著,而把日期丟掉是排程出錯最高產的來源之一。

同一個循環也讓同一個瞬間有兩種寫法。24:00 與 00:00 位置相同、歸屬的日期不同,而時刻表是刻意在用這個區別的:列在 24:00 的班次收掉的是前一個營運日,列在 00:00 的班次開的是下一個。把兩者當成可以互換的軟體,會生出剛好差一天的錯誤,而且那種錯誤很容易通過測試 —— 它一天只在 1440 分鐘裡的那一分鐘出現。

當下班時刻落在一天之中比上班時刻早的位置時,這一頁會假設這一對時刻是跨夜的,並且補回一整天,因為大夜班長的就是這個樣子。它會明講自己這樣做了,而不是偷偷做掉;同時它也會印出「如果兩個時刻其實是同一天」的間隔是多少。那個數字是一段負的時間,而那幾乎一定是兩格填反了的簽名。

十進位工時是第三種寫法,而 7.30 三種都不是

薪資系統、請款單與專案工時表通常要的是十進位小時,所以七小時三十分要寫成 7.5。小數點後面那幾位代表的是「一小時的幾分之幾」而不是分鐘,所以同一段長度的三種寫法 —— 7:30、7.5、7.30 —— 裡面有一對是同一件事,另一個是冒牌貨。第三種是把冒號當小數點讀出來的,它比另外兩個少十八分鐘。

換算結果只有在分鐘是六的倍數時,才會剛好停在一位小數,因為六分鐘正好是一小時的十分之一。12、18、24、30 換過去都很乾淨;45 變成 0.75;20 變成 0.333 循環 —— 這正是兩位小數的十進位工時表落不到每一分鐘上的原因。一小時的百分之一是三十六秒,所以一個存 7.33 的系統,跟一個存 7:20 的打卡紀錄,已經差了十二秒。

一筆看不出來,兩百筆就全部看得出來。薪資系統取到兩位小數、打卡系統存整數分鐘,兩邊每一個班會差幾秒,而差的方向取決於那一筆的數字本身。要決定哪一邊才是紀錄,是行政上的判斷不是算術上的判斷;但一個不知道這是兩種寫法的人,連這個判斷都做不出來。

先扣休息再除以 60,順序反過來就會多給八分鐘

一個 09:00 到 17:30、中間有一小時不給薪休息的班,不是拿十進位的數字照著感覺相減就好。整段都用分鐘做:時鐘上是 510 分鐘,扣掉 60,剩下 450,最後一步才除以 60 得到 7.5 小時。先除再減在這個例子裡剛好會得到一樣的答案,而只要休息不是整數小時,兩者就會立刻分家。

二十分鐘是最容易中招的那一個。先扣:510 減 20 剩 490 分鐘,也就是 8.1666 小時。先換算再扣:8.5 減 0.2 得到 8.3 —— 那個 0.2 描述的是「一小時的兩成」而不是二十分鐘,結果多給了八分鐘。這個錯誤能通過複核,是因為 0.2 看起來就是一個非常合理的「二十」的寫法。

四捨五入是同一個問題的另一半。每一個班先進位到最接近的十五分鐘再加總,跟先把精確分鐘加總、最後才進位一次,得到的月份數字不一樣,而且筆數越多差越大。這兩種算法沒有哪一種天生正確,它們只是兩條由制度訂下來的規則;當兩套系統跑出不一樣的月總數,元兇多半是這件事,而不是其中一邊的程式有問題。

台灣的出勤紀錄,法律要求記到分鐘

勞動基準法第三十條把口徑寫得很死:雇主應置備勞工出勤紀錄,並且逐日記載出勤情形「至分鐘為止」,這份紀錄要保存五年。也就是說,台灣的法定紀錄單位是分鐘 —— 不是十分之一小時,也不是四分之一小時。那兩種是薪資系統為了自己方便訂出來的口徑,法律沒有要求任何人接受它們。

這件事在對帳的時候會變成真問題。打卡機記的是分鐘,薪資系統存的是兩位小數的十進位小時,於是每一筆都可能差幾秒到幾十秒;月底加總之後的落差,看起來就像有人少算了工時。要講清楚哪一邊才是紀錄,前提是知道那是兩種不同的寫法,而不是同一個數字的兩種顯示方式。

另一個常被略過的細節是休息。勞基法第三十五條規定勞工繼續工作四小時至少要有三十分鐘休息,而那段休息通常不計入工時。所以「九點到六點」這種講法本身沒有回答「這個班算幾小時」—— 中間要扣的是三十分鐘還是一小時,是一個必須另外講清楚的數字。這一頁把它放在自己的欄位裡,就是為了讓它不會被默默省略掉。

台灣沒有日光節約時間,但你的班表可能有

台灣其實實施過日光節約時間,而且不只一次:戰後到一九六一年、一九七四到一九七五年,以及一九七九年。一九八〇年起就沒有再實施過,所以在台灣長大的人對「一年要調兩次時鐘」幾乎沒有實感。這也正是為什麼跨國排班、跨國會議與國際航班的時間在這裡特別容易被算錯 —— 錯的不是算術,是一個沒有人想到要放進去的前提。

歐美多數地區每年春天把時鐘往前撥一小時、秋天再撥回來。春天那一夜,二十二點到隔天六點的班只有七小時;秋天同一個班有九小時。過程中每一個時鐘顯示的都是對的,變的是那一夜本身的長度。一場固定在台北時間的週會,換算到對方那邊的當地時間,一年會自己前後移動兩次,而移動的那兩週正是全年最容易錯過會議的兩週。

面對這種日子,可靠的做法是改用「經過了多少時間」而不是「從幾點到幾點」。系統如果記下某個流程跑了四百八十分鐘,這個數字撐得過時鐘調整;如果只記下它一點半開始、三點結束,那段長度就取決於一個根本不在紀錄裡的資訊。這一頁刻意不套用任何時區,因為要套用就得先猜你指的是哪一個地方 —— 而猜錯會給你一個安靜地差一小時的答案。

整數的算術,以及一個沒有東西可以送出去的計算機

用分鐘表示的時間是整數,而這種大小的整數,瀏覽器存得下也存得精確。這裡沒有會累積的誤差,沒有一長串多出來的尾數,也沒有任何需要先收斂到十二位有效數字才敢顯示的東西。整頁唯一出現小數的地方,是最後把分鐘除成十進位小時的那一步 —— 那是顯示用的最後一步,不會再往下餵給任何計算。

一個計算機另一半會出錯的地方是「它在哪裡執行」。兩個時刻看起來沒什麼,直到你注意到人們拿它來查什麼:這個班是不是被記少了、兼職一共幾小時、某個人幾點離開公司。那是就業相關的資料,而那正是一個線上工時服務最有商業理由留下來的東西。這一頁的算術是幾 KB 的 JavaScript,隨著頁面一次送到你手上就結束了;那些時刻從頭到尾沒有被包進任何一筆請求。

要驗證這件事,花的時間大概跟讀完這一段差不多。把瀏覽器裡那張網路請求清單打開擺在旁邊,然後動上面任何一格。答案、算式與說明都會跟著動,那張面板卻連一列新的紀錄都長不出來 —— 一個時刻沒有地方可以被送去。載入完成之後把網路線拔掉,照樣算得出答案;那與其說是功能,不如說是另一端空無一物的必然後果。

常見問題

為什麼 7:45 加 6:30 不是 13.75?

因為一般計算機把冒號當成小數點、用逢十進位去算,而分鐘那一欄是逢六十進位。換成分鐘之後是 465 加 390 等於 855,而 855 分鐘是 14:15。兩種讀法差四十分鐘;只要總表是用那種寫法一筆一筆加起來的,這個誤差每一行都會再犯一次。

7:30 換成十進位是多少?為什麼不是 7.3?

是 7.5。小數點後面的數字代表的是「一小時的幾分之幾」而不是分鐘,所以三十分鐘是半小時、寫成 0.5。寫成 7.3 描述的是七小時十八分 —— 出勤紀錄跟薪資單開始對不起來的時候,差的那十二分鐘通常就是從這裡來的。

跨過午夜的班次算得出來嗎?

可以。當下班時刻在一天之中比上班時刻早的時候,這一頁會補回一整天,並且明白告訴你它這樣做了。它同時會印出「如果兩個時刻其實是同一天」的間隔是多少 —— 那會是一段負的時間,通常代表兩格填反了。

這個計算機會處理時區跟日光節約時間嗎?

不會,而且是刻意的。要套用這兩者必須知道日期與地點,而兩個時刻裡沒有這兩樣東西。猜錯的代價是給你一個安靜地差一小時的答案,那比不給答案更糟。台灣自一九八〇年起就沒有再實施日光節約時間,但排到國外的班表、跨國會議與國際航班仍然會撞上它。

休息時間要填分鐘還是小時?

填分鐘,欄位也是這樣標的。午休一小時如果打成 1,扣掉的是一分鐘,而算出來的總數看起來幾乎是對的。如果休息填得跟整個班一樣長甚至更長,這一頁會直接拒絕,並且講出為什麼,而不是回一個 0 —— 一個長得很像答案的 0,正是最容易被原封不動抄進薪資系統的那種東西。

輸入框可以打哪些時間寫法?

24 小時制的 17:45、十二小時制的 5:45 pm、時刻表那種不帶冒號的 1745、代表一天結束的 24:00,以及中文的「上午9點30分」「下午7點半」「中午」都可以。用中文或日文鍵盤打出來的全形數字也讀得懂。秒數只接受 :00,因為這一頁一律以分鐘為單位。

我打的上下班時間會離開這個分頁嗎?

不會,而且根本沒有可以離開的請求。算術由一段你的瀏覽器早就拿到的程式完成,所以你還在打字答案就已經動了;載入之後斷網也不影響它。人們拿兩個時刻去查的東西是就業相關的資料,它留在你打字的那台裝置上。