Rocksolid Light

Welcome to RetroBBS

mail  files  register  newsreader  groups  login

Message-ID:  

Please go away.


devel / comp.unix.shell / Re: Datediff script

SubjectAuthor
* Datediff scriptcastAway
+* Re: Datediff scriptJanis Papanagnou
|+* Re: Datediff scriptcastAway
||+* Re: Datediff scriptSpiros Bousbouras
|||`- Re: Datediff scriptcastAway
||`* Re: Datediff scriptJanis Papanagnou
|| +* Re: Datediff scriptJanis Papanagnou
|| |+* Re: Datediff scriptJanis Papanagnou
|| ||`* Re: Datediff scriptcastAway
|| || `- Re: Datediff scriptKeith Thompson
|| |`- Re: Datediff scriptJalen Q
|| +* Re: Datediff scriptcastAway
|| |`* Re: Datediff scriptJanis Papanagnou
|| | `* Re: Datediff scriptChris Elvidge
|| |  +- Re: Datediff scriptSpiros Bousbouras
|| |  `- Re: Datediff scriptcastAway
|| +* Re: Datediff scriptcastAway
|| |`* Re: Datediff scriptcastAway
|| | `* Re: Datediff scriptJanis Papanagnou
|| |  `- Re: Datediff scriptcastAway
|| +* Re: Datediff scriptcastAway
|| |+- Re: Datediff scriptBen Bacarisse
|| |+- Re: Datediff scriptJanis Papanagnou
|| |`- Re: Datediff scriptJohn-Paul Stewart
|| `* Re: Datediff scriptcastAway
||  `- Re: Datediff scriptJanis Papanagnou
|`* Re: Datediff scriptcastAway
| +- Re: Datediff scriptJanis Papanagnou
| `* Re: Datediff scriptJanis Papanagnou
|  `* Re: Datediff scriptJanis Papanagnou
|   `- Re: Datediff scriptJanis Papanagnou
`* Re: Datediff scriptcastAway
 +* Re: Datediff scriptJanis Papanagnou
 |+* Re: Datediff scriptcastAway
 ||+- Re: Datediff scriptcastAway
 ||`- Re: Datediff scriptcastAway
 |`* Re: Datediff scriptcastAway
 | `- Re: Datediff scriptcastAway
 `* Re: Datediff scriptJanis Papanagnou
  `* Re: Datediff scriptcastAway
   `* Re: Datediff scriptJanis Papanagnou
    +* Re: Datediff scriptcastAway
    |`* Re: Datediff scriptJanis Papanagnou
    | `* Re: Datediff scriptcastAway
    |  `* Re: Datediff scriptapplemcg
    |   +- Re: Datediff scriptcastAway
    |   +* Re: Datediff scriptcastAway
    |   |`- Formatting considerations (was Re: Datediff script)Janis Papanagnou
    |   `* Re: Datediff scriptJanis Papanagnou
    |    +- Re: Datediff scriptJanis Papanagnou
    |    +- Re: Datediff scriptapplemcg
    |    `* Re: Datediff scriptapplemcg
    |     +- Re: Datediff scriptJanis Papanagnou
    |     +- Re: Datediff scriptcastAway
    |     `* Re: Datediff scriptcastAway
    |      `- Re: Datediff scriptJanis Papanagnou
    +- Re: Datediff scriptJanis Papanagnou
    `- Re: Datediff scriptcastAway

Pages:123
Re: Datediff script

<tl46mq$2fvu5$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5849&group=comp.unix.shell#5849

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 17 Nov 2022 03:36:09 +0100
Organization: A noiseless patient Spider
Lines: 18
Message-ID: <tl46mq$2fvu5$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tkk621$l9ma$1@dont-email.me>
<tkoep2$1b7q$1@gioia.aioe.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 17 Nov 2022 02:36:10 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="e227ec2413eb6bef2b12cafeaf56588d";
logging-data="2621381"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18KYRwg0V/xIoJ+zibhs6Yj"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:M2pXXRWN+h5IL3IZ2uL5UJXITUE=
In-Reply-To: <tkoep2$1b7q$1@gioia.aioe.org>
 by: Janis Papanagnou - Thu, 17 Nov 2022 02:36 UTC

On 12.11.2022 16:40, castAway wrote:
>
> However, the functionality seems to be very basic:
>
> % $AST/date -E '2002-01-01' '2012-01-01'
> 9Y11M
> % $AST/date -E '12:01:01' '19:02:02'
> 7h01m
> % $AST/date -E '2002-01-01 12:01:01' '2012-01-01 19:01:01'
> 9Y11M

What does it return if you provide ISO dates?

$AST/date -E '2002-01-01T12:01:01' '2012-01-01T19:01:01'

Janis

Re: Datediff script

<tl48o7$2iue4$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5850&group=comp.unix.shell#5850

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 17 Nov 2022 04:11:02 +0100
Organization: A noiseless patient Spider
Lines: 23
Message-ID: <tl48o7$2iue4$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tkk621$l9ma$1@dont-email.me>
<tkoep2$1b7q$1@gioia.aioe.org> <tl46mq$2fvu5$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 17 Nov 2022 03:11:03 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="e227ec2413eb6bef2b12cafeaf56588d";
logging-data="2718148"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19KjZ9VlXKouV6VYKn0f740"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:XtX1efpJDgpR/PzW5s3eevyPdOk=
In-Reply-To: <tl46mq$2fvu5$1@dont-email.me>
X-Enigmail-Draft-Status: N1110
 by: Janis Papanagnou - Thu, 17 Nov 2022 03:11 UTC

On 17.11.2022 03:36, Janis Papanagnou wrote:
> On 12.11.2022 16:40, castAway wrote:
>>
>> However, the functionality seems to be very basic:
>>
>> % $AST/date -E '2002-01-01' '2012-01-01'
>> 9Y11M
>> % $AST/date -E '12:01:01' '19:02:02'
>> 7h01m
>> % $AST/date -E '2002-01-01 12:01:01' '2012-01-01 19:01:01'
>> 9Y11M
>
> What does it return if you provide ISO dates?
>
> $AST/date -E '2002-01-01T12:01:01' '2012-01-01T19:01:01'

Nevermind. I found an AST date in some forgotten directory and the
result is the same. Seems we'd need two calls for sub-day accuracy,
and some formatting to create correctly formatted ISO time periods.

> Janis
>

Re: Datediff script

<tl497o$2ivbj$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5851&group=comp.unix.shell#5851

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 17 Nov 2022 04:19:20 +0100
Organization: A noiseless patient Spider
Lines: 31
Message-ID: <tl497o$2ivbj$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tkk621$l9ma$1@dont-email.me>
<tkoep2$1b7q$1@gioia.aioe.org> <tl46mq$2fvu5$1@dont-email.me>
<tl48o7$2iue4$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 17 Nov 2022 03:19:20 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="e227ec2413eb6bef2b12cafeaf56588d";
logging-data="2719091"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/VXnpi+dq/J5iJiIGplXUH"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:vkZ88zQXkY/xmILsbD+LN8bvYuw=
In-Reply-To: <tl48o7$2iue4$1@dont-email.me>
 by: Janis Papanagnou - Thu, 17 Nov 2022 03:19 UTC

On 17.11.2022 04:11, Janis Papanagnou wrote:
> On 17.11.2022 03:36, Janis Papanagnou wrote:
>> On 12.11.2022 16:40, castAway wrote:
>>>
>>> However, the functionality seems to be very basic:
>>>
>>> % $AST/date -E '2002-01-01' '2012-01-01'
>>> 9Y11M
>>> % $AST/date -E '12:01:01' '19:02:02'
>>> 7h01m
>>> % $AST/date -E '2002-01-01 12:01:01' '2012-01-01 19:01:01'
>>> 9Y11M
>>
>> What does it return if you provide ISO dates?
>>
>> $AST/date -E '2002-01-01T12:01:01' '2012-01-01T19:01:01'
>
> Nevermind. I found an AST date in some forgotten directory and the
> result is the same. Seems we'd need two calls for sub-day accuracy,
> and some formatting to create correctly formatted ISO time periods.

And the man page (strelapsed.3) says:

The two largest time units are used, limiting the return value length
to at most 6 characters.

>
>> Janis
>>
>

Re: Datediff script

<tl6oea$8aj$1@gioia.aioe.org>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5852&group=comp.unix.shell#5852

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!aioe.org!svGMjj4JAseXRzIUqGFGng.user.46.165.242.75.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 17 Nov 2022 22:51:05 -0300
Organization: Aioe.org NNTP Server
Message-ID: <tl6oea$8aj$1@gioia.aioe.org>
References: <tkju7j$54v$1@gioia.aioe.org> <tkk621$l9ma$1@dont-email.me>
<tkkfse$1e9d$1@gioia.aioe.org> <tkltmu$sve7$1@dont-email.me>
<tkqqm4$vrv$1@gioia.aioe.org> <tkrjo7$asl$1@gioia.aioe.org>
<tl450e$2frv6$1@dont-email.me>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="8531"; posting-host="svGMjj4JAseXRzIUqGFGng.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Content-Language: pt-BR, en-GB
X-Notice: Filtered by postfilter v. 0.9.2
 by: castAway - Fri, 18 Nov 2022 01:51 UTC

On 11/16/22 23:07, Janis Papanagnou wrote:
> No. The C source function is doing the last step as _binary_ operation
> ... & 7
> which is equivalent here to the _arithmetic_ counterpart
> ... % 8
> that uses the modulo operator (as opposed to bit-wise 'and').

Thanks, I had missed the operator was different! The explanation
could not be any clearer! I did some testing and could not find
differences in results using and not using the floor() function of Ksh.

Re: Datediff script

<tlaivk$37mt8$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5855&group=comp.unix.shell#5855

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 09:42:28 -0300
Organization: A noiseless patient Spider
Lines: 1346
Message-ID: <tlaivk$37mt8$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 12:42:29 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="c8e09f965d0c49b79a6c694f0134c3d4";
logging-data="3398568"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+jJkOXlQXaLdjOKVBdMV98yX/mOza3p+4="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:PFmXI4RDgXAstlsPTTeA5XGNQDE=
In-Reply-To: <tkju7j$54v$1@gioia.aioe.org>
Content-Language: pt-BR, en-GB
 by: castAway - Sat, 19 Nov 2022 12:42 UTC

Hello!

I am afraid to have gone a little over the top. The lunar phase function
was implemented, as well as another function from NetHack to print following
Friday the 13th dates.

Porting the script to Ksh was OK. It was tested with AST Ksh93u+. I understand
one would generally omit Bc code because Ksh has got FP arithmetics already,
but it was left intact so it can run unders Bash. When the script code was
tested in my mobile phone Termux, Zsh emulation of Ksh didn't work because,
I believe, Zsh emulates Ksh88. It was not hard to setopt Zsh options and now
the code works with Zsh as well. The code looks a little clunky, in my
opinion, when it comes to all the hack code spread over about. Ksh93 `superior'
parameter scoping in functions was a litte hard to deal with but hopefully
the script code hacks will work correctly. Ksh code is much faster.

Most advice from c.u.shell was incorporated. There was a regression bug
in which UNIX times were not generated properly, that is now fixed. Improved
$TZ support (there were some out-of-range combinations of $TZ and date
offset which were unaccounted for). The script `calculation code' was
thoroughly tested in Ksh (see links for testing scripts in source). Sorry if
there are bugs still present. Specially, the new friday_13th() function
may still need some more work.
I will update it at my GitLab <https://gitlab.com/mountaineerbr/scripts>

I reckon it would be cool to have a shell function to convert UNIX times to
ISO-8601 (and RFC-5322) formats.

Hyroptatyr's C-code dateutils `datediff' is required to validate the script
calculations, that is run when the debug function is set.

Many thanks to all, it meant a whole lot for the code.

#!/usr/bin/env ksh
# datediff.sh - Calculate time ranges between dates
# v0.21 nov/2022 mountaineerbr GPLv3+
[[ $BASH_VERSION ]] && shopt -s extglob #bash2.05b+/ksh93u+/zsh5+
[[ $ZSH_VERSION ]] && setopt KSH_GLOB KSH_ARRAYS SH_WORD_SPLIT

HELP="NAME
${0##*/} - Calculate time ranges/intervals between dates


SYNOPSIS
${0##*/} [-NUM] [-Rrttuvvv] [-f\"FMT\"] \"DATE1\" \"DATE2\" [UNIT]
${0##*/} -FF [-vv] [[DAY_IN_WEEK] [DAY_IN_MONTH]] [START_DATE]
${0##*/} -e [-v] YEAR..
${0##*/} -l [-v] YEAR..
${0##*/} -m [-v] DATE..
${0##*/} -h


DESCRIPTION
Calculate time interval (elapsed) between DATE1 and DATE2 in var-
ious time units. The \`date' programme is optionally run to process
dates.

Other functions include checking if YEAR is leap, Easter date on
a given YEAR and phase of the moon at DATE.

In the main function, \`GNU date' accepts mostly free format human
readable date strings. If using \`FreeBSD date', input DATE strings
must be ISO-8601, \`YYYY-MM-DDThh:mm:ss' unless option \`-f FMT' is
set to a new input time format. If \`date' programme is not avail-
able then input must be ISO-8601 formatted.

If DATE is not set, defaults to \`now'. To flag DATE as UNIX time,
prepend an at sign \`@' to it or set option -r. Stdin input sup-
ports one DATE string per line (max two lines) or two ISO-8601
DATES separated by space in a single line. Input is processed in
a best effort basis.

Output RANGES section displays intervals in different units of
time (years or months or weeks or days or hours or minutes or
seconds alone). It also displays a compound time range with all
the above units into consideration to each other.

Single UNIT time periods can be displayed in table format -t and
their scale set with -NUM where NUM is an integer. Result least
significant digit is subject to rounding. When last positional
parameter UNIT is exactly one of \`Y', \`MO', \`W', \`D', \`H',
\`M' or \`S', only a single UNIT interval is printed.

Output DATE section prints two dates in ISO-8601 format or, if
option -R is set, RFC-5322 format.

Option -e prints Easter date for given YEARs (for western churches).

Option -u sets or prints dates in Coordinated Universal Time (UTC)
in the main function.

Option -l checks if YEAR is leap. Set option -v to decrease ver-
bose. ISO-8601 system assumes proleptic Gregorian calendar, year
zero and no leap seconds.

Option -m prints lunar phase at DATE as \`YYYY[-MM[-DD]]', auto
expansion takes place on partial DATE input. DATE ought to be UTC
time. Code snippet adapted from NetHack.

Option -F prints the date of next Friday the 13th, START_DATE must
be formated as \`YYY[-MM[-DD]]'. Set twice to prints the following
10 matches. Optionally, set a day in the week, such as Sunday, and
a month day number as first and second positional parameters.

ISO-8601 DATE offset is supported throughout this script. When
environment \$TZ is a positive or negative decimal number, such
as \`UTC+3', it is read as offset. Variable \$TZ with timezone name
or ID (e.g. \`America/Sao_Paulo') is supported by \`date' programme.

This script uses Bash/Ksh arithmetics to perform most time range
calculations, as long as input is a valid ISO-8601 date format.

Option -d sets \$TZ=UTC, unsets verbose switches and run checks
against C-code \`datediff' and \`date' (dump only when results
differ), set twice to code exit only.

Option -D disables \`date' package warping and -DD disables Bash/
Ksh \`printf %()T' warping, too.


ENVIRONMENT
TZ Offset time. POSIX time zone definition by the \$TZ vari-
able takes a different form from ISO-8601 standards, so
that ISO UTC-03 is equivalent to setting \$TZ=UTC+03. Only
the \`date' programme can parse timezone names and IDS.


REFINEMENT RULES
Some date intervals can be calculated in more than one way depend-
ing on the logic used in the \`compound time range' display. We
decided to mimic hroptatyr's \`datediff' refinement rules as often
as possible.

Script error rate of the core code is estimated to be lower than
one percent after extensive testing with selected and corner-case
sample dates and times. Check script source code for details.


SEE ALSO
\`Datediff' from \`dateutils', by Hroptatyr.
<www.fresse.org/dateutils/>

\`Units' from GNU.
<https://www.gnu.org/software/units/>

Do calendrical savants use calculation to answer date questions?
A functional magnetic resonance imaging study, Cowan and Frith, 2009.
<https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2677581/#!po=21.1864>

Calendrical calculation, Dershowitz and Reingold, 1990
<http://www.cs.tau.ac.il/~nachum/papers/cc-paper.pdf>
<https://books.google.com.br/books?id=DPbx0-qgXu0C>

How many days are in a year? Manning, 1997.
<https://pumas.nasa.gov/files/04_21_97_1.pdf>

Iana Time zone database
<https://www.iana.org/time-zones>

Fun with Date Arithmetic (see replies)
<https://linuxcommando.blogspot.com/2009/11/fun-with-date-arithmetic.html>

Tip: Division is but subtractions and multiplication but additions.
--Lost reference


WARRANTY
Licensed under the GNU General Public License 3 or better. This
software is distributed without support or bug corrections. Many
thanks for all whose advice improved this script from c.u.shell.

Bash2.05b+ or Ksh93u+ is required. \`Bc' or Ksh is required for
single-unit calculations. FreeBSD12+ or GNU \`date' is option-
ally required.


EXAMPLES
Leap year check
$ ${0##*/} -l 2000
$ ${0##*/} -l {1980..2000}
$ echo 2000 | ${0##*/} -l

Moon phases for January 1996
$ ${0##*/} -m 1996-01

Print following Friday, 13th
$ ${0##*/} -F
Print following Sunday, 12th after 1999
$ ${0##*/} -F sun 12 1999

Single unit time periods
$ ${0##*/} 2022-03-01T00:00:00 2022-03-01T10:10:10 m #(m)ins
$ ${0##*/} '10 years ago' mo #(mo)nths
$ ${0##*/} 1970-01-01 2000-02-02 y #(y)ears

Time ranges/intervals
$ ${0##*/} 2020-01-03T14:30:10 2020-12-24T00:00:00
$ ${0##*/} 0921-04-12 1999-01-31
$ echo 1970-01-01 2000-02-02 | ${0##*/}
$ TZ=UTC+3 ${0##*/} 2020-01-03T14:30:10-06 2021-12-30T21:00:10-03:20

\`GNU date' warping
$ ${0##*/} 'next monday'
$ ${0##*/} 2019/6/28 1Aug
$ ${0##*/} '5min 34seconds'
$ ${0##*/} 1aug1990-9month now
$ ${0##*/} -- -2week-3day
$ ${0##*/} -- \"today + 1day\" @1952292365
$ ${0##*/} -2 -- '1hour ago 30min ago'
$ ${0##*/} today00:00 '12 May 2020 14:50:50'
$ ${0##*/} '2020-01-01 - 6months' 2020-01-01
$ ${0##*/} '05 jan 2005' 'now - 43years -13 days'
$ ${0##*/} @1561243015 @1592865415

\`BSD date' warping
$ ${0##*/} -f'%m/%d/%Y' 6/28/2019 9/04/1970
$ ${0##*/} -r 1561243015 1592865415
$ ${0##*/} 200002280910.33 0003290010.00
$ ${0##*/} -- '-v +2d' '-v -3w'


OPTIONS
-[0-9] Set scale for single unit intervals.
-DDdd Debug, check help page.
-e Print Western Easter date.
-FF Print following Friday the 13th date.
-f FMT Input time format string (only with BSD \`date').
-h Print this help page.
-l Check if YEAR is leap year.
-m Print lunar phase at DATE (ISO UTC time).
-R Print human time in RFC-5322 format (verbose).
-r, -@ Input DATES are UNIX times.
-tt Table layout display of single unit intervals.
-u Set or print UTC time instead of local time.
-vvv Verbose level, change print layout of functions."

#TESTING RESULTS
#!# MAIN TESTING SCRIPT: <https://pastebin.com/suw4Bif3>
# Hroptatyr's `man datediff' says ``refinement rules'' cover over 99% cases.
# Calculated C-code `datediff' error rate is at least 0.26% of total tested dates (compound range).
# Results differ from C-code `datediff' in the ~0.6% of all tested dates in script v0.21 (compound range).
# All differences occur with ``end-of-month vs. start-of-month'' dates, such as days `29, 30 or 31' of one date against days `1, 2 or 3' of the other date.
# Different results from C-code `datediff' in compound range are not necessarily errors in all cases and may be considered correct albeit with different refinements. This seems to be the case for most, if not all, other differences obtained in testing results.
# A bug was fixed in v0.20 in which UNIX time generationw was affected. No errors were found in range (seconds) calculation since.
#!# OFFSET AND $TZ TESTING SCRIPT: <https://pastebin.com/ZXnHLrY8>
# Note `datediff' offset ranges between -14h and +14h.
# Offset-aware date results passed checking against `datediff' as of v0.21.
#Ksh exec time is ~2x faster than Bash (main function).

#NOTES
##Time zone / Offset support
#dbplunkett: <https://stackoverflow.com/questions/38641982/converting-date-between-timezones-swift>
#-00:00 and +24:00 are valid and should equal to +00:00; however -0 is denormal;
#support up to `seconds' for time zone adjustment; POSIX time does not
#account for leap seconds; POSIX time zone definition by the $TZ variable
#takes a different form from ISO8601 standards; environment $TZ applies to both dates;
#it is easier to support OFFSET instead of TIME ZONE; should not support
#STD (standard) or DST (daylight saving time) in timezones, only offsets;
# America/Sao_Paulo is a TIMEZONE ID, not NAME; `Pacific Standard Time' is a tz name.
#<https://stackoverflow.com/questions/3010035/converting-a-utc-time-to-a-local-time-zone-in-java>
#<https://www.iana.org/time-zones>, <https://www.w3.org/TR/NOTE-datetime>
#<https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html>
##A year zero does not exist in the Anno Domini (AD) calendar year system
#commonly used to number years in the Gregorian calendar (nor in its
#predecessor, the Julian calendar); in this system, the year 1 BC is
#followed directly by year AD 1. However, there is a year zero in both
#the astronomical year numbering system (where it coincides with the
#Julian year 1 BC), and the ISO 8601:2004 system, the interchange standard
#for all calendar numbering systems (where year zero coincides with the
#Gregorian year 1 BC). In Proleptic Gregorian calendar, year 0000 is leap.
#<https://docs.julialang.org/en/v1/stdlib/Dates/>
#Serge3leo - https://stackoverflow.com/questions/26861118/rounding-numbers-with-bc-in-bash
#MetroEast - https://askubuntu.com/questions/179898/how-to-round-decimals-using-bc-in-bash
#``Rounding is more accurate than chopping/truncation''.
#https://wiki.math.ntnu.no/_media/ma2501/2016v/lecture1-intro.pdf
##Negative zeros have some subtle properties that will not be evident in
#most programs. A zero exponent with a nonzero mantissa is a "denormal."
#A denormal is a number whose magnitude is too small to be represented
#with an integer bit of 1 and can have as few as one significant bit.
#https://www.lahey.com/float.htm


#globs
SEP='Tt/.:+-'
EPOCH=1970-01-01T00:00:00
GLOBOPT='@(y|mo|w|d|h|m|s|Y|MO|W|D|H|M|S)'
GLOBUTC='*(+|-)@(?([Uu])[Tt][Cc]|?([Uu])[Cc][Tt]|?([Gg])[Mm][Tt]|Z|z)' #see bug ``*?(exp)'' in bash2.05b extglob; [UG] are marked optional for another hack in this script
GLOBTZ="?($GLOBUTC)?(+|-)@(2[0-4]|?([01])[0-9])?(?(:?([0-5])[0-9]|:60)?(:?([0-5])[0-9]|:60)|?(?([0-5])[0-9]|60)?(?([0-5])[0-9]|60))"
GLOBDATE='?(+|-)+([0-9])[/.-]@(1[0-2]|?(0)[1-9])[/.-]@(3[01]|?(0)[1-9]|[12][0-9])'
GLOBTIME="@(2[0-4]|?([01])[0-9]):?(?([0-5])[0-9]|60)?(:?([0-5])[0-9]|:60)?($GLOBTZ)"
#https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html
#custom support for 24h clock and leap second

DAY_OF_WEEK=(Thursday Friday Saturday Sunday Monday Tuesday Wednesday)
MONTH_OF_YEAR=(January February March April May June July August September October November December)
YEAR_MONTH_DAYS=(31 28 31 30 31 30 31 31 30 31 30 31)
TIME_ISO8601_FMT='%Y-%m-%dT%H:%M:%S%z'
TIME_RFC5322_FMT='%a, %d %b %Y %H:%M:%S %z'


# Choose between GNU or BSD date
# datefun.sh [-u|-R|-v[val]|-I[fmt]] [YYY-MM-DD|@UNIX] [+OUTPUT_FORMAT]
# datefun.sh [-u|-R|-v[val]|-I[fmt]]
# By defaults, input should be ISO8601 date or UNIX time (append @).
# Option -I `fmt' may be `date', `hours', `minutes' or `seconds' (added in FreeBSD12).
# Setting environment TZ=UTC is equivalent to -u.
function datefun
{
typeset options unix_input input_fmt globtest ar chars start
input_fmt="${INPUT_FMT:-${TIME_ISO8601_FMT%??}}"
[[ $1 = -[RIv]* ]] && options="$1" && shift

if ((BSDDATE))
then globtest="*([$IFS])@($GLOBDATE?([$SEP])?(+([$SEP])$GLOBTIME)|$GLOBTIME)?([$SEP])*([$IFS])"
[[ ! $1 ]] && set --
if [[ $1 = +([0-9])?(.[0-9][0-9]) && ! $OPTF ]] #default fmt [[[[[cc]yy]mm]dd]HH]MM[.ss]
then ${DATE_CMD} ${options} -j "$@" && return
elif [[ $1 = $globtest && ! $OPTF ]] #ISO8601 variable length
then ar=(${1//[$SEP]/ })
[[ ${1//[$IFS]} = +([0-9])[:]* ]] && start=9 || start=0
((chars=(${#ar[@]}*2)+(${#ar[@]}-1) ))
${DATE_CMD} ${options} -j -f "${TIME_ISO8601_FMT:start:chars}" "${@/$GLOBUTC}" && return
fi
[[ ${1:-+%} != @(+%|@|-f)* ]] && set -- -f"${input_fmt}" "$@"
[[ $1 = @* ]] && set -- "-r${1#@}" "${@:2}"
${DATE_CMD} ${options} -j "$@"
else
[[ ${1:-+%} != @(+%|-d)* ]] && set -- -d"${unix_input}${1}" "${@:2}"
${DATE_CMD} ${options} "$@"
fi
}

#leap fun
function is_leapyear
{
((!($1 % 4) && ($1 % 100 || !($1 % 400) ) ))
}

#print the maximum number of days of a given month
#usage: month_maxday [MONTH] [YEAR]
#MONTH range 1-12; YEAR cannot be nought.
function month_maxday
{
typeset month year
month="$1" year="$2"
if ((month==2)) && is_leapyear $year
then echo 29
else echo ${YEAR_MONTH_DAYS[month-1]}
fi
}

#year days, leap years only if date1's month is before or at feb.
function year_days_adj
{
typeset month year
month="$1" year="$2"
if ((month<=2)) && is_leapyear $year
then echo 366
else echo 365
fi
}

#check if input is an integer year
function is_year
{
if [[ $1 = +([0-9]) ]]
then return 0
else printf 'err: year must be in the format YYYY -- %s\n' "$1" >&2
fi
return 1
}

#verbose check if year is leap
function is_leapyear_verbose
{
typeset year
year="$1"
if is_leapyear $year
then ((OPTVERBOSE)) || printf 'leap year -- %04d\n' $year
else ((OPTVERBOSE)) || printf 'not leap year -- %04d\n' $year
false
fi
}
#https://stackoverflow.com/questions/32196629/my-shell-script-for-checking-leap-year-is-showing-error

#check Easter date in a given year
function easterf
{
echo ${*:?year required} '[ddsf[lfp[too early
]Pq]s@1583>@
ddd19%1+sg100/1+d3*4/12-sx8*5+25/5-sz5*4/lx-10-sdlg11*20+lz+lx-30%
d[30+]s@0>@d[[1+]s@lg11<@]s@25=@d[1+]s@24=@se44le-d[30+]s@21>@dld+7%-7+
[March ]smd[31-[April ]sm]s@31<@psnlmPpsn1z>p]splpx' | dc
}
#Dershowitz' and Reingold' Calendrical Calculations book

#get day in the week
#usage: get_day_in_week unix_time
function get_day_in_week
{
echo ${DAY_OF_WEEK[( ( ($1+($1<0?1:0))/(24*60*60))%7 +($1<0?6:7))%7]}
}

#get day in the year
#usage: get_day_in_year year month day
function get_day_in_year
{
typeset day month year month_test daysum
day="${1#0}" month="${2#0}" year="${3##+(0)}"
for ((month_test=1;month_test<month;++month_test))
do ((daysum+=$(month_maxday "$month_test" "$year")))
done
echo $((day+daysum))
}

#return phase of the moon, use UTC time
#usage: phase_of_the_moon year [month] [day]
function phase_of_the_moon #0-7, with 0: new, 4: full
{
typeset day month year diy goldn epact
day="${1#0}" month="${2#0}" year="${3##+(0)}"
day=${day:-1} month=${month:-1} year=${year:-0}

diy=$(get_day_in_year "$day" "$month" "$year")
((goldn = (year % 19) + 1))
((epact = (11 * goldn + 18) % 30))
(((epact == 25 && goldn > 11) || epact == 24 )) && ((epact++))

case $(( ( ( ( ( (diy + epact) * 6) + 11) % 177) / 22) & 7)) in
0) set -- 'New Moon' ;; #.0
1) set -- 'Waxing Crescent' ;;
2) set -- 'First Quarter' ;; #.25
3) set -- 'Waxing Gibbous' ;;
4) set -- 'Full Moon' ;; #.5
5) set -- 'Waning Gibbous' ;;
6) set -- 'Last Quarter' ;; #.75
7) set -- 'Waning Crescent' ;;
esac
#Bash's integer division truncates towards zero, as in C.
[[ $*${OPTM#2} = $PHASE_SKIP ]] && return || PHASE_SKIP="$*"
if ((OPTVERBOSE))
then printf '%s\n' "$*"
else printf '%04d-%02d-%02d %s\n' "$year" "$month" "$day" "$*"
fi
}
#<https://nethack.org/>
#<https://aa.usno.navy.mil/data/MoonPhases>
#<https://aa.usno.navy.mil/faq/moon_phases>
#<http://astropixels.com/ephemeris/phasescat/phases1901.html>
#<https://www.nora.ai/competition/fishai-dataset-competition/about-the-dataset/>
#<https://www.kaggle.com/datasets/lsind18/full-moon-calendar-1900-2050>
#<https://www.fullmoon.info/en/fullmoon-calendar_1900-2050.html>

#get current time
#usage: get_timef [unix_time] [print_format]
function get_timef
{
typeset fmt
fmt="${2:-${TIME_ISO8601_FMT}}"
if ((OPTDD))
then echo $EPOCH ;false
elif [[ $ZSH_VERSION ]]
then zmodload -aF zsh/datetime b:strftime && strftime "$fmt" $1
else printf "%(${fmt})T\n" ${BASH_VERSION:+${1:--1}}
fi
}

#get friday 13th dates
#usage: friday_13th [weekday_name] [day] [start_year]
function friday_13th
{
typeset dow_name d_tgt diw_tgt day month year unix diw maxday skip n
dow_name=("${DAY_OF_WEEK[@]}") ;DAY_OF_WEEK=(0 1 2 3 4 5 6)

#set day of week and day of month
[[ $2 = [SsMmTtWwFf]* && $1 = ?([0-3])[0-9] ]] && set -- "$2" "$1" "${@:3}"
if [[ $1 = [SsMmTtWwFf]* && $2 = ?([0-3])[0-9] ]]
then case $1 in
[Ss][Aa]*) diw_tgt=${DAY_OF_WEEK[2]};;
[Ff]*) diw_tgt=${DAY_OF_WEEK[1]};;
[Tt]*) diw_tgt=${DAY_OF_WEEK[0]};;
[Ww]*) diw_tgt=${DAY_OF_WEEK[6]};;
[Tt][Uu]*) diw_tgt=${DAY_OF_WEEK[5]};;
[Mm]*) diw_tgt=${DAY_OF_WEEK[4]};;
[Ss]*) diw_tgt=${DAY_OF_WEEK[3]};;
esac
d_tgt=$2 ;shift 2
fi ;diw_tgt=${diw_tgt:-1} d_tgt=${d_tgt:-13}

[[ $1 ]] || set -- $(get_timef) ;set -- ${*//[$SEP]/ }
day="${3#0}" month="${2#0}" year="${1##+(0)}"
day="${day:-1}" month="${month:-1}" year="${year:-0}"

unix=$(GETUNIX=1 OPTVERBOSE=1 OPTRR= TZ=UTC \
mainf $EPOCH ${year}-${month}-${day}) || return $?

while diw=$(get_day_in_week $((unix+(d_away*24*60*60) )) )
do if ((diw==diw_tgt && day==d_tgt))
then if ((!(d_away+OPTVERBOSE+OPTFF-1) ))
then printf "%s, %02d %s %04d is today!\n" \
"${dow_name[diw_tgt]:0:3}" "$day" "${MONTH_OF_YEAR[month-1]:0:3}" "$year"
elif ((OPTVERBOSE))
then printf "%04d-%02d-%02d\n" "$year" "$month" "$day"
else printf "%s, %02d %s %04d is %4d days ahead\n" \
"${dow_name[diw_tgt]:0:3}" "$day" "${MONTH_OF_YEAR[month-1]:0:3}" "$year" "$d_away"
fi
((++n))
((OPTFF==1||(OPTFF==2&&n>=10) )) && break
fi
maxday=$(month_maxday $month $year)
if ((day<d_tgt))
then ((d_away=d_tgt-day, day=d_tgt, skip=1))
elif ((day>d_tgt))
then ((d_away=(maxday-day+d_tgt), day=d_tgt))
else ((d_away+=maxday))
fi
if ((!skip))
then ((month==12)) && ((++year))
((month=(month==12?1:month+1) ))
fi ;skip=
done
}

#printing helper
#(A). check if floating point in $1 is `>0', set return signal and $SS to `s' when `>1.0'.
#usage: prHelpf 1.23
#(B). set padding of $1 length until [max] chars and set $SSS.
#usage: prHelpf 1.23 [max]
function prHelpf
{
typeset val valx int dec x z
#(B)
if (($#>1))
then SSS= x=$(( ${2} - ${#1} ))
for ((z=0;z<x;++z))
do SSS="$SSS "
done
fi

#(A)
SS= val=${1#-} val=${val#0} valx=${val//[0.]} int=${val%.*}
[[ $val = *.* ]] && dec=${val#*.} dec=${dec//0}
[[ $1 && $OPTT ]] || ((valx)) || return
(( int>1 || ( (int==1) && (dec) ) )) && SS=s
return 0
}

#datediff fun
function mainf
{
${DEBUG:+unset} typeset date1_iso8601 date2_iso8601 unix1 unix2 inputA inputB range neg_range yearA monthA dayA hourA minA secA tzA neg_tzA tzAh tzAm tzAs yearB monthB dayB hourB minB secB tzB neg_tzB tzBh tzBm tzBs years_between y_test leapcount daycount_leap_years daycount_years fullmonth_days fullmonth_days_save monthcount month_test month_tgt d1_mmd d2_mmd date1_month_max_day date3_month_max_day date1_year_days_adj d_left y mo w d h m s bc bcy bcmo bcw bcd bch bcm range_pr sh d_left_save d_sum date1_iso8601_pr date2_iso8601_pr yearAtz monthAtz dayAtz hourAtz minAtz secAtz yearBtz monthBtz dayBtz hourBtz minBtz secBtz yearAprtz monthAprtz dayAprtz hourAprtz minAprtz secAprtz yearBprtz monthBprtz dayBprtz hourBprtz minBprtz secBprtz range_check now badges date1_diw date2_diw prfmt varname buf var ok ar ret n p q r v TZh TZm TZs TZ_neg TZ_pos spcr #SS SSS

(($# == 1)) && set -- '' "$1"

#warp `date' when available
if unix1=$(datefun "${1:-+%s}" ${1:++%s}) &&
unix2=$(datefun "${2:-+%s}" ${2:++%s})
then ((GETUNIX)) && { echo $((unix1+unix2)) ;unset GETUNIX ;return ${ret:-0} ;}
#sort dates
if ((unix1 > unix2))
then buf=$unix2 unix2=$unix1 unix1=$buf neg_range=-1
set -- "$2" "$1" "${@:3}"
fi
{
date1_iso8601=$(datefun -Iseconds @"$unix1")
date2_iso8601=$(datefun -Iseconds @"$unix2")
if [[ ! $OPTVERBOSE && $OPTRR ]]
then date1_iso8601_pr=$(datefun -R @"$unix1")
date2_iso8601_pr=$(datefun -R @"$unix2")
fi
} 2>/dev/null #avoid printing errs from FreeBSD<12 `date'
else unset unix1 unix2
#set default date -- AD
[[ ! $1 || ! $2 ]] && now=$(get_timef)
[[ ! $1 ]] && { set -- "${now}" "${@:2}" ;date1_iso8601="$now" ;}
[[ ! $2 ]] && { set -- "$1" "${now}" "${@:3}" ;date2_iso8601="$now" ;}
fi

#load ISO8601 dates from `date' or user input
inputA="${date1_iso8601:-$1}" inputB="${date2_iso8601:-$2}"
if [[ ! $unix2 ]] #time only input, no `date' pkg available
then [[ $inputA = *([0-9]):* ]] && inputA="${EPOCH:0:10}T${inputA}"
[[ $inputB = *([0-9]):* ]] && inputB="${EPOCH:0:10}T${inputB}"
fi
IFS="${IFS}${SEP}UuGgZz" read yearA monthA dayA hourA minA secA tzA <<<"${inputA##*(+|-)}"
IFS="${IFS}${SEP}UuGgZz" read yearB monthB dayB hourB minB secB tzB <<<"${inputB##*(+|-)}"
IFS="${IFS}${SEP/[Tt]}" read tzAh tzAm tzAs var <<<"${tzA##?($GLOBUTC?(+|-)|[+-])}"
IFS="${IFS}${SEP/[Tt]}" read tzBh tzBm tzBs var <<<"${tzB##?($GLOBUTC?(+|-)|[+-])}"
IFS="${IFS}${SEP/[Tt]}" read TZh TZm TZs var <<<"${TZ##?($GLOBUTC?(+|-)|[+-])}"

#fill in some defaults
monthA=${monthA:-1} dayA=${dayA:-1} monthB=${monthB:-1} dayB=${dayB:-1}
#support offset as `[+-]XXXX??'
[[ $tzAh = [0-9][0-9][0-9][0-9]?([0-9][0-9]) ]] \
&& tzAs=${tzAh:4:2} tzAm=${tzAh:2:2} tzAh=${tzAh:0:2}
[[ $tzBh = [0-9][0-9][0-9][0-9]?([0-9][0-9]) ]] \
&& tzBs=${tzBh:4:2} tzBm=${tzBh:2:2} tzBh=${tzBh:0:2}
[[ ${TZh} = [0-9][0-9][0-9][0-9]?([0-9][0-9]) ]] \
&& TZs=${TZh:4:2} TZm=${TZh:2:2} TZh=${TZh:0:2}

#set parameters as decimals ASAP
for varname in yearA monthA dayA hourA minA secA \
yearB monthB dayB hourB minB secB \
tzAh tzAm tzAs tzBh tzBm tzBs TZh TZm TZs
do eval "[[ \${$varname} = *[A-Za-z_]* ]] && continue" #avoid printing errs
eval "(($varname=\${$varname//[!+-]}10#0\${$varname#[+-]}))"
done

#negative years
[[ $inputA = -?* ]] && yearA=-$yearA
[[ $inputB = -?* ]] && yearB=-$yearB
#
#iso8601 date string offset
[[ ${inputA%"${tzA##?($GLOBUTC?(+|-)|[+-])}"} = *?- ]] && neg_tzA=-1 || neg_tzA=+1
[[ ${inputB%"${tzB##?($GLOBUTC?(+|-)|[+-])}"} = *?- ]] && neg_tzB=-1 || neg_tzB=+1
((tzAh==0 && tzAm==0 && tzAs==0)) && neg_tzA=+1
((tzBh==0 && tzBm==0 && tzBs==0)) && neg_tzB=+1
#
#environment $TZ
[[ ${TZ##*$GLOBUTC} = -?* ]] && TZ_neg=-1 || TZ_neg=+1
((TZh==0 && TZm==0 && TZs==0)) && TZ_neg=+1
((TZ_neg<0)) && TZ_pos=+1 || TZ_pos=-1
[[ $TZh$TZm$TZs = *([0-9+-]) && ! $unix2 ]] || unset TZh TZm TZs

#24h clock and input leap second support (these $tz* parameters will be zeroed later)
((hourA==24)) && (( (neg_tzA>0 ? (tzAh-=hourA-23) : (tzAh+=hourA-23) ) , (hourA-=hourA-23) ))
((hourB==24)) && (( (neg_tzB>0 ? (tzBh-=hourB-23) : (tzBh+=hourB-23) ) , (hourB-=hourB-23) ))
((minA==60)) && (( (neg_tzA>0 ? (tzAm-=minA-59) : (tzAm+=minA-59) ) , (minA-=minA-59) ))
((minB==60)) && (( (neg_tzB>0 ? (tzBm-=minB-59) : (tzBm+=minB-59) ) , (minB-=minB-59) ))
((secA==60)) && (( (neg_tzA>0 ? (tzAs-=secA-59) : (tzAs+=secA-59) ) , (secA-=secA-59) ))
((secB==60)) && (( (neg_tzB>0 ? (tzBs-=secB-59) : (tzBs+=secB-59) ) , (secB-=secB-59) ))
#CHECK SCRIPT `GLOBS', TOO, as they may fail with weyrd dates and formats.

#check input validity
d1_mmd=$(month_maxday "$monthA" "$yearA") ;d2_mmd=$(month_maxday "$monthB" "$yearB")
if ! (( (yearA||yearA==0) && (yearB||yearB==0) && monthA && monthB && dayA && dayB )) ||
((
monthA>12 || monthB>12 || dayA>d1_mmd || dayB>d2_mmd
|| hourA>23 || hourB>23 || minA>59 || minB>59 || secA>59 || secB>59
))
then echo "err: illegal user input -- ISO-8601 DATE required" >&2 ;return 2
fi

#offset and $TZ support
if ((tzAh||tzAm||tzAs||tzBh||tzBm||tzBs||TZh||TZm||TZs))
then #check validity
if ((tzAh>24||tzBh>24||tzAm>60||tzBm>60||tzAs>60||tzBs>60))
then echo "warning: illegal offsets" >&2
unset tzA tzB tzAh tzAm tzAs tzBh tzBm tzBs
fi
if ((TZh>23||TZm>59||TZs>59))
then echo "warning: illegal environment \$TZ" >&2
unset TZh TZm TZs
fi #offset specs:
#<https://www.w3.org/TR/NOTE-datetime>
#<https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html>

#environment $TZ support #only for printing
if ((!OPTVERBOSE)) && ((TZh||TZm||TZs))
then ((hourAprtz-=(TZh*TZ_neg), minAprtz-=(TZm*TZ_neg), secAprtz-=(TZs*TZ_neg) ))
((hourBprtz-=(TZh*TZ_neg), minBprtz-=(TZm*TZ_neg), secBprtz-=(TZs*TZ_neg) ))
[[ ! $tzA ]] && ((tzAh-=(TZh*TZ_neg), tzAm-=(TZm*TZ_neg), tzAs-=(TZs*TZ_neg) ))
[[ ! $tzB ]] && ((tzBh-=(TZh*TZ_neg), tzBm-=(TZm*TZ_neg), tzBs-=(TZs*TZ_neg) ))
else unset TZh TZm TZs
fi

#convert dates to UTC for internal range calculations
((tzAh||tzAm||tzAs)) && var="A" || var=""
((tzBh||tzBm||tzBs)) && var="$var B"
((TZh||TZm||TZs)) && var="$var A.pr B.pr"
for v in $var #A B A.pr B.pr
do
[[ $v = ?.* ]] && p=${v#*.} v=${v%.*} || p=

#secAtz secBtz secAprtz secBprtz
((sec${v}${p}tz=sec${v}-(tz${v}s*neg_tz${v}) )) #neg_tzA neg_tzB
if ((sec${v}${p}tz<0))
then ((min${v}${p}tz+=((sec${v}${p}tz-59)/60) , sec${v}${p}tz=(sec${v}${p}tz%60+60)%60))
elif ((sec${v}${p}tz>59))
then ((min${v}${p}tz+=(sec${v}${p}tz/60) , sec${v}${p}tz%=60))
fi

#minAtz minBtz minAprtz minBprtz
((min${v}${p}tz+=min${v}-(tz${v}m*neg_tz${v}) ))
if ((min${v}${p}tz<0))
then ((hour${v}${p}tz+=((min${v}${p}tz-59)/60) , min${v}${p}tz=(min${v}${p}tz%60+60)%60))
elif ((min${v}${p}tz>59))
then ((hour${v}${p}tz+=(min${v}${p}tz/60) , min${v}${p}tz%=60))
fi

#hourAtz hourBtz hourAprtz hourBprtz
((hour${v}${p}tz+=hour${v}-(tz${v}h*neg_tz${v}) ))
if ((hour${v}${p}tz<0))
then ((day${v}${p}tz+=((hour${v}${p}tz-23)/24) , hour${v}${p}tz=(hour${v}${p}tz%24+24)%24))
elif ((hour${v}${p}tz>23))
then ((day${v}${p}tz+=(hour${v}${p}tz/24) , hour${v}${p}tz%=24))
fi

#dayAtz dayBtz dayAprtz dayBprtz
((day${v}${p}tz+=day${v}))
if ((day${v}${p}tz<1))
then var=$(month_maxday "$((month${v}==1 ? 12 : month${v}-1))" "$((year${v}))")
((day${v}${p}tz+=var))
if ((month${v}>1))
then ((--month${v}${p}tz))
else ((month${v}${p}tz-=month${v}))
fi
elif var=$(month_maxday "$((month${v}))" "$((year${v}))")
((day${v}${p}tz>var))
then ((++month${v}${p}tz))
((day${v}${p}tz%=var))
fi

#monthAtz monthBtz monthAprtz monthBprtz
((month${v}${p}tz+=month${v}))
if ((month${v}${p}tz<1))
then ((--year${v}${p}tz))
((month${v}${p}tz+=12))
elif ((month${v}${p}tz>12))
then ((++year${v}${p}tz))
((month${v}${p}tz%=12))
fi

((year${v}${p}tz+=year${v})) #yearAtz yearBtz yearAprtz yearBprtz
done
#modulus as (a%b + b)%b to avoid negative remainder.
#<https://www.geeksforgeeks.org/modulus-on-negative-numbers/>

if [[ $yearAtz ]]
then (( yearA=yearAtz , monthA=monthAtz , dayA=dayAtz,
hourA=hourAtz , minA=minAtz , secA=secAtz ,
tzAh=0 , tzAm=0 , tzAs=0
))
fi
if [[ $yearBtz ]]
then (( yearB=yearBtz , monthB=monthBtz , dayB=dayBtz,
hourB=hourBtz , minB=minBtz , secB=secBtz ,
tzBh=0 , tzBm=0 , tzBs=0
))
fi

if [[ $yearAprtz ]]
then date1_iso8601_pr=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d:%02d\\n \
"$yearAprtz" "$monthAprtz" "${dayAprtz}" \
"${hourAprtz}" "${minAprtz}" "${secAprtz}" \
"${TZ_pos%1}" "$TZh" "$TZm" "$TZs")
fi
if [[ $yearBprtz ]]
then date2_iso8601_pr=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d:%02d\\n \
"$yearBprtz" "$monthBprtz" "${dayBprtz}" \
"${hourBprtz}" "${minBprtz}" "${secBprtz}" \
"${TZ_pos%1}" "$TZh" "$TZm" "$TZs")
fi

elif [[ ! $unix2$OPTVERBOSE && $tzA$tzB$TZ = *+([A-Za-z_])* ]]
then #echo "warning: input DATE or \$TZ contains timezone ID or name. Support requires package \`date'" >&2
unset tzA tzB tzAh tzBh tzAm tzBm tzAs tzBs TZh TZm TZs
else unset tzA tzB tzAh tzBh tzAm tzBm tzAs tzBs TZh TZm TZs
fi #Offset is *from* UTC, while $TZ is *to* UTC.


#sort `UTC' dates (if no `date' package)
if [[ ! $unix2 ]] && ((
(yearA>yearB)
|| ( (yearA==yearB) && (monthA>monthB) )
|| ( (yearA==yearB) && (monthA==monthB) && (dayA>dayB) )
|| ( (yearA==yearB) && (monthA==monthB) && (dayA==dayB) && (hourA>hourB) )
|| ( (yearA==yearB) && (monthA==monthB) && (dayA==dayB) && (hourA==hourB) && (minA>minB) )
|| ( (yearA==yearB) && (monthA==monthB) && (dayA==dayB) && (hourA==hourB) && (minA==minB) && (secA>secB) )
))
then neg_range=-1
for varname in inputA yearA monthA dayA hourA minA secA \
yearAtz monthAtz dayAtz hourAtz minAtz secAtz \
yearAprtz monthAprtz dayAprtz hourAprtz minAprtz secAprtz \
tzA tzAh tzAm tzAs neg_tzA date1_iso8601 date1_iso8601_pr
do #swap $varA/$varB or $var1/$var2 values
[[ $varname = *A* ]] && p=A q=B || p=1 q=2
eval "buf=\"\$$varname\""
eval "$varname=\"\$${varname/$p/$q}\" ${varname/$p/$q}=\"\$buf\""
done
unset varname p q
set -- "$2" "$1" "${@:3}"
fi


##Count leap years and sum leap and non leap years days,
for ((y_test=(yearA+1);y_test<yearB;++y_test))
do
#((y_test==0)) && continue #ISO8601 counts year zero, proleptic gregorian/julian do not
is_leapyear $y_test && ((++leapcount))
((++years_between))
((monthcount += 12))
done
##count days in non and leap years
(( daycount_leap_years = (366 * leapcount) ))
(( daycount_years = (365 * (years_between - leapcount) ) ))

#date2 days so far this year (this month)
#days in prior months `this' year
((month_tgt = (yearA==yearB ? monthA : 0) ))
for ((month_test=(monthB-1);month_test>month_tgt;--month_test))
do
if ((month_test==2)) && is_leapyear $yearB
then (( fullmonth_days += 29 ))
else (( fullmonth_days += ${YEAR_MONTH_DAYS[month_test-1]} ))
fi
((++monthcount))
done

#date1 days until end of `that' year
#days in prior months `that' year
((yearA==yearB)) ||
for ((month_test=(monthA+1);month_test<13;++month_test))
do
if ((month_test==2)) && is_leapyear $yearA
then (( fullmonth_days += 29 ))
else (( fullmonth_days += ${YEAR_MONTH_DAYS[month_test-1]} ))
fi
((++monthcount))
done
((fullmonth_days_save = fullmonth_days))

#some info about input dates and their context..
date3_month_max_day=$(month_maxday "$((monthB==1 ? 12 : monthB-1))" "$yearB")
date1_month_max_day=$(month_maxday "$monthA" "$yearA")
date1_year_days_adj=$(year_days_adj "$monthA" "$yearA")


#set years and months
(( y = years_between ))
(( mo = ( monthcount - ( (years_between) ? (years_between * 12) : 0) ) ))

#days left
if ((yearA==yearB && monthA==monthB))
then
((d_left = (dayB - dayA) ))
((d_left_save = d_left))
elif ((dayA<dayB))
then
((++mo))
((fullmonth_days += date1_month_max_day))
((d_left = (dayB - dayA) ))
((d_left_save = d_left))
elif ((dayA>dayB))
then #refinement rules (or hacks)
((d_left = ( (date3_month_max_day>=dayA) ? (date3_month_max_day-dayA) : (date1_month_max_day-dayA) ) + dayB ))
((d_left_save = (date1_month_max_day-dayA) + dayB ))
if ((dayA>date3_month_max_day && date3_month_max_day<date1_month_max_day && dayB>1))
then
((dayB>=dayA-date3_month_max_day)) && ##addon2 -- prevents negative days
((d_left -= date1_month_max_day-date3_month_max_day))
((d_left==0 && ( (24-hourA)+hourB<24 || ( (24-hourA)+hourB==24 && (60-minA)+minB<60 ) || ( (24-hourA)+hourB==24 && (60-minA)+minB==60 && (60-secA)+secB<60 ) ) && (++d_left) )) ##addon3 -- prevents breaking down a full month
if ((d_left < 0))
then if ((w))
then ((--w , d_left+=7))
elif ((mo))
then ((--mo , w=date3_month_max_day/7 , d_left+=date3_month_max_day%7))
elif ((y))
then ((--y , mo+=11 , w=date3_month_max_day/7 , d_left+=date3_month_max_day%7))
fi
fi
elif ((dayA>date3_month_max_day)) #dayB==1
then
((d_left = (date1_month_max_day - dayA + date3_month_max_day + dayB) ))
((w = d_left/7 , d_left%=7))
if ((mo))
then ((--mo))
elif ((y))
then ((--y , mo+=11))
fi
fi
else #`dayA' equals `dayB'
((++mo))
((fullmonth_days += date1_month_max_day))
#((d_left_save = d_left)) #set to 0
fi


((h += (24-hourA)+hourB))
if ((h && h<24))
then if ((d_left))
then ((--d_left , ++ok))
elif ((mo))
then ((--mo , d_left+=date3_month_max_day-1 , ++ok))
elif ((y))
then ((--y , mo+=11 , d_left+=date3_month_max_day-1 , ++ok))
fi
fi
((h %= 24))

((m += (60-minA)+minB))
if ((m && m<60))
then if ((h))
then ((--h))
elif ((d_left))
then ((--d_left , h+=23 , ++ok))
elif ((mo))
then ((--mo , d_left+=date3_month_max_day-1 , h+=23 , ++ok))
elif ((y))
then ((--y , mo+=11 , d_left+=date3_month_max_day-1 , h+=23 , ++ok))
fi
fi
((m %= 60))

((s = (60-secA)+secB))
if ((s && s<60))
then if ((m))
then ((--m))
elif ((h))
then ((--h , m+=59))
elif ((d_left))
then ((--d_left , h+=23 , m+=59 , ++ok))
elif ((mo))
then ((--mo , d_left+=date3_month_max_day-1 , h+=23 , m+=59 , ++ok))
elif ((y))
then ((--y , mo+=11 , d_left+=date3_month_max_day-1 , h+=23 , m+=59 , ++ok))
fi
fi
((s %= 60))
((ok && (--d_left_save) ))

((m += s/60 , s %= 60))
((h += m/60 , m %= 60))
((d_left_save += h/24))
((d_left += h/24 , h %= 24))
((y += mo/12 , mo %= 12))
((w += d_left/7))
((d = d_left%7))


#total sum of full days { range = unix2-unix1 }
((d_sum = ( (d_left_save) + (fullmonth_days + daycount_years + daycount_leap_years) ) ))
((range = (d_sum * 3600 * 24) + (h * 3600) + (m * 60) + s))

#generate unix times arithmetically?
((GETUNIX)) && { echo ${neg_range%1}${range} ;unset GETUNIX ;return ${ret:-0} ;}
if [[ ! $unix2 ]]
then badges="$badges#"
if ((
(yearA>1970 ? yearA-1970 : 1970-yearA)
> (yearB>1970 ? yearB-1970 : 1970-yearB)
))
then var=$yearB-$monthB-${dayB}T$hourB:$minB:$secB varname=B #utc times
else var=$yearA-$monthA-${dayA}T$hourA:$minA:$secA varname=A
fi

var=$(GETUNIX=1 DATE_CMD=false OPTVERBOSE=1 OPTRR= TZ= \
mainf $EPOCH $var) || ((ret+=$?))

if [[ $varname = B ]]
then ((unix2=var , unix1=unix2-range))
else ((unix1=var , unix2=unix1+range))
fi

if ((OPTRR)) #make RFC-5322 format string
then if ! { date2_iso8601_pr=$(get_timef "$unix2" "$TIME_RFC5322_FMT") &&
date1_iso8601_pr=$(get_timef "$unix1" "$TIME_RFC5322_FMT") ;}
then #calculate Day Of Week (bash v<3.1)
date2_diw=$(get_day_in_week $((unix2-( ( (TZh*60*60)+(TZm*60)+TZs)*TZ_neg) )) )
date1_diw=$(get_day_in_week $((unix1-( ( (TZh*60*60)+(TZm*60)+TZs)*TZ_neg) )) )
date2_iso8601_pr=$(printf \
'%s, %02d %s %04d %02d:%02d:%02d %s%02d:%02d:%02d\n' \
"${date2_diw:0:3}" "${dayBprtz:-${dayBtz:-$dayB}}" \
"${MONTH_OF_YEAR[${monthBprtz:-${monthBtz:-$monthB}}-1]:0:3}" \
"${yearBprtz:-${yearBtz:-$yearB}}" \
"${hourBprtz:-${hourBtz:-$hourB}}" \
"${minBprtz:-${minBtz:-$minB}}" \
"${secBprtz:-${secBtz:-$secB}}" \
"${TZ_pos%1}" "$TZh" "$TZm" "$TZs")
date1_iso8601_pr=$(printf \
'%s, %02d %s %04d %02d:%02d:%02d %s%02d:%02d:%02d\n' \
"${date1_diw:0:3}" "${dayAprtz:-${dayAtz:-$dayA}}" \
"${MONTH_OF_YEAR[${monthAprtz:-${monthAtz:-$monthA}}-1]:0:3}" \
"${yearAprtz:-${yearAtz:-$yearA}}" \
"${hourAprtz:-${hourAtz:-$hourA}}" \
"${minAprtz:-${minAtz:-$minA}}" \
"${secAprtz:-${secAtz:-$secA}}" \
"${TZ_pos%1}" "$TZh" "$TZm" "$TZs")
fi
fi
fi

#single unit time durations (when `bc' is available)
if ((OPTT || OPTVERBOSE<3))
then if [[ $BASH_VERSION ]]
then bc=( $(bc <<<" /* round argument 'x' to 'd' digits */
define r(x, d) { auto r, s; if(0 > x) { return -r(-x, d); };
r = x + 0.5*10^-d; s = scale; scale = d; r = r*10/10;
scale = s; return r; }; scale = ($SCL + 1);
r( (${years_between:-0} + ( (${range:-0} - ( (${daycount_years:-0} + ${daycount_leap_years:-0}) * 24 * 60 * 60) ) / (${date1_year_days_adj:-0} * 24 * 60 * 60) ) ) , $SCL); /** YEARS **/
r( (${monthcount:-0} + ( (${range:-0} - (${fullmonth_days_save:-0} * 24 * 60 * 60) ) / (${date1_month_max_day:-0} * 24 * 60 * 60) ) ) , $SCL); /** MONTHS **/
r( (${range:-0} / ( 7 * 24 * 60 * 60)) , $SCL); /** WEEKS **/
r( (${range:-0} / (24 * 60 * 60)) , $SCL); /** DAYS **/
r( (${range:-0} / (60 * 60)) , $SCL); /** HOURS **/
r( (${range:-0} / 60) , $SCL); /** MINUTES **/")
)
bcy=${bc[0]} bcmo=${bc[1]} bcw=${bc[2]} bcd=${bc[3]} bch=${bc[4]} bcm=${bc[5]}
#ARRAY: 0=YEARS 1=MONTHS 2=WEEKS 3=DAYS 4=HOURS 5=MINUTES
else typeset -F $SCL bcy bcmo bcw bcd bch bcm
bcy="${years_between:-0} + ( (${range:-0} - ( (${daycount_years:-0} + ${daycount_leap_years:-0}) * 24 * 60 * 60.) ) / (${date1_year_days_adj:-0} * 24 * 60 * 60.) )" #YEARS
bcmo="${monthcount:-0} + ( (${range:-0} - (${fullmonth_days_save:-0} * 24 * 60 * 60.) ) / (${date1_month_max_day:-0} * 24 * 60 * 60.) )" #MONTHS
bcw="${range:-0} / ( 7 * 24 * 60 * 60.)" #WEEKS
bcd="${range:-0} / (24 * 60 * 60.)" #DAYS
bch="${range:-0} / (60 * 60.)" #HOURS
bcm="${range:-0} / 60." #MINUTES
fi

#choose layout of single units
if ((OPTT || !OPTLAYOUT))
then #layout one
spcr=' | ' #spacer
prHelpf ${OPTTy:+${bcy}} && range_pr="${bcy} year$SS"
prHelpf ${OPTTmo:+${bcmo}} && range_pr="${range_pr}${range_pr:+$spcr}${bcmo} month$SS"
prHelpf ${OPTTw:+${bcw}} && range_pr="${range_pr}${range_pr:+$spcr}${bcw} week$SS"
prHelpf ${OPTTd:+${bcd}} && range_pr="${range_pr}${range_pr:+$spcr}${bcd} day$SS"
prHelpf ${OPTTh:+${bch}} && range_pr="${range_pr}${range_pr:+$spcr}${bch} hour$SS"
prHelpf ${OPTTm:+${bcm}} && range_pr="${range_pr}${range_pr:+$spcr}${bcm} min$SS"
prHelpf $range ;((!OPTT||OPTTs)) && range_pr="$range_pr${range_pr:+$spcr}$range sec$SS"
((OPTT&&OPTV)) && range_pr="${range_pr%%*([$IFS])}" #bug in ksh93u+ ${var% *}
else #layout two
((n = ${#range}+SCL+1)) #range in seconds is the longest string
prHelpf ${bcy} $n && range_pr=Year$SS$'\t'$SSS${bcy}
prHelpf ${bcmo} $n && range_pr="$range_pr"$'\n'Month$SS$'\t'$SSS${bcmo}
prHelpf ${bcw} $n && range_pr="$range_pr"$'\n'Week$SS$'\t'$SSS${bcw}
prHelpf ${bcd} $n && range_pr="$range_pr"$'\n'Day$SS$'\t'$SSS${bcd}
prHelpf ${bch} $n && range_pr="$range_pr"$'\n'Hour$SS$'\t'$SSS${bch}
prHelpf ${bcm} $n && range_pr="$range_pr"$'\n'Min$SS$'\t'$SSS${bcm}
prHelpf $range $((n - (SCL>0 ? (SCL+1) : 0) ))
range_pr="$range_pr"$'\n'Sec$SS$'\t'$SSS$range
range_pr="${range_pr#*([$IFS])}"
#https://www.themathdoctors.org/should-we-put-zero-before-a-decimal-point/
((OPTLAYOUT>1)) && { p= q=. ;for ((p=0;p<SCL;++p)) ;do q="${q}0" ;done
range_pr="${range_pr// ./0.}" range_pr="${range_pr}${q}" ;}
fi
unset SS SSS
fi

#set printing array with shell results
sh=("$y" "$mo" "$w" "$d" "$h" "$m" "$s")
((y<0||mo<0||w<0||d<0||h<0||m<0||s<0)) && ret=${ret:-1} #negative unit error

# Debugging
if ((DEBUG))
then
#!#
debugf "$@"
fi

#print results
if ((!OPTVERBOSE))
then if [[ ! $date1_iso8601_pr$date1_iso8601 ]]
then date1_iso8601=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d:%02d\\n \
"$yearA" "$monthA" "$dayA" \
"$hourA" "$minA" "$secA" \
"${neg_tzA%1}" "$tzAh" "$tzAm" "$tzAs")
date1_iso8601=${date1_iso8601%%*(:00)}
else date1_iso8601_pr=${date1_iso8601_pr%%*(:00)} #remove excess zeroes
fi
if [[ ! $date2_iso8601_pr$date2_iso8601 ]]
then date2_iso8601=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d:%02d\\n \
"$yearB" "$monthB" "$dayB" \
"$hourB" "$minB" "$secB" \
"${neg_tzB%1}" "$tzBh" "$tzBm" "$tzBs")
date2_iso8601=${date2_iso8601%%*(:00)}
else date2_iso8601_pr=${date2_iso8601_pr%%*(:00)}
fi

printf '%s%s\n%s%s%s\n%s%s%s\n%s\n' \
DATES "${OPTDD+#}${badges}${neg_range%1}" \
"${date1_iso8601_pr:-${date1_iso8601:-$inputA}}" ''${unix1:+$'\t'} "$unix1" \
"${date2_iso8601_pr:-${date2_iso8601:-$inputB}}" ''${unix2:+$'\t'} "$unix2" \
RANGES
fi
prfmt='%dY %02dM %02dW %02dD %02dh %02dm %02ds' #print format for the compound range
((OPTVERBOSE>3)) && prfmt='%dY%02dM%02dW%02dD%02dh%02dm%02ds' #AST `date -E' style
((OPTVERBOSE<2 || OPTVERBOSE>2)) && printf "${prfmt}\n" "${sh[@]}"
((OPTVERBOSE<3)) && printf '%s\n' "${range_pr:-$range secs}"

return ${ret:-0}
}

#execute result checks against `datediff' and `date'
#check manually in case of divergence as this function is overloaded
#beware of opt -R and unset $TZ and offsets (we defaults to UTC while `date' may set random offsets)
function debugf
{
unset iA iB tA tB dd ddout y_dd mo_dd w_dd d_dd h_dd m_dd s_dd range_check unix1t unix2t checkA_pr checkB_pr checkA_pr_dow checkB_pr_dow checkA_utc checkB_utc date_cmd_save TZ_save brk
date_cmd_save="${DATE_CMD}" DATE_CMD=date TZ_save=$TZ TZ=UTC${TZ##*$GLOBUTC}

[[ $2 = *[Tt:]*[+-]$GLOBTZ && $1 = *[Tt:]*[+-]$GLOBTZ ]] || echo warning: input dates are missing offset/tz bits! >&2
iB="${2:-${inputB}}" iA="${1:-${inputA}}"
iB="${iB:0:25}" iA="${iA:0:25}"
((${#iB}==10)) && iB=${iB}T00:00:00
((${#iA}==10)) && iA=${iA}T00:00:00
((${#iB}==19)) && iB="${iB}+00:00"
((${#iA}==19)) && iA="${iA}+00:00"
iB=${iB/-00:00/+00:00} iA=${iA/-00:00/+00:00}

#utc time strings
tB=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d\\n \
"$yearB" "$monthB" "$dayB" \
"$hourB" "$minB" "$secB" \
"${neg_tzB%1}" $tzBh $tzBm)
tA=$(printf \
%04d-%02d-%02dT%02d:%02d:%02d%s%02d:%02d\\n \
"$yearA" "$monthA" "$dayA" \
"$hourA" "$minA" "$secA" \
"${neg_tzA%1}" $tzAh $tzAm)
tB=${tB:0:25} tA=${tA:0:25}
tB=${tB/-00:00/+00:00} tA=${tA/-00:00/+00:00}

if [[ $date_cmd_save = false ]]
then
if ((TZs)) || [[ $TZ = *:*:*:* ]] || [[ $tzA = *:*:*:* ]] || [[ $tzB = *:*:*:* ]]
then echo "warning: \`datediff' and \`date' may not take offsets with seconds" >&2
((ret+=230))
fi

if ((TZh||TZm))
then checkB_pr=$(datefun -Iseconds $iB)
checkA_pr=$(datefun -Iseconds $iA)
else checkB_pr=$date2_iso8601_pr checkA_pr=$date1_iso8601_pr
fi
if ((OPTRR))
then checkB_pr_dow=$(datefun "$iB")
checkA_pr_dow=$(datefun "$iA")
fi

checkB_utc=$(TZ=UTC datefun -Iseconds $iB)
checkA_utc=$(TZ=UTC datefun -Iseconds $iA)
#`date' iso offset must not exceed minute precision [+-]XX:XX !

#check generated unix times against `date'
unix2t=$(datefun "$iB" +%s)
unix1t=$(datefun "$iA" +%s)
range_check=$((unix2t-unix1t))
fi
if ((OPTRR))
then checkB_pr_dow="${checkB_pr_dow:-$date2_iso8601_pr}"
checkA_pr_dow="${checkA_pr_dow:-$date1_iso8601_pr}"
fi

#compound range check against `datediff'
#`datediff' offset range is between -14h and +14h!
ddout=$(datediff -f'%Y %m %w %d %H %M %S' "$tA" "$tB") || ((ret+=250))
read y_dd mo_dd w_dd d_dd h_dd m_dd s_dd <<<"$ddout"
dd=(${y_dd#-} $mo_dd $w_dd $d_dd $h_dd $m_dd $s_dd)

DATE_CMD="$date_cmd_save" TZ=$TZ_save
{
{
{ [[ ${date2_iso8601_pr:0:25} = $checkB_pr ]] &&
[[ ${date1_iso8601_pr:0:25} = $checkA_pr ]] ;} ||
{ [[ ${date2_iso8601_pr:0:3} = ${checkB_pr_dow:0:3} ]] &&
[[ ${date1_iso8601_pr:0:3} = ${checkA_pr_dow:0:3} ]] ;}
} &&

[[ $tB = ${checkB_utc:-$tB} ]] &&
[[ $tA = ${checkA_utc:-$tA} ]] &&

[[ $unix1 = ${unix1t:-$unix1} && $unix2 = ${unix2t:-$unix2} ]] &&
[[ $range = "${range_check:-$range}" ]] &&

[[ ${sh[*]} = "${dd[*]:-${sh[*]}}" ]]
} || { #brk='\n'
echo -ne "\033[2K" >&2
echo ${brk+-e} "\
sh=${sh[*]} dd=${dd[*]} | $brk"\
"$iA $iB | $brk"\
"${range:-unavail} ${range_check:-unavail} | $brk"\
"${date1_iso8601_pr:0:25} $checkA_pr | $brk"\
"${date2_iso8601_pr:0:25} $checkB_pr | $brk"\
"${date1_iso8601_pr:0:3} ${checkA_pr_dow:0:3} | $brk"\
"${date2_iso8601_pr:0:3} ${checkB_pr_dow:0:3} | $brk"\
"$tB $checkB_utc | $brk"\
"$tA $checkA_utc | $brk"\
"$unix1 $unix1t | $brk"\
"$unix2 $unix2t | $brk"\
"${date_cmd_save%date}"

((ret+=1))
}

#((DEBUG>1)) && return ${ret:-0} #!#
((DEBUG>1)) && exit ${ret:-0} #!#
return 0
}


## Parse options
while getopts 01234567890DdeFf:hlmRr@tuv opt
do case $opt in
[0-9]) SCL="$SCL$opt"
;;
d) ((++DEBUG))
;;
D) [[ ${DATE_CMD} = false ]] && OPTDD=1 ;DATE_CMD=false
;;
e) OPTE=1 OPTL=
;;
F) ((++OPTFF))
;;
f) INPUT_FMT="$OPTARG" OPTF=1 #input format string for `BSD date'
;;
h) while read
do [[ "$REPLY" = \#\ v* ]] && echo "$REPLY $SHELL" && break
done <"$0"
echo "$HELP" ;exit
;;
l) OPTL=1 OPTE=
;;
m) OPTM=1
;;
R) OPTRR=1
;;
r|@) OPTR=1
;;
t) ((++OPTLAYOUT))
;;
u) OPTU=1
;;
v) ((++OPTVERBOSE, ++OPTV))
;;
\?) exit 1
;;
esac
done
shift $((OPTIND -1)); unset opt

#set proper environment!
SCL="${SCL:-1}" #scale defaults
((OPTU)) && TZ=UTC #set UTC time zone
export TZ

#test for BSD or GNU date for datefun()
[[ ${DATE_CMD} ]] ||
if DATE_CMD=date;
! ${DATE_CMD} --version
then if gdate --version
then DATE_CMD=gdate
elif command -v date
then BSDDATE=1
else DATE_CMD=false
fi
fi >/dev/null 2>&1

#stdin input (skip it for option -F)
[[ ${1//[$IFS]}$OPTFF = $GLOBOPT ]] && opt="$1" && shift
if ((!($#+OPTFF) )) && [[ ! -t 0 ]]
then
globtest="*([$IFS])@($GLOBDATE?(+([$SEP])$GLOBTIME)|$GLOBTIME)*([$IFS])@($GLOBDATE?(+([$SEP])$GLOBTIME)|$GLOBTIME)?(+([$IFS])$GLOBOPT)*([$IFS])" #glob for two ISO8601 dates and possibly pos arg option for single unit range
while IFS= read -r || [[ $REPLY ]]
do ar=($REPLY) ;((${#ar[@]})) || continue
if ((!$#))
then set -- "$REPLY" ;((OPTL)) && break
#check if arg contains TWO ISO8601 dates and break
if ((${#ar[@]}==3||${#ar[@]}==2)) && [[ \ $REPLY = @(*[$IFS]$GLOBOPT*|$globtest) ]]
then set -- $REPLY ;[[ $1 = $GLOBOPT ]] || break
fi
else if ((${#ar[@]}==2)) && [[ \ $REPLY = @(*[$IFS]$GLOBOPT|$globtest) ]]
then set -- "$@" $REPLY
else set -- "$@" "$REPLY"
fi ;break
fi
done ;unset ar globtest REPLY
[[ ${1//[$IFS]} = $GLOBOPT ]] && opt="$1" && shift
fi
[[ $opt ]] && set -- "$@" "$opt"

#set single time unit
opt="${opt:-${@: -1}}" opt="${opt//[$IFS]}"
if [[ $opt$OPTFF = $GLOBOPT ]]
then OPTT=1 OPTVERBOSE=2 OPTLAYOUT=
case $opt in
[yY]) OPTTy=1;;
[mM][oO]) OPTTmo=1;;
[wW]) OPTTw=1;;
[dD]) OPTTd=1;;
[hH]) OPTTh=1;;
[mM]) OPTTm=1;;
[sS]) OPTTs=1;;
esac ;set -- "${@:1:$#-1}"
else OPTTy=1 OPTTmo=1 OPTTw=1 OPTTd=1 OPTTh=1 OPTTm=1 OPTTs=1
fi ;unset opt
#caveat: `gnu date' understands `-d[a-z]', do `-d[a-z]0' to pass.

#whitespace trimming
if (($#>1))
then set -- "${1#"${1%%[!$IFS]*}"}" "${2#"${2%%[!$IFS]*}"}" "${@:3}"
set -- "${1%"${1##*[!$IFS]}"}" "${2%"${2##*[!$IFS]}"}" "${@:3}"
elif (($#))
then set -- "${1#"${1%%[!$IFS]*}"}" ;set -- "${1%"${1##*[!$IFS]}"}"
fi

if ((OPTL))
then for YEAR
do is_year "$YEAR" || continue
if ! is_leapyear_verbose "$YEAR"
then (($?>1)) && RET=2 ;RET="${RET:-$?}"
fi
done ;exit $RET
elif ((OPTE))
then for YEAR
do is_year "$YEAR" || continue
DATE=$(easterf "$YEAR") ;echo $DATE
done
elif ((OPTM))
then for DATE_Y #fill in months and days
do if [[ $DATE_Y = +([0-9]) ]]
then set -- ;OPTM=2
for ((M=1;M<=12;++M)) ;do set -- "$@" "${DATE_Y}-$M" ;done
else set -- "$DATE_Y" ;PHASE_SKIP=
fi
for DATE_M
do if [[ $DATE_M = +([0-9])[$SEP]+([0-9]) ]]
then set -- ;OPTM=2
DMAX=$(month_maxday "${DATE_M#*[$SEP]}" "${DATE_M%[$SEP]*}")
for ((D=1;D<=DMAX;++D)) ;do set -- "$@" "${DATE_M}-$D" ;done
else set -- "$DATE_M" ;PHASE_SKIP=
fi
for DATE
do set -- ${DATE//[$SEP]/ } #input is ISO8601
phase_of_the_moon "$3" "$2" "$1"
done
done
done
elif ((OPTFF))
then friday_13th "$@"
else
#-r, unix times
if ((OPTR && $#>1))
then set -- @"${1#@}" @"${2#@}" "${@:3}"
elif ((OPTR && $#))
then set -- @"${1#@}"
fi
mainf "$@"
fi


Click here to read the complete article
Re: Datediff script

<tlambo$37ur7$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5856&group=comp.unix.shell#5856

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 14:40:08 +0100
Organization: A noiseless patient Spider
Lines: 38
Message-ID: <tlambo$37ur7$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 13:40:08 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="b71fd446f419096a1018c48ad7ed0857";
logging-data="3406695"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+5P6zWEV73BUXZ2KxdNU0C"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:EnqM492cg5R4Q6Pr0Wi50QS4O04=
X-Enigmail-Draft-Status: N1110
In-Reply-To: <tlaivk$37mt8$1@dont-email.me>
 by: Janis Papanagnou - Sat, 19 Nov 2022 13:40 UTC

On 19.11.2022 13:42, castAway wrote:
> Ksh93 `superior'
> parameter scoping in functions was a litte hard to deal with [...]

Note that ksh's 'typeset' specifies variables' meta-attributes.
The local scope in functions is just one, so it's not comparable
with bash's simple 'local' keyword. Any ksh's 'typeset' is also
not that portable. As mentioned upthread there's also the more
portable f()(...) instead of f(){...;} if all you want is
local-scoped variables.

> [...] Specially, the new friday_13th() function
> may still need some more work.

Is there anything more about that function than just checking the
day-of-week (Friday) and date-in-month (13)?

> I reckon it would be cool to have a shell function to convert UNIX times to
> ISO-8601 (and RFC-5322) formats.

You mean to convert "seconds since 'Unix Epoch'" to e.g. ISO time?
A lot of things can be dome with ksh's built-in printf function and
its "%(...)T" specifier. You can resort to GNU date or GNU awk for
other time functions, e.g.

$ awk -v s=1668864108 'BEGIN{print strftime("%FT%T",s)}'
2022-11-19T14:21:48

but I'm not sure about your portability requirements and GNU tools
might not be available.

I'm also still unsure about the supported date ranges. I a post
quite some time ago I posted some observations with the different
ranges of time functions in 'date', 'ksh', and 'awk'; all we seems
to be able to rely on was (IIRC) the rather short Unix-Epoch range.

Janis

Re: Datediff script

<jtsegcFqnnaU1@mid.individual.net>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5857&group=comp.unix.shell#5857

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!news.swapon.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail
From: jpstewart@personalprojects.net (John-Paul Stewart)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 11:27:25 -0500
Lines: 15
Message-ID: <jtsegcFqnnaU1@mid.individual.net>
References: <tkju7j$54v$1@gioia.aioe.org> <tkk621$l9ma$1@dont-email.me>
<tkkfse$1e9d$1@gioia.aioe.org> <tkltmu$sve7$1@dont-email.me>
<tl1dhb$25vcc$2@dont-email.me>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-Trace: individual.net 3Tpty/f3/OZZP1OQFnLrcQUkDvjT1uPGjnSlAQtICd9DDekZre
Cancel-Lock: sha1:ZfYfIGvtIO3aOEGO/L7f9QmW+xk=
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Content-Language: en-CA
In-Reply-To: <tl1dhb$25vcc$2@dont-email.me>
 by: John-Paul Stewart - Sat, 19 Nov 2022 16:27 UTC

On 2022-11-15 20:14, castAway wrote:
> On 11/11/22 13:36, Janis Papanagnou wrote:
>
>>    function phase_of_the_moon (now)    // 0-7, with 0: new, 4: full
>
> Bash integer arithmetics do floor rounding by deafults, don't trust,
> check it, thus $(( 7/4 )) returns 1... Like Ksh, so maybe the floor rounding
> function you mentioned is an overhead... Maybe in Java scripting all integers
> are calculated as floating point?

Yes, in JavaScript all numbers are indeed floating point. Well, unless
you explicitly use the BigInt type:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Numbers_and_dates#numbers

Re: Datediff script

<tlb0o4$38op5$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5858&group=comp.unix.shell#5858

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 13:37:23 -0300
Organization: A noiseless patient Spider
Lines: 56
Message-ID: <tlb0o4$38op5$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlambo$37ur7$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 16:37:24 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="c8e09f965d0c49b79a6c694f0134c3d4";
logging-data="3433253"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19hbmIIAYxDF0jH2/zKHMCG+LTbxyvEDoI="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:7Jk6Kb/dVfnMYWMQifS81T9y9MI=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlambo$37ur7$1@dont-email.me>
 by: castAway - Sat, 19 Nov 2022 16:37 UTC

On 11/19/22 10:40, Janis Papanagnou wrote:
> As mentioned upthread there's also the more
> portable f()(...) instead of f(){...;} if all you want is
> local-scoped variables.

I had missed that subtlety in the thread. The f() (...) syntax may
make the script run slower but maxes out compatibility, that is very
useful to learn!

>
> I'm also still unsure about the supported date ranges. I a post
> quite some time ago I posted some observations with the different
> ranges of time functions in 'date', 'ksh', and 'awk'; all we seems
> to be able to rely on was (IIRC) the rather short Unix-Epoch range.

Indeed, I remember having read the thread `Range of dates' (15 Jan 2021)
after a search on Usenet at the start of this year about ranges of
times. My datediff.sh script does not rely on `date' because I had
seen some narrow calendrical limits of `date' depending on the system
(`date' run under Termux has narrower time ranges, if I remember
correctly). The script follows the proleptic Gregorian calendar,
as already said, and there is just one adjustment I could think of
to get Julian dates that is skipping year 0000, but that would differ
from `date' command logic.

% date -u -d 0000-01-01 +%s
-62167219200

% datediff.sh -- -0001-01-01 -0000-01-01
DATES##
-001-01-01T00:00:00+00 -62198755200
0000-01-01T00:00:00+00 -62167219200
RANGES
1Y 00M 00W 00D 00h 00m 00s
1.0 year | 12.0 months | 52.1 weeks | 365.0 days | 8760.0 hours | 525600.0 mins | 31536000 secs

In the example above, `date' will be warped to process input dates
into UNIX times. However, GNU date will fail and the script will,
first, calculate the time elapsed between both dates, and then calculate
the time interval/elapsed from the closest year to UNIX epoch zero
time. That way, that is possible to generate UINX times with
arithmetics, as we count all days between these dates to get the
time in seconds.

> Is there anything more about that function than just checking the
> day-of-week (Friday) and date-in-month (13)?

You can also set positional arguments to get the combination of
day-of-week and date-in-month, for example:

% datediff.sh -F 1 mon
Mon, 01 May 2023 is 163 days ahead

Cheers,
JSN

Re: Datediff script

<tlb27f$38rr9$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5859&group=comp.unix.shell#5859

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 14:02:39 -0300
Organization: A noiseless patient Spider
Lines: 21
Message-ID: <tlb27f$38rr9$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlambo$37ur7$1@dont-email.me> <tlb0o4$38op5$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 17:02:39 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="c8e09f965d0c49b79a6c694f0134c3d4";
logging-data="3436393"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+lf5Yg6aTlp4R4Z7SARwgHK6o6SvM3Ip8="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:AQKvDYzo3aG/ljgceFVTmBibrJQ=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlb0o4$38op5$1@dont-email.me>
 by: castAway - Sat, 19 Nov 2022 17:02 UTC

On 11/19/22 13:37, castAway wrote:

Sorry, in the previous example, `date' will fail but shell
time function is still used to get current time. For the
manual UNIX time generation facility to work, the running
shell must not support built-in time functions (must be
earlier than bash 4.2, for example). To force manual UNIX
time generation in the script, set flags -DD to disable
`date' and shell time built-ins wrapping.

% datediff.sh -DD -- -0001-01-01 -0000-01-01
DATES##
-001-01-01T00:00:00+00 -62198755200
0000-01-01T00:00:00+00 -62167219200
RANGES
1Y 00M 00W 00D 00h 00m 00s
1.0 year | 12.0 months | 52.1 weeks | 365.0 days | 8760.0 hours | 525600.0 mins | 31536000 secs

JSN

Re: Datediff script

<tlb2eq$38t5l$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5860&group=comp.unix.shell#5860

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 14:06:34 -0300
Organization: A noiseless patient Spider
Lines: 6
Message-ID: <tlb2eq$38t5l$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlambo$37ur7$1@dont-email.me> <tlb0o4$38op5$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 17:06:34 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="c8e09f965d0c49b79a6c694f0134c3d4";
logging-data="3437749"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18m5Vkzo1cbf7hqFlqcyuDxNbylRggjGRE="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:ZcTGYcn1qdpr7qSZYZUGKKFy/1Q=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlb0o4$38op5$1@dont-email.me>
 by: castAway - Sat, 19 Nov 2022 17:06 UTC

No, in the previous examples, both will require manual
UNIX time generation. Shell time facility is only used to
print RFC timestamps, and get current time if any date1
or date2 is not set by user input. So in those previous
e-mail examples I just sent, it does not matter if using
flag -DD or not.

Re: Datediff script

<tlb9ao$39fvp$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5861&group=comp.unix.shell#5861

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 20:03:52 +0100
Organization: A noiseless patient Spider
Lines: 39
Message-ID: <tlb9ao$39fvp$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Sat, 19 Nov 2022 19:03:52 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="b71fd446f419096a1018c48ad7ed0857";
logging-data="3457017"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/LVKgUBM6G5b3Nd3qAg4be"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:+6kld6Lp+aLkzQFOD10Ht1XDHbE=
In-Reply-To: <tlaivk$37mt8$1@dont-email.me>
X-Enigmail-Draft-Status: N1110
 by: Janis Papanagnou - Sat, 19 Nov 2022 19:03 UTC

On 19.11.2022 13:42, castAway wrote:
> I am afraid to have gone a little over the top. The lunar phase function
> was implemented, [...]

> #return phase of the moon, use UTC time
> #usage: phase_of_the_moon year [month] [day]
> function phase_of_the_moon #0-7, with 0: new, 4: full
> {
> typeset day month year diy goldn epact
> day="${1#0}" month="${2#0}" year="${3##+(0)}"
> day=${day:-1} month=${month:-1} year=${year:-0}
> diy=$(get_day_in_year "$day" "$month" "$year")
> ((goldn = (year % 19) + 1))
> ((epact = (11 * goldn + 18) % 30))
> (((epact == 25 && goldn > 11) || epact == 24 )) && ((epact++))
> case $(( ( ( ( ( (diy + epact) * 6) + 11) % 177) / 22) &
> 7)) in
> 0) set -- 'New Moon' ;; #.0
> 1) set -- 'Waxing Crescent' ;;
> 2) set -- 'First Quarter' ;; #.25
> 3) set -- 'Waxing Gibbous' ;;
> 4) set -- 'Full Moon' ;; #.5
> 5) set -- 'Waning Gibbous' ;;
> 6) set -- 'Last Quarter' ;; #.75
> 7) set -- 'Waning Crescent' ;;
> esac

One thing I forgot that I wanted to point out...
We should be aware that the 8-value quantization will result in phases
of 3 or 4 consecutive days with the same moon phase. I noticed that in
the game of Nethack (where that code stems from) the "Nethack new moon"
phase _starts_ at the day when _real_ new moon actually is. That might
not be what one expects, though. At least my expectation was that it
would be better to either center the real moon phase date around these
3-4 days phase, or give up the quantization and calculate it on a 29.5
days per month basis.

Janis

Re: Datediff script

<tlbqsb$3aqsd$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5862&group=comp.unix.shell#5862

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 21:03:22 -0300
Organization: A noiseless patient Spider
Lines: 65
Message-ID: <tlbqsb$3aqsd$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlambo$37ur7$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sun, 20 Nov 2022 00:03:23 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="5d5cda34b45fca886cb781fc218be21d";
logging-data="3500941"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+xtIyAOAG52iQt1qEjad9yPlDRYyfNh5M="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:AP4+ftHggkFCEie5O9ln7eD4/r0=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlambo$37ur7$1@dont-email.me>
 by: castAway - Sun, 20 Nov 2022 00:03 UTC

On 11/19/22 10:40, Janis Papanagnou wrote:
> I'm also still unsure about the supported date ranges. I a post
> quite some time ago I posted some observations with the different
> ranges of time functions in 'date', 'ksh', and 'awk'; all we seems
> to be able to rely on was (IIRC) the rather short Unix-Epoch range.
I am mulling over about shell arithmetics limits.

As the script counts all days between dates and then sums up it all as
seconds before doing divisions to get single unit time intervals, such
as 60.5 years, the FP result incurs in overflow at about 68. years worth
of time.

Some testing reveals that my script can only count up to 2147483647 seconds
(about 68 years), for the FP results of single units of time. That number
is one decrement below 2^32 / 2 = 4294967296 / 2 = 2147483648, because
there is no bits left for a double point after that...

Spurious negative results should exit with 1, but I just check the compound
time range, for negative results (which should not happen!).

That is one of the reasons I decided to use Bc to calculate those FPs,
in retrospective.

The compound time interval, and the UNIX time generation facility of
the script, though, should work for much larger amounts of time.

Those functions work with shell integer arithmetics wich have got a limit
of 19 digits. It should work with time intervals up to close to
9,223,372,036,854,775,807 seconds, which is about 292 billions years!

And, if we use Bc, we can get FP single unit results within that limit
as well... I will revert to using Bc for single unit time ranges by
defaults and add a note on a LIMITS section of the help page!

A Bc script could calculate within much broader FP and integer limits.

### MaxScale - Get the maximum scale from your GNU BC
### BC is currently only 32bit in all cases.
### The package manager recognizes that it might have to install
### 32bit libraries for a 64 bit environment, but continue to be
### 32 bits libraries.
### That is why your maximum scale is always 2147483647 (though
### is safer to use 2147483647, because by reason of the minus or
### the decimal symbol in case of negative or decimal operations
### by reason of the minus and decimal symbol)
### 1111111111111111111111111111110 bits.
### If you try to add just 1 bit more, you will get a fatal error
### 'Out of memory for malloc'.
### Which explain that more memory can't be allocated, even if there
### is not an overflow because you are running a >32 bits computer.
### If you want to use bc in bash
### (such as $(echo "scale=2147483646;1/6" | bc) | tee -a division)
### you will get 'bash: xrealloc: cannot allocate 18446744071562067968
### bytes;'
### (2^31 digits represent A LOT of bytes for a normal 32/64 bits
### computer memory!) and 'Out of memory malloc' in case you want
### to assign the value to a variable or simply copy and paste
### outside bc. However, you can still operate with such a large
### number inside bc without problems while you don't exceed 2^31
### digits. Isn't that awesome?"
#scale=2147483646

Cheers,
JSN

Re: Datediff script

<tlc2f1$3be6l$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5863&group=comp.unix.shell#5863

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sat, 19 Nov 2022 23:12:48 -0300
Organization: A noiseless patient Spider
Lines: 9
Message-ID: <tlc2f1$3be6l$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlambo$37ur7$1@dont-email.me> <tlbqsb$3aqsd$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sun, 20 Nov 2022 02:12:49 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="5d5cda34b45fca886cb781fc218be21d";
logging-data="3520725"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX189wtRltSD/V8KzKOSJpOHJeypUhZy3A9A="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:FinLlK30xV786vhONHfwkcTlrh0=
In-Reply-To: <tlbqsb$3aqsd$1@dont-email.me>
Content-Language: pt-BR, en-GB
 by: castAway - Sun, 20 Nov 2022 02:12 UTC

On 11/19/22 21:03, castAway wrote:
> On 11/19/22 10:40, Janis Papanagnou wrote:
>> [...]

Well, I was testing the script under Termux in my Android mobile phone.
shell arithmetics seem to perform much better (i.e. larger limits for FP)
under Linux 64bit i7 cpu.

JSN

Re: Datediff script

<tlctnl$3g5ff$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5864&group=comp.unix.shell#5864

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sun, 20 Nov 2022 06:58:13 -0300
Organization: A noiseless patient Spider
Lines: 16
Message-ID: <tlctnl$3g5ff$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Sun, 20 Nov 2022 09:58:13 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="5d5cda34b45fca886cb781fc218be21d";
logging-data="3675631"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/Gae6NRYGhqu8WYnMR2tQjyLjDR/XyO5c="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:xmKo1ezMsJdIPjszS0eg395+yqQ=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlb9ao$39fvp$1@dont-email.me>
 by: castAway - Sun, 20 Nov 2022 09:58 UTC

On 11/19/22 16:03, Janis Papanagnou wrote:
> One thing I forgot that I wanted to point out...
> We should be aware that the 8-value quantization will result in phases
> of 3 or 4 consecutive days with the same moon phase. I noticed that in
> the game of Nethack (where that code stems from) the "Nethack new moon"
> phase _starts_ at the day when _real_ new moon actually is. That might
> not be what one expects, though. At least my expectation was that it
> would be better to either center the real moon phase date around these
> 3-4 days phase, or give up the quantization and calculate it on a 29.5
> days per month basis.
>

I think the moon phase is a little subjective as brightness of the moon
varies from the observed GPS location in the globe.

Re: Datediff script

<tlddmm$3hfla$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5865&group=comp.unix.shell#5865

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Sun, 20 Nov 2022 15:30:46 +0100
Organization: A noiseless patient Spider
Lines: 31
Message-ID: <tlddmm$3hfla$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Sun, 20 Nov 2022 14:30:46 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="014f2acb96c92a68192a0429793297f8";
logging-data="3718826"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+PFs9BzkYY7v9W/vZn98rv"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:YHn93SNsYS7d6DhBWmB5QKRnaB0=
X-Enigmail-Draft-Status: N1110
In-Reply-To: <tlctnl$3g5ff$1@dont-email.me>
 by: Janis Papanagnou - Sun, 20 Nov 2022 14:30 UTC

On 20.11.2022 10:58, castAway wrote:
>
> I think the moon phase is a little subjective as brightness of the moon
> varies from the observed GPS location in the globe.

The moon phase is primarily depending the position of moon and sun as
seen from earth; if (for example) moon and sun are in an orthogonal
angle you have a half moon phase. Because of the magnitude of actual
distances and diameters ([avg.] sun ~150'000'000 km, moon ~184'000 km,
earth diameter ~12'700 km) the concrete observation position on earth
is not significant.

S M
E

The very rough 8-value discretization of moon phases that I mentioned
that lead to phases of 3-4 days(!) is quite significant. And the other
consequence - what is a sensible definition - is even more important;

|---------phase---------|
day 1 day 2 day 3 day 4
+-----+-----+-----+-----+
^ ^
a b

whether, say, new moon is defined as starting the quantized phase (a)
or being defined as the mid of the phase (b) means a difference in
accuracy of 1.5 or 2.0 days.

Janis

Re: Datediff script

<tlmg4f$fqs8$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5866&group=comp.unix.shell#5866

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Wed, 23 Nov 2022 22:07:27 -0300
Organization: A noiseless patient Spider
Lines: 19
Message-ID: <tlmg4f$fqs8$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 24 Nov 2022 01:07:27 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="50dccd0e810b3088b34df4402dacb1fa";
logging-data="519048"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/XG2N6/jOZBY0xgPZDTchNsI/Fm9YgUSA="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:9m/Wl0fWhl9bOGwxOMrOFu2cCKA=
Content-Language: pt-BR, en-GB
In-Reply-To: <tlddmm$3hfla$1@dont-email.me>
 by: castAway - Thu, 24 Nov 2022 01:07 UTC

On 11/20/22 11:30, Janis Papanagnou wrote:
> The moon phase is primarily depending the position of moon and sun as
> seen from earth; if (for example) moon and sun are in an orthogonal
> angle you have a half moon phase. Because of the magnitude of actual
> distances and diameters ([avg.] sun ~150'000'000 km, moon ~184'000 km,
> earth diameter ~12'700 km) the concrete observation position on earth
> is not significant.
>
> S M
> E

My thoughts, exactly!

You know we cannot do anything about improving this formula, right?

And yes, brightness does depend on the observer position on Earth,
although Lunar Phases shouldn't because there are precise angles
of Sun & Moon longitudes from Earth which should define moon phases...

Re: Datediff script

<tln9vi$kb35$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5867&group=comp.unix.shell#5867

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 24 Nov 2022 09:28:34 +0100
Organization: A noiseless patient Spider
Lines: 29
Message-ID: <tln9vi$kb35$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 24 Nov 2022 08:28:34 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="5ec9f02d3443f6de531e795631b0eae9";
logging-data="666725"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/uhB8Fg3W+p9d4t9nrT0Nv"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:2qO/BA7lZdyJ0Mi48mor9iioWS8=
In-Reply-To: <tlmg4f$fqs8$1@dont-email.me>
X-Enigmail-Draft-Status: N1110
 by: Janis Papanagnou - Thu, 24 Nov 2022 08:28 UTC

On 24.11.2022 02:07, castAway wrote:
>
> You know we cannot do anything about improving this formula, right?

The quantization[*] could be removed from the formula so that we have
a single matching day [for full moon and new moon], or/and vice versa,
that a single exact date/time result is provided for a specific phase
like these, and provide percentages relative to new/full moon instead
of 8 phase values of 3-4 days each. (Just to name some alternatives.)

That said; I want to recall that it's not necessary a sensible feature
for such a small library. (YMMV, of course.) It's a question of what
features are sensible here - a choice you have to make! A "complete"
date/time library leads probably to a doomed project, considering all
the difficulties, asymmetries, quirks, incoherences, model types, etc.
(Leap-years and leap-seconds, date range coverage, different calender
types, different historic introduction dates, different special dates
(like easter), time zones, set of sensible date functions, flexibility
with date representations (input and output), mapping to astronomical
time/date definitions, etc. - date and time is nothing simple, even if
it appears so at first glance. - OTOH, date and time is so fundamental
that I wonder whether there's already some "complete" library existing
and published?)

Janis

[*] Which is okay for the game of Nethack, where the formula stems from.

Re: Datediff script

<tlna58$kbmk$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5868&group=comp.unix.shell#5868

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 24 Nov 2022 09:31:36 +0100
Organization: A noiseless patient Spider
Lines: 8
Message-ID: <tlna58$kbmk$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 24 Nov 2022 08:31:36 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="5ec9f02d3443f6de531e795631b0eae9";
logging-data="667348"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19s7odF8RftKUURefW0iUYz"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:Jo7xNWm7/1PAfRL6b3BB7R/23go=
In-Reply-To: <tlddmm$3hfla$1@dont-email.me>
 by: Janis Papanagnou - Thu, 24 Nov 2022 08:31 UTC

On 20.11.2022 15:30, Janis Papanagnou wrote:
> distances and diameters ([avg.] sun ~150'000'000 km, moon ~184'000 km,
> earth diameter ~12'700 km) [...]

Sorry, it just occurred to me, a typo; must be: moon ~384'000 km

Janis

Re: Datediff script

<tm6rjb$1if6$1@gioia.aioe.org>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5869&group=comp.unix.shell#5869

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!aioe.org!svGMjj4JAseXRzIUqGFGng.user.46.165.242.75.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Wed, 30 Nov 2022 03:01:14 -0300
Organization: Aioe.org NNTP Server
Message-ID: <tm6rjb$1if6$1@gioia.aioe.org>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="51686"; posting-host="svGMjj4JAseXRzIUqGFGng.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Content-Language: pt-BR, en-GB
X-Notice: Filtered by postfilter v. 0.9.2
 by: castAway - Wed, 30 Nov 2022 06:01 UTC

An older version of this moon phase function, or a Java Script version
of it, it used to subtract 1900 from whatever year was input, so for
e.g. year 1970 would be the same as year number 70 (1970-1900).

For this reason, I thought it may be feasible to adjust this formula
by adding or subtracting some years for the internal calculation.
In the NetHack comment for this formula, it notes the following:

#days moon phase advances on first day of year compared
#to preceding year
# = 365.2422 - 12*29.53058 ~= 11
#years in Metonic cycle (time until same phases fall on
#the same days of the month)
# = 18.6 ~= 19

It means the reading frame of the moon phase can be adjusted if
one can find a good number to correct the input year for internal
calculation.

In order to verify what adjustment could be made, all data for lunar
phases from 1700 to 2102 was scraped from
<https://aa.usno.navy.mil/data/MoonPhases>.

Input year was then adjusted with a value from -200 to +200 years,
meaning that when input year is 1700, moon phases were calculated
as if it were {1500..1900}.

Generated tables were compared with that scraped from US Navy website.
That was possible to determine, within the tested interval of correction
from -200 to +200 years, that adding any `8', `-68', `84', `64' or `-144'
to user input produces more accurate results.

For example, it was possible to check that the original function as
was copied from modern NetHack matches exactly the US Navy dataset
3495 out of 19944 primary phases for the period between 1700-2102.

Adjustment Matches Non-matches
+0 3495 16449
+8 8037 11907
-144 8039 11905
-68 8047 11897
+84 8056 11888

The original formula can have up to 5 days or error, I found.
The following example shows the US Navy scrape information for
moon phases from May 1924. Original function returns results
up to 5 days out of sync. Adding 8 years to internal calculation
delivers much better results.

% grep 1924 ~/navy/all.txt | grep May
New Moon 1924 May 3 23:00
First Quarter 1924 May 12 02:14
Full Moon 1924 May 18 21:52
Last Quarter 1924 May 25 14:16

% datediff.sh -m 1924-05 | grep -v -e Wan -e Wax
1924-05-01 New Moon
1924-05-07 First Quarter
1924-05-15 Full Moon
1924-05-22 Last Quarter
1924-05-29 New Moon

~ % ADD_YEARS=8 datediff.sh -m 1924-05 | grep -v -e Wan -e Wax
1924-05-03 New Moon
1924-05-10 First Quarter
1924-05-18 Full Moon
1924-05-25 Last Quarter

As far as I can tell, it may be worth correcting the input year
for internal calculation, however deciding if the correction factor
should be `8' or `-144' is to me a little arbitrary. Even though `-144'
corrects a little better according to my tests, it may well be
that a value out of the tested range ( -200 >= tested range <= +200 )
may be even slightly better correction factor. This is just
a preliminary test.

Cheers,
JSN

Re: Datediff script

<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5884&group=comp.unix.shell#5884

  copy link   Newsgroups: comp.unix.shell
X-Received: by 2002:a05:620a:8c8:b0:6fb:cf37:a30e with SMTP id z8-20020a05620a08c800b006fbcf37a30emr57268020qkz.306.1669907573230;
Thu, 01 Dec 2022 07:12:53 -0800 (PST)
X-Received: by 2002:a05:6808:16a9:b0:35a:76f3:f550 with SMTP id
bb41-20020a05680816a900b0035a76f3f550mr32240023oib.219.1669907572859; Thu, 01
Dec 2022 07:12:52 -0800 (PST)
Path: i2pn2.org!i2pn.org!usenet.blueworldhosting.com!feed1.usenet.blueworldhosting.com!peer03.iad!feed-me.highwinds-media.com!news.highwinds-media.com!news-out.google.com!nntp.google.com!postnews.google.com!google-groups.googlegroups.com!not-for-mail
Newsgroups: comp.unix.shell
Date: Thu, 1 Dec 2022 07:12:52 -0800 (PST)
In-Reply-To: <tm6rjb$1if6$1@gioia.aioe.org>
Injection-Info: google-groups.googlegroups.com; posting-host=2600:4040:a284:300:4507:fb89:7b30:ca7b;
posting-account=cdsHlAoAAAChJwblggpJABTs6mDsS965
NNTP-Posting-Host: 2600:4040:a284:300:4507:fb89:7b30:ca7b
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
User-Agent: G2/1.0
MIME-Version: 1.0
Message-ID: <89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
Subject: Re: Datediff script
From: marty.mcgowan@gmail.com (applemcg)
Injection-Date: Thu, 01 Dec 2022 15:12:53 +0000
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
X-Received-Bytes: 6060
 by: applemcg - Thu, 1 Dec 2022 15:12 UTC

a little late to the party, saw some discussion of function syntax, definition.

from this:

#get day in the week
#usage: get_day_in_week unix_time
function get_day_in_week
{ echo ${DAY_OF_WEEK[( ( ($1+($1<0?1:0))/(24*60*60))%7 +($1<0?6:7))%7]}
}

i'd write:

get_day_in_week ()
{ : get day in the week
: example: get_day_in_week unix_time 2300000
: uses: DAY_OF_WEEK

echo ${DAY_OF_WEEK[( ( ($1+($1<0?1:0))/(24*60*60))%7 +($1<0?6:7))%7]}
}

this is the format returned by "declare -f", which i use as a shell-beautifier. it uses the null-command colon (:) as a comment, the first of which i call the abstract, a "shdoc" runs to the first non-Tag such lines, the "abstract" being the first such, where a Tag is ": {tag}: ". "date" is a common tag, in this case "example" is backed up by an eval_example function.

this has the advantage of dragging around the useful information with in the function itself. i've a ~ 2400 member function collection where i'm always looking for the right place to keep a function, including a "retiredlib". and an "app" is little more than a few high-level functions which gather up all the necessary functions, awk scripts, and text files.

On Wednesday, November 30, 2022 at 1:01:27 AM UTC-5, castAway wrote:
> An older version of this moon phase function, or a Java Script version
> of it, it used to subtract 1900 from whatever year was input, so for
> e.g. year 1970 would be the same as year number 70 (1970-1900).
>
> For this reason, I thought it may be feasible to adjust this formula
> by adding or subtracting some years for the internal calculation.
> In the NetHack comment for this formula, it notes the following:
>
>
> #days moon phase advances on first day of year compared
> #to preceding year
> # = 365.2422 - 12*29.53058 ~= 11
> #years in Metonic cycle (time until same phases fall on
> #the same days of the month)
> # = 18.6 ~= 19
>
>
> It means the reading frame of the moon phase can be adjusted if
> one can find a good number to correct the input year for internal
> calculation.
>
> In order to verify what adjustment could be made, all data for lunar
> phases from 1700 to 2102 was scraped from
> <https://aa.usno.navy.mil/data/MoonPhases>.
>
> Input year was then adjusted with a value from -200 to +200 years,
> meaning that when input year is 1700, moon phases were calculated
> as if it were {1500..1900}.
>
> Generated tables were compared with that scraped from US Navy website.
> That was possible to determine, within the tested interval of correction
> from -200 to +200 years, that adding any `8', `-68', `84', `64' or `-144'
> to user input produces more accurate results.
>
> For example, it was possible to check that the original function as
> was copied from modern NetHack matches exactly the US Navy dataset
> 3495 out of 19944 primary phases for the period between 1700-2102.
>
> Adjustment Matches Non-matches
> +0 3495 16449
> +8 8037 11907
> -144 8039 11905
> -68 8047 11897
> +84 8056 11888
>
>
> The original formula can have up to 5 days or error, I found.
> The following example shows the US Navy scrape information for
> moon phases from May 1924. Original function returns results
> up to 5 days out of sync. Adding 8 years to internal calculation
> delivers much better results.
>
>
> % grep 1924 ~/navy/all.txt | grep May
> New Moon 1924 May 3 23:00
> First Quarter 1924 May 12 02:14
> Full Moon 1924 May 18 21:52
> Last Quarter 1924 May 25 14:16
>
> % datediff.sh -m 1924-05 | grep -v -e Wan -e Wax
> 1924-05-01 New Moon
> 1924-05-07 First Quarter
> 1924-05-15 Full Moon
> 1924-05-22 Last Quarter
> 1924-05-29 New Moon
>
> ~ % ADD_YEARS=8 datediff.sh -m 1924-05 | grep -v -e Wan -e Wax
> 1924-05-03 New Moon
> 1924-05-10 First Quarter
> 1924-05-18 Full Moon
> 1924-05-25 Last Quarter
>
>
> As far as I can tell, it may be worth correcting the input year
> for internal calculation, however deciding if the correction factor
> should be `8' or `-144' is to me a little arbitrary. Even though `-144'
> corrects a little better according to my tests, it may well be
> that a value out of the tested range ( -200 >= tested range <= +200 )
> may be even slightly better correction factor. This is just
> a preliminary test.
>
> Cheers,
> JSN

Re: Datediff script

<329d735d-3c54-15d6-19e0-3f8a3c1a3ea3@where.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5885&group=comp.unix.shell#5885

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!aioe.org!svGMjj4JAseXRzIUqGFGng.user.46.165.242.75.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 1 Dec 2022 12:53:23 -0300
Organization: Aioe.org NNTP Server
Message-ID: <329d735d-3c54-15d6-19e0-3f8a3c1a3ea3@where.com>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Info: gioia.aioe.org; logging-data="4954"; posting-host="svGMjj4JAseXRzIUqGFGng.user.gioia.aioe.org"; mail-complaints-to="abuse@aioe.org";
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
X-Notice: Filtered by postfilter v. 0.9.2
Content-Language: pt-BR, en-GB
 by: castAway - Thu, 1 Dec 2022 15:53 UTC

On 12/1/22 12:12, applemcg wrote:
>
> this is the format returned by "declare -f", which i use as a shell-beautifier. it uses the null-command colon (:) as a comment, the first of which i call the abstract, a "shdoc" runs to the first non-Tag such lines, the "abstract" being the first such, where a Tag is ": {tag}: ". "date" is a common tag, in this case "example" is backed up by an eval_example function.
>
> this has the advantage of dragging around the useful information with in the function itself. i've a ~ 2400 member function collection where i'm always looking for the right place to keep a function, including a "retiredlib". and an "app" is little more than a few high-level functions which gather up all the necessary functions, awk scripts, and text files.
>
>
I avoid using the : command to add a comment because it is run by the shell and makes the function run slower.

Re: Datediff script

<4ee1698b-5de2-c957-d432-910afa8de313@where.com>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5886&group=comp.unix.shell#5886

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: no@where.com (castAway)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 1 Dec 2022 14:40:56 -0300
Organization: A noiseless patient Spider
Lines: 9
Message-ID: <4ee1698b-5de2-c957-d432-910afa8de313@where.com>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8; format=flowed
Content-Transfer-Encoding: 7bit
Injection-Info: reader01.eternal-september.org; posting-host="8394186d81a8df61e8abf1a773e134e1";
logging-data="2996975"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18ROqi8NrZFXxvpyleKbNR4m1VVgxIvMKg="
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
Thunderbird/102.4.1
Cancel-Lock: sha1:gmKRFx5O4cPa3oFhlrK2OW9yN8o=
Content-Language: pt-BR, en-GB
In-Reply-To: <89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
 by: castAway - Thu, 1 Dec 2022 17:40 UTC

On 12/1/22 12:12, applemcg wrote:
>
> this is the format returned by "declare -f", which i use as a shell-beautifier. it uses the null-command colon (:) as a comment, the first of which i call the abstract, a "shdoc" runs to the first non-Tag such lines, the "abstract" being the first such, where a Tag is ": {tag}: ". "date" is a common tag, in this case "example" is backed up by an eval_example function.
>
> this has the advantage of dragging around the useful information with in the function itself. i've a ~ 2400 member function collection where i'm always looking for the right place to keep a function, including a "retiredlib". and an "app" is little more than a few high-level functions which gather up all the necessary functions, awk scripts, and text files.
>
>
I avoid using the : command to add a comment because it is run by the shell and makes the function run slower.

Formatting considerations (was Re: Datediff script)

<tmb7jj$2sin2$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5888&group=comp.unix.shell#5888

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Formatting considerations (was Re: Datediff script)
Date: Thu, 1 Dec 2022 22:50:43 +0100
Organization: A noiseless patient Spider
Lines: 26
Message-ID: <tmb7jj$2sin2$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
<4ee1698b-5de2-c957-d432-910afa8de313@where.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 1 Dec 2022 21:50:43 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="a07f9c5006eb7d138904bca22f6e8a43";
logging-data="3033826"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19qHppRvWNIGN4nGDzWES9d"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:xxHpmPGCeBK73BrkIyopwyi1S/8=
In-Reply-To: <4ee1698b-5de2-c957-d432-910afa8de313@where.com>
X-Enigmail-Draft-Status: N1110
 by: Janis Papanagnou - Thu, 1 Dec 2022 21:50 UTC

On 01.12.2022 18:40, castAway wrote:
> On 12/1/22 12:12, applemcg wrote:
>>
>> this is the format returned by "declare -f", which i use as a
>> shell-beautifier. it uses the null-command colon (:) as a comment,
>> [...]
>>
> I avoid using the : command to add a comment because it is run by the
> shell and makes the function run slower.

I wouldn't consider the efficiency problem with that built-in as a
substantial speed degradation; it's trivial and a built-in command.
I'd primarily avoid it because it's a command and side-effects can
happen on the arguments or triggered by the arguments; for example

: We're using $(some_program) for efficiency here
: and ${var:=someval} for proper initialization.

where some_program would be run (probably costly) and with possible
undesired side-effects, and the second line manipulates var.

Another (minor) consideration is that your editor might not display
the text (that is intended as comment) as a comment.

Janis

Re: Datediff script

<tmb8jk$2sl6j$1@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5889&group=comp.unix.shell#5889

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 1 Dec 2022 23:07:48 +0100
Organization: A noiseless patient Spider
Lines: 61
Message-ID: <tmb8jk$2sl6j$1@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 1 Dec 2022 22:07:48 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="a07f9c5006eb7d138904bca22f6e8a43";
logging-data="3036371"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+tdo1839Wsc48RQ9prRhym"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:pHQ/T53bPW7n1tsL/V3a6tBDeDA=
X-Enigmail-Draft-Status: N1110
In-Reply-To: <89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
 by: Janis Papanagnou - Thu, 1 Dec 2022 22:07 UTC

On 01.12.2022 16:12, applemcg wrote:
>
> a little late to the party, saw some discussion of function syntax, definition.
>
> from this:
>
> #get day in the week
> #usage: get_day_in_week unix_time
> function get_day_in_week
> {
> echo ${DAY_OF_WEEK[( ( ($1+($1<0?1:0))/(24*60*60))%7 +($1<0?6:7))%7]}
> }
>
> i'd write:
>
>
> get_day_in_week ()
> {
> : get day in the week

Identical to function name, unnecessary bloat, a potential source of
inconsistency.

> : example: get_day_in_week unix_time 2300000

Seems to document a wrong syntax (seems to be inconsistent to code).

> : uses: DAY_OF_WEEK

Already quite obvious.

>
> echo ${DAY_OF_WEEK[( ( ($1+($1<0?1:0))/(24*60*60))%7 +($1<0?6:7))%7]}
> }
>

I'd probably write (using ksh syntax here, but similar for bash)

function get_day_in_week
{
typeset -i unix_time=${1:?}

printf "%s\n" ${DAY_OF_WEEK[ $(( unix_time + ... )) ]
}

and omit the unnecessary comments, add a variable for legibility and
safety (i.e. the test on $1), use arithmetic syntax for clarity, and
standard (and generally safer) printf.

> [...]

Mileages vary.

Janis

>
>
> On Wednesday, November 30, 2022 at 1:01:27 AM UTC-5, castAway wrote:
>> [...]

Re: Datediff script

<tmb8r0$2sl6j$2@dont-email.me>

  copy mid

https://www.rocksolidbbs.com/devel/article-flat.php?id=5890&group=comp.unix.shell#5890

  copy link   Newsgroups: comp.unix.shell
Path: i2pn2.org!i2pn.org!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: janis_papanagnou+ng@hotmail.com (Janis Papanagnou)
Newsgroups: comp.unix.shell
Subject: Re: Datediff script
Date: Thu, 1 Dec 2022 23:11:44 +0100
Organization: A noiseless patient Spider
Lines: 10
Message-ID: <tmb8r0$2sl6j$2@dont-email.me>
References: <tkju7j$54v$1@gioia.aioe.org> <tlaivk$37mt8$1@dont-email.me>
<tlb9ao$39fvp$1@dont-email.me> <tlctnl$3g5ff$1@dont-email.me>
<tlddmm$3hfla$1@dont-email.me> <tlmg4f$fqs8$1@dont-email.me>
<tln9vi$kb35$1@dont-email.me> <tm6rjb$1if6$1@gioia.aioe.org>
<89b43d7e-da90-402f-8521-8080d8752cd4n@googlegroups.com>
<tmb8jk$2sl6j$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 7bit
Injection-Date: Thu, 1 Dec 2022 22:11:44 -0000 (UTC)
Injection-Info: reader01.eternal-september.org; posting-host="a07f9c5006eb7d138904bca22f6e8a43";
logging-data="3036371"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX182IbNE/O5Rjw1OKk06B6gu"
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
Thunderbird/45.8.0
Cancel-Lock: sha1:31qhNb7JkQih70Wy9d8+dd1K8a0=
In-Reply-To: <tmb8jk$2sl6j$1@dont-email.me>
 by: Janis Papanagnou - Thu, 1 Dec 2022 22:11 UTC

On 01.12.2022 23:07, Janis Papanagnou wrote:
>
> printf "%s\n" ${DAY_OF_WEEK[ $(( unix_time + ... )) ]

printf "%s\n" "${DAY_OF_WEEK[ $(( unix_time + ... )) ]}"

(fix of syntax)

Janis


devel / comp.unix.shell / Re: Datediff script

Pages:123
server_pubkey.txt

rocksolid light 0.9.81
clearnet tor