Scheduling of every-jobs.
[whenjobs.git] / lib / whenutils.ml
index 1fbb1c6..362f4f6 100644 (file)
 open Camlp4.PreCast
 open Ast
 
+open CalendarLib
+
 open Big_int
+open Unix
 open Printf
 
 module StringMap = struct
@@ -30,6 +33,13 @@ end
 
 module StringSet = Set.Make (String)
 
+let rec filter_map f = function
+  | [] -> []
+  | x :: xs ->
+    match f x with
+    | Some y -> y :: filter_map f xs
+    | None -> filter_map f xs
+
 type whenexpr =
   | Expr_bool of bool
   | Expr_str of string
@@ -351,3 +361,48 @@ let job_evaluate job variables =
                    job_prev_variables = variables } in
       let job = { job with job_private = jobp } in
       true, job
+
+let next_periodexpr =
+  (* Round up 'a' to the next multiple of 'i'. *)
+  let round_up_float a i =
+    let r = mod_float a i in
+    if r = 0. then a +. i else a +. (i -. r)
+  and round_up a i =
+    let r = a mod i in
+    if r = 0 then a + i else a + (i - r)
+  in
+
+  fun t -> function
+  | Every_seconds i ->
+    let i = float_of_int i in
+    round_up_float t i
+
+  | Every_years i ->
+    let tm = gmtime t in
+
+    (* Round 'tm' up to the first day of the next year. *)
+    let year = round_up tm.tm_year i in
+    let tm = { tm with tm_sec = 0; tm_min = 0; tm_hour = 0;
+                       tm_mday = 1; tm_mon = 0; tm_year = year } in
+    fst (mktime tm)
+
+  | Every_days i ->
+    let t = Date.from_unixfloat t in
+    let t0 = Date.make 1970 1 1 in
+
+    (* Number of whole days since Unix Epoch. *)
+    let nb_days = Date.Period.safe_nb_days (Date.sub t t0) in
+
+    let nb_days = round_up nb_days i in
+    let t' = Date.add t0 (Date.Period.day nb_days) in
+    Date.to_unixfloat t'
+
+  | Every_months i ->
+    (* Calculate number of whole months since Unix Epoch. *)
+    let tm = gmtime t in
+    let months = 12 * (tm.tm_year - 70) + tm.tm_mon in
+
+    let months = round_up months i in
+    let t0 = Date.make 1970 1 1 in
+    let t' = Date.add t0 (Date.Period.month months) in
+    Date.to_unixfloat t'