GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
timestamp.c
Go to the documentation of this file.
1 /*!
2  * \file lib/gis/timestamp.c
3  *
4  * \brief GIS Library - Timestamp management
5  *
6  * Provides DateTime functions for timestamp management.
7  *
8  * The timestamp values must use the format as described in the GRASS
9  * datetime library. The source tree for this library should have a
10  * description of the format. For convience, the formats as of Feb, 1996
11  * are reproduced here:
12  *
13  * There are two types of datetime values: absolute and relative. Absolute
14  * values specify exact dates and/or times. Relative values specify a span
15  * of time. Some examples will help clarify:
16  *
17  * Absolute
18  *
19  * The general format for absolute values is:
20  *
21  * day month year [bc] hour:minute:seconds timezone
22  *
23  * day is 1-31
24  * month is jan,feb,...,dec
25  * year is 4 digit year
26  * [bc] if present, indicates dates is BC
27  * hour is 0-23 (24 hour clock)
28  * mintue is 0-59
29  * second is 0-59.9999 (fractions of second allowed)
30  * timezone is +hhmm or -hhmm (eg, -0600)
31  *
32  * parts can be missing
33  *
34  * 1994 [bc]
35  * Jan 1994 [bc]
36  * 15 jan 1000 [bc]
37  * 15 jan 1994 [bc] 10 [+0000]
38  * 15 jan 1994 [bc] 10:00 [+0100]
39  * 15 jan 1994 [bc] 10:00:23.34 [-0500]
40  *
41  * Relative
42  *
43  * There are two types of relative datetime values, year- month and day-second.
44  *
45  * The formats are:
46  *
47  * [-] # years # months
48  * [-] # days # hours # minutes # seconds
49  *
50  * The words years, months, days, hours, minutes, seconds are literal words,
51  * and the # are the numeric values.
52  *
53  * Examples:
54  *
55  * 2 years
56  * 5 months
57  * 2 years 5 months
58  * 100 days
59  * 15 hours 25 minutes 35.34 seconds
60  * 100 days 25 minutes
61  * 1000 hours 35.34 seconds
62  *
63  * The following are illegal because it mixes year-month and day-second
64  * (because the number of days in a month or in a year vary):
65  *
66  * 3 months 15 days
67  * 3 years 10 days
68  *
69  * (C) 2001-2009 by the GRASS Development Team
70  *
71  * This program is free software under the GNU General Public License
72  * (>=v2). Read the file COPYING that comes with GRASS for details.
73  *
74  * \author Michael Shapiro & Bill Brown, CERL
75  * \author raster3d functions by Michael Pelizzari, LMCO
76  * \author Soeren Gebbert, vector timestamp implementation update
77  */
78 
79 #include <string.h>
80 #include <unistd.h>
81 #include <grass/gis.h>
82 #include <grass/vect/dig_defines.h>
83 #include <grass/glocale.h>
84 
85 #define RAST_MISC "cell_misc"
86 #define GRID3 "grid3"
87 
88 /*!
89  \brief Initialize timestamp structure
90 
91  \param ts pointer to TimeStamp structure
92 */
93 void G_init_timestamp(struct TimeStamp *ts)
94 {
95  ts->count = 0;
96 }
97 
98 /*!
99  \brief Set timestamp (single)
100 
101  \param ts pointer to TimeStamp structure
102  \param dt pointer to DateTime structure (date/time to be set)
103 */
104 void G_set_timestamp(struct TimeStamp *ts, const DateTime * dt)
105 {
106  datetime_copy(&ts->dt[0], dt);
107  ts->count = 1;
108 }
109 
110 /*!
111  \brief Set timestamp (range)
112 
113  \param ts pointer to TimeStamp structure
114  \param dt1,dt2 pointer to DateTime structures
115 */
117  const DateTime * dt1, const DateTime * dt2)
118 {
119  datetime_copy(&ts->dt[0], dt1);
120  datetime_copy(&ts->dt[1], dt2);
121  ts->count = 2;
122 }
123 
124 /*!
125  \brief Read timestamp
126 
127  \param fd file descriptor
128  \param[out] ts pointer to TimeStamp structure
129 
130  \return -2 EOF
131  \return -1 on error
132  \return 0 on success
133 */
134 int G__read_timestamp(FILE * fd, struct TimeStamp *ts)
135 {
136  char buf[1024];
137  char comment[2];
138 
139  while (fgets(buf, sizeof(buf), fd)) {
140  if (sscanf(buf, "%1s", comment) != 1 || *comment == '#')
141  continue;
142  return (G_scan_timestamp(ts, buf) > 0 ? 0 : -1);
143  }
144  return -2; /* nothing in the file */
145 }
146 
147 /*!
148  \brief Output TimeStamp structure to a file as a formatted string
149 
150  A handy fd might be "stdout".
151 
152  \param[in,out] fd file descriptor
153  \param ts pointer to TimeStamp structure
154 
155  \return 0 on success
156  \return -1 on error
157 */
158 int G_write_timestamp(FILE * fd, const struct TimeStamp *ts)
159 {
160  char buf[1024];
161 
162  if (G_format_timestamp(ts, buf) < 0)
163  return -1;
164  fprintf(fd, "%s\n", buf);
165  return 0;
166 }
167 
168 /*!
169  \brief Create text string from TimeStamp structure
170 
171  Fills string *buf with info from TimeStamp structure *ts in a
172  pretty way. The TimeStamp struct is defined in gis.h and populated
173  with e.g. G_read_raster_timestamp().
174 
175  \param ts TimeStamp structure containing time info
176  \param buf string to receive formatted timestamp
177 
178  \return 1 on success
179  \return -1 error
180 */
181 int G_format_timestamp(const struct TimeStamp *ts, char *buf)
182 {
183  char temp1[128], temp2[128];
184 
185  *buf = 0;
186  if (ts->count > 0) {
187  if (datetime_format(&ts->dt[0], temp1) != 0)
188  return -1;
189  }
190  if (ts->count > 1) {
191  if (datetime_format(&ts->dt[1], temp2) != 0)
192  return -1;
193  }
194  if (ts->count == 1)
195  strcpy(buf, temp1);
196  else if (ts->count == 2)
197  sprintf(buf, "%s / %s", temp1, temp2);
198 
199  return 1;
200 }
201 
202 /*!
203  \brief Fill a TimeStamp structure from a datetime string
204 
205  Populate a TimeStamp structure (defined in gis.h) from a text
206  string. Checks to make sure text string is in valid GRASS datetime
207  format.
208 
209  \param ts TimeStamp structure to be populated
210  \param buf string containing formatted time info
211 
212  \return 1 on success
213  \return -1 error
214 */
215 int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
216 {
217  char temp[1024], *t;
218  const char *slash;
219  DateTime dt1, dt2;
220 
221  G_init_timestamp(ts);
222  for (slash = buf; *slash; slash++)
223  if (*slash == '/')
224  break;
225  if (*slash) {
226  t = temp;
227  while (buf != slash)
228  *t++ = *buf++;
229  *t = 0;
230  buf++;
231  if (datetime_scan(&dt1, temp) != 0 || datetime_scan(&dt2, buf) != 0)
232  return -1;
233  G_set_timestamp_range(ts, &dt1, &dt2);
234  }
235  else {
236  if (datetime_scan(&dt2, buf) != 0)
237  return -1;
238  G_set_timestamp(ts, &dt2);
239  }
240  return 1;
241 }
242 
243 /*!
244  \brief Copy TimeStamp into [two] Datetimes structs
245 
246  Use to copy the TimeStamp information into Datetimes, as the members
247  of struct TimeStamp shouldn't be accessed directly.
248 
249  - count=0 means no datetimes were copied
250  - count=1 means 1 datetime was copied into dt1
251  - count=2 means 2 datetimes were copied
252 
253  \param ts source TimeStamp structure
254  \param[out] dt1 first DateTime struct to be filled
255  \param[out] dt2 second DateTime struct to be filled
256  \param[out] count return code
257 */
258 void G_get_timestamps(const struct TimeStamp *ts,
259  DateTime * dt1, DateTime * dt2, int *count)
260 {
261  *count = 0;
262  if (ts->count > 0) {
263  datetime_copy(dt1, &ts->dt[0]);
264  *count = 1;
265  }
266  if (ts->count > 1) {
267  datetime_copy(dt2, &ts->dt[1]);
268  *count = 2;
269  }
270 }
271 
272 /*!
273  \brief Write timestamp file
274 
275  \param maptype map type
276  \param dir directory
277  \param name map name
278  \param ts pointer to TimeStamp
279 
280  \return 1 on success
281  \return -1 error - can't create timestamp file
282  \return -2 error - invalid datetime in ts
283 */
284 static int write_timestamp(const char *maptype, const char *dir,
285  const char *name, const struct TimeStamp *ts)
286 {
287  FILE *fd;
288  int stat;
289 
290  fd = G_fopen_new_misc(dir, "timestamp", name);
291  if (fd == NULL) {
292  G_warning(_("Unable to create timestamp file for %s map <%s@%s>"),
293  maptype, name, G_mapset());
294  return -1;
295  }
296 
297  stat = G_write_timestamp(fd, ts);
298  fclose(fd);
299  if (stat == 0)
300  return 1;
301  G_warning(_("Invalid timestamp specified for %s map <%s@%s>"),
302  maptype, name, G_mapset());
303  return -2;
304 }
305 
306 /*!
307  \brief Read timestamp file
308 
309  \param maptype map type
310  \param dir directory
311  \param name map name
312  \param mapset mapset name
313  \param ts pointer to TimeStamp
314 
315  \return 0 no timestamp file
316  \return 1 on success
317  \return -1 error - can't open timestamp file
318  \return -2 error - invalid datetime values in timestamp file
319 */
320 static int read_timestamp(const char *maptype, const char *dir,
321  const char *name, const char *mapset,
322  struct TimeStamp *ts)
323 {
324  FILE *fd;
325  int stat;
326 
327  if (!G_find_file2_misc(dir, "timestamp", name, mapset))
328  return 0;
329  fd = G_fopen_old_misc(dir, "timestamp", name, mapset);
330  if (fd == NULL) {
331  G_warning(_("Unable to open timestamp file for %s map <%s@%s>"),
332  maptype, name, mapset);
333  return -1;
334  }
335 
336  stat = G__read_timestamp(fd, ts);
337  fclose(fd);
338  if (stat == 0)
339  return 1;
340  G_warning(_("Invalid timestamp file for %s map <%s@%s>"),
341  maptype, name, mapset);
342  return -2;
343 }
344 
345 /*!
346  \brief Check if timestamp for raster map exists
347 
348  \param name map name
349  \param mapset mapset name
350 
351  \return 1 on success
352  \return 0 no timestamp present
353 */
354 int G_has_raster_timestamp(const char *name, const char *mapset)
355 {
356  if (!G_find_file2_misc(RAST_MISC, "timestamp", name, mapset))
357  return 0;
358 
359  return 1;
360 }
361 
362 /*!
363  \brief Read timestamp from raster map
364 
365  \param name map name
366  \param mapset mapset the map lives in
367  \param[out] ts TimeStamp struct to populate
368 
369  \return 1 on success
370  \return 0 or negative on error
371 */
372 int G_read_raster_timestamp(const char *name, const char *mapset,
373  struct TimeStamp *ts)
374 {
375  return read_timestamp("raster", RAST_MISC, name, mapset, ts);
376 }
377 
378 /*!
379  \brief Write timestamp of raster map
380 
381  \param name map name
382  \param[out] ts TimeStamp struct to populate
383 
384  \return 1 on success
385  \return -1 error - can't create timestamp file
386  \return -2 error - invalid datetime in ts
387 
388  */
389 int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
390 {
391  return write_timestamp("raster", RAST_MISC, name, ts);
392 }
393 
394 /*!
395  \brief Remove timestamp from raster map
396 
397  Only timestamp files in current mapset can be removed.
398 
399  \param name map name
400 
401  \return 0 if no file
402  \return 1 on success
403  \return -1 on error
404 */
406 {
407  return G_remove_misc(RAST_MISC, "timestamp", name);
408 }
409 
410 /*!
411  \brief Check if timestamp for vector map exists
412 
413  \param name map name
414  \param layer The layer names, in case of NULL, layer one is assumed
415  \param mapset mapset name
416 
417  \return 1 on success
418  \return 0 no timestamp present
419 */
420 int G_has_vector_timestamp(const char *name, const char *layer, const char *mapset)
421 {
422  char dir[GPATH_MAX];
423  char path[GPATH_MAX + GNAME_MAX];
424  char ele[GNAME_MAX];
425 
426  if(layer != NULL)
427  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
428  else
430 
431  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
432  G_file_name(path, dir, ele, mapset);
433 
434  G_debug(1, "Check for timestamp <%s>", path);
435 
436  if (access(path, R_OK) != 0)
437  return 0;
438 
439  return 1;
440 }
441 
442 /*!
443  \brief Read timestamp from vector map
444 
445  \param name map name
446  \param layer The layer names, in case of NULL, layer one is assumed
447  \param mapset mapset name
448  \param[out] ts TimeStamp struct to populate
449 
450  \return 1 on success
451  \return 0 no timestamp present
452  \return -1 Unable to open file
453  \return -2 invalid time stamp
454 */
455 int G_read_vector_timestamp(const char *name, const char *layer,
456  const char *mapset, struct TimeStamp *ts)
457 {
458  FILE *fd;
459  int stat;
460  char dir[GPATH_MAX];
461  char ele[GNAME_MAX];
462 
463  /* In case no timestamp file is present return 0 */
464  if (G_has_vector_timestamp(name, layer, mapset) != 1)
465  return 0;
466 
467  if(layer != NULL)
468  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
469  else
471 
472  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
473 
474  G_debug(1, "Read timestamp <%s/%s>", dir, ele);
475 
476  fd = G_fopen_old(dir, ele, mapset);
477 
478  if (fd == NULL) {
479  G_warning(_("Unable to open timestamp file for vector map <%s@%s>"),
480  name, G_mapset());
481  return -1;
482  }
483 
484  stat = G__read_timestamp(fd, ts);
485  fclose(fd);
486  if (stat == 0)
487  return 1;
488  G_warning(_("Invalid timestamp file for vector map <%s@%s>"),
489  name, mapset);
490  return -2;
491 }
492 
493 /*!
494  \brief Write timestamp of vector map
495 
496  \param name map name
497  \param layer The layer names, in case of NULL, layer one is assumed
498  \param[out] ts TimeStamp struct to populate
499 
500  \return 1 on success
501  \return -1 error - can't create timestamp file
502  \return -2 error - invalid datetime in ts
503 
504  */
505 int G_write_vector_timestamp(const char *name, const char *layer, const struct TimeStamp *ts)
506 {
507  FILE *fd;
508  int stat;
509  char dir[GPATH_MAX];
510  char ele[GNAME_MAX];
511 
512  if(layer != NULL)
513  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
514  else
516 
517  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
518 
519  G_debug(1, "Write timestamp <%s/%s>", dir, ele);
520 
521  fd = G_fopen_new(dir, ele);
522 
523  if (fd == NULL) {
524  G_warning(_("Unable to create timestamp file for vector map <%s@%s>"),
525  name, G_mapset());
526  return -1;
527  }
528 
529  stat = G_write_timestamp(fd, ts);
530  fclose(fd);
531  if (stat == 0)
532  return 1;
533  G_warning(_("Invalid timestamp specified for vector map <%s@%s>"),
534  name, G_mapset());
535  return -2;
536 }
537 
538 /*!
539  \brief Remove timestamp from vector map
540 
541  Only timestamp files in current mapset can be removed.
542 
543  \param name map name
544  \param layer The layer names, in case of NULL, layer one is assumed
545 
546  \return 0 if no file
547  \return 1 on success
548  \return -1 on failure
549 */
550 int G_remove_vector_timestamp(const char *name, const char *layer)
551 {
552  char dir[GPATH_MAX];
553  char ele[GNAME_MAX];
554 
555  if(layer)
556  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
557  else
559 
560  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
561  return G_remove(dir, ele);
562 }
563 
564 /*!
565  \brief Check if timestamp for 3D raster map exists
566 
567  \param name map name
568  \param mapset mapset name
569 
570  \return 1 on success
571  \return 0 no timestamp present
572 */
573 int G_has_raster3d_timestamp(const char *name, const char *mapset)
574 {
575  if (!G_find_file2_misc(GRID3, "timestamp", name, mapset))
576  return 0;
577 
578  return 1;
579 }
580 
581 /*!
582  \brief Read timestamp from 3D raster map
583 
584  \param name map name
585  \param mapset mapset name
586  \param[out] ts TimeStamp struct to populate
587 
588  \return 1 on success
589  \return 0 or negative on error
590 */
591 int G_read_raster3d_timestamp(const char *name, const char *mapset,
592  struct TimeStamp *ts)
593 {
594  return read_timestamp("raster3d", GRID3, name, mapset, ts);
595 }
596 
597 /*!
598  \brief Write timestamp of 3D raster map
599 
600  \param name map name
601  \param[out] ts TimeStamp struct to populate
602 
603  \return 1 on success
604  \return -1 error - can't create timestamp file
605  \return -2 error - invalid datetime in ts
606 
607  */
608 int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
609 {
610  return write_timestamp("raster3d", GRID3, name, ts);
611 }
612 
613 /*!
614  \brief Remove timestamp from 3D raster map
615 
616  Only timestamp files in current mapset can be removed.
617 
618  \param name map name
619 
620  \return 0 if no file
621  \return 1 on success
622  \return -1 on failure
623 */
625 {
626  return G_remove_misc(GRID3, "timestamp", name);
627 }
628 
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition: file_name.c:38
int G_remove(const char *, const char *)
Remove a database file.
Definition: remove.c:44
int G_read_raster_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from raster map.
Definition: timestamp.c:372
#define GV_DIRECTORY
Name of vector directory.
Definition: dig_defines.h:8
int G_write_timestamp(FILE *fd, const struct TimeStamp *ts)
Output TimeStamp structure to a file as a formatted string.
Definition: timestamp.c:158
void G_set_timestamp(struct TimeStamp *ts, const DateTime *dt)
Set timestamp (single)
Definition: timestamp.c:104
int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
Fill a TimeStamp structure from a datetime string.
Definition: timestamp.c:215
int count
int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of 3D raster map.
Definition: timestamp.c:608
#define GRID3
Definition: timestamp.c:86
#define R_OK
Definition: dirent.c:21
#define NULL
Definition: ccmath.h:32
int G_has_raster_timestamp(const char *name, const char *mapset)
Check if timestamp for raster map exists.
Definition: timestamp.c:354
int G_remove_misc(const char *, const char *, const char *)
Remove a database misc file.
Definition: remove.c:65
int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of raster map.
Definition: timestamp.c:389
int G__read_timestamp(FILE *fd, struct TimeStamp *ts)
Read timestamp.
Definition: timestamp.c:134
void datetime_copy(DateTime *src, const DateTime *dst)
Copies the DateTime [into/from ???] src.
Definition: datetime/copy.c:20
double t
Definition: r_raster.c:39
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition: gis/open.c:220
int G_remove_vector_timestamp(const char *name, const char *layer)
Remove timestamp from vector map.
Definition: timestamp.c:550
DateTime dt[2]
Definition: gis.h:589
FILE * G_fopen_old_misc(const char *, const char *, const char *, const char *)
open a database file for reading
Definition: open_misc.c:210
void G_get_timestamps(const struct TimeStamp *ts, DateTime *dt1, DateTime *dt2, int *count)
Copy TimeStamp into [two] Datetimes structs.
Definition: timestamp.c:258
#define RAST_MISC
Definition: timestamp.c:85
#define GPATH_MAX
Definition: gis.h:170
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:253
int G_has_vector_timestamp(const char *name, const char *layer, const char *mapset)
Check if timestamp for vector map exists.
Definition: timestamp.c:420
int G_remove_raster3d_timestamp(const char *name)
Remove timestamp from 3D raster map.
Definition: timestamp.c:624
const char * G_find_file2_misc(const char *, const char *, const char *, const char *)
Searches for a file from the mapset search list or in a specified mapset. (look but don&#39;t touch) ...
Definition: find_file.c:267
FILE * G_fopen_new_misc(const char *, const char *, const char *)
open a new database file
Definition: open_misc.c:182
void G_set_timestamp_range(struct TimeStamp *ts, const DateTime *dt1, const DateTime *dt2)
Set timestamp (range)
Definition: timestamp.c:116
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
int datetime_scan(DateTime *dt, const char *buf)
Convert the ascii string into a DateTime. This determines the mode/from/to based on the string...
Definition: scan.c:43
int G_snprintf(char *, size_t, const char *,...) __attribute__((format(printf
#define GNAME_MAX
Definition: gis.h:167
void G_warning(const char *,...) __attribute__((format(printf
Definition: path.h:16
#define _(str)
Definition: glocale.h:10
int G_write_vector_timestamp(const char *name, const char *layer, const struct TimeStamp *ts)
Write timestamp of vector map.
Definition: timestamp.c:505
int G_read_vector_timestamp(const char *name, const char *layer, const char *mapset, struct TimeStamp *ts)
Read timestamp from vector map.
Definition: timestamp.c:455
Definition: gis.h:587
int G_remove_raster_timestamp(const char *name)
Remove timestamp from raster map.
Definition: timestamp.c:405
int G_has_raster3d_timestamp(const char *name, const char *mapset)
Check if timestamp for 3D raster map exists.
Definition: timestamp.c:573
#define GV_TIMESTAMP_ELEMENT
Name of the timestamp file.
Definition: dig_defines.h:32
const char * name
Definition: named_colr.c:7
int count
Definition: gis.h:590
int datetime_format(const DateTime *dt, char *buf)
formats DateTime structure as a human-readable string returns 0 when successful and &#39;buf&#39; is filled w...
int G_format_timestamp(const struct TimeStamp *ts, char *buf)
Create text string from TimeStamp structure.
Definition: timestamp.c:181
int G_debug(int, const char *,...) __attribute__((format(printf
int G_read_raster3d_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from 3D raster map.
Definition: timestamp.c:591
void G_init_timestamp(struct TimeStamp *ts)
Initialize timestamp structure.
Definition: timestamp.c:93