more example scripts from Teckids e.V.
[shellsnippets/shellsnippets.git] / mksh / timefns
1 # From MirOS: www/mk/common,v 1.4 2012/07/15 13:06:14 tg Exp $
2 #-
3 # Copyright © 2012
4 #       Thorsten “mirabilos” Glaser <tg@mirbsd.org>
5 #
6 # Provided that these terms and disclaimer and all copyright notices
7 # are retained or reproduced in an accompanying document, permission
8 # is granted to deal in this work without restriction, including un‐
9 # limited rights to use, publicly perform, distribute, sell, modify,
10 # merge, give away, or sublicence.
11 #
12 # This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to
13 # the utmost extent permitted by applicable law, neither express nor
14 # implied; without malicious intent or gross negligence. In no event
15 # may a licensor, author or contributor be held liable for indirect,
16 # direct, other damage, loss, or other issues arising in any way out
17 # of dealing in the work, even if advised of the possibility of such
18 # damage or existence of a defect, except proven that it results out
19 # of said person’s immediate fault when using the work as intended.
20 #-
21 # Time manipulation functions in Pure mksh™ – POSIX, no leap seconds
22 #
23 # Example use by the MirOS website: https://www.mirbsd.org/cvs.cgi/www/mk/
24
25 # magic from MirOS: src/kern/c/mirtime.c,v 1.3 2011/11/20 23:40:10 tg Exp $
26
27 # struct tm members and (POSIX) time functions
28 typeset -ir tm_sec=0            # seconds [0-59]
29 typeset -ir tm_min=1            # minutes [0-59]
30 typeset -ir tm_hour=2           # hours [0-23]
31 typeset -ir tm_mday=3           # day of month [1-31]
32 typeset -ir tm_mon=4            # month of year - 1 [0-11]
33 typeset -ir tm_year=5           # year - 1900
34 typeset -ir tm_wday=6           # day of week [0 = sunday]      input:ignored
35 typeset -ir tm_yday=7           # day of year [0-365]           input:ignored
36 typeset -ir tm_isdst=8          # summer time act.? [0/1] (0)   input:ignored
37 typeset -ir tm_gmtoff=9         # seconds offset from UTC (0)
38 typeset -ir tm_zone=10          # abbrev. of timezone ("UTC")   input:ignored
39
40 set -A mirtime_months -- Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
41 set -A mirtime_wdays -- Sun Mon Tue Wed Thu Fri Sat
42 readonly mirtime_months[*] mirtime_wdays[*]
43
44 # $ timet2mjd posix_timet
45 # ⇒ mjd sec
46 function timet2mjd {
47         local -i10 mjd=$1 sec
48
49         (( sec = mjd % 86400 ))
50         (( mjd = (mjd / 86400) + 40587 ))
51         while (( sec < 0 )); do
52                 (( --mjd ))
53                 (( sec += 86400 ))
54         done
55
56         print -- $mjd $sec
57 }
58
59 # $ mjd2timet mjd sec
60 # ⇒ posix_timet
61 function mjd2timet {
62         local -i10 t=$1 sec=$2
63
64         (( t = (t - 40587) * 86400 + sec ))
65         print -- $t
66 }
67
68 # $ mjd_explode mjd sec
69 # ⇒ tm_sec tm_min tm_hour tm_mday tm_mon tm_year \
70 #   tm_wday tm_yday "0" "0" "UTC"
71 function mjd_explode {
72         local tm
73         set -A tm
74         local -i10 sec=$2 day yday mon year=$1
75
76         while (( sec < 0 )); do
77                 (( --year ))
78                 (( sec += 86400 ))
79         done
80         while (( sec >= 86400 )); do
81                 (( ++year ))
82                 (( sec -= 86400 ))
83         done
84
85         (( day = year % 146097 + 678881 ))
86         (( year = 4 * ((year / 146097) + (day / 146097)) ))
87         (( day %= 146097 ))
88         (( tm[tm_wday] = (day + 3) % 7 ))
89         if (( day == 146096 )); then
90                 (( year += 3 ))
91                 (( day = 36524 ))
92         else
93                 (( year += day / 36524 ))
94                 (( day %= 36524 ))
95         fi
96         (( year = 4 * ((year * 25) + (day / 1461)) ))
97         (( day %= 1461 ))
98         (( yday = (day < 306) ? 1 : 0 ))
99         if (( day == 1460 )); then
100                 (( year += 3 ))
101                 (( day = 365 ))
102         else
103                 (( year += day / 365 ))
104                 (( day %= 365 ))
105         fi
106         (( yday += day ))
107         (( day *= 10 ))
108         (( mon = (day + 5) / 306 ))
109         (( day = ((day + 5) % 306) / 10 ))
110         if (( mon >= 10 )); then
111                 (( mon -= 10 ))
112                 (( yday -= 306 ))
113                 (( ++year ))
114         else
115                 (( mon += 2 ))
116                 (( yday += 59 ))
117         fi
118         (( tm[tm_sec] = sec % 60 ))
119         (( sec /= 60 ))
120         (( tm[tm_min] = sec % 60 ))
121         (( tm[tm_hour] = sec / 60 ))
122         (( tm[tm_mday] = day + 1 ))
123         (( tm[tm_mon] = mon ))
124         (( tm[tm_year] = (year < 1 ? year - 1 : year) - 1900 ))
125         (( tm[tm_yday] = yday ))
126         (( tm[tm_isdst] = 0 ))
127         (( tm[tm_gmtoff] = 0 ))
128         tm[tm_zone]=UTC
129
130         print -r -- "${tm[@]}"
131 }
132
133 # $ mjd_implode tm_sec tm_min tm_hour tm_mday tm_mon tm_year \
134 #   ignored ignored ignored tm_gmtoff [ignored]
135 # ⇒ mjd sec
136 function mjd_implode {
137         local tm
138         set -A tm -- "$@"
139         local -i10 day x y sec
140
141         (( sec = tm[tm_sec] + 60 * tm[tm_min] + 3600 * tm[tm_hour] - \
142             tm[tm_gmtoff] ))
143         (( (day = tm[tm_year] + 1900) < 0 )) && (( ++day ))
144         (( y = day % 400 ))
145         (( day = (day / 400) * 146097 - 678882 + tm[tm_mday] ))
146         while (( sec < 0 )); do
147                 (( --day ))
148                 (( sec += 86400 ))
149         done
150         while (( sec >= 86400 )); do
151                 (( ++day ))
152                 (( sec -= 86400 ))
153         done
154         (( x = tm[tm_mon] ))
155         while (( x < 0 )); do
156                 (( --y ))
157                 (( x += 12 ))
158         done
159         (( y += x / 12 ))
160         (( x %= 12 ))
161         if (( x < 2 )); then
162                 (( x += 10 ))
163                 (( --y ))
164         else
165                 (( x -= 2 ))
166         fi
167         (( day += (306 * x + 5) / 10 ))
168         while (( y < 0 )); do
169                 (( day -= 146097 ))
170                 (( y += 400 ))
171         done
172         (( day += 146097 * (y / 400) ))
173         (( y %= 400 ))
174         (( day += 365 * (y % 4) ))
175         (( y /= 4 ))
176         (( day += 1461 * (y % 25) + 36524 * (y / 25) ))
177
178         print -- $day $sec
179 }