1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
#!/usr/bin/env texlua
--
-- diadia [options]
--
-- loads and processes a diadia data file
--
-- License: LPPL
--
local version = "v1.0 (2015/05/15)"
local infile = ""
local outfile = ""
local mode = "*"
local startdate = ""
local enddate = ""
local columns = ""
local data = {}
function pversion()
print("diadia.lua " .. version)
print("(C) Josef Kleber 2015 License: LPPL")
os.exit(0)
end
function phelp()
print([[
diadia.lua [options]
allows you to
- cut a chunk out of the data file
e.g.: -i in.dat -o out.dat -s YYYY-MM-DD -e YYYY-MM-DD
- compose a new data file based on given columns of an
existing data file
e.g.: -i in.dat -o out.dat -c 1,2
- create a new data file with date and value (1st and
2nd column of existing file) and added value average
columns of the last 7, 14, 30, 60 and 90 days
e.g.: -i in.dat -o out.dat [-s YYYY-MM-DD -e YYYY-MM-DD]
Options:
-m specify the mode (cut|compose|average)
-i specify the input file
-o specify the output file
-c specify the columns for compose mode
-s specify the start date (YYYY-MM-DD) in
cut and average mode
-e specify the end date
-v prints version information
-h prints help information
]])
pversion()
end
function check_date(date)
if string.find(date, "(%d%d%d%d)-(%d%d)-(%d%d)") == nil
then
io.stderr:write ("Error 21: wrong date format (YYYY-MM-DD)\n")
os.exit(11)
end
end
function parse_date(date)
return string.match(date, "(%d%d%d%d)%-(%d%d)%-(%d%d)")
end
function parse_dateinline(line)
return string.match(line, "(%d%d%d%d%-%d%d%-%d%d)")
end
function daystring(unixtime)
return os.date("%Y-%m-%d", unixtime)
end
function unixtime(year,month,day)
return os.time{year=year, month=month, day=day}
end
function round(number)
return math.floor(number+0.5)
end
function ptd(value)
local val = tostring(value)
local slen = string.len(val)
if slen == 3
then
return val
else
return val .. " "
end
end
function calc_avg(data,date,days)
local sum = 0
local wdays = 0
local wday
local endday = unixtime(parse_date(date))
local startday = endday - 60*60*24*(days-1)
while startday <= endday
do
wday = daystring(startday)
if data[wday] ~= nil
then
sum = sum + data[wday]
wdays = wdays + 1
end
startday = startday + 60*60*24
end
if wdays == 0
then
return "nan"
else
return tostring(round(sum/wdays))
end
end
function read_data(file)
local data = {}
local date
local startdate
local enddate
local dat
local firstline = true
for line in io.lines(file)
do
if string.match(line, "date")
then
else
date, dat = string.match(line, "(%d%d%d%d%-%d%d%-%d%d)%s+(%S+)")
if firstline == true
then
startdate = date
firstline = false
end
if dat ~= "nan" and dat ~= "{}" and dat ~= ""
then
data[date] = dat
end
end
end
enddate = date
return data,startdate,enddate
end
function write_avg_file(data,file,startdate,enddate)
local sdate
local edate
local wday
sdate = unixtime(parse_date(startdate))
edate = unixtime(parse_date(enddate))
outfile = assert(io.open(file, "w"))
outfile:write("date value avg07 avg14 avg30 avg60 avg90")
while sdate <= edate+7200
do
wday = daystring(sdate)
if data[wday] ~= nil
then
outfile:write("\n" .. wday .. " "
.. ptd(data[wday]) .. " "
.. ptd(calc_avg(data,wday,7)) .. " "
.. ptd(calc_avg(data,wday,14)) .. " "
.. ptd(calc_avg(data,wday,30)) .. " "
.. ptd(calc_avg(data,wday,60)) .. " "
.. ptd(calc_avg(data,wday,90)))
end
sdate = sdate + 60*60*24
end
outfile:close()
end
do
local newarg = {}
local i, limit = 1, #arg
while (i <= limit) do
if arg[i] == "-i" then
infile = arg[i+1]
i = i + 1
elseif arg[i] == "-o" then
outfile = arg[i+1]
i = i + 1
elseif arg[i] == "-s" then
startdate = arg[i+1]
i = i + 1
elseif arg[i] == "-e" then
enddate = arg[i+1]
i = i + 1
elseif arg[i] == "-c" then
columns = arg[i+1]
i = i + 1
elseif arg[i] == "-m" then
mode = arg[i+1]
i = i + 1
elseif arg[i] == "-v" then
pversion()
elseif arg[i] == "-h" then
phelp()
else
newarg[#newarg+1] = arg[i]
end
i = i + 1
end
arg = newarg
end
if mode == "average"
then
local startd
local endd
print("set mode to " .. mode)
print("reading data file " .. infile)
data,startd,endd = read_data(infile)
if startdate ~= ""
then
startd = startdate
end
if enddate ~= ""
then
endd = enddate
end
print("writing data file " .. outfile)
write_avg_file(data,outfile,startd,endd)
os.exit(0)
end
if mode == "compose"
then
local row = 0
local column = 0
local ofile
local cols
print("set mode to " .. mode)
print("reading data file " .. infile)
for line in io.lines(infile)
do
row = row + 1
data[row] = {}
column = 0
for value in string.gmatch(line, "%S+")
do
column = column + 1
data[row][column] = value
end
end
cols = assert(load("return table.concat({"..columns:gsub("%d+","(...)[%0]").."},' ')"))
ofile = assert(io.open(outfile, "w"))
print("writing data file " .. outfile)
for irow = 1,row
do
if irow == row
then
ofile:write(cols(data[irow]))
else
ofile:write(cols(data[irow]).."\n")
end
end
ofile:close()
os.exit(0)
end
if mode == "cut"
then
local ofile
local date
local sdate
local edate
local cdate
check_date(startdate)
check_date(enddate)
sdate = unixtime(parse_date(startdate))
edate = unixtime(parse_date(enddate))
print("set mode to " .. mode)
print("reading data file " .. infile)
print("writing data file " .. outfile)
ofile = assert(io.open(outfile, "w"))
for line in io.lines(infile)
do
if string.match(line, "date")
then
ofile:write(line)
else
date = parse_dateinline(line)
cdate = unixtime(parse_date(date))
if cdate >= sdate and cdate <= edate
then
ofile:write("\n" .. line)
end
end
end
ofile:close()
os.exit(0)
end
if mode == "*"
then
io.stderr:write ("Error 11: no mode specified!")
os.exit(11)
else
io.stderr:write ("Error 12: invalid mode " .. mode)
os.exit(12)
end
|