mu-scm: add string->time and time->string

Replace the iso-date->time-t and v.v. functions with something more
customizable. Add more tests.

Use some (internal for now) %preferences variable for the defaults. TBD... maybe
should become a fluid?
This commit is contained in:
Dirk-Jan C. Binnema
2025-06-30 22:11:46 +03:00
parent f2699a4b95
commit 9360a641a9
3 changed files with 172 additions and 94 deletions

View File

@ -49,7 +49,8 @@
(let ((msg (car (mfind "" #:sort-field 'date #:reverse? #t)))) (let ((msg (car (mfind "" #:sort-field 'date #:reverse? #t))))
(test-equal "test with multi to and cc" (subject msg) ) (test-equal "test with multi to and cc" (subject msg) )
(test-equal "2016-05-15T16:57:25" (time-t->iso-date (date msg)))) (test-equal "2016-05-15 16:57:25"
(time->string (date msg) #:format "%F %T" #:utc? #t)))
(test-end "test-mfind")) (test-end "test-mfind"))
@ -92,7 +93,7 @@
(define (test-options) (define (test-options)
(test-begin "test-options") (test-begin "test-options")
(let ((opts (options))) (let ((opts %options))
(test-assert (>= (length opts) 4)) (test-assert (>= (length opts) 4))
(test-equal (assoc-ref opts 'quiet) #f) (test-equal (assoc-ref opts 'quiet) #f)
(test-equal (assoc-ref opts 'debug) #f) (test-equal (assoc-ref opts 'debug) #f)
@ -102,11 +103,22 @@
(define (test-helpers) (define (test-helpers)
(test-begin "test-helpers") (test-begin "test-helpers")
(test-equal 1750077792 (iso-date->time-t "2025-06-16T12:43:12")) (setenv "TZ" "Europe/Helsinki")
(test-equal 1750075200 (iso-date->time-t "2025-06-16T12")) (tzset)
(test-equal 1750077792 (string->time "2025-06-16T15:43:12" #:utc? #f))
(test-equal 1750077792 (string->time "2025-06-16 12:43:12" #:utc? #t))
(test-equal 1750075200 (string->time "2025-06-16 12" #:utc? #t))
(test-equal "2025-06-16T12:43:12" (time-t->iso-date 1750077792)) (test-equal "2025-06-16 12:43:12" (time->string 1750077792 #:utc? #t))
(test-equal " " (time-t->iso-date #f)) (test-equal "2025-06-16 15:43:12" (time->string 1750077792 #:utc? #f))
(test-equal "12:43:12" (time->string 1750077792 #:utc? #t #:format "%T"))
;; (define old-prefs %preferences)
;; (define %preferences '((utc? . #t) (short-date . "%T %F")))
;; (test-equal "12:43:12 2025-06-16" (time->string 1750077792))
;; (set! %preferences old-prefs)
(test-equal #f (time->string #f))
(test-end "test-helpers")) (test-end "test-helpers"))
(define* (main _ #:rest args) (define* (main _ #:rest args)

View File

@ -16,7 +16,6 @@
;; Note: this Scheme code depends on being loaded as part of "mu scm" ;; Note: this Scheme code depends on being loaded as part of "mu scm"
;; which does so automatically. It is not a general Guile module. ;; which does so automatically. It is not a general Guile module.
(define-module (mu) (define-module (mu)
:use-module (oop goops) :use-module (oop goops)
:use-module (system foreign) :use-module (system foreign)
@ -77,11 +76,12 @@
header header
;; misc ;; misc
options %options
;; %preferences
;; helpers ;; helpers
iso-date->time-t string->time
time-t->iso-date)) time->string))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; some helpers for dealing with plists / alists ;; some helpers for dealing with plists / alists
@ -416,39 +416,70 @@ The pattern is mandatory; the other (keyword) arguments are optional.
;;; Misc ;;; Misc
(define (options) ;; Get an alist with the general options this instance of \"mu\" started with.
"Get an alist with the general options this instance of \"mu\" started with. ;; These are based on the command-line arguments, environment etc., see the
These are based on the command-line arguments, environment etc., see ;; mu-scm(1) manpage for details.
the mu-scm(1) manpage for details. ;;
;; The alist maps symbols to values; a value of #f indicates that the value is at
;; its default.
%options ;; defined in c++
The alist maps symbols to values; a value of #f indicates that the value ;; Alist of user-preferences.
is at its default." ;;
%options) ;; - short-date: a strftime-compatibie string for the display
;; format of short dates.
;; - utc? : whether to assume use UTC for dates/times
(define %preferences
'( (short-date . "%F %T")
(utc? . #f)))
;; XXX; not exposed yet. Perhaps we need a "fluid" here?
(define (value-or-preference val key)
"If VAL is the symbol 'preference, return the value for KEY from %preferences.
Otherwise, return VAL."
(if (eq? val 'preference)
(assoc-ref %preferences key)
val))
;;; Helpers ;;; Helpers
(define* (iso-date->time-t isodate) (define* (string->time datestr #:key (utc? 'preference))
"Convert an ISO-8601 ISODATE to a number of seconds since epoch. "Convert an ISO-8601-style DATESTR to a number of seconds since epoch.
(like time_t, (current-time).
ISODATE is a string with the strftime format \"%FT%T\", i.e., ISODATE is a string with the strftime format \"%FT%T\", i.e.,
yyyy-mm-ddThh:mm:ss or any prefix there of. The 'T', ':', '-' or any non-numeric yyyy-mm-ddThh:mm:ss or any prefix there of. The 'T', ':', '-' or any non-numeric
characters re optional. characters re optional.
ISODATE is assumed to represent some UTC date." UTC? determines whether ISODATE should be interpreted as an UTC time.
(let* ((tmpl "00000101000000")
(isodate (string-filter char-numeric? isodate)) ;; filter out 'T' ':' '-' etc
(isodate ;; fill out isodate
(if (> (string-length tmpl) (string-length isodate))
(string-append isodate (substring tmpl (string-length isodate)))
isodate)))
;;(format #t "~a\n" isodate)
(car (mktime (car (strptime "%Y%m%d%H%M%S" isodate)) "Z"))))
(define-method (time-t->iso-date time-t) The input date format is fixed."
"Convert a time_t (second-since-epoch) value TIME-T to an ISO-8601 ;; XXX If not set, read the default from the %preferences variable.
string for the corresponding UTC time. (let* ((utc? (value-or-preference utc? 'utc?))
(tmpl "00000101000000")
(datestr (string-filter char-numeric? datestr)) ;; filter out 'T' ':' '-' etc
(datestr ;; fill out datestr
(if (> (string-length tmpl) (string-length datestr))
(string-append datestr (substring tmpl (string-length datestr)))
datestr))
(sbdtime (car (strptime "%Y%m%d%H%M%S" datestr))))
(car (if utc?
(mktime sbdtime "UTC")
(mktime sbdtime)))))
If TIME-T is #f, return an empty string of the same length."
(define* (time->string time-t #:key (format 'preference) (utc? 'preference))
"Convert a time_t (second-since-epoch) value TIME-T into a string.
FORMAT is the strftime-compatible format-string UTC? determines whether to use
UTC time.
If TIME-T is #f, return #f."
;; If not specified, both are determined from %preferences ('short-date
;; and 'utc?, respectively).
(let* ((format (value-or-preference format 'short-date))
(utc? (value-or-preference utc? 'utc?)))
(if time-t (if time-t
(strftime "%FT%T" (gmtime time-t)) (let ((t (if utc? (gmtime time-t) (localtime time-t))))
" ")) (strftime format t))
#f)))

View File

@ -94,6 +94,7 @@ Appendices
Indices Indices
* Procedure Index:: * Procedure Index::
* Variable Index::
@end menu @end menu
@ -681,30 +682,56 @@ For example:
@node Miscellaneous @node Miscellaneous
@section Miscellaneous @section Miscellaneous
@deffn {Scheme Procedure} options @defvar %options
@end deffn @end defvar
This yields an association-list (alist) of general options passed to @command{mu An association-list (alist) of general options passed to @command{mu scm} or
scm}. Values at @t{#f} indicate that the value is at its default. their default values.
@lisp @lisp
(options) %options
=> ((mu-home . #f) (quiet . #f) (debug . #f) (verbose . #f)) => ((mu-home . #f) (quiet . #f) (debug . #f) (verbose . #f))
@end lisp @end lisp
@c @defvar %preferences
@c @end defvar
@c An association list (alist) of user-preferences that influence interactive use.
@c E.g., the way how certain things are displayed. The alist maps symbols to values:
@c @itemize
@c @item @code{short-date}
@c a @code{strftime}-compatible string for the display format of short dates.
@c @item @code{utc?}
@c boolean, whether to assume UTC for dates/times, such as for @code{string->time} and @code{time->string}
@c @end itemize
@c @lisp
@c %preferences
@c ((short-date-format . "%F %T") (input-utc? . #f) (output-utc? . #f))
@c @end lisp
@node Helpers @node Helpers
@section Helpers @section Helpers
@deffn {Scheme Procedure} iso-date->time-t iso-date @deffn {Scheme Procedure} string->time timestr [#:utc? (assoc-ref %preferences 'utc?)]
@end deffn @end deffn
Convert some ISO-8601 compatible time-point (assuming UTC) to a Convert some ISO-8601-style time-string to a seconds-since-epoch @t{time_t}
seconds-since-epoch @t{time_t} value. @var{iso-date} is expected to be in the value. @var{timestr} is expected to be in the @t{strftime}-format @t{%F%T}, or a
@t{strftime}-format @t{%F%T}, or a prefix thereof. Non-numerical characters are prefix thereof. Non-numerical characters are ignored.
ignored.
@deffn {Scheme Procedure} time-t->iso-date time-t You can influence whether UTC is assumed using the optional @code{#:utc?}
parameter. The input time/date format is fixed.
@c which uses @code{%preferences} for its default.
@deffn {Scheme Procedure} time->string
[#:format (assoc-ref %preferences 'short-date)]
[#:utc? (assoc-ref %preferences 'utc?)]
@end deffn @end deffn
Convert a @t{time_t} value to an ISO-8601 compatible string (assuming UTC). If Convert a @t{time_t} value (``seconds-since-epoch'') to a string. The optional
@var{time_t} is @t{#f}, return an empty string of the same length. @code{#:format} parameter (an @code{strftime}-compatible string) determines the
output format, while the @code{#:utc?} determines whether to use UTC.
@c Defaults are determined by the @code{%preferences} variable.
If @var{time_t} is @t{#f}, return @code{#f}.
@node GNU Free Documentation License @node GNU Free Documentation License
@appendix GNU Free Documentation License @appendix GNU Free Documentation License
@ -715,8 +742,16 @@ Convert a @t{time_t} value to an ISO-8601 compatible string (assuming UTC). If
@node Procedure Index @node Procedure Index
@unnumbered Procedure Index @unnumbered Procedure Index
This is an alphabetical list of all the procedures and macros in @t{mu-scm}. This is an alphabetical list of all the public procedures and macros in @t{mu-scm}.
@printindex fn @printindex fn
@page
@node Variable Index
@unnumbered Variables Index
This is an alphabetical list of all the public variables @t{mu-scm}.
@printindex vr
@bye @bye