diff --git a/commands/command.cpp b/commands/command.cpp
index 721f51c64..aa1d18183 100644
--- a/commands/command.cpp
+++ b/commands/command.cpp
@@ -145,6 +145,11 @@ void purgeUnusedDiveSites()
 	execute(new PurgeUnusedDiveSites);
 }
 
+void applyGPSFixes(const std::vector<DiveAndLocation> &fixes)
+{
+	execute(new ApplyGPSFixes(fixes));
+}
+
 // Execute an edit-command and return number of edited dives
 static int execute_edit(EditDivesBase *cmd)
 {
diff --git a/commands/command.h b/commands/command.h
index 7a8ea81b0..281c1635c 100644
--- a/commands/command.h
+++ b/commands/command.h
@@ -5,6 +5,9 @@
 #include "core/dive.h"
 #include <QVector>
 #include <QAction>
+#include <vector>
+
+struct DiveAndLocation;
 
 // We put everything in a namespace, so that we can shorten names without polluting the global namespace
 namespace Command {
@@ -41,6 +44,7 @@ void splitDiveComputer(dive *d, int dc_num);
 void moveDiveComputerToFront(dive *d, int dc_num);
 void deleteDiveComputer(dive *d, int dc_num);
 void mergeDives(const QVector <dive *> &dives);
+void applyGPSFixes(const std::vector<DiveAndLocation> &fixes);
 
 // 3) Dive-site related commands
 
diff --git a/commands/command_divesite.cpp b/commands/command_divesite.cpp
index 56372ff41..8c61f224b 100644
--- a/commands/command_divesite.cpp
+++ b/commands/command_divesite.cpp
@@ -391,4 +391,51 @@ void MergeDiveSites::undo()
 	emit diveListNotifier.divesChanged(divesChanged, DiveField::DIVESITE);
 }
 
+ApplyGPSFixes::ApplyGPSFixes(const std::vector<DiveAndLocation> &fixes)
+{
+	setText(tr("apply GPS fixes"));
+
+	for (const DiveAndLocation &dl: fixes) {
+		struct dive_site *ds = dl.d->dive_site;
+		if (ds) {
+			// Arbitrary choice: if we find multiple fixes for the same dive, we use the first one.
+			if (std::find_if(siteLocations.begin(), siteLocations.end(),
+					 [ds] (const SiteAndLocation &sl) { return sl.ds == ds; }) == siteLocations.end()) {
+				siteLocations.push_back({ ds, dl.location });
+			}
+		} else {
+			ds = create_dive_site(qPrintable(dl.name), &dive_site_table);
+			ds->location = dl.location;
+			add_dive_to_dive_site(dl.d, ds);
+			dl.d->dive_site = nullptr; // This will be set on redo()
+			sitesToAdd.emplace_back(ds);
+		}
+	}
+}
+
+bool ApplyGPSFixes::workToBeDone()
+{
+	return !sitesToAdd.empty() || !siteLocations.empty();
+}
+
+void ApplyGPSFixes::editDiveSites()
+{
+	for (SiteAndLocation &sl: siteLocations) {
+		std::swap(sl.location, sl.ds->location);
+		emit diveListNotifier.diveSiteChanged(sl.ds, LocationInformationModel::LOCATION); // Inform frontend of changed dive site.
+	}
+}
+
+void ApplyGPSFixes::redo()
+{
+	sitesToRemove = addDiveSites(sitesToAdd);
+	editDiveSites();
+}
+
+void ApplyGPSFixes::undo()
+{
+	sitesToAdd = removeDiveSites(sitesToRemove);
+	editDiveSites();
+}
+
 } // namespace Command
diff --git a/commands/command_divesite.h b/commands/command_divesite.h
index 3fcf085ae..db0c5c73e 100644
--- a/commands/command_divesite.h
+++ b/commands/command_divesite.h
@@ -5,6 +5,7 @@
 #define COMMAND_DIVESITE_H
 
 #include "command_base.h"
+#include "core/gpslocation.h"
 
 #include <QVector>
 
@@ -110,7 +111,6 @@ private:
 	QString value; // Value to be set
 };
 
-
 class EditDiveSiteCountry : public Base {
 public:
 	EditDiveSiteCountry(dive_site *ds, const QString &country);
@@ -165,6 +165,30 @@ private:
 	std::vector<OwningDiveSitePtr> sitesToAdd;
 };
 
+class ApplyGPSFixes : public Base {
+public:
+	// Note: the dive site table is consumed after the call it will be empty.
+	ApplyGPSFixes(const std::vector<DiveAndLocation> &fixes);
+private:
+	bool workToBeDone() override;
+	void undo() override;
+	void redo() override;
+
+	// For undo
+	std::vector<dive_site *> sitesToRemove;
+
+	// For redo
+	std::vector<OwningDiveSitePtr> sitesToAdd;
+
+	// For redo and undo
+	struct SiteAndLocation {
+		dive_site *ds;
+		location_t location;
+	};
+	std::vector<SiteAndLocation> siteLocations;
+	void editDiveSites();
+};
+
 } // namespace Command
 
 #endif // COMMAND_DIVESITE_H