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:
@ -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)
|
||||||
|
|||||||
179
scm/mu-scm.scm
179
scm/mu-scm.scm
@ -16,72 +16,72 @@
|
|||||||
|
|
||||||
;; 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)
|
||||||
:use-module (ice-9 optargs)
|
:use-module (ice-9 optargs)
|
||||||
#:export (
|
#:export (
|
||||||
;; classes
|
;; classes
|
||||||
<store>
|
<store>
|
||||||
|
|
||||||
mfind
|
mfind
|
||||||
mcount
|
mcount
|
||||||
cfind
|
cfind
|
||||||
|
|
||||||
<message>
|
<message>
|
||||||
sexp
|
sexp
|
||||||
|
|
||||||
date
|
date
|
||||||
last-change
|
last-change
|
||||||
|
|
||||||
message-id
|
message-id
|
||||||
path
|
path
|
||||||
priority
|
priority
|
||||||
subject
|
subject
|
||||||
|
|
||||||
references
|
references
|
||||||
thread-id
|
thread-id
|
||||||
|
|
||||||
mailing-list
|
mailing-list
|
||||||
|
|
||||||
language
|
language
|
||||||
size
|
size
|
||||||
|
|
||||||
;; message flags / predicates
|
;; message flags / predicates
|
||||||
flags
|
flags
|
||||||
flag?
|
flag?
|
||||||
draft?
|
draft?
|
||||||
flagged?
|
flagged?
|
||||||
passed?
|
passed?
|
||||||
replied?
|
replied?
|
||||||
seen?
|
seen?
|
||||||
trashed?
|
trashed?
|
||||||
new?
|
new?
|
||||||
signed?
|
signed?
|
||||||
encrypted?
|
encrypted?
|
||||||
attach?
|
attach?
|
||||||
unread?
|
unread?
|
||||||
list?
|
list?
|
||||||
personal?
|
personal?
|
||||||
calendar?
|
calendar?
|
||||||
|
|
||||||
;; contact fields
|
;; contact fields
|
||||||
from
|
from
|
||||||
to
|
to
|
||||||
cc
|
cc
|
||||||
bcc
|
bcc
|
||||||
|
|
||||||
;; message-body
|
;; message-body
|
||||||
body
|
body
|
||||||
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."
|
|
||||||
(if time-t
|
(define* (time->string time-t #:key (format 'preference) (utc? 'preference))
|
||||||
(strftime "%FT%T" (gmtime time-t))
|
"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
|
||||||
|
(let ((t (if utc? (gmtime time-t) (localtime time-t))))
|
||||||
|
(strftime format t))
|
||||||
|
#f)))
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user