/*! * \file gis/timestamp.c * * \brief GIS Library - Timestamp management * * Provides DateTime functions for timestamp management. * * The timestamp values must use the format as described in the GRASS * datetime library. The source tree for this library should have a * description of the format. For convience, the formats as of Feb, 1996 * are reproduced here: * * There are two types of datetime values: absolute and relative. Absolute * values specify exact dates and/or times. Relative values specify a span * of time. Some examples will help clarify: * * Absolute * * The general format for absolute values is: * * day month year [bc] hour:minute:seconds timezone * * day is 1-31 * month is jan,feb,...,dec * year is 4 digit year * [bc] if present, indicates dates is BC * hour is 0-23 (24 hour clock) * mintue is 0-59 * second is 0-59.9999 (fractions of second allowed) * timezone is +hhmm or -hhmm (eg, -0600) * * parts can be missing * * 1994 [bc] * Jan 1994 [bc] * 15 jan 1000 [bc] * 15 jan 1994 [bc] 10 [+0000] * 15 jan 1994 [bc] 10:00 [+0100] * 15 jan 1994 [bc] 10:00:23.34 [-0500] * * Relative * * There are two types of relative datetime values, year- month and day-second. * * The formats are: * * [-] # years # months * [-] # days # hours # minutes # seconds * * The words years, months, days, hours, minutes, seconds are literal words, * and the # are the numeric values. * * Examples: * * 2 years * 5 months * 2 years 5 months * 100 days * 15 hours 25 minutes 35.34 seconds * 100 days 25 minutes * 1000 hours 35.34 seconds * * The following are illegal because it mixes year-month and day-second * (because the number of days in a month or in a year vary): * * 3 months 15 days * 3 years 10 days * * (C) 2001-2009 by the GRASS Development Team * * This program is free software under the GNU General Public License * (>=v2). Read the file COPYING that comes with GRASS for details. * * \author Michael Shapiro & Bill Brown, CERL * \author grid3 functions by Michael Pelizzari, LMCO */ #include #include #include #define RAST_MISC "cell_misc" #define VECT_MISC "dig_misc" #define GRID3 "grid3" /*! \brief Initialize timestamp structure \param ts pointer to TimeStamp structure */ void G_init_timestamp(struct TimeStamp *ts) { ts->count = 0; } /*! \brief Set timestamp (single) \param ts pointer to TimeStamp structure \param dt pointer to DateTime structure (date/time to be set) */ void G_set_timestamp(struct TimeStamp *ts, const DateTime * dt) { datetime_copy(&ts->dt[0], dt); ts->count = 1; } /*! \brief Set timestamp (range) \param ts pointer to TimeStamp structure \param dt1,dt2 pointer to DateTime structures */ void G_set_timestamp_range(struct TimeStamp *ts, const DateTime * dt1, const DateTime * dt2) { datetime_copy(&ts->dt[0], dt1); datetime_copy(&ts->dt[1], dt2); ts->count = 2; } /*! \brief Read timestamp \param fd file descriptor \param[out] ts pointer to TimeStamp structure \return -2 EOF \return -1 on error \return 0 on success */ int G__read_timestamp(FILE * fd, struct TimeStamp *ts) { char buf[1024]; char comment[2]; while (fgets(buf, sizeof(buf), fd)) { if (sscanf(buf, "%1s", comment) != 1 || *comment == '#') continue; return (G_scan_timestamp(ts, buf) > 0 ? 0 : -1); } return -2; /* nothing in the file */ } /*! \brief Output TimeStamp structure to a file as a formatted string A handy fd might be "stdout". \param[in,out] fd file descriptor \param ts pointer to TimeStamp structure \return 0 on success \return -1 on error */ int G__write_timestamp(FILE * fd, const struct TimeStamp *ts) { char buf[1024]; if (G_format_timestamp(ts, buf) < 0) return -1; fprintf(fd, "%s\n", buf); return 0; } /*! \brief Create text string from TimeStamp structure Fills string *buf with info from TimeStamp structure *ts in a pretty way. The TimeStamp struct is defined in gis.h and populated with e.g. G_read_raster_timestamp(). \param ts TimeStamp structure containing time info \param buf string to receive formatted timestamp \return 1 on success \return -1 error */ int G_format_timestamp(const struct TimeStamp *ts, char *buf) { char temp1[128], temp2[128]; *buf = 0; if (ts->count > 0) { if (datetime_format(&ts->dt[0], temp1) != 0) return -1; } if (ts->count > 1) { if (datetime_format(&ts->dt[1], temp2) != 0) return -1; } if (ts->count == 1) strcpy(buf, temp1); else if (ts->count == 2) sprintf(buf, "%s / %s", temp1, temp2); return 1; } /*! \brief Fill a TimeStamp structure from a datetime string Populate a TimeStamp structure (defined in gis.h) from a text string. Checks to make sure text string is in valid GRASS datetime format. \param ts TimeStamp structure to be populated \param buf string containing formatted time info \return 1 on success \return -1 error */ int G_scan_timestamp(struct TimeStamp *ts, const char *buf) { char temp[1024], *t; const char *slash; DateTime dt1, dt2; G_init_timestamp(ts); for (slash = buf; *slash; slash++) if (*slash == '/') break; if (*slash) { t = temp; while (buf != slash) *t++ = *buf++; *t = 0; buf++; if (datetime_scan(&dt1, temp) != 0 || datetime_scan(&dt2, buf) != 0) return -1; G_set_timestamp_range(ts, &dt1, &dt2); } else { if (datetime_scan(&dt2, buf) != 0) return -1; G_set_timestamp(ts, &dt2); } return 1; } /*! \brief Copy TimeStamp into [two] Datetimes structs Use to copy the TimeStamp information into Datetimes, as the members of struct TimeStamp shouldn't be accessed directly. - count=0 means no datetimes were copied - count=1 means 1 datetime was copied into dt1 - count=2 means 2 datetimes were copied \param ts source TimeStamp structure \param[out] dt1 first DateTime struct to be filled \param[out] dt2 second DateTime struct to be filled \param[out] count return code */ void G_get_timestamps(const struct TimeStamp *ts, DateTime * dt1, DateTime * dt2, int *count) { *count = 0; if (ts->count > 0) { datetime_copy(dt1, &ts->dt[0]); *count = 1; } if (ts->count > 1) { datetime_copy(dt2, &ts->dt[1]); *count = 2; } } /*! \brief Write timestamp file \param maptype map type \param dir directory \param name map name \param ts pointer to TimeStamp \return 1 on success \return -1 error - can't create timestamp file \return -2 error - invalid datetime in ts */ static int write_timestamp(const char *maptype, const char *dir, const char *name, const struct TimeStamp *ts) { FILE *fd; int stat; fd = G_fopen_new_misc(dir, "timestamp", name); if (fd == NULL) { G_warning(_("Unable to create timestamp file for %s map <%s@%s>"), maptype, name, G_mapset()); return -1; } stat = G__write_timestamp(fd, ts); fclose(fd); if (stat == 0) return 1; G_warning(_("Invalid timestamp specified for %s map <%s@%s>"), maptype, name, G_mapset()); return -2; } /*! \brief Read timestamp file \param maptype map type \param dir directory \param name map name \param mapset mapset name \param ts pointer to TimeStamp \return 0 no timestamp file \return 1 on success \return -1 error - can't open timestamp file \return -2 error - invalid datetime values in timestamp file */ static int read_timestamp(const char *maptype, const char *dir, const char *name, const char *mapset, struct TimeStamp *ts) { FILE *fd; int stat; if (!G_find_file2_misc(dir, "timestamp", name, mapset)) return 0; fd = G_fopen_old_misc(dir, "timestamp", name, mapset); if (fd == NULL) { G_warning(_("Unable to open timestamp file for %s map <%s@%s>"), maptype, name, mapset); return -1; } stat = G__read_timestamp(fd, ts); fclose(fd); if (stat == 0) return 1; G_warning(_("Invalid timestamp file for %s map <%s@%s>"), maptype, name, mapset); return -2; } /*! \brief Read timestamp from raster map \param name map name \param mapset mapset the map lives in \param[out] ts TimeStamp struct to populate \return 1 on success \return 0 or negative on error */ int G_read_raster_timestamp(const char *name, const char *mapset, struct TimeStamp *ts) { return read_timestamp("raster", RAST_MISC, name, mapset, ts); } /*! \brief Remove timestamp from raster map Only timestamp files in current mapset can be removed. \param name map name \return 0 if no file \return 1 on success \return -1 on error */ int G_remove_raster_timestamp(const char *name) { return G_remove_misc(RAST_MISC, "timestamp", name); } /*! \brief Read timestamp from vector map Is this used anymore with the new GRASS 6 vector engine??? \param name map name \param mapset mapset name \param[out] ts TimeStamp struct to populate \return 1 on success \return 0 or negative on error */ int G_read_vector_timestamp(const char *name, const char *mapset, struct TimeStamp *ts) { return read_timestamp("vector", VECT_MISC, name, mapset, ts); } /*! \brief Remove timestamp from vector map Is this used anymore with the new GRASS 6 vector engine??? Only timestamp files in current mapset can be removed. \param name map name \return 0 if no file \return 1 on success \return -1 on failure */ int G_remove_vector_timestamp(const char *name) { return G_remove_misc(VECT_MISC, "timestamp", name); } /*! \brief Read timestamp from 3D raster map \param name map name \param mapset mapset name \param[out] ts TimeStamp struct to populate \return 1 on success \return 0 or negative on error */ int G_read_grid3_timestamp(const char *name, const char *mapset, struct TimeStamp *ts) { return read_timestamp("grid3", GRID3, name, mapset, ts); } /*! \brief Remove timestamp from 3D raster map Only timestamp files in current mapset can be removed. \param name map name \return 0 if no file \return 1 on success \return -1 on failure */ int G_remove_grid3_timestamp(const char *name) { return G_remove_misc(GRID3, "timestamp", name); } /*! \brief Write timestamp of raster map \param name map name \param[out] ts TimeStamp struct to populate \return 1 on success \return -1 error - can't create timestamp file \return -2 error - invalid datetime in ts */ int G_write_raster_timestamp(const char *name, const struct TimeStamp *ts) { return write_timestamp("raster", RAST_MISC, name, ts); } /*! \brief Write timestamp of vector map \param name map name \param[out] ts TimeStamp struct to populate \return 1 on success \return -1 error - can't create timestamp file \return -2 error - invalid datetime in ts */ int G_write_vector_timestamp(const char *name, const struct TimeStamp *ts) { return write_timestamp("vector", VECT_MISC, name, ts); } /*! \brief Write timestamp of 3D raster map \param name map name \param[out] ts TimeStamp struct to populate \return 1 on success \return -1 error - can't create timestamp file \return -2 error - invalid datetime in ts */ int G_write_grid3_timestamp(const char *name, const struct TimeStamp *ts) { return write_timestamp("grid3", GRID3, name, ts); }