ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/JSOC/proj/util/apps/time_convert.c
Revision: 1.5
Committed: Mon Nov 16 22:25:03 2009 UTC (13 years, 10 months ago) by kehcheng
Content type: text/plain
Branch: MAIN
CVS Tags: Ver_6-0, Ver_6-1, Ver_6-2, Ver_6-3, Ver_6-4, Ver_9-1, Ver_5-14, Ver_5-13, Ver_5-12, Ver_5-11, Ver_5-10, Ver_LATEST, Ver_9-3, Ver_5-7, Ver_5-6, Ver_9-41, Ver_9-2, Ver_5-9, Ver_8-8, Ver_5-8, Ver_8-2, Ver_8-3, Ver_8-0, Ver_8-1, Ver_8-6, Ver_8-7, Ver_8-4, Ver_8-5, Ver_7-1, Ver_7-0, Ver_9-5, Ver_9-4, Ver_8-10, Ver_8-11, Ver_8-12, Ver_9-0
Changes since 1.4: +1 -1 lines
Log Message:
Fix typo (1997 -> 1977).

File Contents

# Content
1 /*
2 * time_convert - change TAI time since 1977 into ascii with a given timezone
3 * and from an ascii time to seconds. Takes one argument of time or seconds and an optional
4 * flag argument of time zone. Default is UTC for conversion to ascii.
5 */
6
7 /**
8 @defgroup time_convert time_convert
9 @ingroup su_util
10
11 @brief Convert among the internal DRMS time representation and other time representations.
12
13 @par Synopsis:
14 @code
15 time_convert -h
16 time_convert s=<secondsJSOC> | sdo=<secondsSDO> | egse=<secondsEGSE> | time=<calenderTime> |
17 ord=<ordinalDate> [o=jsoc | o=sdo | o=egse | o=ord | o=cal] [zone=<zone>] [p=<precision>]
18
19 @endcode
20
21 Converts internal DRMS time (seconds since 15 seconds
22 before January 1, 1977 UTC) to an external ascii string
23 representation. The exact external representation depends on the command-line
24 arguments provided to this utility. Possiblities include: <tt>SDO time</tt>,
25 <tt>EGSE time</tt>, <tt>Ordinal date</tt>, and <tt>Calendar time</tt>.
26 <tt>SDO time</tt> is the number of seconds that have elapsed since
27 January 1, 1958 TAI, i.e. SDO onboard time. The full format is the string
28 representation of a double data type. <tt>EGSE time</tt> is
29 the number of seconds that have elapsed since @e APPROXIMATELY January 1, 2004 UTC
30 (actual epoch is 2003.12.30_23:59:36.000_UTC). The full format is also the string
31 representation of a double data type. <tt>Ordinal date</tt> is
32 the day number of the year (starting at day 1 on January 1). The full format
33 is YYYY.DDD[_ZZZ], where YYYY is the year, DDD is the day number, and ZZZ is the
34 zone (e.g., UTC, TDT, PDT, etc.). <tt>Calendar time</tt> gives the year, month, date, hour,
35 minutes, and seconds for a given system of time (like @e UTC). The full format is
36 specified in <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html),
37 but in short it looks like:
38
39 @par
40 1. year.month.fracday[_type]
41 @par
42 2. year.month.day_hour:minute[:second][_type]
43 @par
44 3. {MJD|JD}_julday[_type]
45
46 where @a type refers to the time system or time zone (e.g., @e UTC, or @e PST), @e MJD and
47 @e JD refer to Modified Julian Date and Julian Date, and @e julday refers to a Julian
48 day number.
49
50 The precision of the seconds field is specified with the <tt>p</tt> parameter. The default is 0. Setting p=3 will produce output identical to the original version of time_convert.
51
52 Alternatively, and with the appropriate command-line parameters, @ref time_convert
53 converts from any supported time representation to any other representation.
54
55 If multiple input format strings are specified as arguments
56 (e.g., time_convert s=234235235.35 ord=1982.035), only one will be used. A descriptive
57 string will be printed describing which input string was used. Given a definitive
58 input format, @ref time_convert chooses a default output format. If the input is
59 an internal time, an SDO time, an EGSE time, or an ordinal date, the default output
60 is a calendar time. If the definitive input format is a calendar time, the default
61 output is an internal time. The default output format can be overwritten
62 by providing the @a o=format argument.
63
64 When the output format is either an ordinal time or a calendar time, the
65 time can be expressed in any of several supported time systems (e.g., @e UTC,
66 @e TDT, @e TAI, or even a time zone, like @e PDT). This is accomplished by
67 supplying the appropriate @a zone=system argument. Refer to
68 <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html) for a
69 complete list of the supported "zones".
70
71 The default time format is with no fractions of seconds. If o=jsoc is specified the seconds are provided to the nearest ms.
72
73 @par Flags:
74 @c -h: Show usage message.
75
76 @param s An input time formatted as an internal time.
77 <secondsJSOC> is seconds since 15 seconds before January 1, 1977 UTC.
78 @param sdo An input time formatted as an SDO time.
79 <secondsSDO> is seconds since January 1, 1958 TAI.
80 @param egse An input time formatted as an EGSE time.
81 <secondsEGSE> is seconds since 2003.12.30_23:59:36.000_UTC
82 @param time An input time formatted as a calendar time.
83 <calenderTime> is as specified in
84 <tt>JSOC TN 07-001</tt> (http://jsoc.stanford.edu/doc/timerep.html)
85 @param ord An input time formatted as an ordinal date.
86 <ordinalDate> is yyyy.ddd[_zone], where @a zone is any supported
87 time system as specified in <tt>JSOC TN 07-001</tt>
88 (http://jsoc.stanford.edu/doc/timerep.html).
89 @param o The output format to be used. "jsoc" refers to internal time;
90 "sdo" refers to SDO time; "egse" refers to EGSE time;
91 "ord" refers to ordinal date; and "cal" refers to calendar time.
92
93 @par Example to convert an internal time to the default output format (UTC calendar time):
94 @code
95 time_convert s=234253535.23
96 @endcode
97
98 @par Example to convert an internal time to the default output format (calendar time), but in TAI time:
99 @code
100 time_convert s=234253535.23 zone=TAI
101 @endcode
102
103 @par Example to convert an internal time to an EGSE time:
104 @code
105 time_convert s=234253535.23 o=egse
106 @endcode
107
108 @par Example to convert an EGSE time to a calendar time in the PDT time zone:
109 @code
110 time_convert egse=232533636.362 o=cal zone=PDT
111 @endcode
112
113 @par Example to convert an ordinal time to a calendar time in the TDT system:
114 @code
115 time_convert ord=2007.352 o=cal zone=TDT
116 @endcode
117
118 @par Example to convert a calendar time to an internal time:
119 @code
120 time_convert time=1998.02.04_06:00:17.230_UTC
121 @endcode
122
123 @par Example to convert a calendar time to an internal time (explicitly):
124 @code
125 time_convert time=1998.02.04_06:00:17.230_UTC o=jsoc
126 @endcode
127
128 @par Example to convert a calendar time to an SDO time
129 @code
130 time_convert time=1998.02.04_06:00:17.230_UTC o=sdo
131 @endcode
132 */
133 /* @{ */
134 #include <stdlib.h>
135 #include <time.h>
136 #include <errno.h>
137 #include <stdio.h>
138 #include "timeio.h"
139 #include "jsoc.h"
140 #include "cmdparams.h"
141
142 ModuleArgs_t module_args[] =
143 {
144 {ARG_STRING, "s", "NOT SPECIFIED", "<DSDS/JSOC time in seconds>"},
145 {ARG_STRING, "sdo", "NOT SPECIFIED", "<SDO time in seconds>"},
146 {ARG_STRING, "egse", "NOT SPECIFIED", "<EGSE time in seconds>"},
147 {ARG_STRING, "time", "NOT SPECIFIED", "<Time as yyyy.mm...>"},
148 {ARG_STRING, "ord", "NOT SPECIFIED", "<Time as yyyy.ddd...>"},
149 {ARG_STRING, "zone", "UTC", "<Time zone>"},
150 {ARG_STRING, "o", "NOT SPECIFIED", "format of time output"},
151 {ARG_INT, "p", "0", "precision of seconds for time output"},
152 {ARG_FLAG, "h", "0", "help message"},
153 {ARG_END}
154 };
155
156 ModuleArgs_t *gModArgs = module_args;
157 /* @} */
158
159 CmdParams_t cmdparams;
160
161 #define SEC1970TO2004 1072828800
162 #define SECSPERDAY 86400.0
163
164 typedef enum
165 {
166 kTimeFormat_None = 0,
167 kTimeFormat_Internal,
168 kTimeFormat_SDO,
169 kTimeFormat_EGSE,
170 kTimeFormat_Ordinal,
171 kTimeFormat_Calendar
172 } TimeFormat_t;
173
174 char *TimeFormatStr[] =
175 {
176 "None",
177 "Internal/JSOC",
178 "SDO",
179 "EGSE",
180 "Ordinal",
181 "Calendar"
182 };
183
184 static void PrintTime(TIME t, TimeFormat_t f, int precision);
185 static TIME ZoneAdjustment(TIME t, char *zone, int precision);
186
187 int nice_intro ()
188 {
189 int usage = cmdparams_get_int (&cmdparams, "h", NULL);
190 if (usage)
191 {
192 printf ("Usage:\ntime_convert -h\n"
193 "time_convert s=<secondsJSOC>|sdo=<secondsSDO>|egse=<secondsEGSE>|time=<calender time>|ord=<ordinal date> [o=jsoc | o=sdo | o=egse | o=ord | o=cal] [zone=<zone>]\n"
194 "<secondsJSOC> = JSOC standard internal time, i.e. secs since 1977.01.01_TAI \n"
195 "<secondsSDO> = seconds since January 1, 1958 TAI, i.e. SDO onboard time\n"
196 "<secondsEGSE> = seconds since APPROXIMATELY January 1, 2004 \n"
197 "<calender time> = yyyy.mm.dd_hh:mm:ss<zone>\n"
198 "<ordinal date> = yyyy.ddd<zone>\n"
199 "<zone> = time zone as UT, TAI, PST, etc. - default is UTC\n"
200 "h - show usage message\n"
201 "o - output time in format specified\n"
202 "p - precision of seconds printed\n");
203 return(1);
204 }
205 return (0);
206 }
207
208 int main(int argc, char **argv)
209 {
210 int status;
211 TIME sscan_time(char *s);
212
213 char *s, *sdo, *time;
214 char *ord; /* Users can now supply the time argument as an ordinal date ('day-of-year' format - ISO 8601): YYYY.DDD */
215 char *egse = NULL;
216 char *oArg = NULL;
217 int precision = 0;
218
219 TIME t;
220
221 /* Parse command line parameters */
222 status = cmdparams_parse (&cmdparams, argc, argv);
223 if (status == CMDPARAMS_QUERYMODE)
224 {
225 cmdparams_usage (argv[0]);
226 return 0;
227 }
228
229 if (nice_intro ())
230 return (0);
231
232 /* The are the different types of input. */
233 s = cmdparams_get_str(&cmdparams, "s", NULL);
234 sdo = cmdparams_get_str(&cmdparams, "sdo", NULL);
235 time = cmdparams_get_str(&cmdparams, "time", NULL);
236 ord = cmdparams_get_str(&cmdparams, "ord", NULL);
237 egse = cmdparams_get_str(&cmdparams, "egse", NULL);
238
239 /* Determine seconds precision */
240 precision = cmdparams_get_int(&cmdparams, "p", NULL);
241
242 int err = 0;
243
244 TIME timeToPrint;
245 TimeFormat_t inputFormat = kTimeFormat_None;
246 TimeFormat_t outputFormat = kTimeFormat_None;
247 TimeFormat_t outputOverride = kTimeFormat_None;
248 int mFormats = 0;
249
250 /* These are the different types of output. */
251 oArg = cmdparams_get_str(&cmdparams, "o", NULL);
252 if (strcmp(oArg, "NOT SPECIFIED") != 0)
253 {
254 if (strcmp(oArg, "jsoc") == 0)
255 {
256 outputOverride = kTimeFormat_Internal;
257 }
258 else if (strcmp(oArg, "sdo") == 0)
259 {
260 outputOverride = kTimeFormat_SDO;
261 }
262 else if (strcmp(oArg, "egse") == 0)
263 {
264 outputOverride = kTimeFormat_EGSE;
265 }
266 else if (strcmp(oArg, "ord") == 0)
267 {
268 outputOverride = kTimeFormat_Ordinal;
269 }
270 else if (strcmp(oArg, "cal") == 0)
271 {
272 outputOverride = kTimeFormat_Calendar;
273 }
274 else
275 {
276 fprintf(stderr, "Output format %s is not recognized. Using default.\n", oArg);
277 }
278 }
279
280 if (strcmp(s, "NOT SPECIFIED")!= 0)
281 {
282 /* internal seconds was specified */
283 if (inputFormat == kTimeFormat_None)
284 {
285 sscanf(s, "%lf", &t);
286 timeToPrint = t;
287 outputFormat = kTimeFormat_Calendar;
288 inputFormat = kTimeFormat_Internal;
289 }
290 else
291 {
292 mFormats = 1;
293 }
294 }
295 if (strcmp(sdo, "NOT SPECIFIED")!= 0)
296 {
297 /* SDO seconds was specified */
298 if (inputFormat == kTimeFormat_None)
299 {
300 sscanf(sdo, "%lf", &t);
301 timeToPrint = t + sscan_time("1958.01.01_00:00:00_TAI");
302 outputFormat = kTimeFormat_Calendar;
303 inputFormat = kTimeFormat_SDO;
304 }
305 else
306 {
307 mFormats = 1;
308 }
309 }
310 if (strcmp(egse, "NOT SPECIFIED") != 0)
311 {
312 /* Time since ~ 1/1/2004 was provided as input */
313 if (inputFormat == kTimeFormat_None)
314 {
315 sscanf(egse, "%lf", &t);
316 timeToPrint = t + SEC1970TO2004 + sscan_time("1970.01.01_00:00_UTC");
317 outputFormat = kTimeFormat_Calendar;
318 inputFormat = kTimeFormat_EGSE;
319 }
320 else
321 {
322 mFormats = 1;
323 }
324 }
325 if (strcmp(time, "NOT SPECIFIED")!= 0)
326 {
327 /* calendar time string was specified */
328 if (inputFormat == kTimeFormat_None)
329 {
330 t = sscan_time(time);
331 timeToPrint = t;
332 outputFormat = kTimeFormat_Internal;
333 inputFormat = kTimeFormat_Calendar;
334 }
335 else
336 {
337 mFormats = 1;
338 }
339 }
340 if (ord != NULL && *ord != NULL && strcmp(ord, "NOT SPECIFIED") != 0)
341 {
342 /* day-of-year was specified - convert to internal representation */
343 if (inputFormat == kTimeFormat_None)
344 {
345 err = 1;
346
347 long year = 0;
348 int day = 0;
349 char *tFormat = NULL;
350
351 char *ordDate = strdup(ord);
352 int timeStrLen = strlen(ordDate);
353
354 if (ordDate != NULL)
355 {
356 char *loc = strchr(ordDate, '.');
357 char *loc2 = strchr(ordDate, '_');
358
359 if (loc != NULL)
360 {
361 *loc = '\0';
362
363 if (sscanf(ordDate, "%ld", &year) != 0)
364 {
365 if (loc2 != NULL && loc2 > loc)
366 {
367 *loc2 = '\0';
368 sscanf(loc + 1, "%d", &day);
369
370 if (loc2 + 1 <= &ordDate[timeStrLen - 1])
371 {
372 tFormat = (char *)malloc(sizeof(char) * strlen(loc2 + 1) + 1);
373 if (tFormat)
374 {
375 sscanf(loc2 + 1, "%s", tFormat);
376 }
377 }
378 }
379 else if (loc + 1 <= &ordDate[timeStrLen - 1])
380 {
381 sscanf((loc + 1), "%d", &day);
382 }
383
384 err = (day < 1 || day > 366);
385
386 if (!err)
387 {
388 /* first convert to calendar date */
389 char timeBuf[64];
390 snprintf(timeBuf, sizeof(timeBuf), "%ld.01.%d_00:00_%s", year, day, tFormat ? tFormat : "UT");
391 /* then use sscan_time to convert to internal time */
392 // t = sscan_time(timeBuf) - sscan_time("1977.01.01_00:00_TAI");
393 // sscan_time("1977.01.01_00:00_TAI") == 0
394 t = sscan_time(timeBuf);
395 timeToPrint = t;
396 outputFormat = kTimeFormat_Internal;
397 inputFormat = kTimeFormat_Ordinal;
398 }
399 else
400 {
401 fprintf(stderr, "invalid day of year\n");
402 }
403 }
404 else
405 {
406 fprintf(stderr, "invalid year\n");
407 }
408 }
409 else
410 {
411 fprintf(stderr, "missing day of year\n");
412 }
413
414 free(ordDate);
415 }
416
417 if (tFormat)
418 {
419 free(tFormat);
420 }
421 }
422 else
423 {
424 mFormats = 1;
425 }
426 }
427
428 if (inputFormat == kTimeFormat_None)
429 {
430 fprintf(stderr, "No input format specified.\n");
431 err = 1;
432 }
433 else if (mFormats)
434 {
435 fprintf(stderr,
436 "Multiple input formats specified, using %s time\n",
437 TimeFormatStr[inputFormat]);
438 }
439
440 if (outputOverride != kTimeFormat_None)
441 {
442 outputFormat = outputOverride;
443 }
444
445 if (!err)
446 {
447 PrintTime(timeToPrint, outputFormat, precision);
448 }
449
450 if (err)
451 {
452 fprintf(stderr,"time_convert call error\n");
453 return(1);
454 }
455 else
456 {
457 return(0);
458 }
459 }
460
461 /* t is time in TAI seconds since 1/1/1977, f is the format in which to print the time string */
462 void PrintTime(TIME t, TimeFormat_t f, int precision)
463 {
464 if (f == kTimeFormat_Calendar)
465 {
466 char at[128];
467 sprint_time(at, t, cmdparams_get_str(&cmdparams, "zone", NULL), precision);
468 // broken for precision == 3, causes seg fault, fixed maybe
469 // sprint_time(at, t, cmdparams_get_str(&cmdparams, "zone", NULL), 0);
470 printf("%s\n", at);
471 }
472 else if (f == kTimeFormat_SDO)
473 {
474 /* no zone associated with sdo time, so zone parameter is ignored */
475 printf("%12.*f\n", precision, t - sscan_time("1958.01.01_00:00:00_TAI"));
476 }
477 else if (f == kTimeFormat_EGSE)
478 {
479 /* no zone associated with egse time, so zone parameter is ignored */
480 printf("%12.*f\n", precision, t - SEC1970TO2004 - sscan_time("1970.01.01_00:00_UTC"));
481 }
482 else if (f == kTimeFormat_Ordinal)
483 {
484 /* This does NOT provide a fractional day - any fractional part is discarded. */
485 int ordTimeDays = 0;
486 char zoneStr[32];
487 char at[128];
488 TIME jan1 = 0;
489 TIME secsSinceJan1 = 0;
490
491 char *zone = cmdparams_get_str(&cmdparams, "zone", NULL);
492
493 /* First, get internal time for January 1 of the year we are going to output. */
494 sprint_time(at, t, zone, precision);
495 char *tz = strrchr(at, '_');
496
497 if (tz)
498 {
499 snprintf(zoneStr, sizeof(zoneStr), "_%s", tz + 1);
500 }
501
502 char *dot = strchr(at, '.');
503 if (dot != NULL)
504 {
505 *dot = '\0';
506 char timeStr[64];
507 snprintf(timeStr, sizeof(timeStr), "%s.01.01_00:00:00%s", at, zoneStr);
508 jan1 = sscan_time(timeStr);
509 }
510
511 secsSinceJan1 = t - jan1;
512
513 /* Now, get zone adjustment for jan1 and t. Subtract Adj(t) - Adj(jan1) from
514 * secsSinceJan1. */
515 TIME adjJan1 = ZoneAdjustment(jan1, zone, precision);
516 TIME adjT = ZoneAdjustment(t, zone, precision);
517 TIME ordTimeSecs = secsSinceJan1 - (adjT - adjJan1);
518
519 /* Divide by TAI secs per day (86400). */
520 ordTimeDays = 1 + ordTimeSecs / SECSPERDAY;
521
522 /* Output */
523 printf("%s.%03d%s\n", at, ordTimeDays, zoneStr);
524 }
525 else
526 {
527 if (f != kTimeFormat_Internal)
528 {
529 // format error
530 fprintf(stderr, "Invalid output format, defaulting to JSOC time.\n");
531 }
532 printf("%0.*f\n", precision, t);
533 }
534 }
535
536 /* <t> is the TAI-seconds equivalent of a time in the <zone> time zone. */
537 TIME ZoneAdjustment(TIME t, char *zone, int precision)
538 {
539 char timestr[128];
540 sprint_time(timestr, t, zone, precision);
541
542 char *tz = strrchr(timestr, '_');
543 tz[1] = 'T';
544 tz[2] = 'A';
545 tz[3] = 'I';
546 tz[4] = '\0';
547
548 TIME taiDateSecs = sscan_time(timestr);
549 return t - taiDateSecs;
550 }