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

simplify formatting of date/time in garmin_txt #1205

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 0 additions & 2 deletions defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -966,8 +966,6 @@ 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 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
173 changes: 47 additions & 126 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 @@ -121,7 +120,7 @@ static std::array<QList<std::pair<QString, int>>, unknown_header> header_mapping
static QStringList header_column_names;

static constexpr double kGarminUnknownAlt = 1.0e25;
static constexpr char kDefaultDateFormat[] = "dd/mm/yyyy";
static constexpr char kDefaultDateFormat[] = "dd/MM/yyyy";
static constexpr char kDefaultTimeFormat[] = "HH:mm:ss";

static bool is_valid_alt(double alt)
Expand All @@ -140,22 +139,22 @@ static char* opt_grid = nullptr;

static
QVector<arglist_t> garmin_txt_args = {
{"date", &opt_date_format, "Read/Write date format (i.e. yyyy/mm/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"date", &opt_date_format, "Read/Write date format (e.g. yyyy/MM/dd)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"datum", &opt_datum, "GPS datum (def. WGS 84)", "WGS 84", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"dist", &opt_dist, "Distance unit [m=metric, s=statute]", "m", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"grid", &opt_grid, "Write position using this grid.", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"prec", &opt_precision, "Precision of coordinates", "3", ARGTYPE_INT, ARG_NOMINMAX, nullptr},
{"temp", &opt_temp, "Temperature unit [c=Celsius, f=Fahrenheit]", "c", ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"time", &opt_time_format, "Read/Write time format (i.e. HH:mm:ss xx)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"time", &opt_time_format, "Read/Write time format (e.g. HH:mm:ss)", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr},
{"utc", &opt_utc, "Write timestamps with offset x to UTC time", nullptr, ARGTYPE_INT, "-23", "+23", nullptr},
};

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 @@ -190,16 +189,9 @@ get_option_val(const char* option, const char* def)
static void
init_date_and_time_format()
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a constructor wearing C groucho glasses?

{
// 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);

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

date_time_format = QStringLiteral("%1 %2").arg(d1, t1);
date_time_format = QStringLiteral("%1 %2").arg(d, t);
}

static void
Expand Down Expand Up @@ -263,11 +255,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,30 +356,37 @@ print_position(const Waypoint* wpt)
}

static void
print_date_and_time(const time_t time, const bool time_only)
print_duration(int time)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider a name for time that hints what it is. 'seconds', I think? print_duration_as_hms() ? I'm not sure.

{
std::tm tm{};
char tbuf[32];

if (time < 0) {
*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 1
// perhaps durations can be longer than the max QTime of 23:59:59
auto res = std::div(time, 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(time);
*fout << qt.toString("H:mm:ss\t");
#endif
}

static void
print_date_and_time(const QDateTime& dt)
{
if (!dt.isValid()) {
*fout << "\t";
return;
}
*fout << "\t";
if (gtxt_flags.utc) {
*fout << dt.toOffsetFromUtc(utc_offs).toString(date_time_format);
} else {
*fout << dt.toLocalTime().toString(date_time_format);
}
*fout << " \t";
}

static void
Expand Down Expand Up @@ -444,7 +443,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)
Copy link
Collaborator

Choose a reason for hiding this comment

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

While you're in here, can ouo please do a sarch and replace and make these 'meters' and 'seconds' maybe?

{
double dist = distance;
const char* unit;
Expand Down Expand Up @@ -576,7 +575,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 +656,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 +678,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 +695,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 +734,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 Down Expand Up @@ -867,88 +864,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
4 changes: 2 additions & 2 deletions gpsbabel-sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

;------------------------------------------------------------------
[ garmin_txt ]
Date = DD.MM.YYYY
Time = HH:mm:ss XX
Date = dd.MM.yyyy
Time = HH:mm:ss
Dist = M
Temp = C
Prec = 6
Expand Down
4 changes: 2 additions & 2 deletions reference/format3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ option gdb roadbook Include major turn points (with description) from calculated

file rwrwrw garmin_txt txt Garmin MapSource - txt (tab delimited) garmin_txt
https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html
option garmin_txt date Read/Write date format (i.e. yyyy/mm/dd) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_date
option garmin_txt date Read/Write date format (e.g. yyyy/MM/dd) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_date

option garmin_txt datum GPS datum (def. WGS 84) string WGS 84 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_datum

Expand All @@ -222,7 +222,7 @@ option garmin_txt prec Precision of coordinates integer 3 https://www.gpsbabel

option garmin_txt temp Temperature unit [c=Celsius, f=Fahrenheit] string c https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_temp

option garmin_txt time Read/Write time format (i.e. HH:mm:ss xx) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_time
option garmin_txt time Read/Write time format (e.g. HH:mm:ss) string https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_time

option garmin_txt utc Write timestamps with offset x to UTC time integer -23 +23 https://www.gpsbabel.org/WEB_DOC_DIR/fmt_garmin_txt.html#fmt_garmin_txt_o_utc

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 13:45:12 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
4 changes: 2 additions & 2 deletions reference/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -110,13 +110,13 @@ File Types (-i and -o options):
dropwpt (0/1) Don't create waypoints for non-user points
roadbook (0/1) Include major turn points (with description) from
garmin_txt Garmin MapSource - txt (tab delimited)
date Read/Write date format (i.e. yyyy/mm/dd)
date Read/Write date format (e.g. yyyy/MM/dd)
datum GPS datum (def. WGS 84)
dist Distance unit [m=metric, s=statute]
grid Write position using this grid.
prec Precision of coordinates
temp Temperature unit [c=Celsius, f=Fahrenheit]
time Read/Write time format (i.e. HH:mm:ss xx)
time Read/Write time format (e.g. HH:mm:ss)
utc Write timestamps with offset x to UTC time
garmin_poi Garmin POI database
snlen Max synthesized shortname length
Expand Down
Loading