SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
sddstimeconvert.c
Go to the documentation of this file.
1/**
2 * @file sddstimeconvert.c
3 * @brief Perform time conversions on SDDS data.
4 *
5 * @details
6 * This program enables users to perform various time-related operations on SDDS files.
7 * These operations include breaking down epoch times into components, converting date
8 * strings to epoch times, and specifying the major order of output data.
9 *
10 * @section Usage
11 * ```
12 * sddstimeconvert [<SDDSinput>] [<SDDSoutput>]
13 * [-pipe=<input>[,<output>]]
14 * [-majorOrder=row|column]
15 * [-breakdown={column|parameter},<timeName>[,year=<newName>][,julianDay=<newName>][,month=<newName>][,day=<newName>][,hour=<newName>][,text=<newName>]]
16 * [-dateToTime={column|parameter},<timeName>,<newName>,<stringName>,format=<formatString>]
17 * [-epoch={column|parameter},<newName>,year=<name>,[julianDay=<name>|month=<name>,day=<name>],hour=<name>]
18 * ```
19 *
20 * @section Options
21 * | Optional | Description |
22 * |---------------------------------------|---------------------------------------------------------------------------------------|
23 * | `-pipe` | Enable pipe-based input/output processing. |
24 * | `-majorOrder` | Specify output data order: row-major or column-major. |
25 * | `-breakdown=` | Break down epoch time into components such as year, month, day, hour, etc. |
26 * | `-dateToTime` | Convert date strings to epoch times based on a specified format string. |
27 * | `-epoch` | Generate a new epoch time column or parameter with optional qualifiers. |
28 *
29 * @subsection Incompatibilities
30 * - For `-epoch`, the following requirements must be met:
31 * - Specify either `julianDay` or both `month` and `day` names.
32 * - For `-breakdown`, at least one of the following must be specified:
33 * - `year`, `julianDay`, `month`, `day`, `hour`, or `text` qualifiers.
34 * - For `-dateToTime`, the `format` string is required.
35 *
36 * @copyright
37 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
38 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
39 *
40 * @license
41 * This file is distributed under the terms of the Software License Agreement
42 * found in the file LICENSE included with this distribution.
43 *
44 * @authors
45 * - M. Borland
46 * - R. Soliday
47 * - H. Shang
48 */
49
50#define _XOPEN_SOURCE
51#include <time.h>
52#include "mdb.h"
53#include "SDDS.h"
54#include "scan.h"
55
56/* Enumeration for option types */
57enum option_type {
58 SET_EPOCH,
59 SET_PIPE,
60 SET_BREAKDOWN,
61 SET_MAJOR_ORDER,
62 SET_DATE,
63 N_OPTIONS
64};
65
66char *option[N_OPTIONS] = {
67 "epoch",
68 "pipe",
69 "breakdown",
70 "majorOrder",
71 "date",
72};
73
74/* Improved and more readable usage message */
75char *USAGE =
76 "Usage:\n"
77 " sddstimeconvert [<SDDSinput>] [<SDDSoutput>] \n"
78 " [-pipe=<input>[,<output>]] \n"
79 " [-majorOrder=row|column]\n"
80 " [-breakdown={column|parameter},<timeName>[,year=<newName>]\n"
81 " [,julianDay=<newName>]\n"
82 " [,month=<newName>]\n"
83 " [,day=<newName>]\n"
84 " [,hour=<newName>]\n"
85 " [,text=<newName>]]\n"
86 " [-dateToTime={column|parameter},<timeName>,<newName>,<stringName>,format=<formatString>]\n"
87 " [-epoch={column|parameter},<newName>,year=<name>,[julianDay=<name>|month=<name>,day=<name>],hour=<name>]\n"
88 "Options:\n"
89 " -pipe Enable standard SDDS Toolkit pipe processing.\n"
90 " -majorOrder Specify output file order: row or column major.\n"
91 " -breakdown Break down epoch time into components.\n"
92 " -epoch Create a new epoch time column or parameter.\n"
93 " -dateToTime Convert date string to epoch time.\n\n"
94 "Program by Michael Borland. (" __DATE__ " " __TIME__ ", SVN revision: " SVN_VERSION ")\n";
95
96#define IS_COLUMN 0x0001U
97#define IS_PARAMETER 0x0002U
98#define EPOCH_GIVEN 0x0004U
99#define YEAR_GIVEN 0x0008U
100#define JDAY_GIVEN 0x0010U
101#define MONTH_GIVEN 0x0020U
102#define DAY_GIVEN 0x0040U
103#define HOUR_GIVEN 0x0080U
104#define DO_BREAKDOWN 0x0100U
105#define DO_EPOCH 0x0200U
106#define TEXT_GIVEN 0x0400U
107#define FORMAT_GIVEN 0x0800U
108#define DO_DATECONVERSION 0x1000U
109
110typedef struct
111{
112 char *epochName, *yearName, *jDayName, *monthName, *dayName, *hourName;
113 char *textName, *format;
114 long epochIndex, yearIndex, jDayIndex, monthIndex, dayIndex, hourIndex;
115 long textIndex;
116 unsigned long flags;
118
119void DoColumnEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
120void DoParameterEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
121void DoColumnDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
122void DoParameterDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
123void DoColumnBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
124void DoParameterBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion);
125void InitializeOutput(SDDS_DATASET *SDDSout, char *outputfile, TIME_CONVERSION *conversion, long conversions,
126 SDDS_DATASET *SDDSin, short columnMajorOrder);
127void CheckEpochConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
128void CheckBreakdownConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
129void CheckDateConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions);
130
131int main(int argc, char **argv) {
132 SDDS_DATASET SDDSin, SDDSout;
133 long i_arg, iconv;
134 SCANNED_ARG *s_arg;
135 char *input, *output;
136 TIME_CONVERSION *conversion;
137 long conversions;
138 unsigned long pipeFlags, majorOrderFlag;
139 short columnMajorOrder = -1;
140
142 argc = scanargs(&s_arg, argc, argv);
143 if (argc < 3) {
144 fprintf(stderr, "%s", USAGE);
145 exit(EXIT_FAILURE);
146 }
147
148 input = output = NULL;
149 conversions = 0;
150 conversion = NULL;
151 pipeFlags = 0;
152
153 for (i_arg = 1; i_arg < argc; i_arg++) {
154 if (s_arg[i_arg].arg_type == OPTION) {
155 switch (match_string(s_arg[i_arg].list[0], option, N_OPTIONS, 0)) {
156 case SET_MAJOR_ORDER:
157 majorOrderFlag = 0;
158 s_arg[i_arg].n_items--;
159 if (s_arg[i_arg].n_items > 0 &&
160 (!scanItemList(&majorOrderFlag, s_arg[i_arg].list + 1, &s_arg[i_arg].n_items, 0,
161 "row", -1, NULL, 0, SDDS_ROW_MAJOR_ORDER,
162 "column", -1, NULL, 0, SDDS_COLUMN_MAJOR_ORDER, NULL)))
163 SDDS_Bomb("invalid -majorOrder syntax/values");
164 if (majorOrderFlag & SDDS_COLUMN_MAJOR_ORDER)
165 columnMajorOrder = 1;
166 else if (majorOrderFlag & SDDS_ROW_MAJOR_ORDER)
167 columnMajorOrder = 0;
168 break;
169 case SET_EPOCH:
170 if (s_arg[i_arg].n_items < 4)
171 SDDS_Bomb("Invalid -epoch syntax");
172 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
173 SDDS_Bomb("Memory allocation failure");
174 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
175 conversion[conversions].epochName = s_arg[i_arg].list[2];
176 s_arg[i_arg].list[2] = s_arg[i_arg].list[1];
177 s_arg[i_arg].n_items -= 2;
178 if (!scanItemList(&conversion[conversions].flags,
179 s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
180 "column", -1, NULL, 0, IS_COLUMN,
181 "parameter", -1, NULL, 0, IS_PARAMETER,
182 "year", SDDS_STRING, &conversion[conversions].yearName, 1, YEAR_GIVEN,
183 "julianday", SDDS_STRING, &conversion[conversions].jDayName, 1, JDAY_GIVEN,
184 "month", SDDS_STRING, &conversion[conversions].monthName, 1, MONTH_GIVEN,
185 "day", SDDS_STRING, &conversion[conversions].dayName, 1, DAY_GIVEN,
186 "hour", SDDS_STRING, &conversion[conversions].hourName, 1, HOUR_GIVEN, NULL))
187 SDDS_Bomb("invalid -epoch syntax");
188 conversion[conversions].flags |= EPOCH_GIVEN | DO_EPOCH;
189 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
190 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -epoch");
191 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
192 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -epoch");
193 if (!(conversion[conversions].flags & YEAR_GIVEN))
194 SDDS_Bomb("Specify year name with -epoch");
195 if (!(conversion[conversions].flags & JDAY_GIVEN) &&
196 (conversion[conversions].flags & (MONTH_GIVEN | DAY_GIVEN)) != (MONTH_GIVEN | DAY_GIVEN))
197 SDDS_Bomb("Specify either julianDay name, or both month and day names with -epoch");
198 if (conversion[conversions].flags & JDAY_GIVEN && conversion[conversions].flags & (MONTH_GIVEN | DAY_GIVEN))
199 SDDS_Bomb("Invalid combination of julianDay name with month or day name for -epoch");
200 conversions++;
201 break;
202 case SET_BREAKDOWN:
203 if (s_arg[i_arg].n_items < 4)
204 SDDS_Bomb("Invalid -breakdown syntax");
205 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
206 SDDS_Bomb("Memory allocation failure");
207 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
208 conversion[conversions].epochName = s_arg[i_arg].list[2];
209 s_arg[i_arg].list[2] = s_arg[i_arg].list[1];
210 s_arg[i_arg].n_items -= 2;
211 if (!scanItemList(&conversion[conversions].flags,
212 s_arg[i_arg].list + 2, &s_arg[i_arg].n_items, 0,
213 "column", -1, NULL, 0, IS_COLUMN,
214 "parameter", -1, NULL, 0, IS_PARAMETER,
215 "year", SDDS_STRING, &conversion[conversions].yearName, 1, YEAR_GIVEN,
216 "julianday", SDDS_STRING, &conversion[conversions].jDayName, 1, JDAY_GIVEN,
217 "month", SDDS_STRING, &conversion[conversions].monthName, 1, MONTH_GIVEN,
218 "day", SDDS_STRING, &conversion[conversions].dayName, 1, DAY_GIVEN,
219 "hour", SDDS_STRING, &conversion[conversions].hourName, 1, HOUR_GIVEN,
220 "text", SDDS_STRING, &conversion[conversions].textName, 1, TEXT_GIVEN, NULL))
221 SDDS_Bomb("invalid -breakdown syntax");
222 conversion[conversions].flags |= EPOCH_GIVEN | DO_BREAKDOWN;
223 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
224 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -breakdown");
225 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
226 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -breakdown");
227 if (!(conversion[conversions].flags & (YEAR_GIVEN | JDAY_GIVEN | MONTH_GIVEN | DAY_GIVEN | HOUR_GIVEN | TEXT_GIVEN)))
228 SDDS_Bomb("Specify at least one of year, julianDay, month, day, hour, or text qualifiers with -breakdown");
229 conversions++;
230 break;
231 case SET_DATE:
232 if (s_arg[i_arg].n_items < 4)
233 SDDS_Bomb("Invalid -dateToTime syntax");
234 if (!(conversion = SDDS_Realloc(conversion, sizeof(*conversion) * (conversions + 1))))
235 SDDS_Bomb("Memory allocation failure");
236 memset((char *)(conversion + conversions), 0, sizeof(*conversion));
237 conversion[conversions].textName = s_arg[i_arg].list[3];
238 conversion[conversions].epochName = s_arg[i_arg].list[2];
239 s_arg[i_arg].list[3] = s_arg[i_arg].list[1];
240 s_arg[i_arg].n_items -= 3;
241 if (!scanItemList(&conversion[conversions].flags,
242 s_arg[i_arg].list + 3, &s_arg[i_arg].n_items, 0,
243 "column", -1, NULL, 0, IS_COLUMN,
244 "parameter", -1, NULL, 0, IS_PARAMETER,
245 "format", SDDS_STRING, &conversion[conversions].format, 1, FORMAT_GIVEN, NULL))
246 SDDS_Bomb("invalid -dateToTime syntax");
247 conversion[conversions].flags |= DO_DATECONVERSION;
248 if (!(conversion[conversions].flags & (IS_COLUMN | IS_PARAMETER)))
249 SDDS_Bomb("Specify 'column' or 'parameter' qualifier with -dateToTime");
250 if (conversion[conversions].flags & IS_COLUMN && conversion[conversions].flags & IS_PARAMETER)
251 SDDS_Bomb("Specify only one of 'column' or 'parameter' qualifier with -dateToTime");
252 if (!(conversion[conversions].flags & FORMAT_GIVEN))
253 SDDS_Bomb("Format string not provided for date to time conversion");
254 conversions++;
255 break;
256 case SET_PIPE:
257 if (!processPipeOption(s_arg[i_arg].list + 1, s_arg[i_arg].n_items - 1, &pipeFlags))
258 SDDS_Bomb("Invalid -pipe syntax");
259 break;
260 default:
261 fprintf(stderr, "Error: Unknown option: %s\n", s_arg[i_arg].list[0]);
262 SDDS_Bomb(NULL);
263 break;
264 }
265 } else {
266 if (!input)
267 input = s_arg[i_arg].list[0];
268 else if (!output)
269 output = s_arg[i_arg].list[0];
270 else {
271 fprintf(stderr, "Error: Argument '%s' is invalid: too many filenames (sddstimeconvert)\n", s_arg[i_arg].list[0]);
272 exit(EXIT_FAILURE);
273 }
274 }
275 }
276
277 processFilenames("sddstimeconvert", &input, &output, pipeFlags, 0, NULL);
278
279 if (!SDDS_InitializeInput(&SDDSin, input)) {
280 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
281 exit(EXIT_FAILURE);
282 }
283
284 CheckEpochConversionElements(&SDDSin, conversion, conversions);
285 CheckBreakdownConversionElements(&SDDSin, conversion, conversions);
286 CheckDateConversionElements(&SDDSin, conversion, conversions);
287
288 InitializeOutput(&SDDSout, output, conversion, conversions, &SDDSin, columnMajorOrder);
289
290 while (SDDS_ReadPage(&SDDSin) > 0) {
291 if (!SDDS_CopyPage(&SDDSout, &SDDSin)) {
292 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
293 exit(EXIT_FAILURE);
294 }
295 for (iconv = 0; iconv < conversions; iconv++) {
296 if (conversion[iconv].flags & DO_EPOCH) {
297 if (conversion[iconv].flags & IS_PARAMETER)
298 DoParameterEpochConversion(&SDDSout, &SDDSin, conversion + iconv);
299 else
300 DoColumnEpochConversion(&SDDSout, &SDDSin, conversion + iconv);
301 } else if (conversion[iconv].flags & DO_BREAKDOWN) {
302 if (conversion[iconv].flags & IS_PARAMETER)
303 DoParameterBreakdownConversion(&SDDSout, &SDDSin, conversion + iconv);
304 else
305 DoColumnBreakdownConversion(&SDDSout, &SDDSin, conversion + iconv);
306 } else {
307 /* Convert date string to double time */
308 if (conversion[iconv].flags & IS_PARAMETER)
309 DoParameterDateToTimeConversion(&SDDSout, &SDDSin, conversion + iconv);
310 else
311 DoColumnDateToTimeConversion(&SDDSout, &SDDSin, conversion + iconv);
312 }
313 }
314 if (!SDDS_WritePage(&SDDSout)) {
315 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
316 exit(EXIT_FAILURE);
317 }
318 }
319 if (!SDDS_Terminate(&SDDSin) || !SDDS_Terminate(&SDDSout)) {
320 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
321 exit(EXIT_FAILURE);
322 }
323
324 return EXIT_SUCCESS;
325}
326
327void CheckEpochConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
328 while (conversions-- > 0) {
329 if (!(conversion[conversions].flags & DO_EPOCH))
330 continue;
331 if (conversion->flags & IS_PARAMETER) {
332 if (SDDS_CheckParameter(SDDSin, conversion->yearName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK ||
333 (conversion->jDayName &&
334 SDDS_CheckParameter(SDDSin, conversion->jDayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
335 (conversion->dayName &&
336 SDDS_CheckParameter(SDDSin, conversion->dayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
337 (conversion->monthName &&
338 SDDS_CheckParameter(SDDSin, conversion->monthName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
339 SDDS_CheckParameter(SDDSin, conversion->hourName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
340 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
341 conversion->yearIndex = SDDS_GetParameterIndex(SDDSin, conversion->yearName);
342 conversion->hourIndex = SDDS_GetParameterIndex(SDDSin, conversion->hourName);
343 conversion->dayIndex = conversion->jDayIndex = conversion->monthIndex = -1;
344 if (conversion->dayName)
345 conversion->dayIndex = SDDS_GetParameterIndex(SDDSin, conversion->dayName);
346 if (conversion->jDayName)
347 conversion->jDayIndex = SDDS_GetParameterIndex(SDDSin, conversion->jDayName);
348 if (conversion->monthName)
349 conversion->monthIndex = SDDS_GetParameterIndex(SDDSin, conversion->monthName);
350 } else {
351 if (SDDS_CheckColumn(SDDSin, conversion->yearName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK ||
352 (conversion->jDayName &&
353 SDDS_CheckColumn(SDDSin, conversion->jDayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
354 (conversion->dayName &&
355 SDDS_CheckColumn(SDDSin, conversion->dayName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
356 (conversion->monthName &&
357 SDDS_CheckColumn(SDDSin, conversion->monthName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK) ||
358 SDDS_CheckColumn(SDDSin, conversion->hourName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
359 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
360 conversion->yearIndex = SDDS_GetColumnIndex(SDDSin, conversion->yearName);
361 conversion->hourIndex = SDDS_GetColumnIndex(SDDSin, conversion->hourName);
362 conversion->dayIndex = conversion->jDayIndex = conversion->monthIndex = -1;
363 if (conversion->dayName)
364 conversion->dayIndex = SDDS_GetColumnIndex(SDDSin, conversion->dayName);
365 if (conversion->jDayName)
366 conversion->jDayIndex = SDDS_GetColumnIndex(SDDSin, conversion->jDayName);
367 if (conversion->monthName)
368 conversion->monthIndex = SDDS_GetColumnIndex(SDDSin, conversion->monthName);
369 }
370 conversion++;
371 }
372}
373
374void CheckBreakdownConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
375 while (conversions-- > 0) {
376 if (!(conversion[conversions].flags & DO_BREAKDOWN))
377 continue;
378 if (conversion->flags & IS_PARAMETER) {
379 if (SDDS_CheckParameter(SDDSin, conversion->epochName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
380 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
381 conversion->epochIndex = SDDS_GetParameterIndex(SDDSin, conversion->epochName);
382 } else {
383 if (SDDS_CheckColumn(SDDSin, conversion->epochName, NULL, SDDS_ANY_NUMERIC_TYPE, stderr) != SDDS_CHECK_OK)
384 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
385 conversion->epochIndex = SDDS_GetColumnIndex(SDDSin, conversion->epochName);
386 }
387 conversion++;
388 }
389}
390
391void CheckDateConversionElements(SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion, long conversions) {
392 while (conversions-- > 0) {
393 if (!(conversion[conversions].flags & DO_DATECONVERSION))
394 continue;
395 if (conversion->flags & IS_PARAMETER) {
396 if (SDDS_CheckParameter(SDDSin, conversion->textName, NULL, SDDS_STRING, stderr) != SDDS_CHECK_OK)
397 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
398 conversion->textIndex = SDDS_GetParameterIndex(SDDSin, conversion->textName);
399 } else {
400 if (SDDS_CheckColumn(SDDSin, conversion->textName, NULL, SDDS_STRING, stderr) != SDDS_CHECK_OK)
401 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
402 conversion->textIndex = SDDS_GetColumnIndex(SDDSin, conversion->textName);
403 }
404 if (conversion->textIndex < 0) {
405 fprintf(stderr, "Error: '%s' does not exist in input file.\n", conversion->textName);
406 exit(EXIT_FAILURE);
407 }
408 conversion++;
409 }
410}
411
412void InitializeOutput(SDDS_DATASET *SDDSout, char *outputfile, TIME_CONVERSION *conversion, long conversions,
413 SDDS_DATASET *SDDSin, short columnMajorOrder) {
414 if (!SDDS_InitializeCopy(SDDSout, SDDSin, outputfile, "w"))
415 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
416 if (columnMajorOrder != -1)
417 SDDSout->layout.data_mode.column_major = columnMajorOrder;
418 else
419 SDDSout->layout.data_mode.column_major = SDDSin->layout.data_mode.column_major;
420 while (conversions-- > 0) {
421 if (conversion->flags & DO_EPOCH) {
422 if (conversion->flags & IS_PARAMETER) {
423 if ((conversion->epochIndex = SDDS_DefineParameter(SDDSout, conversion->epochName,
424 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, NULL)) < 0)
425 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
426 } else {
427 if ((conversion->epochIndex = SDDS_DefineColumn(SDDSout, conversion->epochName,
428 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, 0)) < 0)
429 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
430 }
431 } else if (conversion->flags & DO_BREAKDOWN) {
432 if (conversion->flags & IS_PARAMETER) {
433 if ((conversion->yearName &&
434 (conversion->yearIndex = SDDS_DefineParameter(SDDSout, conversion->yearName, NULL, NULL, "Year", NULL,
435 SDDS_SHORT, NULL)) < 0) ||
436 (conversion->dayName &&
437 (conversion->dayIndex = SDDS_DefineParameter(SDDSout, conversion->dayName, NULL, NULL, "Day of month",
438 NULL, SDDS_SHORT, NULL)) < 0) ||
439 (conversion->monthName &&
440 (conversion->monthIndex = SDDS_DefineParameter(SDDSout, conversion->monthName, NULL, NULL, "Month", NULL,
441 SDDS_SHORT, NULL)) < 0) ||
442 (conversion->jDayName &&
443 (conversion->jDayIndex = SDDS_DefineParameter(SDDSout, conversion->jDayName, NULL, NULL, "Julian day",
444 NULL, SDDS_SHORT, NULL)) < 0) ||
445 (conversion->hourName &&
446 (conversion->hourIndex = SDDS_DefineParameter(SDDSout, conversion->hourName, NULL, NULL, "Hour of day",
447 NULL, SDDS_DOUBLE, NULL)) < 0) ||
448 (conversion->textName &&
449 (conversion->textIndex = SDDS_DefineParameter(SDDSout, conversion->textName, NULL, NULL, "Timestamp",
450 NULL, SDDS_STRING, NULL)) < 0))
451 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
452 } else {
453 if ((conversion->yearName &&
454 (conversion->yearIndex = SDDS_DefineColumn(SDDSout, conversion->yearName, NULL, NULL, "Year", NULL,
455 SDDS_SHORT, 0)) < 0) ||
456 (conversion->dayName &&
457 (conversion->dayIndex = SDDS_DefineColumn(SDDSout, conversion->dayName, NULL, NULL, "Day of month",
458 NULL, SDDS_SHORT, 0)) < 0) ||
459 (conversion->monthName &&
460 (conversion->monthIndex = SDDS_DefineColumn(SDDSout, conversion->monthName, NULL, NULL, "Month", NULL,
461 SDDS_SHORT, 0)) < 0) ||
462 (conversion->jDayName &&
463 (conversion->jDayIndex = SDDS_DefineColumn(SDDSout, conversion->jDayName, NULL, NULL, "Julian day",
464 NULL, SDDS_SHORT, 0)) < 0) ||
465 (conversion->hourName &&
466 (conversion->hourIndex = SDDS_DefineColumn(SDDSout, conversion->hourName, NULL, NULL, "Hour of day",
467 NULL, SDDS_DOUBLE, 0)) < 0) ||
468 (conversion->textName &&
469 (conversion->textIndex = SDDS_DefineColumn(SDDSout, conversion->textName, NULL, NULL, "Timestamp",
470 NULL, SDDS_STRING, 0)) < 0))
471 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
472 }
473 } else {
474 /* Date to time conversion */
475 if (conversion->flags & IS_PARAMETER) {
476 if ((conversion->epochIndex = SDDS_DefineParameter(SDDSout, conversion->epochName,
477 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, NULL)) < 0)
478 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
479 } else {
480 if ((conversion->epochIndex = SDDS_DefineColumn(SDDSout, conversion->epochName,
481 NULL, "s", "Time since start of epoch", NULL, SDDS_DOUBLE, 0)) < 0)
482 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
483 }
484 }
485 conversion++;
486 }
487 if (!SDDS_WriteLayout(SDDSout))
488 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
489}
490
491void DoParameterEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
492 double hour;
493 double month = 0, day = 0, jDay = 0, year, epochTime;
494
495 jDay = 0;
496 if (!SDDS_GetParameterAsDouble(SDDSin, conversion->hourName, &hour) ||
497 !SDDS_GetParameterAsDouble(SDDSin, conversion->yearName, &year) ||
498 (conversion->jDayName && !SDDS_GetParameterAsDouble(SDDSin, conversion->jDayName, &jDay)) ||
499 (conversion->monthName && !SDDS_GetParameterAsDouble(SDDSin, conversion->monthName, &month)) ||
500 (conversion->dayName && !SDDS_GetParameterAsDouble(SDDSin, conversion->dayName, &day))) {
501 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
502 exit(EXIT_FAILURE);
503 }
504 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, &epochTime);
505 if (!SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_NAME | SDDS_PASS_BY_VALUE, conversion->epochName, epochTime, NULL))
506 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
507}
508
509void DoParameterBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
510 double hour, epochTime;
511 short year, jDay, month, day;
512 char text[30];
513
514 if (!SDDS_GetParameterAsDouble(SDDSin, conversion->epochName, &epochTime))
515 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
516 TimeEpochToBreakdown(&year, &jDay, &month, &day, &hour, epochTime);
517 TimeEpochToText(text, epochTime);
518 if ((conversion->yearName &&
519 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
520 conversion->yearIndex, (double)year, -1)) ||
521 (conversion->dayName &&
522 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
523 conversion->dayIndex, (double)day, -1)) ||
524 (conversion->jDayName &&
525 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
526 conversion->jDayIndex, (double)jDay, -1)) ||
527 (conversion->monthName &&
528 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
529 conversion->monthIndex, (double)month, -1)) ||
530 (conversion->hourName &&
531 !SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE,
532 conversion->hourIndex, (double)hour, -1)) ||
533 (conversion->textName &&
534 !SDDS_SetParameters(SDDSout, SDDS_BY_INDEX | SDDS_PASS_BY_VALUE, conversion->textIndex, text, -1)))
535 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
536}
537
538void DoParameterDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
539#if defined(_WIN32)
540 fprintf(stderr, "Error: strptime function needed by DoParameterDateToTimeConversion is not available on Windows\n");
541 exit(EXIT_FAILURE);
542#else
543 double hour;
544 double month = 0, day = 0, jDay = 0, year, epochTime;
545 char *timestr = NULL;
546 struct tm tm = {0};
547 /* Note that tm struct:
548 tm_year: years since 1900
549 tm_mon: months since January (0-11)
550 */
551
552 if (!SDDS_GetParameter(SDDSin, conversion->textName, &timestr)) {
553 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors);
554 exit(EXIT_FAILURE);
555 }
556 if (strptime(timestr, conversion->format, &tm) == NULL) {
557 fprintf(stderr, "Error: Failed to parse date string '%s' with format '%s'\n", timestr, conversion->format);
558 exit(EXIT_FAILURE);
559 }
560 year = tm.tm_year + 1900;
561 month = tm.tm_mon + 1;
562 day = tm.tm_mday;
563 hour = tm.tm_hour + tm.tm_min / 60.0 + tm.tm_sec / 3600.0;
564
565 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, &epochTime);
566 if (!SDDS_SetParametersFromDoubles(SDDSout, SDDS_BY_NAME | SDDS_PASS_BY_VALUE, conversion->epochName, epochTime, NULL))
567 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
568#endif
569}
570
571void DoColumnEpochConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
572 double *hour;
573 double *month, *day, *jDay, *year, *epochTime;
574 int64_t row, rows;
575
576 year = NULL;
577
578 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
579 return;
580
581 jDay = month = day = NULL;
582 if (!(hour = SDDS_GetColumnInDoubles(SDDSin, conversion->hourName)) ||
583 !(year = SDDS_GetColumnInDoubles(SDDSin, conversion->yearName)) ||
584 (conversion->jDayName && !(jDay = SDDS_GetColumnInDoubles(SDDSin, conversion->jDayName))) ||
585 (conversion->monthName && !(month = SDDS_GetColumnInDoubles(SDDSin, conversion->monthName))) ||
586 (conversion->dayName && !(day = SDDS_GetColumnInDoubles(SDDSin, conversion->dayName))))
587 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
588
589 if (!(epochTime = (double *)malloc(sizeof(*epochTime) * rows)))
590 SDDS_Bomb("Memory allocation failure");
591
592 for (row = 0; row < rows; row++)
593 TimeBreakdownToEpoch((short)year[row], jDay ? (short)jDay[row] : 0, month ? (short)month[row] : 0, day ? (short)day[row] : 0, hour[row], epochTime + row);
594 if (!SDDS_SetColumnFromDoubles(SDDSout, SDDS_BY_NAME, epochTime, rows, conversion->epochName))
595 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
596 free(hour);
597 free(year);
598 free(epochTime);
599 if (jDay)
600 free(jDay);
601 if (month)
602 free(month);
603 if (day)
604 free(day);
605}
606
607void DoColumnDateToTimeConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
608#if defined(_WIN32)
609 fprintf(stderr, "Error: strptime function needed by DoColumnDateToTimeConversion is not available on Windows\n");
610 exit(EXIT_FAILURE);
611#else
612 double hour;
613 double month = 0, day = 0, year = 0, jDay = 0, *epochTime;
614 int64_t row, rows;
615 char **timestr = NULL;
616 struct tm tm = {0};
617 /* Note that tm struct:
618 tm_year: years since 1900
619 tm_mon: months since January (0-11)
620 */
621 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
622 return;
623
624 if (!(timestr = SDDS_GetColumn(SDDSin, conversion->textName)))
625 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
626
627 if (!(epochTime = (double *)malloc(sizeof(*epochTime) * rows)))
628 SDDS_Bomb("Memory allocation failure");
629
630 for (row = 0; row < rows; row++) {
631 if (strptime(timestr[row], conversion->format, &tm) == NULL) {
632 fprintf(stderr, "Error: Failed to parse date string '%s' with format '%s'\n", timestr[row], conversion->format);
633 exit(EXIT_FAILURE);
634 }
635 year = tm.tm_year + 1900;
636 month = tm.tm_mon + 1;
637 day = tm.tm_mday;
638 hour = tm.tm_hour + tm.tm_min / 60.0 + tm.tm_sec / 3600.0;
639 TimeBreakdownToEpoch((short)year, (short)jDay, (short)month, (short)day, hour, epochTime + row);
640 }
641 if (!SDDS_SetColumnFromDoubles(SDDSout, SDDS_BY_NAME, epochTime, rows, conversion->epochName))
642 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
643 SDDS_FreeStringArray(timestr, rows);
644 free(epochTime);
645#endif
646}
647
648void DoColumnBreakdownConversion(SDDS_DATASET *SDDSout, SDDS_DATASET *SDDSin, TIME_CONVERSION *conversion) {
649 double *hour, *epochTime;
650 short *month, *day, *jDay, *year;
651 char **text;
652 int64_t row, rows;
653
654 if (!(rows = SDDS_CountRowsOfInterest(SDDSin)))
655 return;
656
657 if (!(epochTime = SDDS_GetColumnInDoubles(SDDSin, conversion->epochName)))
658 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
659
660 hour = NULL;
661 month = day = jDay = year = NULL;
662 text = NULL;
663 if ((conversion->hourName && !(hour = (double *)malloc(sizeof(*hour) * rows))) ||
664 (conversion->monthName && !(month = (short *)malloc(sizeof(*month) * rows))) ||
665 (conversion->dayName && !(day = (short *)malloc(sizeof(*day) * rows))) ||
666 (conversion->jDayName && !(jDay = (short *)malloc(sizeof(*jDay) * rows))) ||
667 (conversion->textName && !(text = (char **)malloc(sizeof(*text) * rows))) ||
668 (conversion->yearName && !(year = (short *)malloc(sizeof(*year) * rows))))
669 SDDS_Bomb("Memory allocation failure");
670
671 for (row = 0; row < rows; row++) {
672 if (text)
673 text[row] = malloc(sizeof(**text) * 30);
674 if (!TimeEpochToBreakdown(year ? year + row : NULL, jDay ? jDay + row : NULL, month ? month + row : NULL, day ? day + row : NULL, hour ? hour + row : NULL, epochTime[row]) ||
675 (text && !TimeEpochToText(text[row], epochTime[row])))
676 SDDS_Bomb("Problem performing time breakdown");
677 }
678
679 if ((year && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, year, rows, conversion->yearName)) ||
680 (day && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, day, rows, conversion->dayName)) ||
681 (month && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, month, rows, conversion->monthName)) ||
682 (jDay && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, jDay, rows, conversion->jDayName)) ||
683 (hour && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, hour, rows, conversion->hourName)) ||
684 (text && !SDDS_SetColumn(SDDSout, SDDS_BY_NAME, text, rows, conversion->textName)))
685 SDDS_PrintErrors(stderr, SDDS_VERBOSE_PrintErrors | SDDS_EXIT_PrintErrors);
686 if (hour)
687 free(hour);
688 if (year)
689 free(year);
690 if (epochTime)
691 free(epochTime);
692 if (jDay)
693 free(jDay);
694 if (month)
695 free(month);
696 if (day)
697 free(day);
698 if (text) {
699 for (row = 0; row < rows; row++)
700 free(text[row]);
701 free(text);
702 }
703}
SDDS (Self Describing Data Set) Data Types Definitions and Function Prototypes.
int32_t SDDS_InitializeCopy(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source, char *filename, char *filemode)
Definition SDDS_copy.c:40
int32_t SDDS_CopyPage(SDDS_DATASET *SDDS_target, SDDS_DATASET *SDDS_source)
Definition SDDS_copy.c:578
int32_t SDDS_SetParametersFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetParameters(SDDS_DATASET *SDDS_dataset, int32_t mode,...)
int32_t SDDS_SetColumnFromDoubles(SDDS_DATASET *SDDS_dataset, int32_t mode, double *data, int64_t rows,...)
Sets the values for a single data column using double-precision floating-point numbers.
int32_t SDDS_SetColumn(SDDS_DATASET *SDDS_dataset, int32_t mode, void *data, int64_t rows,...)
Sets the values for one data column in the current data table of an SDDS dataset.
void * SDDS_GetColumn(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves a copy of the data for a specified column, including only rows marked as "of interest".
double * SDDS_GetParameterAsDouble(SDDS_DATASET *SDDS_dataset, char *parameter_name, double *memory)
Retrieves the value of a specified parameter as a double from the current data table of an SDDS datas...
int64_t SDDS_CountRowsOfInterest(SDDS_DATASET *SDDS_dataset)
Counts the number of rows marked as "of interest" in the current data table.
void * SDDS_GetParameter(SDDS_DATASET *SDDS_dataset, char *parameter_name, void *memory)
Retrieves the value of a specified parameter from the current data table of a data set.
double * SDDS_GetColumnInDoubles(SDDS_DATASET *SDDS_dataset, char *column_name)
Retrieves the data of a specified numerical column as an array of doubles, considering only rows mark...
int32_t SDDS_InitializeInput(SDDS_DATASET *SDDS_dataset, char *filename)
Definition SDDS_input.c:49
int32_t SDDS_Terminate(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_ReadPage(SDDS_DATASET *SDDS_dataset)
int32_t SDDS_WritePage(SDDS_DATASET *SDDS_dataset)
Writes the current data table to the output file.
int32_t SDDS_DefineColumn(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, int32_t field_length)
Defines a data column within the SDDS dataset.
int32_t SDDS_WriteLayout(SDDS_DATASET *SDDS_dataset)
Writes the SDDS layout header to the output file.
int32_t SDDS_DefineParameter(SDDS_DATASET *SDDS_dataset, const char *name, const char *symbol, const char *units, const char *description, const char *format_string, int32_t type, char *fixed_value)
Defines a data parameter with a fixed string value.
int32_t SDDS_FreeStringArray(char **string, int64_t strings)
Frees an array of strings by deallocating each individual string.
int32_t SDDS_GetParameterIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named parameter in the SDDS dataset.
int32_t SDDS_GetColumnIndex(SDDS_DATASET *SDDS_dataset, char *name)
Retrieves the index of a named column in the SDDS dataset.
int32_t SDDS_CheckColumn(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a column exists in the SDDS dataset with the specified name, units, and type.
void SDDS_PrintErrors(FILE *fp, int32_t mode)
Prints recorded error messages to a specified file stream.
Definition SDDS_utils.c:432
void SDDS_RegisterProgramName(const char *name)
Registers the executable program name for use in error messages.
Definition SDDS_utils.c:288
void SDDS_Bomb(char *message)
Terminates the program after printing an error message and recorded errors.
Definition SDDS_utils.c:342
int32_t SDDS_CheckParameter(SDDS_DATASET *SDDS_dataset, char *name, char *units, int32_t type, FILE *fp_message)
Checks if a parameter exists in the SDDS dataset with the specified name, units, and type.
void * SDDS_Realloc(void *old_ptr, size_t new_size)
Reallocates memory to a new size.
Definition SDDS_utils.c:677
#define SDDS_STRING
Identifier for the string data type.
Definition SDDStypes.h:85
#define SDDS_SHORT
Identifier for the signed short integer data type.
Definition SDDStypes.h:73
#define SDDS_ANY_NUMERIC_TYPE
Special identifier used by SDDS_Check*() routines to accept any numeric type.
Definition SDDStypes.h:157
#define SDDS_DOUBLE
Identifier for the double data type.
Definition SDDStypes.h:37
long match_string(char *string, char **option, long n_options, long mode)
Matches a given string against an array of option strings based on specified modes.
int scanargs(SCANNED_ARG **scanned, int argc, char **argv)
Definition scanargs.c:36
long processPipeOption(char **item, long items, unsigned long *flags)
Definition scanargs.c:356
void processFilenames(char *programName, char **input, char **output, unsigned long pipeFlags, long noWarnings, long *tmpOutputUsed)
Definition scanargs.c:390
long scanItemList(unsigned long *flags, char **item, long *items, unsigned long mode,...)
Scans a list of items and assigns values based on provided keywords and types.
short TimeEpochToBreakdown(short *year, short *jDay, short *month, short *day, double *hour, double epochTime)
Breaks down epoch time into its constituent components.
short TimeBreakdownToEpoch(short year, short jDay, short month, short day, double hour, double *epochTime)
Converts a broken-down time into epoch time.
short TimeEpochToText(char *text, double epochTime)
Converts epoch time to a formatted text string.