Posix implementation of non-Unix date getter

This commit is contained in:
John Whitington 2020-12-01 17:40:50 +00:00
parent 7de182229f
commit d19187a072
6 changed files with 120 additions and 91 deletions

18
cpdf.ml
View File

@ -3703,15 +3703,15 @@ let make_xmp_date_from_components d =
Printf.sprintf "%02i" d.offset_minutes Printf.sprintf "%02i" d.offset_minutes
in in
Cpdfstrftime.strftime Cpdfstrftime.strftime
~time:{Unix.tm_sec = d.second; ~time:{Cpdfstrftime._tm_sec = d.second;
Unix.tm_min = d.minute; Cpdfstrftime._tm_min = d.minute;
Unix.tm_hour = d.hour; Cpdfstrftime._tm_hour = d.hour;
Unix.tm_mday = d.day; Cpdfstrftime._tm_mday = d.day;
Unix.tm_mon = d.month - 1; Cpdfstrftime._tm_mon = d.month - 1;
Unix.tm_year = d.year - 1900; Cpdfstrftime._tm_year = d.year - 1900;
Unix.tm_wday = 0; Cpdfstrftime._tm_wday = 0;
Unix.tm_yday = 0; Cpdfstrftime._tm_yday = 0;
Unix.tm_isdst = false} Cpdfstrftime._tm_isdst = false}
"%Y-%m-%dT%H:%M:%S" "%Y-%m-%dT%H:%M:%S"
^ ^
tzd tzd

Binary file not shown.

View File

@ -1454,8 +1454,8 @@ font size and color.
\texttt{\%p} & "a.m" or "p.m"\\ \texttt{\%p} & "a.m" or "p.m"\\
\texttt{\%S} & Second of the minute (00--61)\\ \texttt{\%S} & Second of the minute (00--61)\\
\texttt{\%T} & Same as \%H:\%M:\%S\\ \texttt{\%T} & Same as \%H:\%M:\%S\\
\texttt{\%u} & Weekday (1--7, 1 = Monday)\\ \texttt{\%u} & Weekday (1--7, 1 = Sunday)\\
\texttt{\%w} & Weekday (0--6, 0 = Monday)\\ \texttt{\%w} & Weekday (0--6, 0 = Sunday)\\
\texttt{\%Y} & Year (0000--9999)\\ \texttt{\%Y} & Year (0000--9999)\\
\texttt{\%\%} & The \% character. \texttt{\%\%} & The \% character.
\end{tabular} \end{tabular}

View File

@ -1,8 +1,30 @@
(* C-Style strftime *) (* C-Style strftime *)
open Pdfutil open Pdfutil
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}
let t_of_unix u =
{_tm_sec = u.Unix.tm_sec;
_tm_min = u.Unix.tm_min;
_tm_hour = u.Unix.tm_hour;
_tm_mday = u.Unix.tm_mday;
_tm_mon = u.Unix.tm_mon;
_tm_year = u.Unix.tm_year;
_tm_wday = u.Unix.tm_wday;
_tm_yday = u.Unix.tm_yday;
_tm_isdst = u.Unix.tm_isdst}
let strf_A t = let strf_A t =
match t.Unix.tm_wday with match t._tm_wday with
| 0 -> "Sunday" | 1 -> "Monday" | 2 -> "Tuesday" | 0 -> "Sunday" | 1 -> "Monday" | 2 -> "Tuesday"
| 3 -> "Wednesday" | 4 -> "Thursday" | 5 -> "Friday" | 3 -> "Wednesday" | 4 -> "Thursday" | 5 -> "Friday"
| 6 -> "Saturday" | 6 -> "Saturday"
@ -12,7 +34,7 @@ let strf_a t =
String.sub (strf_A t) 0 3 String.sub (strf_A t) 0 3
let strf_B t = let strf_B t =
match t.Unix.tm_mon with match t._tm_mon with
| 0 -> "January" | 1 -> "February" | 2 -> "March" | 3 -> "April" | 0 -> "January" | 1 -> "February" | 2 -> "March" | 3 -> "April"
| 4 -> "May" | 5 -> "June" | 6 -> "July" | 7 -> "August" | 4 -> "May" | 5 -> "June" | 6 -> "July" | 7 -> "August"
| 8 -> "September" | 9 -> "October" | 10 -> "November" | 8 -> "September" | 9 -> "October" | 10 -> "November"
@ -22,56 +44,56 @@ let strf_b t =
String.sub (strf_B t) 0 3 String.sub (strf_B t) 0 3
let strf_d t = let strf_d t =
let s = string_of_int t.Unix.tm_mday in let s = string_of_int t._tm_mday in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_e t = let strf_e t =
let s = string_of_int t.Unix.tm_mday in let s = string_of_int t._tm_mday in
if String.length s = 1 then " " ^ s else s if String.length s = 1 then " " ^ s else s
let strf_H t = let strf_H t =
let s = string_of_int t.Unix.tm_hour in let s = string_of_int t._tm_hour in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_I t = let strf_I t =
let s = string_of_int (t.Unix.tm_hour mod 12) in let s = string_of_int (t._tm_hour mod 12) in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_j t = let strf_j t =
let s = string_of_int t.Unix.tm_yday in let s = string_of_int t._tm_yday in
match String.length s with match String.length s with
| 1 -> "00" ^ s | 1 -> "00" ^ s
| 2 -> "0" ^ s | 2 -> "0" ^ s
| _ -> s | _ -> s
let strf_m t = let strf_m t =
let s = string_of_int (t.Unix.tm_mon + 1) in let s = string_of_int (t._tm_mon + 1) in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_M t = let strf_M t =
let s = string_of_int t.Unix.tm_min in let s = string_of_int t._tm_min in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_p t = let strf_p t =
if t.Unix.tm_hour >= 12 then "p.m" else "a.m" if t._tm_hour >= 12 then "p.m" else "a.m"
let strf_S t = let strf_S t =
let s = string_of_int t.Unix.tm_sec in let s = string_of_int t._tm_sec in
if String.length s = 1 then "0" ^ s else s if String.length s = 1 then "0" ^ s else s
let strf_T t = let strf_T t =
strf_H t ^ ":" ^ strf_M t ^ ":" ^ strf_S t strf_H t ^ ":" ^ strf_M t ^ ":" ^ strf_S t
let strf_u t = let strf_u t =
match t.Unix.tm_wday with match t._tm_wday with
| 0 -> "7" | 0 -> "7"
| n -> string_of_int (n + 1) | n -> string_of_int (n + 1)
let strf_w t = let strf_w t =
string_of_int t.Unix.tm_wday string_of_int t._tm_wday
let strf_Y t = let strf_Y t =
string_of_int (t.Unix.tm_year + 1900) string_of_int (t._tm_year + 1900)
let strf_percent _ = "%" let strf_percent _ = "%"
@ -82,9 +104,64 @@ let strftime_pairs =
"%p", strf_p; "%S", strf_S; "%T", strf_T; "%u", strf_u; "%p", strf_p; "%S", strf_S; "%T", strf_T; "%u", strf_u;
"%w", strf_w; "%Y", strf_Y; "%%", strf_percent] "%w", strf_w; "%Y", strf_Y; "%%", strf_percent]
(* On Posix, call out to 'date'. On Windows, read %DATE% and %TIME% with 'cmd
* /C echo %TIME%'. On failure, exception escapes to caller. *)
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
let return_date () =
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;
_tm_isdst = false}
| _ ->
(* Run 'cmd /C echo %TIME%' and 'cmd /C echo %DATE%' *)
{_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}
let current_time () =
(*t_of_unix (Unix.localtime (Unix.gettimeofday ()))*)
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}
let strftime ?time text = let strftime ?time text =
let time = let time =
match time with None -> Unix.localtime (Unix.gettimeofday ()) | Some t -> t match time with None -> current_time () | Some t -> t
in in
let text = ref text in let text = ref text in
iter iter
@ -92,4 +169,3 @@ let strftime ?time text =
text := string_replace_all search (replace_fun time) !text) text := string_replace_all search (replace_fun time) !text)
strftime_pairs; strftime_pairs;
!text !text

View File

@ -1,4 +1,19 @@
(** C-style strftime *) (** C-style strftime *)
(** This supports the following format specifiers: %a %A %b %B %s %e %H %I %j %m %M %p %S %T %u %w %Y %% *) (** Supports the following format specifiers:
val strftime : ?time:Unix.tm -> string -> string %a %A %b %B %s %e %H %I %j %m %M %p %S %T %u %w %Y %% *)
(** Our version of Unix's tm, so Unix not required *)
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}
(** If time omitted, the current time is used. *)
val strftime : ?time:t -> string -> string

View File

@ -1,62 +0,0 @@
/**************************************************************************/
/* */
/* OCaml */
/* */
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
/* */
/* Copyright 1996 Institut National de Recherche en Informatique et */
/* en Automatique. */
/* */
/* All rights reserved. This file is distributed under the terms of */
/* the GNU Lesser General Public License version 2.1, with the */
/* special exception on linking described in the file LICENSE. */
/* */
/**************************************************************************/
/* This is not presently used. We need to bring in the win32unix implementation
* too and have the correct one chosen. Also need to copy across the OCaml
* interface to these functions */
#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/fail.h>
#include <caml/memory.h>
#include <sys/time.h>
double cpdf_unix_gettimeofday_unboxed(value unit)
{
struct timeval tp;
gettimeofday(&tp, NULL);
return ((double) tp.tv_sec + (double) tp.tv_usec / 1e6);
}
CAMLprim value cpdf_unix_gettimeofday(value unit)
{
return caml_copy_double(cpdf_unix_gettimeofday_unboxed(unit));
}
static value cpdf_alloc_tm(struct tm *tm)
{
value res;
res = caml_alloc_small(9, 0);
Field(res,0) = Val_int(tm->tm_sec);
Field(res,1) = Val_int(tm->tm_min);
Field(res,2) = Val_int(tm->tm_hour);
Field(res,3) = Val_int(tm->tm_mday);
Field(res,4) = Val_int(tm->tm_mon);
Field(res,5) = Val_int(tm->tm_year);
Field(res,6) = Val_int(tm->tm_wday);
Field(res,7) = Val_int(tm->tm_yday);
Field(res,8) = tm->tm_isdst ? Val_true : Val_false;
return res;
}
CAMLprim value cpdf_unix_localtime(value t)
{
time_t clock;
struct tm * tm;
clock = (time_t) Double_val(t);
tm = localtime(&clock);
return cpdf_alloc_tm(tm);
}