GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-d6dec75dd4
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 <stdio.h>
80 #include <string.h>
81 #include <unistd.h>
82 
83 #include <grass/gis.h>
84 #include <grass/vect/dig_defines.h>
85 #include <grass/glocale.h>
86 
87 #define RAST_MISC "cell_misc"
88 #define GRID3 "grid3"
89 
90 /*!
91  \brief Initialize timestamp structure
92 
93  \param ts pointer to TimeStamp structure
94  */
95 void G_init_timestamp(struct TimeStamp *ts)
96 {
97  ts->count = 0;
98 }
99 
100 /*!
101  \brief Set timestamp (single)
102 
103  \param ts pointer to TimeStamp structure
104  \param dt pointer to DateTime structure (date/time to be set)
105  */
106 void G_set_timestamp(struct TimeStamp *ts, const DateTime *dt)
107 {
108  datetime_copy(&ts->dt[0], dt);
109  ts->count = 1;
110 }
111 
112 /*!
113  \brief Set timestamp (range)
114 
115  \param ts pointer to TimeStamp structure
116  \param dt1,dt2 pointer to DateTime structures
117  */
118 void G_set_timestamp_range(struct TimeStamp *ts, const DateTime *dt1,
119  const DateTime *dt2)
120 {
121  datetime_copy(&ts->dt[0], dt1);
122  datetime_copy(&ts->dt[1], dt2);
123  ts->count = 2;
124 }
125 
126 /*!
127  \brief Read timestamp
128 
129  \param fd file descriptor
130  \param[out] ts pointer to TimeStamp structure
131 
132  \return -2 EOF
133  \return -1 on error
134  \return 0 on success
135  */
136 int G__read_timestamp(FILE *fd, struct TimeStamp *ts)
137 {
138  char buf[1024];
139  char comment[2];
140 
141  while (fgets(buf, sizeof(buf), fd)) {
142  if (sscanf(buf, "%1s", comment) != 1 || *comment == '#')
143  continue;
144  return (G_scan_timestamp(ts, buf) > 0 ? 0 : -1);
145  }
146  return -2; /* nothing in the file */
147 }
148 
149 /*!
150  \brief Output TimeStamp structure to a file as a formatted string
151 
152  A handy fd might be "stdout".
153 
154  \param[in,out] fd file descriptor
155  \param ts pointer to TimeStamp structure
156 
157  \return 0 on success
158  \return -1 on error
159  */
160 int G_write_timestamp(FILE *fd, const struct TimeStamp *ts)
161 {
162  char buf[1024];
163 
164  if (G_format_timestamp(ts, buf) < 0)
165  return -1;
166  fprintf(fd, "%s\n", buf);
167  return 0;
168 }
169 
170 /*!
171  \brief Create text string from TimeStamp structure
172 
173  Fills string *buf with info from TimeStamp structure *ts in a
174  pretty way. The TimeStamp struct is defined in gis.h and populated
175  with e.g. G_read_raster_timestamp().
176 
177  \param ts TimeStamp structure containing time info
178  \param buf string to receive formatted timestamp
179 
180  \return 1 on success
181  \return -1 error
182  */
183 int G_format_timestamp(const struct TimeStamp *ts, char *buf)
184 {
185  char temp1[128], temp2[128];
186 
187  *buf = 0;
188  if (ts->count > 0) {
189  if (datetime_format(&ts->dt[0], temp1) != 0)
190  return -1;
191  }
192  if (ts->count > 1) {
193  if (datetime_format(&ts->dt[1], temp2) != 0)
194  return -1;
195  }
196  if (ts->count == 1)
197  strcpy(buf, temp1);
198  else if (ts->count == 2)
199  sprintf(buf, "%s / %s", temp1, temp2);
200 
201  return 1;
202 }
203 
204 /*!
205  \brief Fill a TimeStamp structure from a datetime string
206 
207  Populate a TimeStamp structure (defined in gis.h) from a text
208  string. Checks to make sure text string is in valid GRASS datetime
209  format.
210 
211  \param ts TimeStamp structure to be populated
212  \param buf string containing formatted time info
213 
214  \return 1 on success
215  \return -1 error
216  */
217 int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
218 {
219  char temp[1024], *t;
220  const char *slash;
221  DateTime dt1, dt2;
222 
223  G_init_timestamp(ts);
224  for (slash = buf; *slash; slash++)
225  if (*slash == '/')
226  break;
227  if (*slash) {
228  t = temp;
229  while (buf != slash)
230  *t++ = *buf++;
231  *t = 0;
232  buf++;
233  if (datetime_scan(&dt1, temp) != 0 || datetime_scan(&dt2, buf) != 0)
234  return -1;
235  G_set_timestamp_range(ts, &dt1, &dt2);
236  }
237  else {
238  if (datetime_scan(&dt2, buf) != 0)
239  return -1;
240  G_set_timestamp(ts, &dt2);
241  }
242  return 1;
243 }
244 
245 /*!
246  \brief Copy TimeStamp into [two] Datetimes structs
247 
248  Use to copy the TimeStamp information into Datetimes, as the members
249  of struct TimeStamp shouldn't be accessed directly.
250 
251  - count=0 means no datetimes were copied
252  - count=1 means 1 datetime was copied into dt1
253  - count=2 means 2 datetimes were copied
254 
255  \param ts source TimeStamp structure
256  \param[out] dt1 first DateTime struct to be filled
257  \param[out] dt2 second DateTime struct to be filled
258  \param[out] count return code
259  */
260 void G_get_timestamps(const struct TimeStamp *ts, DateTime *dt1, DateTime *dt2,
261  int *count)
262 {
263  *count = 0;
264  if (ts->count > 0) {
265  datetime_copy(dt1, &ts->dt[0]);
266  *count = 1;
267  }
268  if (ts->count > 1) {
269  datetime_copy(dt2, &ts->dt[1]);
270  *count = 2;
271  }
272 }
273 
274 /*!
275  \brief Write timestamp file
276 
277  \param maptype map type
278  \param dir directory
279  \param name map name
280  \param ts pointer to TimeStamp
281 
282  \return 1 on success
283  \return -1 error - can't create timestamp file
284  \return -2 error - invalid datetime in ts
285  */
286 static int write_timestamp(const char *maptype, const char *dir,
287  const char *name, const struct TimeStamp *ts)
288 {
289  FILE *fd;
290  int stat;
291 
292  fd = G_fopen_new_misc(dir, "timestamp", name);
293  if (fd == NULL) {
294  G_warning(_("Unable to create timestamp file for %s map <%s@%s>"),
295  maptype, name, G_mapset());
296  return -1;
297  }
298 
299  stat = G_write_timestamp(fd, ts);
300  fclose(fd);
301  if (stat == 0)
302  return 1;
303  G_warning(_("Invalid timestamp specified for %s map <%s@%s>"), maptype,
304  name, G_mapset());
305  return -2;
306 }
307 
308 /*!
309  \brief Read timestamp file
310 
311  \param maptype map type
312  \param dir directory
313  \param name map name
314  \param mapset mapset name
315  \param ts pointer to TimeStamp
316 
317  \return 0 no timestamp file
318  \return 1 on success
319  \return -1 error - can't open timestamp file
320  \return -2 error - invalid datetime values in timestamp file
321  */
322 static int read_timestamp(const char *maptype, const char *dir,
323  const char *name, const char *mapset,
324  struct TimeStamp *ts)
325 {
326  FILE *fd;
327  int stat;
328 
329  if (!G_find_file2_misc(dir, "timestamp", name, mapset))
330  return 0;
331  fd = G_fopen_old_misc(dir, "timestamp", name, mapset);
332  if (fd == NULL) {
333  G_warning(_("Unable to open timestamp file for %s map <%s@%s>"),
334  maptype, name, mapset);
335  return -1;
336  }
337 
338  stat = G__read_timestamp(fd, ts);
339  fclose(fd);
340  if (stat == 0)
341  return 1;
342  G_warning(_("Invalid timestamp file for %s map <%s@%s>"), maptype, name,
343  mapset);
344  return -2;
345 }
346 
347 /*!
348  \brief Check if timestamp for raster map exists
349 
350  \param name map name
351  \param mapset mapset name
352 
353  \return 1 on success
354  \return 0 no timestamp present
355  */
356 int G_has_raster_timestamp(const char *name, const char *mapset)
357 {
358  if (!G_find_file2_misc(RAST_MISC, "timestamp", name, mapset))
359  return 0;
360 
361  return 1;
362 }
363 
364 /*!
365  \brief Read timestamp from raster map
366 
367  \param name map name
368  \param mapset mapset the map lives in
369  \param[out] ts TimeStamp struct to populate
370 
371  \return 1 on success
372  \return 0 or negative on error
373  */
374 int G_read_raster_timestamp(const char *name, const char *mapset,
375  struct TimeStamp *ts)
376 {
377  return read_timestamp("raster", RAST_MISC, name, mapset, ts);
378 }
379 
380 /*!
381  \brief Write timestamp of raster map
382 
383  \param name map name
384  \param[out] ts TimeStamp struct to populate
385 
386  \return 1 on success
387  \return -1 error - can't create timestamp file
388  \return -2 error - invalid datetime in ts
389 
390  */
391 int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
392 {
393  return write_timestamp("raster", RAST_MISC, name, ts);
394 }
395 
396 /*!
397  \brief Remove timestamp from raster map
398 
399  Only timestamp files in current mapset can be removed.
400 
401  \param name map name
402 
403  \return 0 if no file
404  \return 1 on success
405  \return -1 on error
406  */
408 {
409  return G_remove_misc(RAST_MISC, "timestamp", name);
410 }
411 
412 /*!
413  \brief Check if timestamp for vector map exists
414 
415  \param name map name
416  \param layer The layer names, in case of NULL, layer one is assumed
417  \param mapset mapset name
418 
419  \return 1 on success
420  \return 0 no timestamp present
421  */
422 int G_has_vector_timestamp(const char *name, const char *layer,
423  const char *mapset)
424 {
425  char dir[GPATH_MAX];
426  char path[GPATH_MAX + GNAME_MAX];
427  char ele[GNAME_MAX];
428 
429  if (layer != NULL)
430  snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
431  else
432  snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
433 
434  snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
435  G_file_name(path, dir, ele, mapset);
436 
437  G_debug(1, "Check for timestamp <%s>", path);
438 
439  if (access(path, R_OK) != 0)
440  return 0;
441 
442  return 1;
443 }
444 
445 /*!
446  \brief Read timestamp from vector map
447 
448  \param name map name
449  \param layer The layer names, in case of NULL, layer one is assumed
450  \param mapset mapset name
451  \param[out] ts TimeStamp struct to populate
452 
453  \return 1 on success
454  \return 0 no timestamp present
455  \return -1 Unable to open file
456  \return -2 invalid time stamp
457  */
458 int G_read_vector_timestamp(const char *name, const char *layer,
459  const char *mapset, struct TimeStamp *ts)
460 {
461  FILE *fd;
462  int stat;
463  char dir[GPATH_MAX];
464  char ele[GNAME_MAX];
465 
466  /* In case no timestamp file is present return 0 */
467  if (G_has_vector_timestamp(name, layer, mapset) != 1)
468  return 0;
469 
470  if (layer != NULL)
471  snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
472  else
473  snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
474 
475  snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
476 
477  G_debug(1, "Read timestamp <%s/%s>", dir, ele);
478 
479  fd = G_fopen_old(dir, ele, mapset);
480 
481  if (fd == NULL) {
482  G_warning(_("Unable to open timestamp file for vector map <%s@%s>"),
483  name, G_mapset());
484  return -1;
485  }
486 
487  stat = G__read_timestamp(fd, ts);
488  fclose(fd);
489  if (stat == 0)
490  return 1;
491  G_warning(_("Invalid timestamp file for vector map <%s@%s>"), name, mapset);
492  return -2;
493 }
494 
495 /*!
496  \brief Write timestamp of vector map
497 
498  \param name map name
499  \param layer The layer names, in case of NULL, layer one is assumed
500  \param[out] ts TimeStamp struct to populate
501 
502  \return 1 on success
503  \return -1 error - can't create timestamp file
504  \return -2 error - invalid datetime in ts
505 
506  */
507 int G_write_vector_timestamp(const char *name, const char *layer,
508  const struct TimeStamp *ts)
509 {
510  FILE *fd;
511  int stat;
512  char dir[GPATH_MAX];
513  char ele[GNAME_MAX];
514 
515  if (layer != NULL)
516  snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
517  else
518  snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
519 
520  snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
521 
522  G_debug(1, "Write timestamp <%s/%s>", dir, ele);
523 
524  fd = G_fopen_new(dir, ele);
525 
526  if (fd == NULL) {
527  G_warning(_("Unable to create timestamp file for vector map <%s@%s>"),
528  name, G_mapset());
529  return -1;
530  }
531 
532  stat = G_write_timestamp(fd, ts);
533  fclose(fd);
534  if (stat == 0)
535  return 1;
536  G_warning(_("Invalid timestamp specified for vector map <%s@%s>"), name,
537  G_mapset());
538  return -2;
539 }
540 
541 /*!
542  \brief Remove timestamp from vector map
543 
544  Only timestamp files in current mapset can be removed.
545 
546  \param name map name
547  \param layer The layer names, in case of NULL, layer one is assumed
548 
549  \return 0 if no file
550  \return 1 on success
551  \return -1 on failure
552  */
553 int G_remove_vector_timestamp(const char *name, const char *layer)
554 {
555  char dir[GPATH_MAX];
556  char ele[GNAME_MAX];
557 
558  if (layer)
559  snprintf(ele, GNAME_MAX, "%s_%s", GV_TIMESTAMP_ELEMENT, layer);
560  else
561  snprintf(ele, GNAME_MAX, "%s_1", GV_TIMESTAMP_ELEMENT);
562 
563  snprintf(dir, GPATH_MAX, "%s/%s", GV_DIRECTORY, name);
564  return G_remove(dir, ele);
565 }
566 
567 /*!
568  \brief Check if timestamp for 3D raster map exists
569 
570  \param name map name
571  \param mapset mapset name
572 
573  \return 1 on success
574  \return 0 no timestamp present
575  */
576 int G_has_raster3d_timestamp(const char *name, const char *mapset)
577 {
578  if (!G_find_file2_misc(GRID3, "timestamp", name, mapset))
579  return 0;
580 
581  return 1;
582 }
583 
584 /*!
585  \brief Read timestamp from 3D raster map
586 
587  \param name map name
588  \param mapset mapset name
589  \param[out] ts TimeStamp struct to populate
590 
591  \return 1 on success
592  \return 0 or negative on error
593  */
594 int G_read_raster3d_timestamp(const char *name, const char *mapset,
595  struct TimeStamp *ts)
596 {
597  return read_timestamp("raster3d", GRID3, name, mapset, ts);
598 }
599 
600 /*!
601  \brief Write timestamp of 3D raster map
602 
603  \param name map name
604  \param[out] ts TimeStamp struct to populate
605 
606  \return 1 on success
607  \return -1 error - can't create timestamp file
608  \return -2 error - invalid datetime in ts
609 
610  */
611 int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
612 {
613  return write_timestamp("raster3d", GRID3, name, ts);
614 }
615 
616 /*!
617  \brief Remove timestamp from 3D raster map
618 
619  Only timestamp files in current mapset can be removed.
620 
621  \param name map name
622 
623  \return 0 if no file
624  \return 1 on success
625  \return -1 on failure
626  */
628 {
629  return G_remove_misc(GRID3, "timestamp", name);
630 }
#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
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:614
DateTime dt[2]
Definition: gis.h:615
int count
Definition: gis.h:616
Definition: path.h:15
void G_init_timestamp(struct TimeStamp *ts)
Initialize timestamp structure.
Definition: timestamp.c:95
int G_read_raster_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from raster map.
Definition: timestamp.c:374
int G_has_raster_timestamp(const char *name, const char *mapset)
Check if timestamp for raster map exists.
Definition: timestamp.c:356
int G_has_raster3d_timestamp(const char *name, const char *mapset)
Check if timestamp for 3D raster map exists.
Definition: timestamp.c:576
int G_write_timestamp(FILE *fd, const struct TimeStamp *ts)
Output TimeStamp structure to a file as a formatted string.
Definition: timestamp.c:160
int G_format_timestamp(const struct TimeStamp *ts, char *buf)
Create text string from TimeStamp structure.
Definition: timestamp.c:183
int G_read_raster3d_timestamp(const char *name, const char *mapset, struct TimeStamp *ts)
Read timestamp from 3D raster map.
Definition: timestamp.c:594
int G_remove_raster3d_timestamp(const char *name)
Remove timestamp from 3D raster map.
Definition: timestamp.c:627
int G__read_timestamp(FILE *fd, struct TimeStamp *ts)
Read timestamp.
Definition: timestamp.c:136
void G_set_timestamp(struct TimeStamp *ts, const DateTime *dt)
Set timestamp (single)
Definition: timestamp.c:106
int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of raster map.
Definition: timestamp.c:391
int G_scan_timestamp(struct TimeStamp *ts, const char *buf)
Fill a TimeStamp structure from a datetime string.
Definition: timestamp.c:217
#define GRID3
Definition: timestamp.c:88
#define RAST_MISC
Definition: timestamp.c:87
void G_set_timestamp_range(struct TimeStamp *ts, const DateTime *dt1, const DateTime *dt2)
Set timestamp (range)
Definition: timestamp.c:118
int G_has_vector_timestamp(const char *name, const char *layer, const char *mapset)
Check if timestamp for vector map exists.
Definition: timestamp.c:422
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:458
int G_write_raster3d_timestamp(const char *name, const struct TimeStamp *ts)
Write timestamp of 3D raster map.
Definition: timestamp.c:611
int G_write_vector_timestamp(const char *name, const char *layer, const struct TimeStamp *ts)
Write timestamp of vector map.
Definition: timestamp.c:507
int G_remove_vector_timestamp(const char *name, const char *layer)
Remove timestamp from vector map.
Definition: timestamp.c:553
void G_get_timestamps(const struct TimeStamp *ts, DateTime *dt1, DateTime *dt2, int *count)
Copy TimeStamp into [two] Datetimes structs.
Definition: timestamp.c:260
int G_remove_raster_timestamp(const char *name)
Remove timestamp from raster map.
Definition: timestamp.c:407