2013-08-20 16:32:57 +02:00
|
|
|
(* C-Style strftime *)
|
|
|
|
open Pdfutil
|
|
|
|
|
2020-12-01 18:40:50 +01:00
|
|
|
type t =
|
|
|
|
{_tm_sec : int;
|
|
|
|
_tm_min : int;
|
|
|
|
_tm_hour : int;
|
|
|
|
_tm_mday : int;
|
|
|
|
_tm_mon : int;
|
|
|
|
_tm_year : int;
|
|
|
|
_tm_wday : int;
|
|
|
|
_tm_yday : int;
|
|
|
|
_tm_isdst : bool}
|
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_A t =
|
2020-12-01 18:40:50 +01:00
|
|
|
match t._tm_wday with
|
2013-08-20 16:32:57 +02:00
|
|
|
| 0 -> "Sunday" | 1 -> "Monday" | 2 -> "Tuesday"
|
|
|
|
| 3 -> "Wednesday" | 4 -> "Thursday" | 5 -> "Friday"
|
|
|
|
| 6 -> "Saturday"
|
2013-11-11 17:43:03 +01:00
|
|
|
| _ -> "strf_AFail"
|
2013-08-20 16:32:57 +02:00
|
|
|
|
|
|
|
let strf_a t =
|
|
|
|
String.sub (strf_A t) 0 3
|
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_B t =
|
2020-12-01 18:40:50 +01:00
|
|
|
match t._tm_mon with
|
2013-08-20 16:32:57 +02:00
|
|
|
| 0 -> "January" | 1 -> "February" | 2 -> "March" | 3 -> "April"
|
|
|
|
| 4 -> "May" | 5 -> "June" | 6 -> "July" | 7 -> "August"
|
|
|
|
| 8 -> "September" | 9 -> "October" | 10 -> "November"
|
2013-11-11 17:43:03 +01:00
|
|
|
| 11 -> "December" | _ -> "strf_Bfail"
|
2013-08-20 16:32:57 +02:00
|
|
|
|
|
|
|
let strf_b t =
|
|
|
|
String.sub (strf_B t) 0 3
|
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_d t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_mday in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_e t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_mday in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then " " ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_H t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_hour in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_I t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int (t._tm_hour mod 12) in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_j t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_yday in
|
2013-08-20 16:32:57 +02:00
|
|
|
match String.length s with
|
|
|
|
| 1 -> "00" ^ s
|
|
|
|
| 2 -> "0" ^ s
|
2013-11-11 17:43:03 +01:00
|
|
|
| _ -> s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_m t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int (t._tm_mon + 1) in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_M t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_min in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_p t =
|
2020-12-01 18:40:50 +01:00
|
|
|
if t._tm_hour >= 12 then "p.m" else "a.m"
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_S t =
|
2020-12-01 18:40:50 +01:00
|
|
|
let s = string_of_int t._tm_sec in
|
2013-11-11 17:43:03 +01:00
|
|
|
if String.length s = 1 then "0" ^ s else s
|
2013-08-20 16:32:57 +02:00
|
|
|
|
|
|
|
let strf_T t =
|
|
|
|
strf_H t ^ ":" ^ strf_M t ^ ":" ^ strf_S t
|
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_u t =
|
2020-12-01 18:40:50 +01:00
|
|
|
match t._tm_wday with
|
2013-08-20 16:32:57 +02:00
|
|
|
| 0 -> "7"
|
2013-11-11 17:43:03 +01:00
|
|
|
| n -> string_of_int (n + 1)
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_w t =
|
2020-12-01 18:40:50 +01:00
|
|
|
string_of_int t._tm_wday
|
2013-08-20 16:32:57 +02:00
|
|
|
|
2013-11-11 17:43:03 +01:00
|
|
|
let strf_Y t =
|
2020-12-01 18:40:50 +01:00
|
|
|
string_of_int (t._tm_year + 1900)
|
2013-08-20 16:32:57 +02:00
|
|
|
|
|
|
|
let strf_percent _ = "%"
|
|
|
|
|
|
|
|
let strftime_pairs =
|
|
|
|
["%a", strf_a; "%A", strf_A; "%b", strf_b; "%B", strf_B;
|
|
|
|
"%d", strf_d; "%e", strf_e; "%H", strf_H;
|
|
|
|
"%I", strf_I; "%j", strf_j; "%m", strf_m; "%M", strf_M;
|
|
|
|
"%p", strf_p; "%S", strf_S; "%T", strf_T; "%u", strf_u;
|
|
|
|
"%w", strf_w; "%Y", strf_Y; "%%", strf_percent]
|
|
|
|
|
2020-12-01 18:40:50 +01:00
|
|
|
let contents_of_file filename =
|
|
|
|
let ch = open_in_bin filename in
|
|
|
|
let s = really_input_string ch (in_channel_length ch) in
|
|
|
|
close_in ch;
|
|
|
|
s
|
|
|
|
|
2020-12-01 20:20:27 +01:00
|
|
|
(* Platform-independent current time and date with no Unix module *)
|
|
|
|
let debug_str s =
|
|
|
|
for x = 0 to String.length s - 1 do
|
|
|
|
Printf.printf "%i\t%C\n" x s.[x]
|
|
|
|
done
|
|
|
|
|
|
|
|
let utf8_of_utf16le s =
|
|
|
|
implode (drop_evens (tl (tl (explode s))))
|
|
|
|
|
2020-12-02 17:19:06 +01:00
|
|
|
let year_day d m y =
|
|
|
|
let n1 = 275 * m / 9 in
|
|
|
|
let n2 = (m + 9) / 12 in
|
|
|
|
let n3 = 1 + (y - 4 * (y / 4) + 2) / 3 in
|
|
|
|
n1 - n2 * n3 + d - 30
|
|
|
|
|
2020-12-01 18:40:50 +01:00
|
|
|
let return_date () =
|
2020-12-02 15:06:17 +01:00
|
|
|
match Sys.os_type with
|
|
|
|
"Unix" ->
|
|
|
|
(* Call the POSIX 'date' program, redirected to a temp file, and parse. *)
|
|
|
|
let tempfile = Filename.temp_file "cpdf" "strftime" in
|
|
|
|
let command = Filename.quote_command "date" ~stdout:tempfile ["+%S-%M-%H-%d-%m-%Y-%w-%j"] in
|
|
|
|
let outcode = Sys.command command in
|
|
|
|
if outcode > 0 then raise (Failure "Date command returned non-zero exit code") else
|
|
|
|
let r = contents_of_file tempfile in
|
|
|
|
let get_int o l = int_of_string (String.sub r o l) in
|
|
|
|
Sys.remove tempfile;
|
|
|
|
{_tm_sec = get_int 0 2;
|
|
|
|
_tm_min = get_int 3 2;
|
|
|
|
_tm_hour = get_int 6 2;
|
|
|
|
_tm_mday = get_int 9 2;
|
|
|
|
_tm_mon = get_int 12 2 - 1;
|
|
|
|
_tm_year = get_int 15 4 - 1900;
|
|
|
|
_tm_wday = get_int 20 1;
|
|
|
|
_tm_yday = get_int 22 3 - 1;
|
2020-12-01 18:40:50 +01:00
|
|
|
_tm_isdst = false}
|
2020-12-02 17:19:06 +01:00
|
|
|
| "Win32" | "Cygwin" ->
|
2020-12-02 15:06:17 +01:00
|
|
|
(* Run 'wmic os get LocalDateTime' (exists on XP Pro or later, Vista or later). *)
|
|
|
|
let get_int r o l = int_of_string (String.sub r o l) in
|
|
|
|
let tempfile = Filename.temp_file "cpdf" "strftime" in
|
|
|
|
let command = Filename.quote_command "wmic.exe" ~stdout:tempfile ["os"; "get"; "LocalDateTime"] in
|
|
|
|
let outcode = Sys.command command in
|
|
|
|
if outcode > 0 then raise (Failure "wmic.exe os get LocalDateTime command returned non-zero exit code") else
|
|
|
|
let r = contents_of_file tempfile in
|
|
|
|
Sys.remove tempfile;
|
|
|
|
let r = utf8_of_utf16le r in
|
|
|
|
(* Run 'wmic path win32_localtime get dayofweek' (exists on XP Pro or later, Vista or later). *)
|
|
|
|
let tempfile = Filename.temp_file "cpdf" "strftime" in
|
|
|
|
let command = Filename.quote_command "wmic.exe" ~stdout:tempfile ["path"; "win32_localtime"; "get"; "dayofweek"] in
|
|
|
|
let outcode = Sys.command command in
|
|
|
|
if outcode > 0 then raise (Failure "wmic.exe path win32_localtime get dayofweek returned non-zero exit code") else
|
|
|
|
let r2 = contents_of_file tempfile in
|
|
|
|
Sys.remove tempfile;
|
|
|
|
let r2 = utf8_of_utf16le r2 in
|
2020-12-02 17:19:06 +01:00
|
|
|
let day = get_int r 35 2 in
|
|
|
|
let month = get_int r 33 2 in
|
|
|
|
let year = get_int r 29 4 in
|
2020-12-02 15:06:17 +01:00
|
|
|
{_tm_sec = get_int r 41 2;
|
|
|
|
_tm_min = get_int r 39 2;
|
|
|
|
_tm_hour = get_int r 37 2;
|
2020-12-02 17:19:06 +01:00
|
|
|
_tm_mday = day;
|
|
|
|
_tm_mon = month;
|
|
|
|
_tm_year = year;
|
2020-12-02 15:06:17 +01:00
|
|
|
_tm_wday = get_int r2 13 1;
|
2020-12-02 17:19:06 +01:00
|
|
|
_tm_yday = year_day day month year;
|
2020-12-02 15:06:17 +01:00
|
|
|
_tm_isdst = false}
|
|
|
|
| _ -> failwith "Unknown Sys.os_type in Cpdfstrftime.return_date"
|
2020-12-01 18:40:50 +01:00
|
|
|
|
|
|
|
let current_time () =
|
|
|
|
try return_date () with
|
|
|
|
e ->
|
|
|
|
Printf.eprintf "Failed to retrieve time due to %s\n" (Printexc.to_string e);
|
|
|
|
{_tm_sec = 0;
|
|
|
|
_tm_min = 0;
|
|
|
|
_tm_hour = 0;
|
|
|
|
_tm_mday = 1;
|
|
|
|
_tm_mon = 0;
|
|
|
|
_tm_year = 0;
|
|
|
|
_tm_wday = 0;
|
|
|
|
_tm_yday = 0;
|
|
|
|
_tm_isdst = false}
|
|
|
|
|
2019-06-29 15:04:27 +02:00
|
|
|
let strftime ?time text =
|
|
|
|
let time =
|
2020-12-01 18:40:50 +01:00
|
|
|
match time with None -> current_time () | Some t -> t
|
2019-06-29 15:04:27 +02:00
|
|
|
in
|
2013-08-20 16:32:57 +02:00
|
|
|
let text = ref text in
|
|
|
|
iter
|
|
|
|
(fun (search, replace_fun) ->
|
|
|
|
text := string_replace_all search (replace_fun time) !text)
|
|
|
|
strftime_pairs;
|
2013-11-11 17:43:03 +01:00
|
|
|
!text
|