From 024f31843152d913684ee1b5557db9957f2e44d9 Mon Sep 17 00:00:00 2001 From: Russ Rew Date: Thu, 7 Jun 2012 18:14:02 +0000 Subject: [PATCH] Fixed bug NCF-175: ncdump -t incorrectly interpreting units attribute (such as "days") without a base time (such as "since 2007-01-01") as a time unit. --- libdispatch/nctime.c | 1 - ncdump/nctime0.c | 53 ++++++++++++++++++++++++++++++++++++++++ ncdump/nctime0.h | 1 + ncdump/ref_times.cdl | 7 ++++++ ncdump/tst_calendars.cdl | 7 ++++++ 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/libdispatch/nctime.c b/libdispatch/nctime.c index 2cb55deed..e21d920c2 100644 --- a/libdispatch/nctime.c +++ b/libdispatch/nctime.c @@ -327,7 +327,6 @@ cdParseRelunits(cdCalenType timetype, char* relunits, cdUnitTime* unit, cdCompTi } else { nconv = sscanf(relunits,"%s since %[^T]T%s",charunits,basetime_1,basetime_2); } - /* Get the units */ cdTrim(charunits,CD_MAX_RELUNITS); if(!strncmp(charunits,"sec",3) || !strcmp(charunits,"s")){ diff --git a/ncdump/nctime0.c b/ncdump/nctime0.c index 408e02960..e5e6ba36f 100644 --- a/ncdump/nctime0.c +++ b/ncdump/nctime0.c @@ -108,6 +108,55 @@ is_bounds_var(char *varname, int *pargrpidp, int *parvaridp) { return false; } +/* Test if attribute is of form required by cdtime: + * since + * where + * : + */ +boolean +is_valid_time_unit(const char *units) { + char charunits[CD_MAX_RELUNITS]; + char basetime_1[CD_MAX_CHARTIME]; + char basetime_2[CD_MAX_CHARTIME]; + int nconv1, nconv2; + boolean okunit = false; + + /* Allow ISO-8601 "T" date-time separator as well as blank separator */ + nconv1 = sscanf(units,"%s since %[^T]T%s", charunits, basetime_1, basetime_2); + nconv2 = sscanf(units,"%s since %s %s", charunits, basetime_1, basetime_2); + if (!(nconv1 > 1 || nconv2 > 1)) + return false; + /* Check for unit compatible with cdtime library, no attempt + * to enforce CF-compliance or udunits compliance here ... */ + if(!strncmp(charunits,"sec",3) || !strcmp(charunits,"s")){ + okunit = true; + } + else if(!strncmp(charunits,"min",3) || !strcmp(charunits,"mn")){ + okunit = true; + } + else if(!strncmp(charunits,"hour",4) || !strcmp(charunits,"hr")){ + okunit = true; + } + else if(!strncmp(charunits,"day",3) || !strcmp(charunits,"dy")){ + okunit = true; + } + else if(!strncmp(charunits,"week",4) || !strcmp(charunits,"wk")){ + okunit = true; + } + else if(!strncmp(charunits,"month",5) || !strcmp(charunits,"mo")){ + okunit = true; + } + else if(!strncmp(charunits,"season",6)){ + okunit = true; + } + else if(!strncmp(charunits,"year",4) || !strcmp(charunits,"yr")){ + okunit = true; + } + if (!okunit) + return false; + return true; +} + /* Return true only if this is a "bounds" attribute */ boolean is_bounds_att(ncatt_t *attp) { @@ -158,6 +207,10 @@ get_timeinfo(int ncid1, int varid1, ncvar_t *vp) { units = emalloc(uatt.len + 1); NC_CHECK(nc_get_att(ncid, varid, "units", units)); units[uatt.len] = '\0'; + if(!is_valid_time_unit(units)) { + free(units); + return; + } /* check for calendar attribute (not required even for time vars) */ vp->timeinfo = (timeinfo_t *)emalloc(sizeof(timeinfo_t)); memset((void*)vp->timeinfo,0,sizeof(timeinfo_t)); diff --git a/ncdump/nctime0.h b/ncdump/nctime0.h index 17fce574a..91b4e92ba 100644 --- a/ncdump/nctime0.h +++ b/ncdump/nctime0.h @@ -8,6 +8,7 @@ extern void insert_bounds_info(int ncid, int varid, ncatt_t att); +extern int is_valid_time_unit(const char *units); extern int is_bounds_att(ncatt_t *attp); extern void get_timeinfo(int ncid, int varid, ncvar_t *vp); extern void print_att_times(int ncid, int varid, ncatt_t att); diff --git a/ncdump/ref_times.cdl b/ncdump/ref_times.cdl index 81a172b0e..40688d823 100644 --- a/ncdump/ref_times.cdl +++ b/ncdump/ref_times.cdl @@ -82,6 +82,11 @@ variables: // "1804-04-26", "1804-04-27", "1804-04-28", "1804-04-29", // "1804-04-30" double t3_bnds(t3, bnds) ; + int t4 ; + t4:units = "days" ; + t4:att1 = 1 ; + t4:att2 = 5, 6 ; + t4:att3 = 7.125f, 8.75f ; data: t1_days = "2009-01-01" ; @@ -132,4 +137,6 @@ data: "1804-01-10 12", "1804-01-11 12", "1804-01-11 12", "1804-01-12 12", "1804-01-12 12", "1804-01-13 12" ; + + t4 = _ ; } diff --git a/ncdump/tst_calendars.cdl b/ncdump/tst_calendars.cdl index dc66983ca..1c10604a7 100644 --- a/ncdump/tst_calendars.cdl +++ b/ncdump/tst_calendars.cdl @@ -86,6 +86,13 @@ variables: t3:time5 = 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120 ; double t3_bnds(t3, bnds) ; // no attributes, since a cell bounds variable +// test -t bug fix, time unit without base time should not interpret numeric atts as times + int t4 ; + t4:units = "days" ; + t4:att1 = 1 ; + t4:att2 = 5, 6 ; + t4:att3 = 7.125f, 8.75f ; + data: // Should all represent 2009-01-01 00:00:00 t1_days = 185900;