This adds timezone support for TCX files. - Julian Simioni

This commit is contained in:
Justin Knotzke
2009-08-21 20:26:47 -04:00
parent 5a453fb210
commit d3ea473f60
4 changed files with 109 additions and 66 deletions

View File

@@ -18,12 +18,12 @@
*/
#include <QString>
#include <assert.h>
#include "TcxParser.h"
#include <assert.h>
#include "TimeUtils.h"
TcxParser::TcxParser (RideFile* rideFile)
: rideFile_(rideFile)
: rideFile(rideFile)
{
}
@@ -32,93 +32,109 @@ TcxParser::startElement( const QString&, const QString&,
const QString& qName,
const QXmlAttributes& qAttributes)
{
buf_.clear();
buffer.clear();
if (qName == "Activity") {
lap_ = 0;
} else if (qName == "Lap") {
// Use the time of the first lap as the time of the activity.
if (lap_ == 0) {
start_time_ = QDateTime::fromString(qAttributes.value("StartTime"),
Qt::ISODate);
rideFile_->setStartTime(start_time_);
last_km_ = 0.0;
last_time_ = start_time_;
}
++lap_;
} else if (qName == "Trackpoint") {
watts_ = 0.0;
cad_ = 0.0;
hr_ = 0.0;
km_ = -1; // nh - we set this to -1 so we can detect if there was a distance in the trackpoint.
if (qName == "Activity")
{
lap = 0;
}
else if (qName == "Lap")
{
// Use the time of the first lap as the time of the activity.
if (lap == 0)
{
start_time = convertToLocalTime(qAttributes.value("StartTime"));
rideFile->setStartTime(start_time);
lastDistance = 0.0;
last_time = start_time;
}
lap++;
}
else if (qName == "Trackpoint")
{
power = 0.0;
cadence = 0.0;
hr = 0.0;
distance = -1; // nh - we set this to -1 so we can detect if there was a distance in the trackpoint.
}
return TRUE;
}
bool
TcxParser::endElement( const QString&, const QString&, const QString& qName)
{
if (qName == "Time") {
time_ = QDateTime::fromString(buf_, Qt::ISODate);
if (qName == "Time")
{
time = convertToLocalTime(buffer);
}
if (qName == "DistanceMeters") {
km_ = buf_.toDouble() / 1000;
} else if (qName == "Watts") {
watts_ = buf_.toDouble();
} else if (qName == "Value") {
hr_ = buf_.toDouble();
} else if (qName == "Cadence") {
cad_ = buf_.toDouble();
} else if (qName == "Trackpoint")
else if (qName == "DistanceMeters")
{
distance = buffer.toDouble() / 1000;
}
else if (qName == "Watts")
{
power = buffer.toDouble();
}
else if (qName == "Value")
{
hr = buffer.toDouble();
}
else if (qName == "Cadence")
{
cadence = buffer.toDouble();
}
else if (qName == "Trackpoint")
{
// nh - there are track points that don't have any distance info. We need to ignore them
if (km_>=0)
if (distance>=0)
{
// compute the elapsed time and distance traveled since the
// last recorded trackpoint
double delta_t = last_time_.secsTo(time_);
double delta_d = km_ - last_km_;
assert(delta_d>=0);
double delta_t = last_time.secsTo(time);
double delta_d = distance - lastDistance;
if (delta_d<0)
{
delta_d=0;
}
// compute speed for this trackpoint by dividing the distance
// traveled by the elapsed time. The elapsed time will be 0.0
// for the first trackpoint -- so set speed to 0.0 instead of
// dividing by zero.
double kph = ((delta_t != 0.0) ? ((delta_d / delta_t) * 3600.0) : 0.0);
assert(kph>=0);
double speed = 0.0;
if (delta_t > 0.0)
{
speed=delta_d / delta_t * 3600.0;
}
// Don't know what to do about torque
double nm = 0.0;
double torque = 0.0;
// Time from beginning of activity
double secs = start_time_.secsTo(time_);
double secs = start_time.secsTo(time);
// Work around bug in 705 firmware where cadence and
// power values repeat when stopped.
if (delta_d == 0.0) {
watts_ = 0.0;
cad_ = 0.0;
if (delta_d == 0.0)
{
power = 0.0;
cadence = 0.0;
}
// Record trackpoint
rideFile_->appendPoint(secs, cad_, hr_, km_,
kph, nm, watts_, lap_);
rideFile->appendPoint(secs, cadence, hr, distance,
speed, torque, power, lap);
last_km_ = km_;
lastDistance = distance;
}
last_time_ = time_;
last_time = time;
}
return TRUE;
}
bool
TcxParser::characters( const QString& str )
bool TcxParser::characters( const QString& str )
{
buf_ += str;
buffer += str;
return TRUE;
}

View File

@@ -38,20 +38,21 @@ public:
private:
RideFile* rideFile_;
RideFile* rideFile;
QString buf_;
QString buffer;
QDateTime start_time_;
QDateTime last_time_;
QDateTime time_;
double last_km_;
double km_;
QDateTime start_time;
QDateTime last_time;
QDateTime time;
double lastDistance;
double distance;
int lap_;
double watts_;
double cad_;
double hr_;
int lap;
double power;
double cadence;
double hr;
double lastAltitude;
};
#endif // _TcxParser_h

View File

@@ -63,3 +63,24 @@ QString interval_to_str(double secs)
return result;
}
QDateTime convertToLocalTime(QString timestamp)
{
//check if the last character is Z designating the timezone to be UTC
if (timestamp[timestamp.size()-1].toLower()=='z')
{
QDateTime datetime = QDateTime::fromString(timestamp, Qt::ISODate);
datetime.setTimeSpec(Qt::UTC);
datetime=datetime.toLocalTime();
return datetime;
}
//otherwise assume the timestamp is already in local time and simply convert it
//something to add here would be a handler for explicitly set timezones
//ex: 2002-05-30T09:30:10+06:00
//see http://www.w3schools.com/Schema/schema_dtypes_date.asp
//for more on this date format
else
{
return QDateTime::fromString(timestamp);
}
}

View File

@@ -19,10 +19,15 @@
#ifndef _TimeUtils_h
#define _TimeUtils_h
#include <QDateTime>
#include <QString>
QString interval_to_str(double secs); // output like 1h 2m 3s
QString time_to_string(double secs); // output like 1:02:03
/* takes a string containing an ISO 8601 timestamp and converts it to local time
*/
QDateTime convertToLocalTime(QString timestamp);
#endif // _TimeUtils_h