2019-01-29 Fred Gleason <fredg@paravelsystems.com>

* Refactored routines for parsing/writing standard date/time strings
	(RFC822 and XML xs:dateTime formats) into 'lib/rddatetime.[cpp|h].
	* Removed the 'RDWebDateTime()', 'RDGetWebDateTime()',
	'RDGetWebDate()', 'RDGetWebTime()', 'RDGetWebMonth()',
	'RDXmlDate()', 'RDXmlTime()', 'RDXmlDateTime()' and
	'RDXmlTimeZoneSuffix()' functions from 'lib/rdweb.[cpp|h].
	* Added a 'dateparse_test' test harness.
This commit is contained in:
Fred Gleason 2019-01-29 15:40:14 -05:00
parent 16d43261a3
commit 0b472716d6
15 changed files with 733 additions and 349 deletions

1
.gitignore vendored
View File

@ -106,6 +106,7 @@ tests/audio_import_test
tests/audio_metadata_test
tests/audio_peaks_test
tests/datedecode_test
tests/dateparse_test
tests/db_charset_test
tests/getpids_test
tests/log_unlink_test

View File

@ -18424,3 +18424,11 @@
* Fixed regression with RDTransportButton taking focus from lists.
2019-01-25 Patrick Linstruth <patrick@deltecent.com>
* Added the ability to duplicate dropboxes in rdadmin(1).
2019-01-29 Fred Gleason <fredg@paravelsystems.com>
* Refactored routines for parsing/writing standard date/time strings
(RFC822 and XML xs:dateTime formats) into 'lib/rddatetime.[cpp|h].
* Removed the 'RDWebDateTime()', 'RDGetWebDateTime()',
'RDGetWebDate()', 'RDGetWebTime()', 'RDGetWebMonth()',
'RDXmlDate()', 'RDXmlTime()', 'RDXmlDateTime()' and
'RDXmlTimeZoneSuffix()' functions from 'lib/rdweb.[cpp|h].
* Added a 'dateparse_test' test harness.

View File

@ -107,6 +107,7 @@ dist_librd_la_SOURCES = dbversion.h\
rddatepicker.cpp rddatepicker.h\
rddb.h rddb.cpp\
rddbheartbeat.cpp rddbheartbeat.h\
rddatetime.cpp rddatetime.h\
rddebug.cpp rddebug.h\
rddeck.cpp rddeck.h\
rddelete.cpp rddelete.h\

View File

@ -74,6 +74,7 @@ SOURCES += rdcut_dialog.cpp
SOURCES += rddatedialog.cpp
SOURCES += rddatedecode.cpp
SOURCES += rddatepicker.cpp
SOURCES += rddatetime.cpp
SOURCES += rddb.cpp
SOURCES += rddbheartbeat.cpp
SOURCES += rddebug.cpp
@ -204,6 +205,7 @@ HEADERS += rdcut.h
HEADERS += rddatedecode.h
HEADERS += rddatedialog.h
HEADERS += rddatepicker.h
HEADERS += rddatetime.h
HEADERS += rddb.h
HEADERS += rddbheartbeat.h
HEADERS += rddebug.h

View File

@ -37,9 +37,10 @@
#include <sys/timex.h>
#include <time.h>
#include <rddb.h>
#include <rdconf.h>
#include <rdescape_string.h>
#include "rddb.h"
#include "rdconf.h"
#include "rddatetime.h"
#include "rdescape_string.h"
#define BUFFER_SIZE 1024
@ -982,7 +983,7 @@ QTime RDUtcToLocal(const QTime &gmttime)
return gmttime.addSecs(-RDTimeZoneOffset());
}
/*
int RDTimeZoneOffset()
{
time_t t=time(&t);
@ -1001,7 +1002,7 @@ int RDTimeZoneOffset()
return offset;
}
*/
QColor RDGetTextColor(const QColor &background_color)
{

View File

@ -101,7 +101,7 @@ QDateTime RDLocalToUtc(const QDateTime &localdatetime);
QTime RDLocalToUtc(const QTime &localtime);
QDateTime RDUtcToLocal(const QDateTime &gmtdatetime);
QTime RDUtcToLocal(const QTime &gmttime);
int RDTimeZoneOffset();
//int RDTimeZoneOffset();
QColor RDGetTextColor(const QColor &background_color);
bool RDProcessActive(const QString &cmd);
bool RDProcessActive(const QStringList &cmds);

360
lib/rddatetime.cpp Normal file
View File

@ -0,0 +1,360 @@
// rddatetime.cpp
//
// Parse and write dates/times in various standard formats.
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <stdio.h>
#include <time.h>
#include <qmap.h>
#include <qstringlist.h>
#include "rddatetime.h"
QString __rddatetime_month_names[]=
{"Jan","Feb","Mar","Apr","Mar","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
QString __rddatetime_dow_names[]=
{"Mod","Tue","Wed","Thu","Fri","Sat","Sun"};
//
// Auto-detect the format (XML xs:dateTime or RFC822)
//
QDateTime RDParseDateTime(const QString &str,bool *ok)
{
if(str.trimmed().contains(" ")) {
return RDParseRfc822DateTime(str,ok);
}
return RDParseXmlDateTime(str,ok);
}
//
// XML xs:date format
//
QDate RDParseXmlDate(const QString &str,bool *ok)
{
QDate ret=QDate::fromString(str,"yyyy-MM-dd");
*ok=ret.isValid();
return ret;
}
QString RDWriteXmlDate(const QDate &date)
{
return date.toString("yyyy-MM-dd");
}
//
// XML xs:time format
//
QTime RDParseXmlTime(const QString &str,bool *ok,int *day_offset)
{
QTime ret;
QStringList f0;
QStringList f1;
QStringList f2;
int tz=0;
QTime time;
QTime tztime;
*ok=false;
if(day_offset!=NULL) {
*day_offset=0;
}
f0=str.trimmed().split(" ");
if(f0.size()!=1) {
*ok=false;
return ret;
}
if(f0[0].right(1).lower()=="z") { // GMT
tz=RDTimeZoneOffset();
f0[0]=f0[0].left(f0[0].length()-1);
f2=f0[0].split(":");
}
else {
f1=f0[0].split("+");
if(f1.size()==2) { // GMT+
f2=f1[1].split(":");
if(f2.size()==2) {
tztime=QTime(f2[0].toInt(),f2[1].toInt(),0);
if(tztime.isValid()) {
tz=RDTimeZoneOffset()+QTime(0,0,0).secsTo(tztime);
}
}
else {
if(ok!=NULL) {
*ok=false;
}
return QTime();
}
}
else {
f1=f0[0].split("-");
if(f1.size()==2) { // GMT-
f2=f1[1].split(":");
if(f2.size()==2) {
tztime=QTime(f2[0].toInt(),f2[1].toInt(),0);
if(tztime.isValid()) {
tz=RDTimeZoneOffset()-QTime(0,0,0).secsTo(tztime);
}
}
else {
if(ok!=NULL) {
*ok=false;
}
return QTime();
}
}
}
f2=f1[0].split(":");
}
if(f2.size()==3) {
QStringList f3=f2[2].split(".");
time=QTime(f2[0].toInt(),f2[1].toInt(),f2[2].toInt());
if(time.isValid()) {
ret=time.addSecs(tz);
if(day_offset!=NULL) {
if((tz<0)&&((3600*time.hour()+60*time.minute()+time.second())<(-tz))) {
*day_offset=-1;
}
if((tz>0)&&(86400-((3600*time.hour()+60*time.minute()+time.second()))<tz)) {
*day_offset=1;
}
}
if(ok!=NULL) {
*ok=true;
}
}
}
return ret;
}
QString RDWriteXmlTime(const QTime &time)
{
int utc_off=RDTimeZoneOffset();
QString tz_str="-";
if(utc_off<0) {
tz_str="+";
}
tz_str+=QString().
sprintf("%02d:%02d",utc_off/3600,(utc_off-3600*(utc_off/3600))/60);
return time.toString("hh:mm:ss")+tz_str;
}
//
// XML xs:dateTime format
//
QDateTime RDParseXmlDateTime(const QString &str,bool *ok)
{
QDateTime ret;
QStringList list;
QStringList f0;
QStringList f1;
QStringList f2;
int day;
int month;
int year;
QTime time;
bool lok=false;
int day_offset=0;
*ok=false;
f0=str.trimmed().split(" ");
if(f0.size()!=1) {
*ok=false;
return ret;
}
f1=f0[0].split("T");
if(f1.size()<=2) {
f2=f1[0].split("-");
if(f2.size()==3) {
year=f2[0].toInt(&lok);
if(lok&&(year>0)) {
month=f2[1].toInt(&lok);
if(lok&&(month>=1)&&(month<=12)) {
day=f2[2].toInt(&lok);
if(lok&&(day>=1)&&(day<=31)) {
if(f1.size()==2) {
time=RDParseXmlTime(f1[1],&lok,&day_offset);
if(lok) {
ret=QDateTime(QDate(year,month,day),time).addDays(day_offset);
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
}
}
}
return ret;
}
QString RDWriteXmlDateTime(const QDateTime &dt)
{
return RDWriteXmlDate(dt.date())+"T"+RDWriteXmlTime(dt.time());
}
//
// RFC822 date/time format
//
QDateTime RDParseRfc822DateTime(const QString &str,bool *ok)
{
QStringList f0=str.trimmed().split(" ",QString::SkipEmptyParts);
//
// Remove useless day-of-the-week tag
//
if(f0.size()==6) {
f0.removeFirst();
}
if(f0.size()!=5) {
*ok=false;
return QDateTime();
}
//
// Read Date
//
int month=-1;
for(int i=0;i<7;i++) {
if(f0.at(1).toLower()==__rddatetime_month_names[i].toLower()) {
month=i;
}
}
if(month<0) {
*ok=false;
return QDateTime();
}
if(f0.at(2).length()==2) {
f0[2]="19"+f0.at(2);
}
QDate date(f0.at(2).toInt(),month+1,f0.at(0).toInt());
if(!date.isValid()) {
*ok=false;
return QDateTime();
}
//
// Read Time
//
QTime time=QTime::fromString(f0.at(3),"hh:mm:ss");
if(!time.isValid()) {
*ok=false;
return QDateTime();
}
//
// Read TZ Offset
//
bool ok1=false;
bool ok2=false;
int tz_offset=3600*f0.at(4).mid(1,2).toInt(&ok1)+
60*f0.at(4).right(2).toInt(&ok2);
if((f0.at(4).length()==5)&&(ok1)&&(ok2)) {
if(f0.at(4).left(1)=="+") {
tz_offset=-tz_offset;
}
else {
if(f0.at(4).left(1)!="-") {
*ok=false;
return QDateTime();
}
}
}
else {
//
// Try legacy timezone names (see RFC822 section 5.1)
//
QMap<QString,int> zones;
zones["ut"]=0;
zones["gmt"]=0;
zones["z"]=0;
zones["est"]=-5;
zones["edt"]=-4;
zones["cst"]=-6;
zones["cdt"]=-5;
zones["mst"]=-7;
zones["mdt"]=-6;
zones["pst"]=-8;
zones["pdt"]=-7;
// "Military" zone IDs are not implemented (see RFC1123 section 5.2.14)
if(zones.value(f0.at(4).toLower(),1)>0) {
*ok=false;
return QDateTime();
}
tz_offset=-3600*zones.value(f0.at(4).toLower());
}
*ok=true;
return QDateTime(date,time).addSecs(tz_offset-RDTimeZoneOffset());
}
QString RDWriteRfc822DateTime(const QDateTime &dt)
{
int utc_off=RDTimeZoneOffset();
QString tz_str="-";
if(utc_off<0) {
tz_str="+";
}
tz_str+=QString().
sprintf("%02d%02d",utc_off/3600,(utc_off-3600*(utc_off/3600))/60);
return __rddatetime_dow_names[dt.date().dayOfWeek()-1]+", "+
QString().sprintf("%d ",dt.date().day())+
__rddatetime_month_names[dt.date().month()-1]+" "+
QString().sprintf("%04d ",dt.date().year())+
dt.toString("hh:mm:ss")+" "+
tz_str;
}
//
// Returns the UTC offset of the curently configured timezone (seconds)
//
int RDTimeZoneOffset()
{
time_t t=time(&t);
struct tm *tm=localtime(&t);
time_t local_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec;
tm=gmtime(&t);
time_t gmt_time=3600*tm->tm_hour+60*tm->tm_min+tm->tm_sec;
int offset=gmt_time-local_time;
if(offset>43200) {
offset=offset-86400;
}
if(offset<-43200) {
offset=offset+86400;
}
return offset;
}

66
lib/rddatetime.h Normal file
View File

@ -0,0 +1,66 @@
// rddatetime.h
//
// Parse and write dates/times in various standard formats.
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef RDDATETIME_H
#define RDDATETIME_H
#include <qstring.h>
#include <qdatetime.h>
//
// Function Prototypes
//
//
// Auto-detect the format (XML xs:dateTime or RFC822)
//
QDateTime RDParseDateTime(const QString &str,bool *ok);
//
// XML xs:date format
//
QDate RDParseXmlDate(const QString &str,bool *ok);
QString RDWriteXmlDate(const QDate &date);
//
// XML xs:time format
//
QTime RDParseXmlTime(const QString &str,bool *ok,int *day_offset=NULL);
QString RDWriteXmlTime(const QTime &time);
//
// XML xs:dateTime format
//
QDateTime RDParseXmlDateTime(const QString &str,bool *ok);
QString RDWriteXmlDateTime(const QDateTime &dt);
//
// RFC822 date/time format
//
QDateTime RDParseRfc822DateTime(const QString &str,bool *ok);
QString RDWriteRfc822DateTime(const QDateTime &dt);
//
// Returns the UTC offset of the curently configured timezone (seconds)
//
int RDTimeZoneOffset();
#endif // RDDATETIME_H

View File

@ -25,8 +25,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <rdconf.h>
#include <rdweb.h>
#include "rdconf.h"
#include "rddatetime.h"
#include "rdweb.h"
#include <rdformpost.h>
@ -237,7 +238,7 @@ bool RDFormPost::getValue(const QString &name,QDateTime *datetime,bool *ok)
}
}
else {
*datetime=RDGetWebDateTime(str,ok);
*datetime=RDParseDateTime(str,ok);
}
return true;
}
@ -257,7 +258,7 @@ bool RDFormPost::getValue(const QString &name,QDate *date,bool *ok)
*date=QDate();
}
else {
*date=RDGetWebDate(str,ok);
*date=RDParseXmlDate(str,ok);
}
return true;
}
@ -277,7 +278,7 @@ bool RDFormPost::getValue(const QString &name,QTime *time,bool *ok)
*time=QTime();
}
else {
*time=RDGetWebTime(str,ok);
*time=RDParseXmlTime(str,ok);
}
return true;
}

View File

@ -31,6 +31,7 @@
#include <qstringlist.h>
#include "rdconf.h"
#include "rddatetime.h"
#include "rddb.h"
#include "rdescape_string.h"
#include "rdtempdirectory.h"
@ -932,7 +933,7 @@ QString RDXmlField(const QString &tag,const QDateTime &value,
str=" "+attrs;
}
if(value.isValid()) {
return QString("<")+tag+str+">"+RDXmlDateTime(value)+"</"+tag+">\n";
return QString("<")+tag+str+">"+RDWriteXmlDateTime(value)+"</"+tag+">\n";
}
return RDXmlField(tag);
}
@ -946,7 +947,7 @@ QString RDXmlField(const QString &tag,const QDate &value,const QString &attrs)
str=" "+attrs;
}
if(value.isValid()&&(!value.isNull())) {
return QString("<")+tag+str+">"+RDXmlDate(value)+"</"+tag+">\n";
return QString("<")+tag+str+">"+RDWriteXmlDate(value)+"</"+tag+">\n";
}
return RDXmlField(tag);
}
@ -960,7 +961,7 @@ QString RDXmlField(const QString &tag,const QTime &value,const QString &attrs)
str=" "+attrs;
}
if(value.isValid()&&(!value.isNull())) {
return QString("<")+tag+str+">"+RDXmlTime(value)+"</"+tag+">\n";
return QString("<")+tag+str+">"+RDWriteXmlTime(value)+"</"+tag+">\n";
}
return RDXmlField(tag);
}
@ -972,47 +973,6 @@ QString RDXmlField(const QString &tag)
}
QString RDXmlDate(const QDate &date)
{
return date.toString("yyyy-MM-dd")+RDXmlTimeZoneSuffix();
}
QString RDXmlTime(const QTime &time)
{
return time.toString("hh:mm:ss")+RDXmlTimeZoneSuffix();
}
QString RDXmlDateTime(const QDateTime &datetime)
{
return datetime.toString("yyyy-MM-dd")+"T"+datetime.toString("hh:mm:ss")+
RDXmlTimeZoneSuffix();
}
QString RDXmlTimeZoneSuffix()
{
QString ret;
int tz=RDTimeZoneOffset();
if(tz==0) {
ret+="Z";
}
else {
if(tz<0) {
ret+="+";
}
if(tz>0) {
ret+="-";
}
ret+=QTime(0,0,0).addSecs(tz).toString("hh:mm");
}
return ret;
}
QString RDXmlEscape(const QString &str)
{
/*
@ -1142,7 +1102,8 @@ QString RDJsonField(const QString &name,const QDateTime &value,int padding,
if(!value.isValid()) {
return RDJsonNullField(name,padding,final);
}
return RDJsonPadding(padding)+"\""+name+"\": \""+RDXmlDateTime(value)+"\""+
return RDJsonPadding(padding)+"\""+name+"\": \""+
RDWriteXmlDateTime(value)+"\""+
comma+"\r\n";
}
@ -1192,284 +1153,3 @@ QString RDUrlUnescape(const QString &str)
return ret;
}
QString RDWebDateTime(const QDateTime &datetime)
{
//
// Generate an RFC 822/1123 compliant date/time string
//
if(!datetime.isValid()) {
return QString();
}
int offset=RDTimeZoneOffset();
QString tzstr="-";
if(offset<0) {
tzstr="+";
}
tzstr+=QString().sprintf("%02d%02d",
offset/3600,(offset/60)-((offset/3600)*60));
if(offset==0) {
tzstr="GMT";
}
return datetime.toString("ddd, dd MMM yyyy hh:mm:ss")+" "+tzstr;
}
QDateTime RDGetWebDateTime(const QString &str,bool *ok)
{
QDateTime ret;
QStringList list;
QStringList f0;
QStringList f1;
QStringList f2;
int day;
int month;
int year;
QTime time;
bool lok=false;
if(ok!=NULL) {
*ok=false;
}
f0=str.trimmed().split(" ");
switch(f0.size()) {
case 1: // XML xs:dateTime Style
f1=f0[0].split("T");
if(f1.size()<=2) {
f2=f1[0].split("-");
if(f2.size()==3) {
year=f2[0].toInt(&lok);
if(lok&&(year>0)) {
month=f2[1].toInt(&lok);
if(lok&&(month>=1)&&(month<=12)) {
day=f2[2].toInt(&lok);
if(lok&&(day>=1)&&(day<=31)) {
if(f1.size()==2) {
time=RDGetWebTime(f1[1],&lok);
if(lok) {
ret=QDateTime(QDate(year,month,day),time);
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
}
}
}
break;
case 4: // RFC 850 Style
f1=f0[1].split("-");
if(f1.size()==3) {
month=RDGetWebMonth(f1[1],&lok);
if(ok) {
time=RDGetWebTime(f0[2]+" "+f0[3],&lok);
if(lok) {
year=f1[2].toInt(&lok);
if(lok&&(year>0)) {
day=f1[0].toInt(&lok);
if(lok&&(day>0)&&(day<=31)) {
ret=QDateTime(QDate(year+2000,month,day),time);
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
}
break;
case 5: // ANSI C asctime() Style
month=RDGetWebMonth(f0[1],&lok);
if(lok) {
time=RDGetWebTime(f0[3]+" GMT",&lok);
if(lok) {
year=f0[4].toInt(&lok);
if(lok&&(year>0)) {
day=f0[2].toInt(&lok);
if(lok&&(day>0)&&(day<=31)) {
ret=QDateTime(QDate(year,month,day),time);
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
break;
case 6: // RFC 822/1123 Style
month=RDGetWebMonth(f0[2],&lok);
if(lok) {
time=RDGetWebTime(f0[4]+" "+f0[5],&lok);
if(lok) {
year=f0[3].toInt(&lok);
if(lok&&(year>0)) {
day=f0[1].toInt(&lok);
if(lok&&(day>0)&&(day<=31)) {
ret=QDateTime(QDate(year,month,day),time);
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
break;
}
return ret;
}
QDate RDGetWebDate(const QString &str,bool *ok)
{
QDate ret;
ret=QDate::fromString(str,Qt::ISODate);
if(ok!=NULL) {
*ok=ret.isValid();
}
return ret;
}
QTime RDGetWebTime(const QString &str,bool *ok)
{
QTime ret;
QStringList f0;
QStringList f1;
QStringList f2;
bool lok=false;
int tz=0;
QTime time;
QTime tztime;
if(ok!=NULL) {
*ok=false;
}
f0=str.trimmed().split(" ");
switch(f0.size()) {
case 1: // XML xs:time Style
if(f0[0].right(1).lower()=="z") { // GMT
tz=RDTimeZoneOffset();
f0[0]=f0[0].left(f0[0].length()-1);
f2=f0[0].split(":");
}
else {
f1=f0[0].split("+");
if(f1.size()==2) { // GMT+
f2=f1[1].split(":");
if(f2.size()==2) {
tztime=QTime(f2[0].toInt(),f2[1].toInt(),0);
if(tztime.isValid()) {
tz=RDTimeZoneOffset()+QTime(0,0,0).secsTo(tztime);
}
}
}
else {
f1=f0[0].split("-");
if(f1.size()==2) { // GMT-
f2=f1[1].split(":");
if(f2.size()==2) {
tztime=QTime(f2[0].toInt(),f2[1].toInt(),0);
if(tztime.isValid()) {
tz=RDTimeZoneOffset()-QTime(0,0,0).secsTo(tztime);
}
}
}
}
f2=f1[0].split(":");
}
if(f2.size()==3) {
time=QTime(f2[0].toInt(),f2[1].toInt(),f2[2].toInt());
if(time.isValid()) {
ret=time.addSecs(tz);
if(ok!=NULL) {
*ok=true;
}
}
}
break;
case 2: // RFC Style
if(f0[1].lower()=="gmt") {
f0=f0[0].split(":");
if(f0.size()==3) {
int hour=f0[0].toInt(&lok);
if(lok) {
int min=f0[1].toInt(&lok);
if(lok) {
int sec=f0[2].toInt(&lok);
if(lok) {
if((hour>=0)&&(hour<=23)&&(min>=0)&&(min<=59)&&(sec>=0)&&
(sec<=60)) {
ret=RDUtcToLocal(QTime(f0[0].toInt(),f0[1].toInt(),
f0[2].toInt()));
if(ok!=NULL) {
*ok=true;
}
}
}
}
}
}
}
break;
}
return ret;
}
int RDGetWebMonth(const QString &str,bool *ok)
{
int ret=0;
if(str.lower()=="jan") {
ret=1;
}
if(str.lower()=="feb") {
ret=2;
}
if(str.lower()=="mar") {
ret=3;
}
if(str.lower()=="apr") {
ret=4;
}
if(str.lower()=="may") {
ret=5;
}
if(str.lower()=="jun") {
ret=6;
}
if(str.lower()=="jul") {
ret=7;
}
if(str.lower()=="aug") {
ret=8;
}
if(str.lower()=="sep") {
ret=9;
}
if(str.lower()=="oct") {
ret=10;
}
if(str.lower()=="nov") {
ret=11;
}
if(str.lower()=="dec") {
ret=12;
}
if(ok!=NULL) {
*ok=ret!=0;
}
return ret;
}

View File

@ -82,10 +82,6 @@ extern QString RDXmlField(const QString &tag,const QDate &value,
extern QString RDXmlField(const QString &tag,const QTime &value,
const QString &attrs="");
extern QString RDXmlField(const QString &tag);
extern QString RDXmlDate(const QDate &date);
extern QString RDXmlTime(const QTime &time);
extern QString RDXmlDateTime(const QDateTime &datetime);
extern QString RDXmlTimeZoneSuffix();
extern QString RDXmlEscape(const QString &str);
extern QString RDXmlUnescape(const QString &str);
extern QString RDJsonPadding(int padding);
@ -101,14 +97,8 @@ extern QString RDJsonField(const QString &name,const QString &value,
int padding=0,bool final=false);
extern QString RDJsonField(const QString &name,const QDateTime &value,
int padding=0,bool final=false);
extern QString RDUrlEscape(const QString &str);
extern QString RDUrlUnescape(const QString &str);
extern QString RDWebDateTime(const QDateTime &datetime);
extern QDateTime RDGetWebDateTime(const QString &str,bool *ok=NULL);
extern QDate RDGetWebDate(const QString &str,bool *ok=NULL);
extern QTime RDGetWebTime(const QString &str,bool *ok=NULL);
extern int RDGetWebMonth(const QString &str,bool *ok=NULL);
#endif // RDWEB_H

View File

@ -32,6 +32,7 @@ noinst_PROGRAMS = audio_convert_test\
audio_metadata_test\
audio_peaks_test\
datedecode_test\
dateparse_test\
db_charset_test\
getpids_test\
log_unlink_test\
@ -63,6 +64,9 @@ audio_peaks_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_datedecode_test_SOURCES = datedecode_test.cpp datedecode_test.h
datedecode_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_dateparse_test_SOURCES = dateparse_test.cpp dateparse_test.h
dateparse_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support
dist_db_charset_test_SOURCES = db_charset_test.cpp db_charset_test.h
db_charset_test_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT4_LIBS@ -lQt3Support

231
tests/dateparse_test.cpp Normal file
View File

@ -0,0 +1,231 @@
// dateparse_test.cpp
//
// Test the Rivendell date/time parser routines.
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <stdlib.h>
#include <stdio.h>
#include <qapplication.h>
#include <qvariant.h>
#include <rdcmd_switch.h>
#include <rddatetime.h>
#include <rdweb.h>
#include "dateparse_test.h"
MainObject::MainObject(QObject *parent)
:QObject(parent)
{
QString time="";
QString datetime="";
MainObject::Format format=MainObject::Unknown;
MainObject::PrintType type=MainObject::None;
//
// Read Command Options
//
RDCmdSwitch *cmd=
new RDCmdSwitch(qApp->argc(),qApp->argv(),"dateparse_test",
DATEPARSE_TEST_USAGE);
for(unsigned i=0;i<cmd->keys();i++) {
if(cmd->key(i)=="--datetime") {
datetime=cmd->value(i);
cmd->setProcessed(i,true);
}
if(cmd->key(i)=="--print") {
if(cmd->value(i).toLower()=="date") {
type=MainObject::Date;
cmd->setProcessed(i,true);
}
if(cmd->value(i).toLower()=="time") {
type=MainObject::Time;
cmd->setProcessed(i,true);
}
if(cmd->value(i).toLower()=="datetime") {
type=MainObject::DateTime;
cmd->setProcessed(i,true);
}
if(!cmd->processed(i)) {
fprintf(stderr,"dataparse_test: unknown --print value\n");
exit(1);
}
}
if(cmd->key(i)=="--format") {
if(cmd->value(i).toLower()=="rfc822") {
format=MainObject::Rfc822;
cmd->setProcessed(i,true);
}
if(cmd->value(i).toLower()=="xml") {
format=MainObject::Xml;
cmd->setProcessed(i,true);
}
if(cmd->value(i).toLower()=="auto") {
format=MainObject::Auto;
cmd->setProcessed(i,true);
}
if(!cmd->processed(i)) {
fprintf(stderr,"dataparse_test: unknown --format value\n");
exit(1);
}
}
if(cmd->key(i)=="--time") {
time=cmd->value(i);
cmd->setProcessed(i,true);
}
if(!cmd->processed(i)) {
fprintf(stderr,"dateparse_test: unknown option \"%s\"\n",
(const char *)cmd->value(i));
exit(256);
}
}
if(format==MainObject::Unknown) {
fprintf(stderr,"dateparse_test: no --format specified\n");
exit(1);
}
if(type!=MainObject::None) {
if(format==MainObject::Auto) {
fprintf(stderr,"dateparse_test: auto not supported for printing\n");
exit(1);
}
switch(type) {
case MainObject::Date:
if(format!=MainObject::Xml) {
fprintf(stderr,"dateparse_test: date unsupported for RFC822 format\n");
exit(1);
}
printf("XML xs:date: %s\n",
(const char *)RDWriteXmlDate(QDate::currentDate()));
break;
case MainObject::Time:
if(format!=MainObject::Xml) {
fprintf(stderr,"dateparse_test: time unsupported for RFC822 format\n");
exit(1);
}
printf("XML xs:time: %s\n",
(const char *)RDWriteXmlTime(QTime::currentTime()));
break;
case MainObject::DateTime:
switch(format) {
case MainObject::Xml:
printf("XML xs:dateTime: %s\n",
(const char *)RDWriteXmlDateTime(QDateTime::currentDateTime()));
break;
case MainObject::Rfc822:
printf("RFC822: %s\n",
(const char *)RDWriteRfc822DateTime(QDateTime::currentDateTime()));
break;
case MainObject::Auto:
case MainObject::Unknown:
break;
}
break;
case MainObject::None:
break;
}
exit(0);
}
if((!datetime.isEmpty())&&(!time.isEmpty())) {
fprintf(stderr,
"dateparse_test: --datetime and --time are mutually exclusive\n");
exit(256);
}
if(datetime.isEmpty()&&time.isEmpty()) {
fprintf(stderr,
"dateparse_test: you must specify --datetime or --time\n");
exit(256);
}
if((!time.isEmpty())&&(format==MainObject::Rfc822)) {
fprintf(stderr,"dateparse_test: RFC822 format has no --time parser\n");
exit(1);
}
if(!datetime.isEmpty()) {
QDateTime dt;
bool ok=false;
switch(format) {
case MainObject::Rfc822:
dt=RDParseRfc822DateTime(datetime,&ok);
break;
case MainObject::Xml:
dt=RDParseXmlDateTime(datetime,&ok);
break;
case MainObject::Auto:
dt=RDParseDateTime(datetime,&ok);
break;
case MainObject::Unknown:
break;
}
if(ok) {
printf("DateTime: %s\n",(const char *)dt.toString("yyyy-MM-dd hh:mm:ss").toUtf8());
}
else {
printf("invalid date/time string\n");
}
}
if(!time.isEmpty()) {
QTime t;
int day_offset=0;
bool ok=false;
switch(format) {
case MainObject::Xml:
case MainObject::Auto:
t=RDParseXmlTime(time,&ok,&day_offset);
break;
case MainObject::Rfc822:
case MainObject::Unknown:
break;
}
if(ok) {
QString offset_str="";
if(day_offset<0) {
offset_str=QString().sprintf(" (lost %d day)",-day_offset);
}
if(day_offset>0) {
offset_str=QString().sprintf(" (gained %d day)",day_offset);
}
printf("Time: %s\n",(const char *)(t.toString("hh:mm:ss")+offset_str).toUtf8());
}
else {
printf("invalid time string\n");
}
}
exit(0);
}
int main(int argc,char *argv[])
{
QApplication a(argc,argv,false);
new MainObject();
return a.exec();
}

37
tests/dateparse_test.h Normal file
View File

@ -0,0 +1,37 @@
// dateparse_test.h
//
// Test the Rivendell date/time parser routines.
//
// (C) Copyright 2019 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef DATEPARSE_TEST_H
#define DATEPARSE_TEST_H
#include <qobject.h>
#define DATEPARSE_TEST_USAGE "[options]\n\nTest the Rivendell date parsing routines\n\nOptions are:\n--fomat=rfc822|xml|auto\n Use RFC822 or XML string formats\n\n--print=date|time|datetime\n If specified, print the system's current date/time, using the\n specified format.\n\n--datetime=<datetime-str>\n Parse the <datetime-str> string using RDGetWebDateTime() and print\n the result on stdout.\n\n--time=<time-str>\n Parse the <time-str> string using RDGetWebTime() and\n print the results on stdout.\n\n"
class MainObject : public QObject
{
public:
enum Format {Unknown=0,Rfc822=1,Xml=2,Auto=3};
enum PrintType {None=0,Date=1,Time=2,DateTime=3};
MainObject(QObject *parent=0);
};
#endif // DATEPARSE_TEST_H

View File

@ -23,6 +23,8 @@
#include <rdapplication.h>
#include <rdweb.h>
#include <rddatetime.h>
#include "rdclilogedit.h"
void MainObject::DispatchCommand(QString cmd)
@ -503,7 +505,7 @@ void MainObject::DispatchCommand(QString cmd)
switch(ttype) {
case RDLogLine::Hard:
if(cmds.size()>=4) {
time=RDGetWebTime(cmds[3],&ok);
time=RDParseXmlTime(cmds[3],&ok);
if(ok) {
Settime(line,ttype,time);
}