Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 18206)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 18207)
@@ -19,4 +19,5 @@
 import java.util.Objects;
 import java.util.Optional;
+import java.util.OptionalLong;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -33,4 +34,5 @@
 import org.openstreetmap.josm.tools.ListenerList;
 import org.openstreetmap.josm.tools.ListeningCollection;
+import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.date.Interval;
 
@@ -386,9 +388,48 @@
 
     /**
-     * Get all tracks contained in this data set.
+     * Get all tracks contained in this data set, without any guaranteed order.
      * @return The tracks.
      */
     public synchronized Collection<IGpxTrack> getTracks() {
         return Collections.unmodifiableCollection(privateTracks);
+    }
+
+    /**
+     * Get all tracks contained in this data set, ordered chronologically.
+     * @return The tracks in chronological order.
+     * @since 18207
+     */
+    public synchronized List<IGpxTrack> getOrderedTracks() {
+        return privateTracks.stream().sorted((t1, t2) -> {
+            boolean t1empty = Utils.isEmpty(t1.getSegments());
+            boolean t2empty = Utils.isEmpty(t2.getSegments());
+            if (t1empty && t2empty) {
+                return 0;
+            } else if (t1empty && !t2empty) {
+                return -1;
+            } else if (!t1empty && t2empty) {
+                return 1;
+            } else {
+                OptionalLong i1 = getTrackFirstWaypointMin(t1);
+                OptionalLong i2 = getTrackFirstWaypointMin(t2);
+                boolean i1absent = !i1.isPresent();
+                boolean i2absent = !i2.isPresent();
+                if (i1absent && i2absent) {
+                    return 0;
+                } else if (i1absent && !i2absent) {
+                    return 1;
+                } else if (!i1absent && i2absent) {
+                    return -1;
+                } else {
+                    return Long.compare(i1.getAsLong(), i2.getAsLong());
+                }
+            }
+        }).collect(Collectors.toList());
+    }
+
+    private static OptionalLong getTrackFirstWaypointMin(IGpxTrack track) {
+        return track.getSegments().stream().map(IGpxTrackSegment::getWayPoints)
+                .filter(Objects::nonNull).flatMap(Collection::stream)
+                .mapToLong(WayPoint::getTimeInMillis).min();
     }
 
Index: trunk/src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 18206)
+++ trunk/src/org/openstreetmap/josm/io/GpxWriter.java	(revision 18207)
@@ -266,5 +266,5 @@
 
     private void writeTracks() {
-        for (IGpxTrack trk : data.getTracks()) {
+        for (IGpxTrack trk : data.getOrderedTracks()) {
             openln("trk");
             writeAttr(trk, RTE_TRK_KEYS);
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 18206)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 18207)
@@ -650,5 +650,5 @@
     public static <T> List<T> toUnmodifiableList(Collection<T> collection) {
         // Java 9: use List.of(...)
-        if (collection == null || collection.isEmpty()) {
+        if (isEmpty(collection)) {
             return Collections.emptyList();
         } else if (collection.size() == 1) {
@@ -672,5 +672,5 @@
     @SuppressWarnings("unchecked")
     public static <K, V> Map<K, V> toUnmodifiableMap(Map<K, V> map) {
-        if (map == null || map.isEmpty()) {
+        if (isEmpty(map)) {
             return Collections.emptyMap();
         } else if (map.size() == 1) {
@@ -689,4 +689,34 @@
 
     /**
+     * Determines if a collection is null or empty.
+     * @param collection collection
+     * @return {@code true} if collection is null or empty
+     * @since 18207
+     */
+    public static boolean isEmpty(Collection<?> collection) {
+        return collection == null || collection.isEmpty();
+    }
+
+    /**
+     * Determines if a map is null or empty.
+     * @param map map
+     * @return {@code true} if map is null or empty
+     * @since 18207
+     */
+    public static boolean isEmpty(Map<?, ?> map) {
+        return map == null || map.isEmpty();
+    }
+
+    /**
+     * Determines if a string is null or empty.
+     * @param string string
+     * @return {@code true} if string is null or empty
+     * @since 18207
+     */
+    public static boolean isEmpty(String string) {
+        return string == null || string.isEmpty();
+    }
+
+    /**
      * Returns the first not empty string in the given candidates, otherwise the default string.
      * @param defaultString default string returned if all candidates would be empty if stripped
@@ -737,5 +767,5 @@
      */
     public static String strip(final String str, final String skipChars) {
-        if (str == null || str.isEmpty()) {
+        if (isEmpty(str)) {
             return str;
         }
@@ -774,5 +804,5 @@
      */
     public static String removeWhiteSpaces(String s) {
-        if (s == null || s.isEmpty()) {
+        if (isEmpty(s)) {
             return s;
         }
