RFC 56: OFTTime/OFTDateTime millisecond accuracy

Author: Even Rouault

Contact: even dot rouault at spatialys dot com

Status: Adopted, implemented

Version: 2.0


This RFC aims at adding millisecond accuracy to OFTTime and OFTDateTime fields, as a number of formats support it explicitly or implicitly : MapInfo, GPX, Atom (GeoRSS driver), GeoPackage, SQLite, PostgreSQL, CSV, GeoJSON, ODS, XLSX, KML (potentially GML too)...

Core changes

The OGRField enumeration is modified as such :

typedef union {
    [... unchanged ... ]

    struct {
        GInt16  Year;
        GByte   Month;
        GByte   Day;
        GByte   Hour;
        GByte   Minute;
        GByte   TZFlag; /* 0=unknown, 1=localtime(ambiguous),
                           100=GMT, 104=GMT+1, 80=GMT-5, etc */
        GByte   Reserved; /* must be set to 0 */
        float   Second; /* with millisecond accuracy. at the end of the structure, so as to keep it 12 bytes on 32 bit */
    } Date;
} OGRField;

So the "GByte Second" field is removed and replaced by a padding Byte reserved for potential later uses. A "float Second" field is added.

On 32 bit builds, the size of OGRField is now 12 bytes instead of 8 bytes. On 64 bit builds, the size of OGRField remains 16 bytes.

New/modified methods

OGRFeature::SetFieldAsDateTime() methods that took a int nSecond now take a float fSecond parameter. The GetFieldAsDateTime() method that took a int* pnSecond is kept, and a new GetFieldAsDateTime() method that takes a float* pfSecond is added.

  • In OGRFeature class :

int                 GetFieldAsDateTime( int i,
                                 int *pnYear, int *pnMonth, int *pnDay,
                                 int *pnHour, int *pnMinute, int *pnSecond,
                                 int *pnTZFlag ); /* unchanged from GDAL 1.X */
int                 GetFieldAsDateTime( int i,
                                 int *pnYear, int *pnMonth, int *pnDay,
                                 int *pnHour, int *pnMinute, float *pfSecond,
                                 int *pnTZFlag ); /* new */
void                SetField( int i, int nYear, int nMonth, int nDay,
                              int nHour=0, int nMinute=0, float fSecond=0.f,
                              int nTZFlag = 0 ); /* modified */
void                SetField( const char *pszFName,
                              int nYear, int nMonth, int nDay,
                              int nHour=0, int nMinute=0, float fSecond=0.f,
                              int nTZFlag = 0 ); /* modified */

OGRFeature::GetFieldAsString() is modified to output milliseconds if the Second member of OGRField.Date is not integral

OGRParseDate() is modified to parse second as floating point number.

The following utility functions have their signature modified to take a OGRField (instead of the full year, month, day, hour, minute, second, TZFlag decomposition) and accept decimal seconds as input/output :

int CPL_DLL OGRParseXMLDateTime( const char* pszXMLDateTime,
                                 OGRField* psField );
int CPL_DLL OGRParseRFC822DateTime( const char* pszRFC822DateTime,
                                    OGRField* psField );
char CPL_DLL * OGRGetRFC822DateTime(const OGRField* psField);
char CPL_DLL * OGRGetXMLDateTime(const OGRField* psField);

C API changes

Only additions :

int   CPL_DLL OGR_F_GetFieldAsDateTimeEx( OGRFeatureH hFeat, int iField,
                                int *pnYear, int *pnMonth, int *pnDay,
                                int *pnHour, int *pnMinute, float *pfSecond,
                                int *pnTZFlag );
void   CPL_DLL OGR_F_SetFieldDateTimeEx( OGRFeatureH, int,
                                       int, int, int, int, int, float, int );

Changes in drivers

The following drivers now accept milliseconds as input/output :

  • GeoJSON

  • CSV

  • PG

  • PGDump (output only)

  • CartoDB

  • GeoPackage

  • SQLite

  • MapInfo .tab and .mif


  • ODS

  • XLSX

  • GeoRSS (Atom format)

  • GPX

Changes in SWIG bindings

Feature.GetFieldAsDateTime() and Feature.SetFieldAsDateTime() now takes/returns a floating point number for seconds


This modifies the C/C++ API and ABI.

Output of above mentioned drivers will now include milliseconds if a DateTime/Time field has such precision.


All new/modified methods are documented. MIGRATION_GUIDE.TXT is updated with a new section for this RFC.


The various aspects of this RFC are tested:

  • core changes

  • driver changes


Implementation will be done by Even Rouault (Spatialys).

The proposed implementation lies in the "subsecond_accuracy" branch of the https://github.com/rouault/gdal2/tree/subsecond_accuracy repository.

The list of changes : https://github.com/rouault/gdal2/compare/subsecond_accuracy

Voting history

+1 from DanielM, JukkaR and EvenR