Skip to content
Permalink
Browse files
gml_[item]_type: modify Date semantics, and add Time and DateTime
Currently, for vector features, we have a Date datatype that is used
indifferently for Date, Time, DateTime, which can cause approximations
in GML or other output formats (such as OGR GeoJSON), since the output
doesn't really know the exact input.
This change modifies the semantics of Date to mean date, without time,
and add Time (time, without date) and DateTime. The type autodetection
is modified in the MSSQL2008, OGR, Oracle and PostGIS backends. On the
output side, the WFS/GML and OGR output are modified to take into account
those 3 separate types.
  • Loading branch information
rouault committed Oct 27, 2019
1 parent 2bd9c0d commit e91a4e57724c7a3f97921f78b79de17453d3df3b
Show file tree
Hide file tree
Showing 25 changed files with 329 additions and 149 deletions.
@@ -1024,14 +1024,14 @@ static void msGMLWriteItem(FILE *stream, gmlItemObj *item,
tag_name = item->name;
if(strchr(tag_name, ':') != NULL) add_namespace = MS_FALSE;

if( item->type && EQUAL(item->type, "Date") ) {
if( item->type && (EQUAL(item->type, "Date") ||
EQUAL(item->type, "DateTime") ||
EQUAL(item->type, "Time")) ) {
struct tm tm;
if( msParseTime(value, &tm) == MS_TRUE ) {
const char* pszStartTag = "";
const char* pszEndTag = "";
int timeresolution;

timeresolution = msTimeGetResolution(value);
encoded_value = (char*) msSmallMalloc(256);
if( outputformat == OWS_GML32 ) {
if( pszFID != NULL )
@@ -1040,11 +1040,16 @@ static void msGMLWriteItem(FILE *stream, gmlItemObj *item,
pszEndTag = "</gml:timePosition>";
}

if( timeresolution == TIME_RESOLUTION_DAY )
if( EQUAL(item->type, "Date") )
snprintf(encoded_value, 256, "%s%04d-%02d-%02d%s",
pszStartTag,
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
pszEndTag);
else if( EQUAL(item->type, "Time") )
snprintf(encoded_value, 256, "%s%02d:%02d:%02dZ%s",
pszStartTag,
tm.tm_hour, tm.tm_min, tm.tm_sec,
pszEndTag);
else
snprintf(encoded_value, 256, "%s%04d-%02d-%02dT%02d:%02d:%02dZ%s",
pszStartTag,
@@ -886,9 +886,13 @@ static int columnName(msODBCconn *conn, int index, char *buffer, int bufferLengt
break;

case SQL_TYPE_DATE:
gml_type = "Date";
break;
case SQL_TYPE_TIME:
gml_type = "Time";
break;
case SQL_TYPE_TIMESTAMP:
gml_type = "Date";
gml_type = "DateTime";
break;

case SQL_BIT:
@@ -2719,9 +2719,13 @@ msOGRPassThroughFieldDefinitions( layerObj *layer, msOGRFileInfo *psInfo )
break;

case OFTDate:
gml_type = "Date";
break;
case OFTTime:
gml_type = "Time";
break;
case OFTDateTime:
gml_type = "Date";
gml_type = "DateTime";
break;

default:
@@ -1067,6 +1067,10 @@ int msOGRWriteFromQuery( mapObj *map, outputFormatObj *format, int sendheaders )
else if( EQUAL(item->type,"Character") )
eType = OFTString;
else if( EQUAL(item->type,"Date") )
eType = OFTDate;
else if( EQUAL(item->type,"Time") )
eType = OFTTime;
else if( EQUAL(item->type,"DateTime") )
eType = OFTDateTime;
else if( EQUAL(item->type,"Boolean") )
eType = OFTInteger;
@@ -2935,12 +2935,16 @@ msOracleSpatialGetFieldDefn( layerObj *layer,

case SQLT_DAT:
case SQLT_DATE:
gml_type = "Date";
break;
case SQLT_TIMESTAMP:
case SQLT_TIMESTAMP_TZ:
case SQLT_TIMESTAMP_LTZ:
gml_type = "DateTime";
break;
case SQLT_TIME:
case SQLT_TIME_TZ:
gml_type = "Date";
gml_type = "Time";
break;

default:
@@ -3199,6 +3199,7 @@ int msPostGISLayerGetShape(layerObj *layer, shapeObj *shape, resultObj *record)
#define VARCHAROID 1043
#define DATEOID 1082
#define TIMEOID 1083
#define TIMETZOID 1266
#define TIMESTAMPOID 1114
#define TIMESTAMPTZOID 1184
#define NUMERICOID 1700
@@ -3260,9 +3261,12 @@ msPostGISPassThroughFieldDefinitions( layerObj *layer,
sprintf( gml_width, "%d", (fmod - 4) >> 16 );
sprintf( gml_precision, "%d", ((fmod-4) & 0xFFFF) );
}
} else if( oid == DATEOID
|| oid == TIMESTAMPOID || oid == TIMESTAMPTZOID ) {
} else if( oid == DATEOID ) {
gml_type = "Date";
} else if( oid == TIMEOID || oid == TIMETZOID ) {
gml_type = "Time";
} else if( oid == TIMESTAMPOID || oid == TIMESTAMPTZOID ) {
gml_type = "DateTime";
}

snprintf( md_item_name, sizeof(md_item_name), "gml_%s_type", item );
@@ -45,9 +45,7 @@ typedef struct {
MS_TIME_RESOLUTION resolution;
} timeFormatObj;

#define MS_NUMTIMEFORMATS 13

timeFormatObj ms_timeFormats[MS_NUMTIMEFORMATS] = {
static timeFormatObj ms_timeFormats[] = {
{"^[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},
@@ -60,9 +58,13 @@ timeFormatObj ms_timeFormats[MS_NUMTIMEFORMATS] = {
{"^[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}
{"^T[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "T%H:%M:%S", "THH:MM:SS", TIME_RESOLUTION_SECOND},
{"^[0-9]{2}:[0-9]{2}:[0-9]{2}Z", NULL, "%H:%M:%SZ", "HH:MM:SSZ", TIME_RESOLUTION_SECOND},
{"^[0-9]{2}:[0-9]{2}:[0-9]{2}", NULL, "%H:%M:%S", "HH:MM:SS", TIME_RESOLUTION_SECOND}
};

#define MS_NUMTIMEFORMATS (int)(sizeof(ms_timeFormats)/sizeof(ms_timeFormats[0]))

int *ms_limited_pattern = NULL;
int ms_num_limited_pattern;

@@ -1060,6 +1060,10 @@ static const char* msWFSMapServTypeToXMLType(const char* type)
element_type = "string";
else if( EQUAL(type,"Date") )
element_type = "date";
else if( EQUAL(type,"Time") )
element_type = "time";
else if( EQUAL(type,"DateTime") )
element_type = "dateTime";
else if( EQUAL(type,"Boolean") )
element_type = "boolean";
return element_type;
@@ -1084,7 +1088,8 @@ static void msWFSWriteItemElement(FILE *stream, gmlItemObj *item, const char *ta

if(item->type)
{
if( outputformat == OWS_GML32_SFE_SCHEMA && EQUAL(item->type,"Date") )
if( outputformat == OWS_GML32_SFE_SCHEMA &&
(EQUAL(item->type,"Date") || EQUAL(item->type,"Time") || EQUAL(item->type,"DateTime")) )
element_type = "gml:TimeInstantType";
else
element_type = msWFSMapServTypeToXMLType(item->type);
@@ -1,2 +1,2 @@
aint,str,areal,adate
1,a,2.4,"2013/10/26 12:00:00"
aint,str,areal,adatetime,adate,atime
1,a,2.4,"2013/10/26 12:00:00","2013/10/26","12:00:00"
@@ -1 +1 @@
Integer,String,Real,DateTime
Integer,String,Real,DateTime,Date,Time
@@ -25,7 +25,9 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8
<element name="aint" minOccurs="0" type="integer"/>
<element name="str" minOccurs="0" type="string"/>
<element name="areal" minOccurs="0" type="double"/>
<element name="adatetime" minOccurs="0" type="dateTime"/>
<element name="adate" minOccurs="0" type="date"/>
<element name="atime" minOccurs="0" type="time"/>
</sequence>
</extension>
</complexContent>
@@ -0,0 +1,35 @@
Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8

<?xml version='1.0' encoding="UTF-8" ?>
<wfs:FeatureCollection
xmlns:ms="http://mapserver.gis.umn.edu/mapserver"
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:wfs="http://www.opengis.net/wfs/2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=date&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
timeStamp="" numberMatched="unknown" numberReturned="1"
next="http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=GetFeature&amp;TYPENAMES=date&amp;MAXFEATURES=1&amp;STARTINDEX=1">
<wfs:boundedBy>
<gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326">
<gml:lowerCorner>37.98000 -130.00000</gml:lowerCorner>
<gml:upperCorner>37.98000 -130.00000</gml:upperCorner>
</gml:Envelope>
</wfs:boundedBy>
<wfs:member>
<ms:date gml:id="date.1">
<gml:boundedBy>
<gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326">
<gml:lowerCorner>37.98000 -130.00000</gml:lowerCorner>
<gml:upperCorner>37.98000 -130.00000</gml:upperCorner>
</gml:Envelope>
</gml:boundedBy>
<ms:msGeometry>
<gml:Point gml:id="date.1.1" srsName="urn:ogc:def:crs:EPSG::4326">
<gml:pos>37.98000 -130.00000</gml:pos>
</gml:Point>
</ms:msGeometry>
<ms:date gml:id="date.1.date"><gml:timePosition>2004-01-01</gml:timePosition></ms:date>
</ms:date>
</wfs:member>
</wfs:FeatureCollection>

@@ -7,6 +7,6 @@ Content-Type: text/xml; subtype=gml/3.1.1; charset=UTF-8
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=time&amp;OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" timeStamp="" numberOfFeatures="6">
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=1.1.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=datetime&amp;OUTPUTFORMAT=text/xml;%20subtype=gml/3.1.1 http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd" timeStamp="" numberOfFeatures="6">
</wfs:FeatureCollection>

@@ -12,17 +12,17 @@ Content-Type: application/gml+xml; version=3.2; charset=UTF-8
<import namespace="http://www.opengis.net/gml/3.2"
schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd" />

<element name="time"
type="ms:timeType"
<element name="datetime"
type="ms:datetimeType"
substitutionGroup="gml:AbstractFeature" />

<complexType name="timeType">
<complexType name="datetimeType">
<complexContent>
<extension base="gml:AbstractFeatureType">
<sequence>
<element name="msGeometry" type="gml:GeometryPropertyType" minOccurs="0" maxOccurs="1"/>
<element name="gid" minOccurs="0" type="string"/>
<element name="time" minOccurs="0" type="gml:TimeInstantType"/>
<element name="gid" minOccurs="0" type="integer"/>
<element name="datetime" minOccurs="0" type="gml:TimeInstantType"/>
</sequence>
</extension>
</complexContent>
@@ -6,7 +6,7 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:wfs="http://www.opengis.net/wfs/2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=time&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=datetime&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
timeStamp="" numberMatched="1" numberReturned="0">
</wfs:FeatureCollection>

@@ -6,7 +6,7 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:wfs="http://www.opengis.net/wfs/2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=time&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=datetime&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
timeStamp="" numberMatched="6" numberReturned="0">
</wfs:FeatureCollection>

@@ -6,7 +6,7 @@ Content-Type: text/xml; subtype="gml/3.2.1"; charset=UTF-8
xmlns:gml="http://www.opengis.net/gml/3.2"
xmlns:wfs="http://www.opengis.net/wfs/2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=time&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
xsi:schemaLocation="http://mapserver.gis.umn.edu/mapserver http://localhost/path/to/wfs_simple?myparam=something&amp;SERVICE=WFS&amp;VERSION=2.0.0&amp;REQUEST=DescribeFeatureType&amp;TYPENAME=datetime&amp;OUTPUTFORMAT=application%2Fgml%2Bxml%3B%20version%3D3.2 http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd http://www.opengis.net/gml/3.2 http://schemas.opengis.net/gml/3.2.1/gml.xsd"
timeStamp="" numberMatched="0" numberReturned="0">
</wfs:FeatureCollection>

0 comments on commit e91a4e5

Please sign in to comment.