/****************************************************************************** * * Project: MapServer * Purpose: Date/Time utility functions. * Author: Steve Lime and the MapServer team. * ****************************************************************************** * Copyright (c) 1996-2005 Regents of the University of Minnesota. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies of this Software or works derived from this Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************** * * $Log: maptime.c,v $ * Revision 1.19 2006/03/14 03:43:30 assefa * Move msValidateTimeValue to maptime so it can be used by WMS and SOS. * (Bug 1710) * * Revision 1.18 2005/09/26 14:51:40 assefa * Correct typo in ms_timeFormats (Bug 1478). * * Revision 1.17 2005/06/14 16:03:35 dan * Updated copyright date to 2005 * * Revision 1.16 2005/05/27 15:00:12 dan * New regex wrappers to solve issues with previous version (bug 1354) * * Revision 1.15 2005/02/18 03:06:47 dan * Turned all C++ (//) comments into C comments (bug 1238) * * Revision 1.14 2004/10/21 10:54:17 assefa * Add postgis date_trunc support. * * Revision 1.13 2004/10/21 04:30:55 frank * Added standardized headers. Added MS_CVSID(). * */ #include #include #include #include "map.h" #include "maptime.h" #include "maperror.h" MS_CVSID("$Id: maptime.c,v 1.19 2006/03/14 03:43:30 assefa Exp $") typedef struct { char pattern[64]; ms_regex_t *regex; char format[32]; char userformat[32]; MS_TIME_RESOLUTION resolution; } timeFormatObj; #define MS_NUMTIMEFORMATS 13 timeFormatObj ms_timeFormats[MS_NUMTIMEFORMATS] = { {"^[0-9]{8}", NULL, "%Y%m%d","YYYYMMDD",TIME_RESOLUTION_DAY}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "%Y-%m-%dT%H:%M:%SZ","YYYY-MM-DDTHH:MM:SSZ",TIME_RESOLUTION_SECOND}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%dT%H:%M:%S", "YYYY-MM-DDTHH:MM:SS",TIME_RESOLUTION_SECOND}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%d %H:%M:%S", "YYYY-MM-DD HH:MM:SS", TIME_RESOLUTION_SECOND}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%dT%H:%M", "YYYY-MM-DDTHH:MM",TIME_RESOLUTION_MINUTE}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}", NULL, "%Y-%m-%d %H:%M", "YYYY-MM-DD HH:MM",TIME_RESOLUTION_MINUTE}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}", NULL, "%Y-%m-%dT%H", "YYYY-MM-DDTHH",TIME_RESOLUTION_HOUR}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}", NULL, "%Y-%m-%d %H", "YYYY-MM-DD HH",TIME_RESOLUTION_HOUR}, {"^[0-9]{4}-[0-9]{2}-[0-9]{2}", NULL, "%Y-%m-%d", "YYYY-MM-DD", TIME_RESOLUTION_DAY}, {"^[0-9]{4}-[0-9]{2}", NULL, "%Y-%m", "YYYY-MM",TIME_RESOLUTION_MONTH}, {"^[0-9]{4}", NULL, "%Y", "YYYY",TIME_RESOLUTION_YEAR}, {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "T%H:%M:%SZ", "THH:MM:SSZ",TIME_RESOLUTION_SECOND}, {"^T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "T%H:%M:%S", "THH:MM:SS", TIME_RESOLUTION_SECOND}, }; int *ms_limited_pattern = NULL; int ms_num_limited_pattern; void msTimeInit(struct tm *time) { /* set all members to zero */ time->tm_sec = 0; time->tm_min = 0; time->tm_hour = 0; time->tm_mday = 0; time->tm_mon = 0; time->tm_year = 0; time->tm_wday = 0; time->tm_yday = 0; time->tm_isdst = 0; return; } static int compareIntVals(int a, int b) { if(ab) return 1; else return 0; } int msDateCompare(struct tm *time1, struct tm *time2) { int result; if((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) return result; /* not equal based on year */ else if((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) return result; /* not equal based on month */ else if((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) return result; /* not equal based on day of month */ return(0); /* must be equal */ } int msTimeCompare(struct tm *time1, struct tm *time2) { int result; if((result = compareIntVals(time1->tm_year, time2->tm_year)) != 0) return result; /* not equal based on year */ else if((result = compareIntVals(time1->tm_mon, time2->tm_mon)) != 0) return result; /* not equal based on month */ else if((result = compareIntVals(time1->tm_mday, time2->tm_mday)) != 0) return result; /* not equal based on day of month */ else if((result = compareIntVals(time1->tm_hour, time2->tm_hour)) != 0) return result; /* not equal based on hour */ else if((result = compareIntVals(time1->tm_min, time2->tm_min)) != 0) return result; /* not equal based on minute */ else if((result = compareIntVals(time1->tm_sec, time2->tm_sec)) != 0) return result; /* not equal based on second */ return(0); /* must be equal */ } #if defined(_WIN32) && !defined(__CYGWIN__) #include void msGettimeofday(struct mstimeval* tp, void* tzp) { struct _timeb theTime; _ftime(&theTime); tp->tv_sec = theTime.time; tp->tv_usec = theTime.millitm * 1000; } #endif #if defined(_WIN32) && !defined(__CYGWIN__) /* we need to provide our own prototype on windows. */ char *strptime( const char *buf, const char *format, struct tm *timeptr ); #endif char *msStrptime(const char *s, const char *format, struct tm *tm) { #if defined(_WIN32) && !defined(__CYGWIN__) /* we are now using a local strptime found strptime.c */ return strptime(s, format, tm); #else /* Use system strptime() on non-windows systems */ return strptime(s, format, tm); #endif } /** return MS_TRUE if the time string matchs the timeformat. else return MS_FALSE. */ int msTimeMatchPattern(char *timestring, char *timeformat) { int i =-1; /* match the pattern format first and then check if the time string */ /* matchs the pattern. If it is the case retrurn the MS_TRUE */ for (i=0; i= 0 && i < MS_NUMTIMEFORMATS) { if(!ms_timeFormats[i].regex) { ms_timeFormats[i].regex = (ms_regex_t *) malloc(sizeof(ms_regex_t)); ms_regcomp(ms_timeFormats[i].regex, ms_timeFormats[i].pattern, MS_REG_EXTENDED|MS_REG_NOSUB); } if (ms_regexec(ms_timeFormats[i].regex, timestring, 0,NULL, 0) == 0) return MS_TRUE; } return MS_FALSE; } void msUnsetLimitedPatternToUse() { if (ms_limited_pattern && ms_num_limited_pattern > 0) free(ms_limited_pattern); ms_num_limited_pattern = 0; } void msSetLimitedPattersToUse(char *patternstring) { int *limitedpatternindice = NULL; int numpatterns=0, i=0, j=0, ntmp=0; char **patterns = NULL; limitedpatternindice = (int *)malloc(sizeof(int)*MS_NUMTIMEFORMATS); /* free previous setting */ msUnsetLimitedPatternToUse(); if (patternstring) { patterns = split(patternstring, ',', &ntmp); if (patterns && ntmp >= 1) { for (i=0; i 0) { ms_limited_pattern = (int *)malloc(sizeof(int)*numpatterns); for (i=0; i 0) num_patterns = ms_num_limited_pattern; else num_patterns = MS_NUMTIMEFORMATS; for(i=0; i 0) indice = ms_limited_pattern[i]; else indice = i; if(!ms_timeFormats[indice].regex) { /* compile the expression */ ms_timeFormats[indice].regex = (ms_regex_t *) malloc(sizeof(ms_regex_t)); if(ms_regcomp(ms_timeFormats[indice].regex, ms_timeFormats[indice].pattern, MS_REG_EXTENDED|MS_REG_NOSUB) != 0) { msSetError(MS_REGEXERR, "Failed to compile expression (%s).", "msParseTime()", ms_timeFormats[indice].pattern); return(MS_FALSE); } } /* test the expression against the string */ if(ms_regexec(ms_timeFormats[indice].regex, string, 0, NULL, 0) == 0) { /* match */ msStrptime(string, ms_timeFormats[indice].format, tm); return(MS_TRUE); } } msSetError(MS_REGEXERR, "Unrecognized date or time format (%s).", "msParseTime()", string); return(MS_FALSE); } /** * Parse the time string and return the reslution */ int msTimeGetResolution(const char *timestring) { int i=0; if (!timestring) return -1; for(i=0; i=2)/*range */ { if (msParseTime(atimeelements[0], &tmtimestart) != MS_TRUE) { msFreeCharArray(atimeelements, numelements); return MS_FALSE; } if (msParseTime(atimeelements[1], &tmtimeend) != MS_TRUE) { msFreeCharArray(atimeelements, numelements); return MS_FALSE; } } msFreeCharArray(atimeelements, numelements); /* Now parse the time extent. Extents can be - one range (2004-09-21/2004-09-25/resolution) - multiple rages 2004-09-21/2004-09-25/res1,2004-09-21/2004-09-25/res2 - one value 2004-09-21 - mutiple values 2004-09-21,2004-09-22,2004-09-23 */ numextents = 0; atimeextents = split (timeextent, ',', &numextents); if (atimeextents == NULL || numextents <= 0) return MS_FALSE; /*the time timestring should at be valid in one of the extents defined */ for (i=0; i= 0) { msFreeCharArray(atimerange, numranges); return MS_TRUE; } } /*2004-09-21/2004-09-25/res1*/ else if (numranges >= 2) { if (msParseTime(atimerange[0], &tmstart) == MS_TRUE && msParseTime(atimerange[1], &tmend) == MS_TRUE && msTimeCompare(&tmstart, &tmtimestart) <= 0 && msTimeCompare(&tmend, &tmtimeend) >= 0) { msFreeCharArray(atimerange, numranges); return MS_TRUE; } } msFreeCharArray(atimerange, numranges); } msFreeCharArray(atimeextents, numextents); return MS_FALSE; } int msValidateTimeValue(char *timestring, const char *timeextent) { char **atimes, **tokens = NULL; int i, numtimes, ntmp = 0; /* we need to validate the time passsed in the request */ /* against the time extent defined */ if (!timestring || !timeextent) return MS_FALSE; /* parse the time string. We support descrete times (eg 2004-09-21), */ /* multiple times (2004-09-21, 2004-09-22, ...) */ /* and range(s) (2004-09-21/2004-09-25, 2004-09-27/2004-09-29) */ if (strstr(timestring, ",") == NULL && strstr(timestring, "/") == NULL) /* discrete time */ { return _msValidateTime(timestring, timeextent); } else { atimes = split (timestring, ',', &numtimes); if (numtimes >=1) /* multiple times */ { tokens = split(atimes[0], '/', &ntmp); if (ntmp == 1) /* multiple descrete times */ { /*msFreeCharArray(tokens, ntmp);*/ for (i=0; i= 2)/* multiple ranges */ { for (i=0; i