Post by alaaHi,
\
https://www.novabbs.com/devel/article-flat.php?id=28040&group=comp.lang.forth#28040
VOCABULARY timestamps-parser ALSO timestamps-parser DEFINITIONS
\ Idea: parse backward
VARIABLE a VARIABLE n
: >an n ! a ! ; : /an 0 a ! 0 n ! ;
: ch+ ( -- ) more? NOT ABORT" exceeded string" -1 n +! ;
: colon ( -- ) more? IF ch ':' <> ABORT" Expected colon!" ch+ THEN ;
: d? ( c -- t/f ) '0' '9' 1+ WITHIN ;
: digit? ( c -- t/f ) d? NOT ABORT" Expected a digit!" ;
: d ( -- ) ch digit? ch 48 - ch+ ;
: [d] ( -- n ) ch d? IF ch 48 - ch+ ELSE 0 THEN ;
: hr ( -- n ) [d] [d] 10 * + ; : min ( -- n ) [d] [d] 10 * + ; : sec (
-- n ) d [d] 10 * + ;
: parse ( a n -- s m h ) >an sec colon min colon hr /an ;
: .hr ( n -- ) ?DUP IF . ." hr " THEN ;
: .min ( n -- ) ?DUP IF . ." min " THEN ;
: .sec ( n -- ) ?DUP IF . ." sec " THEN ;
: .ts ( s m h -- ) .hr .min .sec ;
\ Examples
: e1 S" 1:2:3" ; CR e1 type e1 parse .s .ts
: e2 S" 02:03" ; CR CR e2 type e2 parse .s .ts
: e3 S" 03" ; CR CR e3 type e3 parse .s .ts
: e4 S" 23:59:59" ; CR CR e4 type e4 parse .s .ts
: e5 S" 0:00:03" ; CR CR e5 type e5 parse .s .ts
: e6 S" " ; CR CR e6 type e6 parse .s .ts \ will fail since we expect at
least one digit with 'd' word, we can use '[d]' for optional digit
\ another stupid idea/hack to try: count ':', replace them with BL,
Evaluate string, push missing fields as zeros
Still another way, not complying to this specific implementation:
---8<---
3600 12 * constant (12hours) \ a constant holding 12 hours seconds
: h:m:s>secs ( a1 n1 -- n2)
['] is-type defer@ >r [: is-digit 0= ;] is is-type
0 >r 3600 >r -leading -trailing \ clean up string
begin \ split off all the components
dup \ if a null string, skip loop
while \ if not, convert it to a number
split> number error? dup >r \ if a number, scale it, add to
result
if drop else r> swap r> tuck * r> + >r 60 / >r >r dup if chop then
then r>
until r> drop \ drop scaling factor
dup if \ if remainder, unchop, clean
string up
1+ swap char- swap -leading 2dup s" PM" compare
if \ is it in the afternoon?
s" AM" compare if r> else r> dup (12hours) >= if (12hours) - then
then
else \ is it in the morning?
2drop r> dup (12hours) < if (12hours) + then
then \ then adjust accordingly
else \ if null string, discard it
2drop r> \ and just retrieve result
then r> is is-type
;
---8<---
Basically, it takes any non-digit as a delimiter, parses hours, minutes
and seconds and then checks for any AM or PM remaining, making
adjustments when required. It returns seconds. Those may easily be
combined with other epoch information or split into any required format.
Or be a component in this beauty:
: stamp>iso8601 ( a1 n1 -- a2 n2)
dup if
bl split trim 2swap trim 2>r s>date 2r> h:m:s>secs s>smh .datetime0
then
;
- Split the timestamp at the space;
- Convert the string to a date (d m y);
- Convert the other string to seconds;
- Convert the seconds to time (s m h);
- Push out a 8601 string.
Hans Bezemer