- Add support for "midnight" "noon", dawn etc.

- Add validation to date/time strings by checking that mktime did not change
  the fields of struct tm from the ones requested
- Allow the format "year monthname day".
From kre
This commit is contained in:
christos 2015-12-07 20:55:49 +00:00
parent 432cd4b9b7
commit 5e2a9cf1aa
2 changed files with 58 additions and 9 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: parsedate.3,v 1.17 2015/11/26 09:48:21 wiz Exp $ .\" $NetBSD: parsedate.3,v 1.18 2015/12/07 20:55:49 christos Exp $
.\" .\"
.\" Copyright (c) 2006 The NetBSD Foundation, Inc. .\" Copyright (c) 2006 The NetBSD Foundation, Inc.
.\" All rights reserved. .\" All rights reserved.
@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE. .\" POSSIBILITY OF SUCH DAMAGE.
.\" .\"
.Dd November 25, 2015 .Dd December 7, 2015
.Dt PARSEDATE 3 .Dt PARSEDATE 3
.Os .Os
.Sh NAME .Sh NAME
@ -106,7 +106,14 @@ The following words are recognized in English only:
.Dv AM , .Dv AM ,
.Dv PM , .Dv PM ,
.Dv a.m. , .Dv a.m. ,
.Dv p.m. .Dv p.m. ,
.Dv midnight ,
.Dv mn ,
.Dv noon ,
.Dv dawn ,
.Dv sunup ,
.Dv sunset ,
.Dv sundown .
.Pp .Pp
The months: The months:
.Dv january , .Dv january ,
@ -229,7 +236,7 @@ An ISO-8601 date.
The year in an ISO-8601 date is always taken literally, The year in an ISO-8601 date is always taken literally,
so this is the year 69, not 2069. so this is the year 69, not 2069.
.It 10/1/2000 .It 10/1/2000
October 10, 2000; the common US format. October 1, 2000; the common, but bizarre, US format.
.It 20 Jun 1994 .It 20 Jun 1994
.It 23jun2001 .It 23jun2001
.It 1-sep-06 .It 1-sep-06
@ -253,6 +260,7 @@ As well as times:
.It 12:11:01.000012 .It 12:11:01.000012
.It 12:21-0500 .It 12:21-0500
.El .El
Fractions of seconds (after a decimal point) are parsed, but ignored.
.Pp .Pp
Relative items are also supported: Relative items are also supported:
.Bl -tag -compact -width "this thursday" .Bl -tag -compact -width "this thursday"

View File

@ -14,7 +14,7 @@
#include <sys/cdefs.h> #include <sys/cdefs.h>
#ifdef __RCSID #ifdef __RCSID
__RCSID("$NetBSD: parsedate.y,v 1.22 2015/12/06 14:43:59 christos Exp $"); __RCSID("$NetBSD: parsedate.y,v 1.23 2015/12/07 20:55:49 christos Exp $");
#endif #endif
#include <stdio.h> #include <stdio.h>
@ -99,10 +99,10 @@ struct dateinfo {
} }
%token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT %token tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
%token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN %token tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST AT_SIGN tTIME
%type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT %type <Number> tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
%type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE %type <Number> tSEC_UNIT tSNUMBER tUNUMBER tZONE tTIME
%type <Meridian> tMERIDIAN o_merid %type <Meridian> tMERIDIAN o_merid
%parse-param { struct dateinfo *param } %parse-param { struct dateinfo *param }
@ -215,6 +215,15 @@ time : tUNUMBER tMERIDIAN {
param->yyMeridian = MER24; param->yyMeridian = MER24;
/* XXX: Do nothing with millis */ /* XXX: Do nothing with millis */
} }
| tTIME {
param->yyHour = $1;
param->yyMinutes = 0;
param->yySeconds = 0;
param->yyMeridian = MER24;
/* Tues midnight --> Weds 00:00, midnight Tues -> Tues 00:00 */
if ($1 == 0 && param->yyHaveDay)
param->yyDayNumber++;
}
; ;
time_numericzone : tUNUMBER ':' tUNUMBER tSNUMBER { time_numericzone : tUNUMBER ':' tUNUMBER tSNUMBER {
@ -306,8 +315,13 @@ date : tUNUMBER '/' tUNUMBER {
} }
| tUNUMBER tMONTH tUNUMBER { | tUNUMBER tMONTH tUNUMBER {
param->yyMonth = $2; param->yyMonth = $2;
param->yyDay = $1; if ($1 < 35) {
param->yyYear = $3; param->yyDay = $1;
param->yyYear = $3;
} else {
param->yyDay = $3;
param->yyYear = $1;
}
} }
; ;
@ -589,6 +603,17 @@ static const TABLE MilitaryTable[] = {
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };
static const TABLE TimeNames[] = {
{ "midnight", tTIME, 0 },
{ "mn", tTIME, 0 },
{ "noon", tTIME, 12 },
{ "dawn", tTIME, 6 },
{ "sunup", tTIME, 6 },
{ "sunset", tTIME, 18 },
{ "sundown", tTIME, 18 },
{ NULL, 0, 0 }
};
@ -635,6 +660,7 @@ Convert(
) )
{ {
struct tm tm = {.tm_sec = 0}; struct tm tm = {.tm_sec = 0};
struct tm otm;
time_t result; time_t result;
tm.tm_sec = Seconds; tm.tm_sec = Seconds;
@ -673,6 +699,15 @@ Convert(
fprintf(stderr, " %s", ctime(&result)); fprintf(stderr, " %s", ctime(&result));
#endif #endif
#define TM_NE(fld) (otm.tm_ ## fld != tm.tm_ ## fld)
if (TM_NE(year) || TM_NE(mon) || TM_NE(mday) ||
TM_NE(hour) || TM_NE(min) || TM_NE(sec)) {
/* mktime() "corrected" our tm, so it must have been invalid */
result = -1;
errno = EAGAIN;
}
#undef TM_NE
return result; return result;
} }
@ -800,6 +835,12 @@ LookupWord(YYSTYPE *yylval, char *buff)
if (strcmp(buff, "dst") == 0) if (strcmp(buff, "dst") == 0)
return tDST; return tDST;
for (tp = TimeNames; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) {
yylval->Number = tp->value;
return tp->type;
}
for (tp = UnitsTable; tp->name; tp++) for (tp = UnitsTable; tp->name; tp++)
if (strcmp(buff, tp->name) == 0) { if (strcmp(buff, tp->name) == 0) {
yylval->Number = tp->value; yylval->Number = tp->value;