以後不知道要寫什麼文章
就來寫些小程式誕生的故事
今天第一個故事就是計算下班時間的小工具
雖然說身為 RD 的我們不太可能準時下班
但偶爾也會有早來想要早點下班運動的時候
很不巧的我們的刷卡記錄要明天才能查詢
雖然我們可以偶爾不做滿 8個小時
但奉公守法的我還是覺得很不習慣
於是就想要知道大概的上班時間
這樣才能確定要幾點才能下班
後來靈機一動
想要利用電腦開機的時間來當做刷卡時間
理論上刷卡時間一定會在電腦開機之前
故以這個時間當基準一定不會有錯
註:不管是什麼機器,時間都需要校時
以我以前 MIS 的經驗,刷卡機會跟資料庫主機對時
而資料庫主機又會跟 AD Server 對時
AD Server 又會跟外部服務對時
這樣才能確保大家的時間都一致
以 Windows來說
我們可以去 事件檢視器 -> Windows 記錄 -> 系統
尋找一個事件檢視碼為 12 的事件
裡面就會有我們開機的時間
這時候利用 Google 我們查到了 "wevtutil" 這個指令
它可以用來查詢相關的事件並指定 Filter 條件(時間)
由於這個指令會把所有事件都查詢出來
故我們再加上 Find 這個指令
只挑選出 EventID 12 的行數
wevtutil qe system "/q:*[System[TimeCreated[@SystemTime>='2017-09-10T00:00:00']]]" |
find /N "12</EventID>"
另外一種解法
EventID 12 有一個特殊欄位
只有 EventID 12 才有
wevtutil qe system /q:Event[EventData[Data[@Name='StartTime']>'2017-09-10T00:00:00']]
出來的結果如下
<Event xmlns='http://schemas.microsoft.com/win/2004/08/events/event'>
<System>
<Provider Name='Microsoft-Windows-Kernel-General' Guid='{A68CA8B7-004F-D7B6-A698-07E2DE0F1F5D}'/>
<EventID>12</EventID>
<Version>0</Version>
<Level>4</Level>
<Task>0</Task>
<Opcode>0</Opcode>
<Keywords>0x8000000000000000</Keywords>
<TimeCreated SystemTime='2017-09-12T01:30:41.749600400Z'/>
<EventRecordID>302816</EventRecordID>
<Correlation/>
<Execution ProcessID='4' ThreadID='8'/>
<Channel>System</Channel>
<Computer> xxxxx </Computer>
<Security UserID='S-1-5-18'/>
</System>
<EventData>
<Data Name='MajorVersion'>6</Data>
<Data Name='MinorVersion'>1</Data>
<Data Name='BuildVersion'>7601</Data>
<Data Name='QfeVersion'>23807</Data>
<Data Name='ServiceVersion'>1</Data>
<Data Name='BootMode'>0</Data>
<Data Name='StartTime'>2017-09-12T01:30:41.125599300Z</Data>
</EventData>
</Event>
好了,食材都有了,就讓我們開始下廚吧
我們利用 Golang os/exec, time, strings 等 package
就可以簡單炒出一盤好菜了
package main
import (
"fmt"
"log"
"os/exec"
"strings"
"time"
)
const workTime = 8 * 60 + 75
func getCMDResult(today string) (string, error) {
subcmd := fmt.Sprintf("wevtutil qe system /q:Event[EventData[Data[@Name='StartTime']^>'%s']]", today)
cmd := exec.Command("cmd", "/C", subcmd)
out, err := cmd.Output()
if err != nil {
return "", err
}
return string(out), nil
}
func getStartTime(log string) string {
pattern := "'StartTime'>"
i := strings.Index(log, pattern)
if i >= 0 {
start := i + len(pattern)
out := log[start:start+30]
return out
}
return ""
}
func getHumanTime(t time.Time) string {
return fmt.Sprintf(
"%04d-%02d-%02d %02d:%02d",
t.Year(),
t.Month(),
t.Day(),
t.Hour(),
t.Minute(),
)
}
func printWorkTime(startTime string) {
t1, err := time.Parse(time.RFC3339, startTime)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("")
fmt.Printf("clock in : %s \n", getHumanTime(t1.Local()))
fmt.Printf("clock out : %s \n", getHumanTime(t1.Add(time.Duration(workTime)*time.Minute).Local()))
}
func main() {
t1 := time.Now()
t2 := time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.FixedZone("UTC", 0))
out, err := getCMDResult(t2.Format(time.RFC3339))
if err != nil {
log.Fatal(err)
}
startTime := getStartTime(out)
if startTime != "" {
printWorkTime(startTime)
return
}
fmt.Println("Can't get start time in Windows event log")
}
https://github.com/tylpk1216/go-clockout