一位網友提的問題。
原問題是欲以 script language : AutoIt 完成。給定一準確時間點 t ,計算 1970/1/1 00:00:00 至該時間點 t 所經歷秒數。
這在 C 語言裡面很容易辦到 < 我甚至懷疑要處理的來原資料是用 time_t 存的 >,步驟大致如下。
(1) 將計算時間填入 struct tm
(2) struct tm 轉成 time_t : mktime
(3) time_t 內容即為所求。
OK,翻開 autoit,很明顯沒辦法調用 mktime 函式,然後 autoit 它的時間系統真的也和一般程式語言不同,它沒有用一個整數去做標記的概念,所以不能像 C 這樣如法炮製。不過 autoit 可以調用 win32 API,所以步驟變成下面。
(1) 將開始時間(1970/1/1 00:00:00)、結束時間填入 SYSTEMTIME。
(2) 將兩個時間點之 SYSTEMTIME 轉成 FILETIME : SystemTimeToFileTime。
(3) 將那個時間點之 FILETIME assigned to ULARGE_INTEGER:將 FILETIME 裡之 dwLowDateTime 設給 ULARGE_INTEGER 裡之 LowPart ;dwHighDataTime 設給 HighPare。
(4) 使用 ULARGE_INTEGER 裡頭成員之 QuadPart 做相減,算出來之結果是以 10 ns 為差值單位。
尷尬的問題來了,autoit 可以做 struct 但不能做 union,這問題還是小問題,比較嚴重的問題是,autoit 不支援 64bits 整數資料型態。
本有兩個方法可以解決,一個是一樣硬性調用 Win32 API ,只是後半段得到 FILETIME 後,取得之時間再用大數演算法做減法,這條路估計會比較複雜(特別是套用在很高階的 script language 身上),所以沒走這裡。
另一條路不用講了,自己手動刻,幸運的是之前該做好的函式都已經做好了,參考 [C&++] 時間函式與議題,只是再把函式轉成 script langauge 而已。假設欲計算的年份是 year,運用之前已刻好的函式,步驟大致如下。
(1) 先計算 [1970, year-1] 裡有幾個平年、幾個潤年
之前計算 [year_beg, year_end] 裡面有幾個潤年,公式為
int c1 = year_beg / 4 - (year_beg / 100) + (year_beg / 400); // [1, year_beg] 有幾個潤年
int c2 = year_end / 4 - (year_end / 100) + (year_end / 400);// [1, year_end] 有幾個潤年
int leap_cnt = c2 - c1 + is_leap_year(year_beg) ; // 計算 [year_beg, year_end] 有幾個潤年
有幾個平年就是 int non_leap_cnt = (year_end - year_beg + 1) - leap_cnt; 套用上述公式可得到結果,常數 1970 可事先套入計算。
然後事先計算 365 天有 31536000 秒,366 天有 31622400 秒,得到了 [1970, year-1] 過了
leap_cnt * 31622400 + non_leap_cnt * 31536000 秒。
(2) 再計算日期是該年的第幾天
之前的文章也提過
const int column_days[] = { \ 0, 0, 31, 59, 90, 120, 151, \ 181, 212, 243, 273, 304, 334}; int find_nday(int year, int month, int day) { return column_days[month] + day + \ (month > 2 && is_leap_year(year)); }
留言列表