Skip to content

Commit

Permalink
refactor datetime output (valhalla#4365)
Browse files Browse the repository at this point in the history
  • Loading branch information
nilsnolde authored Dec 22, 2023
1 parent 241daf6 commit d25c8ee
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 98 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
* ADDED: most access restrictions to /locate response [#4431](https://github.com/valhalla/valhalla/pull/4431)
* ADDED: hgv=destination and friends for truck-specific "destination_only" logic [#4450](https://github.com/valhalla/valhalla/issues/4450)
* UPDATED: updated country access overrides [#4460](https://github.com/valhalla/valhalla/pull/4460)
* CHANGED: date_time refactor as a preparation to return DST/timezone related offset in the response [#4365](https://github.com/valhalla/valhalla/pull/4365)

## Release Date: 2023-05-11 Valhalla 3.4.0
* **Removed**
Expand Down
13 changes: 13 additions & 0 deletions src/baldr/datetime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,19 @@ uint32_t second_of_week(uint32_t epoch_time, const date::time_zone* time_zone) {
return day * midgard::kSecondsPerDay + since_midnight.count();
}

std::string
offset_date(const std::string& in_dt, const uint32_t in_tz, const uint32_t out_tz, float offset) {
if (in_dt.empty()) {
return "";
} else if (!offset) {
return in_dt;
}
// get the input UTC time, add the offset and translate to the out timezone
auto iepoch = DateTime::seconds_since_epoch(in_dt, DateTime::get_tz_db().from_index(in_tz));
auto oepoch =
static_cast<uint64_t>(static_cast<double>(iepoch) + static_cast<double>(offset + .5f));
return DateTime::seconds_to_date(oepoch, DateTime::get_tz_db().from_index(out_tz), false);
}
} // namespace DateTime
} // namespace baldr
} // namespace valhalla
10 changes: 10 additions & 0 deletions src/baldr/graphreader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -975,6 +975,16 @@ int GraphReader::GetTimezone(const baldr::GraphId& node, graph_tile_ptr& tile) {
return (tile == nullptr) ? 0 : tile->node(node)->timezone();
}

int GraphReader::GetTimezoneFromEdge(const baldr::GraphId& edge, graph_tile_ptr& tile) {
auto nodes = GetDirectedEdgeNodes(edge, tile);
if (const auto* node = nodeinfo(nodes.first, tile))
return node->timezone();
else if (const auto* node = nodeinfo(nodes.second, tile))
return node->timezone();

return 0;
}

std::shared_ptr<const valhalla::IncidentsTile>
GraphReader::GetIncidentTile(const GraphId& tile_id) const {
return enable_incidents_ ? incident_singleton_t::get(tile_id.Tile_Base())
Expand Down
20 changes: 14 additions & 6 deletions src/thor/costmatrix.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cmath>
#include <vector>

#include "baldr/datetime.h"
#include "midgard/encoded.h"
#include "midgard/logging.h"
#include "sif/recost.h"
Expand Down Expand Up @@ -258,6 +259,7 @@ void CostMatrix::SourceToTarget(Api& request,
}

// Form the matrix PBF output
graph_tile_ptr tile;
uint32_t count = 0;
valhalla::Matrix& matrix = *request.mutable_matrix();
reserve_pbf_arrays(matrix, best_connection_.size());
Expand All @@ -271,18 +273,24 @@ void CostMatrix::SourceToTarget(Api& request,
time_infos[source_idx], invariant, shape_format);

float time = connection.cost.secs;
auto date_time = get_date_time(source_location_list[source_idx].date_time(),
time_infos[source_idx].timezone_index,
edgelabel_[MATRIX_REV][target_idx].front().edgeid(), graphreader,
static_cast<uint64_t>(time));
if (time < kMaxCost) {
auto date_time =
DateTime::offset_date(source_location_list[source_idx].date_time(),
time_infos[source_idx].timezone_index,
graphreader.GetTimezoneFromEdge(edgelabel_[MATRIX_REV][target_idx]
.front()
.edgeid(),
tile),
time);
auto* pbf_date_time = matrix.mutable_date_times()->Add();
*pbf_date_time = date_time;
}
matrix.mutable_from_indices()->Set(count, source_idx);
matrix.mutable_to_indices()->Set(count, target_idx);
matrix.mutable_distances()->Set(count, connection.distance);
matrix.mutable_times()->Set(count, time);
auto* pbf_shape = matrix.mutable_shapes()->Add();
*pbf_shape = shape;
auto* pbf_date_time = matrix.mutable_date_times()->Add();
*pbf_date_time = date_time;
count++;
}
}
Expand Down
74 changes: 23 additions & 51 deletions src/thor/route_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <cstdint>

#include "baldr/attributes_controller.h"
#include "baldr/datetime.h"
#include "baldr/json.h"
#include "baldr/rapidjson_utils.h"
#include "midgard/constants.h"
Expand Down Expand Up @@ -359,6 +360,7 @@ void thor_worker_t::path_arrive_by(Api& api, const std::string& costing) {
valhalla::Trip& trip = *api.mutable_trip();
trip.mutable_routes()->Reserve(options.alternates() + 1);

graph_tile_ptr tile = nullptr;
auto route_two_locations = [&](auto& origin, auto& destination) -> bool {
// Get the algorithm type for this location pair
thor::PathAlgorithm* path_algorithm =
Expand All @@ -378,21 +380,26 @@ void thor_worker_t::path_arrive_by(Api& api, const std::string& costing) {
auto temp_paths = this->get_path(path_algorithm, *origin, *destination, costing, options);
if (temp_paths.empty())
return false;

for (auto& temp_path : temp_paths) {
// back propagate time information
if (!destination->date_time().empty() &&
options.date_time_type() != valhalla::Options::invariant) {
auto origin_dt = offset_date(*reader, destination->date_time(), temp_path.back().edgeid,
-temp_path.back().elapsed_cost.secs, temp_path.front().edgeid);
auto origin_dt =
DateTime::offset_date(destination->date_time(),
reader->GetTimezoneFromEdge(temp_path.back().edgeid, tile),
reader->GetTimezoneFromEdge(temp_path.front().edgeid, tile),
-temp_path.back().elapsed_cost.secs);
origin->set_date_time(origin_dt);
}

// add waiting_secs again from the final destination's datetime, so we output the departing time
// at intermediate locations, not the arrival time
if (destination->waiting_secs() && !destination->date_time().empty()) {
auto dest_dt = offset_date(*reader, destination->date_time(), temp_path.back().edgeid,
destination->waiting_secs(), temp_path.back().edgeid);
auto dest_dt =
DateTime::offset_date(destination->date_time(),
reader->GetTimezoneFromEdge(temp_path.back().edgeid, tile),
reader->GetTimezoneFromEdge(temp_path.back().edgeid, tile),
destination->waiting_secs());
destination->set_date_time(dest_dt);
}

Expand Down Expand Up @@ -457,9 +464,13 @@ void thor_worker_t::path_arrive_by(Api& api, const std::string& costing) {

// advance the time for the next destination (i.e. algo origin) by the waiting_secs
// of this origin (i.e. algo destination)
// TODO(nils): why do we do this twice? above we also do it for a destination..
if (origin->waiting_secs()) {
auto origin_dt = offset_date(*reader, origin->date_time(), path.front().edgeid,
-origin->waiting_secs(), path.front().edgeid);
auto origin_dt =
DateTime::offset_date(origin->date_time(),
reader->GetTimezoneFromEdge(temp_path.front().edgeid, tile),
reader->GetTimezoneFromEdge(temp_path.front().edgeid, tile),
-origin->waiting_secs());
origin->set_date_time(origin_dt);
}
path.clear();
Expand Down Expand Up @@ -532,6 +543,7 @@ void thor_worker_t::path_depart_at(Api& api, const std::string& costing) {
valhalla::Trip& trip = *api.mutable_trip();
trip.mutable_routes()->Reserve(options.alternates() + 1);

graph_tile_ptr tile = nullptr;
auto route_two_locations = [&, this](auto& origin, auto& destination) -> bool {
// Get the algorithm type for this location pair
thor::PathAlgorithm* path_algorithm =
Expand All @@ -555,9 +567,10 @@ void thor_worker_t::path_depart_at(Api& api, const std::string& costing) {
// forward propagate time information
if (!origin->date_time().empty() && options.date_time_type() != valhalla::Options::invariant) {
auto destination_dt =
offset_date(*reader, origin->date_time(), temp_path.front().edgeid,
temp_path.back().elapsed_cost.secs + destination->waiting_secs(),
temp_path.back().edgeid);
DateTime::offset_date(origin->date_time(),
reader->GetTimezoneFromEdge(temp_path.front().edgeid, tile),
reader->GetTimezoneFromEdge(temp_path.back().edgeid, tile),
temp_path.back().elapsed_cost.secs + destination->waiting_secs());
destination->set_date_time(destination_dt);
}

Expand Down Expand Up @@ -664,46 +677,5 @@ void thor_worker_t::path_depart_at(Api& api, const std::string& costing) {
// assign changed locations
*api.mutable_options()->mutable_locations() = std::move(correlated);
}

/**
* Offset a time by some number of seconds, optionally taking into account timezones at the origin &
* destination.
*
* @param reader graphreader for tile/edge/node access
* @param in_dt the input date time string
* @param in_edge the input edgeid (used for timezone lookup)
* @param offset the offset in seconds from the input date time string
* @param out_edge the output edgeid (used for timezone lookup)
* @return out_dt the time at the out_edge in local time after the offset is applied to the in_dt
*/
std::string thor_worker_t::offset_date(GraphReader& reader,
const std::string& in_dt,
const GraphId& in_edge,
float offset,
const GraphId& out_edge) {
uint32_t in_tz = 0;
uint32_t out_tz = 0;
// get the timezone of the input location
graph_tile_ptr tile = nullptr;
auto in_nodes = reader.GetDirectedEdgeNodes(in_edge, tile);
if (const auto* node = reader.nodeinfo(in_nodes.first, tile))
in_tz = node->timezone();
else if (const auto* node = reader.nodeinfo(in_nodes.second, tile))
in_tz = node->timezone();

// get the timezone of the output location
auto out_nodes = reader.GetDirectedEdgeNodes(out_edge, tile);
if (const auto* node = reader.nodeinfo(out_nodes.first, tile))
out_tz = node->timezone();
else if (const auto* node = reader.nodeinfo(out_nodes.second, tile))
out_tz = node->timezone();

// offset the time
uint64_t in_epoch = DateTime::seconds_since_epoch(in_dt, DateTime::get_tz_db().from_index(in_tz));
double out_epoch = static_cast<double>(in_epoch) + offset;
auto out_dt = DateTime::seconds_to_date(static_cast<uint64_t>(out_epoch + .5),
DateTime::get_tz_db().from_index(out_tz), false);
return out_dt;
}
} // namespace thor
} // namespace valhalla
10 changes: 7 additions & 3 deletions src/thor/timedistancematrix.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#include "thor/timedistancematrix.h"
#include "midgard/logging.h"
#include <algorithm>
#include <vector>

#include "baldr/datetime.h"
#include "midgard/logging.h"
#include "thor/timedistancematrix.h"

using namespace valhalla::baldr;
using namespace valhalla::sif;

Expand Down Expand Up @@ -567,6 +569,7 @@ void TimeDistanceMatrix::FormTimeDistanceMatrix(Api& request,
// when it's forward, origin_index will be the source_index
// when it's reverse, origin_index will be the target_index
valhalla::Matrix& matrix = *request.mutable_matrix();
graph_tile_ptr tile;
for (uint32_t i = 0; i < destinations_.size(); i++) {
auto& dest = destinations_[i];
float time = dest.best_cost.secs + .5f;
Expand All @@ -580,7 +583,8 @@ void TimeDistanceMatrix::FormTimeDistanceMatrix(Api& request,
// this logic doesn't work with string repeated fields, gotta collect them
// and process them later
auto date_time =
get_date_time(origin_dt, origin_tz, pred_id, reader, static_cast<uint64_t>(time));
DateTime::offset_date(origin_dt, origin_tz, reader.GetTimezoneFromEdge(pred_id, tile),
static_cast<uint64_t>(time));
out_date_times[pbf_idx] = date_time;
}
}
Expand Down
13 changes: 13 additions & 0 deletions valhalla/baldr/datetime.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,19 @@ bool is_conditional_active(const bool type,
*/
uint32_t second_of_week(uint32_t epoch_time, const date::time_zone* time_zone);

/**
* Offset a time by some number of seconds, optionally taking into account timezones at the origin &
* destination.
*
* @param in_dt the input date time string
* @param in_tz the start timezone
* @param out_tz the end timezone
* @param offset the offset in seconds from the input date time string
* @return out_dt the time at the out_edge in local time after the offset is applied to the in_dt
*/
std::string
offset_date(const std::string& in_dt, const uint32_t in_tz, const uint32_t out_tz, float offset);

/**
* Convert ISO 8601 time into std::tm.
* @param iso ISO time string (YYYY-mm-ddTHH:MM)
Expand Down
10 changes: 10 additions & 0 deletions valhalla/baldr/graphreader.h
Original file line number Diff line number Diff line change
Expand Up @@ -947,6 +947,16 @@ class GraphReader {
*/
int GetTimezone(const baldr::GraphId& node, graph_tile_ptr& tile);

/**
* Convenience method to get the timezone index from an edge. Preferably it returns
* the start's node's timezone.
* @param edge GraphId of the edge to get the timezone index.
* @param tile Current tile. Can be changed to the tile of the edge's end node.
* @return Returns the timezone index. A value of 0 indicates an invalid timezone.
* It's possible that the tile changes to the edge's end node's tile.
*/
int GetTimezoneFromEdge(const baldr::GraphId& edge, graph_tile_ptr& tile);

/**
* Returns an incident tile for the given tile id
* @param tile_id the tile id for which incidents should be returned
Expand Down
32 changes: 0 additions & 32 deletions valhalla/thor/matrix_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,38 +56,6 @@ struct Destination {
}
};

// Will return a destination's date_time string
inline std::string get_date_time(const std::string& origin_dt,
const uint64_t& origin_tz,
const baldr::GraphId& pred_id,
baldr::GraphReader& reader,
const uint64_t& offset) {
if (origin_dt.empty()) {
return "";
} else if (!offset) {
return origin_dt;
}
graph_tile_ptr tile = nullptr;
uint32_t dest_tz = 0;
if (pred_id.Is_Valid()) {
// get the timezone of the output location
auto out_nodes = reader.GetDirectedEdgeNodes(pred_id, tile);
dest_tz = reader.GetTimezone(out_nodes.first, tile);
if (dest_tz == 0)
dest_tz = reader.GetTimezone(out_nodes.second, tile);
}

auto in_epoch =
baldr::DateTime::seconds_since_epoch(origin_dt,
baldr::DateTime::get_tz_db().from_index(origin_tz));
uint64_t out_epoch = in_epoch + offset;
std::string out_dt =
baldr::DateTime::seconds_to_date(out_epoch, baldr::DateTime::get_tz_db().from_index(dest_tz),
false);

return out_dt;
}

// return true if any location had a valid time set
// return false if it doesn't make sense computationally and add warnings accordingly
inline bool check_matrix_time(Api& request, const Matrix::Algorithm algo) {
Expand Down
6 changes: 0 additions & 6 deletions valhalla/thor/worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,6 @@ class thor_worker_t : public service_worker_t {

static void adjust_scores(valhalla::Options& options);

static std::string offset_date(baldr::GraphReader& reader,
const std::string& in_dt,
const baldr::GraphId& in_edge,
float offset,
const baldr::GraphId& out_edge);

void route(Api& request);
std::string matrix(Api& request);
void optimized_route(Api& request);
Expand Down

0 comments on commit d25c8ee

Please sign in to comment.