Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor garmin_txt date time handling #1208

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -966,8 +966,8 @@ QDateTime dotnet_time_to_qdatetime(long long dotnet);
long long qdatetime_to_dotnet_time(const QDateTime& dt);
QString strip_html(const QString& utfstring);
QString strip_nastyhtml(const QString& in);
QString convert_human_date_format(const char* human_datef); /* "MM,YYYY,DD" -> "%m,%Y,%d" */
QString convert_human_time_format(const char* human_timef); /* "HH+mm+ss" -> "%H+%M+%S" */
QString convert_human_date_format(const char* human_datef, bool read); /* "MM,YYYY,DD" -> "MM,yyyy,dd" */
QString convert_human_time_format(const char* human_timef, bool read); /* "HH+mm+ss" -> "HH+mm+ss" */
QString pretty_deg_format(double lat, double lon, char fmt, const char* sep, bool html); /* decimal -> dd.dddd or dd mm.mmm or dd mm ss */

QString get_filename(const QString& fname); /* extract the filename portion */
Expand Down
170 changes: 49 additions & 121 deletions garmin_txt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@
#include <cctype> // for toupper
#include <cmath> // for fabs, floor
#include <cstdint> // for uint16_t
#include <cstdio> // for sscanf, fprintf, snprintf, stderr
#include <cstdlib> // for abs
#include <cstring> // for strstr, strlen
#include <ctime> // for time_t, gmtime, localtime, strftime
#include <cstdio> // for sscanf, fprintf, stderr
#include <cstdlib> // for abs, div
#include <cstring> // for strstr
#include <optional> // for optional
#include <utility> // for pair, make_pair

Expand Down Expand Up @@ -83,7 +82,7 @@ static const char* datum_str;
static int current_line;
static QString date_time_format;
static int precision = 3;
static time_t utc_offs = 0;
static int utc_offs = 0;
static gtxt_flags_t gtxt_flags;

enum header_type {
Expand Down Expand Up @@ -154,8 +153,8 @@ class PathInfo
{
public:
double length {0};
time_t start {0};
time_t time {0};
QDateTime start;
int time {0};
double speed {0};
double total {0};
int count {0};
Expand Down Expand Up @@ -188,16 +187,16 @@ get_option_val(const char* option, const char* def)
}

static void
init_date_and_time_format()
init_date_and_time_format(bool read)
{
// This is old, and weird, code.. date_time_format is a global that's
// explicitly malloced and freed elsewhere. This isn't very C++ at all,
// but this format is on its deathbead for deprecation.
const char* d = get_option_val(opt_date_format, kDefaultDateFormat);
QString d1 = convert_human_date_format(d);
QString d1 = convert_human_date_format(d, read);

const char* t = get_option_val(opt_time_format, kDefaultTimeFormat);
QString t1 = convert_human_time_format(t);
QString t1 = convert_human_time_format(t, read);

date_time_format = QStringLiteral("%1 %2").arg(d1, t1);
}
Expand Down Expand Up @@ -263,11 +262,11 @@ prework_wpt_cb(const Waypoint* wpt)
const Waypoint* prev = cur_info->prev_wpt;

if (prev != nullptr) {
cur_info->time += (wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t());
cur_info->time += prev->GetCreationTime().secsTo(wpt->GetCreationTime());
cur_info->length += waypt_distance_ex(prev, wpt);
} else {
cur_info->first_wpt = wpt;
cur_info->start = wpt->GetCreationTime().toTime_t();
cur_info->start = wpt->GetCreationTime();
}
cur_info->prev_wpt = wpt;
cur_info->count++;
Expand Down Expand Up @@ -364,28 +363,35 @@ print_position(const Waypoint* wpt)
}

static void
print_date_and_time(const time_t time, const bool time_only)
print_duration(int duration_secs)
{
std::tm tm{};
char tbuf[32];
if (duration_secs < 0) {
*fout << "\t";
return;
}
#if 1
// perhaps durations can be longer than the max QTime of 23:59:59
auto res = std::div(duration_secs, 60);
auto sec = res.rem;
res = std::div(res.quot, 60);
*fout << QString::asprintf("%d:%02d:%02d\t", res.quot, res.rem, sec);
#else
QTime qt = QTime(0, 0).addSecs(duration_secs);
*fout << qt.toString("H:mm:ss\t");
#endif
}

if (time < 0) {
static void
print_date_and_time(const QDateTime& dt)
{
if (!dt.isValid()) {
*fout << "\t";
return;
}
if (time_only) {
tm = *gmtime(&time);
snprintf(tbuf, sizeof(tbuf), "%d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec);
*fout << QString::asprintf("%s", tbuf);
} else if (time != 0) {
if (gtxt_flags.utc) {
time_t t = time + utc_offs;
tm = *gmtime(&t);
} else {
tm = *localtime(&time);
}
strftime(tbuf, sizeof(tbuf), CSTR(date_time_format), &tm);
*fout << QString::asprintf("%s ", tbuf);
if (gtxt_flags.utc) {
*fout << dt.toOffsetFromUtc(utc_offs).toString(date_time_format);
} else {
*fout << dt.toLocalTime().toString(date_time_format);
}
*fout << "\t";
}
Expand Down Expand Up @@ -444,7 +450,7 @@ print_distance(const double distance, const bool no_scale, const bool with_tab,
}

static void
print_speed(const double distance, const time_t time)
print_speed(const double distance, int time)
{
double dist = distance;
const char* unit;
Expand Down Expand Up @@ -576,7 +582,7 @@ write_waypt(const Waypoint* wpt)
print_string("%s\t", garmin_fs_t::get_state(gmsd, ""));
const char* country = gt_get_icao_country(garmin_fs_t::get_cc(gmsd, ""));
print_string("%s\t", (country != nullptr) ? country : "");
print_date_and_time(wpt->GetCreationTime().toTime_t(), false);
print_date_and_time(wpt->GetCreationTime());
if (wpt->HasUrlLink()) {
UrlLink l = wpt->GetUrlLink();
print_string("%s\t", l.url_);
Expand Down Expand Up @@ -657,8 +663,8 @@ track_disp_hdr_cb(const route_head* track)
*fout << QStringLiteral("\r\n\r\nHeader\t%1\r\n").arg(headers[track_header]);
}
print_string("\r\nTrack\t%s\t", track->rte_name);
print_date_and_time(cur_info->start, false);
print_date_and_time(cur_info->time, true);
print_date_and_time(cur_info->start);
print_duration(cur_info->time);
print_distance(cur_info->length, false, true, 0);
print_speed(cur_info->length, cur_info->time);
if (track->rte_urls.HasUrlLink()) {
Expand All @@ -679,13 +685,11 @@ static void
track_disp_wpt_cb(const Waypoint* wpt)
{
const Waypoint* prev = cur_info->prev_wpt;
time_t delta;
double dist;

*fout << "Trackpoint\t";

print_position(wpt);
print_date_and_time(wpt->GetCreationTime().toTime_t(), false);
print_date_and_time(wpt->GetCreationTime());
if (is_valid_alt(wpt->altitude)) {
print_distance(wpt->altitude, true, false, 0);
}
Expand All @@ -698,15 +702,15 @@ track_disp_wpt_cb(const Waypoint* wpt)

if (prev != nullptr) {
*fout << "\t";
delta = wpt->GetCreationTime().toTime_t() - prev->GetCreationTime().toTime_t();
int delta = prev->GetCreationTime().secsTo(wpt->GetCreationTime());
float temp = wpt->temperature_value_or(-999);
if (temp != -999) {
print_temperature(temp);
}
*fout << "\t";
dist = waypt_distance_ex(prev, wpt);
double dist = waypt_distance_ex(prev, wpt);
print_distance(dist, false, true, 0);
print_date_and_time(delta, true);
print_duration(delta);
print_speed(dist, delta);
print_course(prev, wpt);
}
Expand Down Expand Up @@ -737,7 +741,7 @@ static void
garmin_txt_adjust_time(QDateTime& dt)
{
if (gtxt_flags.utc) {
dt = dt.toUTC().addSecs(dt.offsetFromUtc() - utc_offs);
dt.setOffsetFromUtc(utc_offs);
}
}

Expand All @@ -751,7 +755,7 @@ garmin_txt_wr_init(const QString& fname)

gtxt_flags.metric = (toupper(*get_option_val(opt_dist, "m")) == 'M');
gtxt_flags.celsius = (toupper(*get_option_val(opt_temp, "c")) == 'C');
init_date_and_time_format();
init_date_and_time_format(false);
if (opt_precision) {
precision = xstrtoi(opt_precision, nullptr, 10);
if (precision < 0) {
Expand Down Expand Up @@ -867,88 +871,12 @@ free_headers()
[](auto& list)->void { list.clear(); });
}

// Super simple attempt to convert strftime/strptime spec to Qt spec.
// This misses a LOT of cases and vagaries, but the reality is that we
// see very few date formats here.
static QString
strftime_to_timespec(const char* s)
{
QString q;
int l = strlen(s);
q.reserve(l * 2); // no penalty if our guess is wrong.

for (int i = 0; i < l; i++) {
switch (s[i]) {
case '%':
if (i < l-1) {
switch (s[++i]) {
case 'd':
q += "dd";
continue;
case 'm':
q += "MM";
continue;
case 'y':
q += "yy";
continue;
case 'Y':
q += "yyyy";
continue;
case 'H':
q += "HH";
continue;
case 'M':
q += "mm";
continue;
case 'S':
q += "ss";
continue;
case 'A':
q += "dddd";
continue;
case 'a':
q += "ddd";
continue;
case 'B':
q += "MMMM";
continue;
case 'C':
q += "yy";
continue;
case 'D':
q += "MM/dd/yyyy";
continue;
case 'T':
q += "hh:mm:ss";
continue;
case 'F':
q += "yyyy-MM-dd";
continue;
case 'p':
q += "AP";
continue;
default:
warning(MYNAME ": omitting unknown strptime conversion \"%%%c\" in \"%s\"\n", s[i], s);
break;
}
}
break;
default:
q += s[i];
break;
}
}
return q;
}


/* data parsers */

static QDateTime
parse_date_and_time(const QString& str)
{
QString timespec = strftime_to_timespec(CSTR(date_time_format));
return QDateTime::fromString(QString(str).trimmed(), timespec);
return QDateTime::fromString(QString(str).trimmed(), date_time_format);
}

static uint16_t
Expand Down Expand Up @@ -1182,7 +1110,7 @@ parse_waypoint(const QStringList& lineparts)
garmin_txt_adjust_time(dt);
wpt->SetCreationTime(dt);
}
break;
break;
case 17: {
wpt->AddUrlLink(str);
}
Expand Down Expand Up @@ -1318,7 +1246,7 @@ parse_track_waypoint(const QStringList& lineparts)
garmin_txt_adjust_time(dt);
wpt->SetCreationTime(dt);
}
break;
break;
case 3:
if (parse_distance(str, &x, 1, MYNAME)) {
wpt->altitude = x;
Expand Down Expand Up @@ -1363,7 +1291,7 @@ garmin_txt_rd_init(const QString& fname)
datum_index = -1;
grid_index = (grid_type) -1;

init_date_and_time_format();
init_date_and_time_format(true);
garmin_txt_utc_option();
}

Expand Down
2 changes: 1 addition & 1 deletion gpsbabel-sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
;------------------------------------------------------------------
[ garmin_txt ]
Date = DD.MM.YYYY
Time = HH:mm:ss XX
Time = hh:mm:ss XX
Dist = M
Temp = C
Prec = 6
Expand Down
2 changes: 1 addition & 1 deletion reference/garmincategories.gpx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<bounds minlat="39.973869717" minlon="-105.498962400" maxlat="40.003967283" maxlon="-105.465850367"/>
</metadata>
<wpt lat="39.973869717" lon="-105.465850367">
<time>2013-03-09T20:45:12Z</time>
<time>2013-03-09T08:45:12Z</time>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this an intentional change from 24H to 12H?

<name>Hwy 119</name>
<cmt>The Diagonal</cmt>
<desc>The Diagonal</desc>
Expand Down
4 changes: 2 additions & 2 deletions reference/garmincategories.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ Datum WGS 84

Header Name Description Type Position Altitude Depth Proximity Temperature Display Mode Color Symbol Facility City State Country Date Modified Link Categories

Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:12 PM Slow food,Category 11
Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 13:45:02 PM
Waypoint Hwy 119 The Diagonal User Waypoint N39 58.432183 W105 27.951022 Symbol & Name Unknown Flag, Blue 09.03.2013 01:45:12 AM Slow food,Category 11
Waypoint Hwy 72 The Peak to Peak User Waypoint N40 00.238037 W105 29.937744 Symbol & Name Unknown Flag, Blue 09.03.2013 01:45:02 PM
Loading