]> Repositorios git - scryer-prolog.git/commitdiff
ADDED: format_time//2 for describing strings involving dates and times
authorMarkus Triska <[email protected]>
Wed, 10 Jun 2020 21:13:14 +0000 (23:13 +0200)
committerMarkus Triska <[email protected]>
Wed, 10 Jun 2020 22:55:38 +0000 (00:55 +0200)
current_time/1 yields the current system time as an opaque time stamp.

Cargo.toml
README.md
src/prolog/clause_types.rs
src/prolog/lib/time.pl
src/prolog/machine/system_calls.rs

index 5bf5abdc50dbebb3d7490bb815da5896f9ba73d1..a7cc588bb8b18d440d674a6ce0b8addab5cf27ef 100644 (file)
@@ -43,3 +43,4 @@ sha3 = "0.8.2"
 blake2 = "0.8.1"
 openssl = { version = "0.10.29", features = ["vendored"] }
 native-tls = "0.2.4"
+chrono = "0.4.11"
index 2a631129f6039e8328dfaed36e78cc4761cf3a70..2762b86f527301f7cf7c5eba4d7b8b85ae0e6126 100644 (file)
--- a/README.md
+++ b/README.md
@@ -400,9 +400,11 @@ The modules that ship with Scryer&nbsp;Prolog are also called
 * [`arithmetic`](src/prolog/lib/arithmetic.pl)
   Arithmetic predicates such as `lsb/2`, `msb/2` and
   `number_to_rational/2`.
-* [`time`](src/prolog/lib/time.pl)
-  `time/1` reports the CPU&nbsp;time of a goal. It is useful
-  for measuring the performance of your code.
+* [`time`](src/prolog/lib/time.pl) Predicates for reasoning about
+  time, including `time/1` to measure the CPU&nbsp;time of a goal,
+  `current_time/1` to obtain the current system time, the nonterminal
+  `format_time//2` to describe strings with dates and times, and
+  `sleep/1` to slow down a computation.
 * [`cont`](src/prolog/lib/cont.pl)
   Provides *delimited continuations* via `reset/3` and `shift/1`.
 * [`random`](src/prolog/lib/random.pl)
index 1d90106844b720cdb85b9ef14ebaed72fdf57ce5..a62570824d6bcec311a6a703760b0a064d1b3b33 100644 (file)
@@ -261,6 +261,7 @@ pub enum SystemClauseType {
     InstallNewBlock,
     Maybe,
     CpuNow,
+    CurrentTime,
     QuotedToken,
     ReadTermFromChars,
     ResetBlock,
@@ -398,6 +399,7 @@ impl SystemClauseType {
             &SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
             &SystemClauseType::Maybe => clause_name!("maybe"),
             &SystemClauseType::CpuNow => clause_name!("$cpu_now"),
+            &SystemClauseType::CurrentTime => clause_name!("$current_time"),
             &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
                 clause_name!("$module_asserta")
             }
@@ -589,6 +591,7 @@ impl SystemClauseType {
             ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
             ("$maybe", 0) => Some(SystemClauseType::Maybe),
             ("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
+            ("$current_time", 1) => Some(SystemClauseType::CurrentTime),
             ("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
             ("$module_of", 2) => Some(SystemClauseType::ModuleOf),
             ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
index ccf45bdf029383d811f9f32c5c68e0132b4baff1..d6b0ebae7944bd87b0de7eb01cb5e12646f13e56 100644 (file)
@@ -1,19 +1,73 @@
 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-   Written April 2020 by Markus Triska ([email protected])
+   Written 2020 by Markus Triska ([email protected])
    Part of Scryer Prolog.
 
    This library provides predicates for reasoning about time.
-   Reasoning about time stamps would be a useful addition, for example
-   by obtaining the current time, comparing and formatting it.
 
-   '$cpu_now' can be replaced by statistics/2 once that is implemented.
+   current_time(T) yields the current system time in an opaque form,
+   called a time stamp. Use format_time//2 to describe strings that
+   contain attributes of the time stamp.
+
+   The nonterminal format_time//2 describes a list of characters that
+   are formatted according to a format string. Usage:
+
+     phrase(format_time(FormatString, TimeStamp), Cs)
+
+   TimeStamp represents a moment in time in an opaque form, as for
+   example obtained by current_time/1.
+
+   FormatString is a list of characters that are interpreted literally,
+   except for the following specifiers (and possibly more in the future):
+
+     %Y    year of the time stamp. Example: 2020.
+     %m    month number (01-12), zero-padded to 2 digits
+     %d    day number (01-31), zero-padded to 2 digits
+     %H    hour number (00-24), zero-padded to 2 digits
+     %M    minute number (00-59), zero-padded to 2 digits
+     %S    second number (00-60), zero-padded to 2 digits
+     %b    abbreviated month name, always 3 letters
+     %a    abbreviated weekday name, always 3 letters
+     %A    full weekday name
+     %j    day of the year (001-366), zero-padded to 3 digits
+     %%    the literal %
+
+   Example:
+
+     ?- current_time(T), phrase(format_time("%d.%m.%Y (%H:%M:%S)", T), Cs).
+        T = [...], Cs = "11.06.2020 (00:24:32)"
+     ;  false.
+
+   sleep(S) sleeps for S seconds (a floating point number).
+
+   time(Goal) reports the execution time of Goal.
+
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
-:- module(time, [max_sleep_time/1, sleep/1, time/1]).
+:- module(time, [max_sleep_time/1, sleep/1, time/1, current_time/1, format_time//2]).
 
 :- use_module(library(format)).
 :- use_module(library(iso_ext)).
 :- use_module(library(error)).
+:- use_module(library(dcgs)).
+:- use_module(library(lists)).
+:- use_module(library(charsio), [read_term_from_chars/2]).
+
+current_time(T) :-
+        '$current_time'(T0),
+        read_term_from_chars(T0, T).
+
+format_time([], _) --> [].
+format_time(['%','%'|Fs], T) --> !, "%", format_time(Fs, T).
+format_time(['%',Spec|Fs], T) --> !,
+        (   { member(Spec=Value, T) } ->
+            list(Value)
+        ;   { domain_error(time_specifier, Spec, format_time//2) }
+        ),
+        format_time(Fs, T).
+format_time([F|Fs], T) --> [F], format_time(Fs, T).
+
+list([]) --> [].
+list([L|Ls]) --> [L], list(Ls).
 
 max_sleep_time(0xfffffffffffffbff).
 
@@ -26,6 +80,9 @@ sleep(T) :-
     ;   '$sleep'(T)
     ).
 
+
+% '$cpu_now' can be replaced by statistics/2 once that is implemented.
+
 time(Goal) :-
         '$cpu_now'(T0),
         setup_call_cleanup(true,
index 887163a0eee84c58459f0715f33619799b90b097..d4607c59e988fe04ed690233fde10654ba8ea16c 100644 (file)
@@ -33,8 +33,9 @@ use std::ops::Sub;
 use std::rc::Rc;
 use std::num::NonZeroU32;
 
-use std::time::Duration;
+use std::time::{Duration, SystemTime};
 use cpu_time::ProcessTime;
+use chrono::{offset::Local,DateTime};
 
 use crate::crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
 use crate::crossterm::terminal::{enable_raw_mode, disable_raw_mode};
@@ -3137,6 +3138,21 @@ impl MachineState {
 
                 self.unify(a1, addr);
             }
+            &SystemClauseType::CurrentTime => {
+                let system_time = SystemTime::now();
+                let datetime: DateTime<Local> = system_time.into();
+
+                let mut fstr = "[".to_string();
+                let specifiers = vec!["d","m","Y","y","H","M","S","b","B","a","A","w","u","U","W","j","D","x","v"];
+                for spec in specifiers {
+                    fstr.push_str(&format!("'{}'=\"%{}\", ", spec, spec).to_string());
+                }
+                fstr.push_str("finis].");
+                let str = { let s = datetime.format(&fstr).to_string();
+                            self.heap.put_complete_string(&s)
+                          };
+                self.unify(self[temp_v!(1)], str);
+            }
             &SystemClauseType::OpDeclaration => {
                 let priority = self[temp_v!(1)];
                 let specifier = self[temp_v!(2)];