GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-535c39c9fc
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 convenience, 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  */
116 void G_set_timestamp_range(struct TimeStamp *ts, const DateTime *dt1,
117  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, DateTime *dt1, DateTime *dt2,
259  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>"), maptype,
302  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>"), maptype, name,
341  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,
421  const char *mapset)
422 {
423  char dir[GPATH_MAX];
424  char path[GPATH_MAX + GNAME_MAX];
425  char ele[GNAME_MAX];
426 
427  if (layer != NULL)
428  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
429  else
431 
432  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
433  G_file_name(path, dir, ele, mapset);
434 
435  G_debug(1, "Check for timestamp <%s>", path);
436 
437  if (access(path, R_OK) != 0)
438  return 0;
439 
440  return 1;
441 }
442 
443 /*!
444  \brief Read timestamp from vector map
445 
446  \param name map name
447  \param layer The layer names, in case of NULL, layer one is assumed
448  \param mapset mapset name
449  \param[out] ts TimeStamp struct to populate
450 
451  \return 1 on success
452  \return 0 no timestamp present
453  \return -1 Unable to open file
454  \return -2 invalid time stamp
455  */
456 int G_read_vector_timestamp(const char *name, const char *layer,
457  const char *mapset, struct TimeStamp *ts)
458 {
459  FILE *fd;
460  int stat;
461  char dir[GPATH_MAX];
462  char ele[GNAME_MAX];
463 
464  /* In case no timestamp file is present return 0 */
465  if (G_has_vector_timestamp(name, layer, mapset) != 1)
466  return 0;
467 
468  if (layer != NULL)
469  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
470  else
472 
473  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
474 
475  G_debug(1, "Read timestamp <%s/%s>", dir, ele);
476 
477  fd = G_fopen_old(dir, ele, mapset);
478 
479  if (fd == NULL) {
480  G_warning(_("Unable to open timestamp file for vector map <%s@%s>"),
481  name, G_mapset());
482  return -1;
483  }
484 
485  stat = G__read_timestamp(fd, ts);
486  fclose(fd);
487  if (stat == 0)
488  return 1;
489  G_warning(_("Invalid timestamp file for vector map <%s@%s>"), 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,
506  const struct TimeStamp *ts)
507 {
508  FILE *fd;
509  int stat;
510  char dir[GPATH_MAX];
511  char ele[GNAME_MAX];
512 
513  if (layer != NULL)
514  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
515  else
517 
518  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
519 
520  G_debug(1, "Write timestamp <%s/%s>", dir, ele);
521 
522  fd = G_fopen_new(dir, ele);
523 
524  if (fd == NULL) {
525  G_warning(_("Unable to create timestamp file for vector map <%s@%s>"),
526  name, G_mapset());
527  return -1;
528  }
529 
530  stat = G_write_timestamp(fd, ts);
531  fclose(fd);
532  if (stat == 0)
533  return 1;
534  G_warning(_("Invalid timestamp specified for vector map <%s@%s>"), name,
535  G_mapset());
536  return -2;
537 }
538 
539 /*!
540  \brief Remove timestamp from vector map
541 
542  Only timestamp files in current mapset can be removed.
543 
544  \param name map name
545  \param layer The layer names, in case of NULL, layer one is assumed
546 
547  \return 0 if no file
548  \return 1 on success
549  \return -1 on failure
550  */
551 int G_remove_vector_timestamp(const char *name, const char *layer)
552 {
553  char dir[GPATH_MAX];
554  char ele[GNAME_MAX];
555 
556  if (layer)
557  G_snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
558  else
560 
561  G_snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
562  return G_remove(dir, ele);
563 }
564 
565 /*!
566  \brief Check if timestamp for 3D raster map exists
567 
568  \param name map name
569  \param mapset mapset name
570 
571  \return 1 on success
572  \return 0 no timestamp present
573  */
574 int G_has_raster3d_timestamp(const char *name, const char *mapset)
575 {
576  if (!G_find_file2_misc(GRID3, "timestamp", name, mapset))
577  return 0;
578 
579  return 1;
580 }
581 
582 /*!
583  \brief Read timestamp from 3D raster map
584 
585  \param name map name
586  \param mapset mapset name
587  \param[out] ts TimeStamp struct to populate
588 
589  \return 1 on success
590  \return 0 or negative on error
591  */
592 int G_read_raster3d_timestamp(const char *name, const char *mapset,
593  struct TimeStamp *ts)
594 {
595  return read_timestamp("raster3d", GRID3, name, mapset, ts);
596 }
597 
598 /*!
599  \brief Write timestamp of 3D raster map
600 
601  \param name map name
602  \param[out] ts TimeStamp struct to populate
603 
604  \return 1 on success
605  \return -1 error - can't create timestamp file
606  \return -2 error - invalid datetime in ts
607 
608  */
609 int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
610 {
611  return write_timestamp("raster3d", GRID3, name, ts);
612 }
613 
614 /*!
615  \brief Remove timestamp from 3D raster map
616 
617  Only timestamp files in current mapset can be removed.
618 
619  \param name map name
620 
621  \return 0 if no file
622  \return 1 on success
623  \return -1 on failure
624  */
626 {
627  return G_remove_misc(GRID3, "timestamp", name);
628 }
#define NULL
Definition: ccmath.h:32
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:41
int datetime_format(const DateTime *dt, char *buf)
formats DateTime structure as a human-readable string returns 0 when successful and 'buf' is filled w...
void datetime_copy(DateTime *src, const DateTime *dst)
Copies the DateTime [into/from ???] src.
Definition: datetime/copy.c:20
FILE * G_fopen_old(const char *, const char *, const char *)
Open a database file for reading.
Definition: gis/open.c:251
FILE * G_fopen_old_misc(const char *, const char *, const char *, const char *)
open a database misc file for reading
Definition: open_misc.c:205
void G_warning(const char *,...) __attribute__((format(printf
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition: file_name.c:61
int G_snprintf(char *, size_t, const char *,...) __attribute__((format(printf
FILE * G_fopen_new_misc(const char *, const char *, const char *)
open a new database misc file
Definition: open_misc.c:178
const char * G_mapset(void)
Get current mapset name.
Definition: gis/mapset.c:33
int G_remove(const char *, const char *)
Remove a database file.
Definition: remove.c:44
const char * G_find_file2_misc(const char *, const char *, const char *, const char *)
Searches for a misc file from the mapset search list or in a specified mapset. (look but don't touch)
Definition: find_file.c:257
int G_remove_misc(const char *, const char *, const char *)
Remove a database misc file.
Definition: remove.c:65
int G_debug(int, const char *,...) __attribute__((format(printf
FILE * G_fopen_new(const char *, const char *)
Open a new database file.
Definition: gis/open.c:219
#define GV_DIRECTORY
Name of vector directory.
Definition: dig_defines.h:8
#define GV_TIMESTAMP_ELEMENT
Name of the timestamp file.
Definition: dig_defines.h:32
#define R_OK
Definition: dirent.c:25
#define GPATH_MAX
Definition: gis.h:194
#define GNAME_MAX
Definition: gis.h:191
#define _(str)
Definition: glocale.h:10
int count
const char * name
Definition: named_colr.c:6
#define strcpy
Definition: parson.c:62
double t
Definition: r_raster.c:39
Definition: gis.h:611
DateTime dt[2]
Definition: gis.h:612
int count
Definition: gis.h:613
Definition: path.h:15
void G_init_timestamp(struct TimeStamp *ts)
Initialize timestamp structure.
Definition: timestamp.c:93
int G_read_raster_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from raster map.
Definition: timestamp.c:372
int G_has_raster_timestamp(const char *name, const char *mapset)
Check if timestamp for raster map exists.
Definition: timestamp.c:354
int G_has_raster3d_timestamp(const char *name, const char *mapset)
Check if timestamp for 3D raster map exists.
Definition: timestamp.c:574
int G_write_timestamp(FILE *fd, const struct TimeStamp *ts)
Output TimeStamp structure to a file as a formatted string.
Definition: timestamp.c:158
int G_format_timestamp(const struct TimeStamp *ts, char *buf)
Create text string from TimeStamp structure.
Definition: timestamp.c:181
int G_read_raster3d_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from 3D raster map.
Definition: timestamp.c:592
int G_remove_raster3d_timestamp(const char *name)
Remove timestamp from 3D raster map.
Definition: timestamp.c:625
int G__read_timestamp(FILE *fd, struct TimeStamp *ts)
Read timestamp.
Definition: timestamp.c:134
void G_set_timestamp(struct TimeStamp *ts, const DateTime *dt)
Set timestamp (single)
Definition: timestamp.c:104
int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of raster map.
Definition: timestamp.c:389
int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
Fill a TimeStamp structure from a datetime string.
Definition: timestamp.c:215
#define GRID3
Definition: timestamp.c:86
#define RAST_MISC
Definition: timestamp.c:85
void G_set_timestamp_range(struct TimeStamp *ts, const DateTime *dt1, const DateTime *dt2)
Set timestamp (range)
Definition: timestamp.c:116
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_read_vector_timestamp(const char *name, const char *layer, const char *mapset, struct TimeStamp *ts)
Read timestamp from vector map.
Definition: timestamp.c:456
int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of 3D raster map.
Definition: timestamp.c:609
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_remove_vector_timestamp(const char *name, const char *layer)
Remove timestamp from vector map.
Definition: timestamp.c:551
void G_get_timestamps(const struct TimeStamp *ts, DateTime *dt1, DateTime *dt2, int *count)
Copy TimeStamp into [two] Datetimes structs.
Definition: timestamp.c:258
int G_remove_raster_timestamp(const char *name)
Remove timestamp from raster map.
Definition: timestamp.c:405