[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Nmh-workers] Back to Dates
From: |
Bob Carragher |
Subject: |
Re: [Nmh-workers] Back to Dates |
Date: |
Sat, 3 Jan 2015 21:25:55 -0800 |
Thank you very much, Ken, both for this nice recipe and the
detailed explanation of the code! It actually cleared up a
couple of misconceptions I had!
It has also helped make a monster of my Date: field. For
example, I now generate the following when viewing this message:
Date: Thu, 01 Jan 2015 23:07:40 -0500 (2015-01-01 20:07:40
[2 days ago])
The recipe for it, for the insanely curious, is:
Date:formatfield="%<(nodate{text})%{text}%|\
%(pretty{text})%(void(szone{text}))%<(eq 1) \
(%(date2local{text})%04(year{text})-%02(mon{text})-%02(mday{text}) \
%02(hour{text}):%02(min{text}):%02(sec{text})\
%<(rclock{text})\
%<(gt 60) [\
%<(gt 299592000)%(void (plus 157680000))%(divide 315360000) decade\
%?(gt 31492800)%(void (plus 15768000))%(divide 31536000) year\
%?(gt 2548800)%(void (plus 1296000))%(divide 2592000) month\
%?(gt 84600)%(void (plus 43200))%(divide 86400) day\
%?(gt 3300)%(void (plus 1800))%(divide 3600) hour\
%|%(void (plus 30))%(divide 60) minute%>%<(gt 1)s%> ago]%>%>)%>%>"
I modified the recipe that Ken posted by extending it in the
obvious way (adding months, years, and even decades), but also to
only output when a message is at least 1 minute old. I also
incorporated the recipe posted a little while back, for displaying
both the sender's date as-is, and my local time (and date).
Bob
> From: Ken Hornstein <address@hidden>
> To: address@hidden
> Date: Thu, 01 Jan 2015 23:07:40 -0500
> Subject: Re: [Nmh-workers] Back to Dates
>
> It occurs to me that it might be useful to break this down a bit, to provide
> some explanation as to what's going on here. You can use fmttest on it to
> get the instructions this decodes into, but that's not always that useful
> unless you've been inside of the format code a lot.
>
> -
> Date:formatfield="%<(nodate{text})%{text}%|%(pretty{text})%(date2local{text})
> [\
> %02(hour{text}):%02(min{text})\
> %<(rclock{text})%<(gt 8596800)%| - \
> %<(gt 84600)%(void (plus 43200))%(divide 86400) day\
> %?(gt 3300)%(void (plus 1800))%(divide 3600) hour\
> %|%(void (plus 30))%(divide 60) minute%>%<(gt 1)s%> ago%>%>]%>"
>
> This is the beginning of the line for the mhl file; it refers to any
> "date" header. formatfield is the flag that says, "Run this header
> through mh-format, and here's the mh-format string". The wrinkle here
> is that the value of the header is made available via the special {text}
> component; in scan(1), the date header is in {date}. Other utilitities
> that make use of mh-format(5) do the same thing.
>
> The decomposed mh-format string is:
>
> 1) %<
> If statement, will execute the next statements if the return value
> is non-zero. Well, if it's a function that returns a string, "true"
> is if the string has a non-zero length.
>
> 2) (nodate{text})
> Returns "true" if the {text} component (see above) is NOT a valid
> date. Note that it does not have a leading '%'; this is because
> the "if" statement above knows that the following entry has to
> be a function or component, so the '%' is assumed. Also note
> that the return value of this function is NOT output.
>
> 3) %{text}
> Outputs the value of the {text}component.
>
> 3) %|
> The "else" statement to 1) above.
>
> 4) %(pretty{text})
> A "user-friendly" rendering of the date header.
>
> 5) %(date2local{text})
> Converts the internally-stored date for {text} into the local
> timezone. This requires some additional explanation.
>
> The first time address and date headers are accessed they are
> run through the respective parsers and internally stored with
> the component information. So things like %(hour) don't have
> to parse the date header text again; they get it directly from
> the internal date structure. What %(date2local) does is convert
> the internal date structure to the local timezone, but it does
> NOT change the text. So in this case, %{text} still has the
> original date header, but things like %(hour{text}) refer to
> the hour in the local timezone.
>
> 6) "\n[ "
> Text, output literally
>
> 7) %02(hour{text})
> The hour part of the time (local timezone, see 5)), width of
> 2 digits, left padded with zeros.
>
> 8) ":"
> Text, output literally
>
> 9) %02(min{text})
> The minutes part of the time, in the local timezone, width of
> 2 digits, left padded with zeros.
>
> 10) %<
> If statement, will execute this branch if 11) returns nonzero.
>
> 11) (rclock{text})
> Returns the number of seconds "date" is off of the current time.
> Stores the value in the "num" register.
>
> 12) %<
> If statement, will execute this branch of 13) returns nonzero.
>
> 13) (gt 8596800)
> If "num" is greater than 8596800 (99.5 hours), execute the next
> branch ... which is null. This is the cutoff that doesn't print
> a date offset if the message is greater than 100 days old.
>
> A digression here: normally functions like "%(gt) would clobber the
> "num" register with a 0 or 1. But this and other functions that
> return boolean values in mh-format(5) are treated a bit special;
> if they are combined with an if (%<) statement and do not store
> their result in the "num" register if they are the test for
> an if statement. You can see this in the fmttest(1) if you look
> carefully.
>
> 14) %|
> Else statement for 13) above; there is no "less than" operator
> in mh-format(5), that's why the there is nothing under the "true"
> branch of the if statement.
>
> 15) " - "
> Text, output literally
>
> 16) %<(gt 86400)
> If statement, will execute the this branch if "num" is greater
> than 86400 (one day).
>
> 15) %(void (plus 43200))
> Add 43200 (1/2 day) to the value of "num" The use of %(void)
> prevents the result from being output (see mh-format(5) for more
> details). This it to round up for the calculation in 16).
>
> 16) %(divide 86400)
> Divide "num" by 86400, which results in the number of days from
> "now" and the original date of this message, and output the
> value of the num register.
>
> 17) " day"
> Text, output literally.
>
> 18) %?(gt 3300)
> Else if statement corresponding to 16) above, will execute this
> branch if "num" is greater than 3300) (almost 1 hour).
>
> 19) %(void (plus 1800))
> Add 1800 (1/2 hour) the value of "num" for rounding purposes.
>
> 20) %(divide 3600)
> Divide "num" by 3600 to get the number of hours the message time
> is offset from current time.
>
> 21) " hour"
> Text, output literally
>
> 22) %|
> The else statement for the if-else if statement in 16) and 18).
> This branch gets executed if no other test was true.
>
> 23) %(void (plus 30))%(divide 60)
> Add 30 to "num" for rounding, and divide it by 60 to get the number
> of minutes.
>
> 24) " minute"
> Text, output literally
>
> 25) %>
> Endif for branch statements in 16), 18), 22).
>
> 26) %<(gt 1)s%>
> At this point "num" contains the value of the days, hours, or
> minutes (depending on previous branches taken). This statement
> will output the character "s" if "num" is greater than one,
> so that days, hours, or minutes is pluralized properly.
>
> 27) " ago"
> Text, output literally.
>
> 28) %>
> Endif, for the if statement in 12)
>
> 29) %>
> Endif, for the if statement in 10
>
> 30) "]"
> Text, output literally
>
> 31) %>
> Endif, for the if statement in 1).
>
> So that's the whole format string broken down; it actually does a few
> clever things, like only requiring one test to cover all time units
> for proper pluralization. It looks like a mess all compacted, but it's
> relatively straightforward once you break it down. The big problem
> when writing mh-format(5) programs is you only have two variables: "num"
> that can hold an integer, and "str" which can hold a string. A lot of
> functions clobber one or the other, so it's tough to keep a value around
> for a large number of statements.
>
> --Ken
>
> _______________________________________________
> Nmh-workers mailing list
> address@hidden
> https://lists.nongnu.org/mailman/listinfo/nmh-workers
- [Nmh-workers] Back to Dates, norm, 2015/01/01
- Re: [Nmh-workers] Back to Dates, Ken Hornstein, 2015/01/01
- Re: [Nmh-workers] Back to Dates, David Levine, 2015/01/01
- Re: [Nmh-workers] Back to Dates, norm, 2015/01/01
- Re: [Nmh-workers] Back to Dates, Ken Hornstein, 2015/01/01
- Re: [Nmh-workers] Back to Dates, Ken Hornstein, 2015/01/01
- Re: [Nmh-workers] Back to Dates, norm, 2015/01/06
- Re: [Nmh-workers] Back to Dates, Ken Hornstein, 2015/01/06
- Re: [Nmh-workers] Back to Dates, Ken Hornstein, 2015/01/06
- Re: [Nmh-workers] Back to Dates,
Bob Carragher <=