Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxData.java	(revision 17715)
@@ -4,4 +4,5 @@
 import java.io.File;
 import java.text.MessageFormat;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -9,5 +10,4 @@
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -200,11 +200,11 @@
                 boolean split = false;
                 WayPoint prevLastOwnWp = null;
-                Date prevWpTime = null;
+                Instant prevWpTime = null;
                 for (WayPoint wp : wpsOld) {
-                    Date wpTime = wp.getDate();
+                    Instant wpTime = wp.getInstant();
                     boolean overlap = false;
                     if (wpTime != null) {
                         for (GpxTrackSegmentSpan ownspan : getSegmentSpans()) {
-                            if (wpTime.after(ownspan.firstTime) && wpTime.before(ownspan.lastTime)) {
+                            if (wpTime.isAfter(ownspan.firstTime) && wpTime.isBefore(ownspan.lastTime)) {
                                 overlap = true;
                                 if (connect) {
@@ -219,6 +219,6 @@
                                 break;
                             } else if (connect && prevWpTime != null
-                                    && prevWpTime.before(ownspan.firstTime)
-                                    && wpTime.after(ownspan.lastTime)) {
+                                    && prevWpTime.isBefore(ownspan.firstTime)
+                                    && wpTime.isAfter(ownspan.lastTime)) {
                                 // the overlapping high priority track is shorter than the distance
                                 // between two waypoints of the low priority track
@@ -287,6 +287,6 @@
     static class GpxTrackSegmentSpan {
 
-        final Date firstTime;
-        final Date lastTime;
+        final Instant firstTime;
+        final Instant lastTime;
         private final boolean inv;
         private final WayPoint firstWp;
@@ -294,7 +294,7 @@
 
         GpxTrackSegmentSpan(WayPoint a, WayPoint b) {
-            Date at = a.getDate();
-            Date bt = b.getDate();
-            inv = bt.before(at);
+            Instant at = a.getInstant();
+            Instant bt = b.getInstant();
+            inv = bt.isBefore(at);
             if (inv) {
                 firstWp = b;
@@ -333,6 +333,6 @@
 
         boolean overlapsWith(GpxTrackSegmentSpan other) {
-            return (firstTime.before(other.lastTime) && other.firstTime.before(lastTime))
-                || (other.firstTime.before(lastTime) && firstTime.before(other.lastTime));
+            return (firstTime.isBefore(other.lastTime) && other.firstTime.isBefore(lastTime))
+                || (other.firstTime.isBefore(lastTime) && firstTime.isBefore(other.lastTime));
         }
 
@@ -720,5 +720,5 @@
      * @return  minimum and maximum dates in array of 2 elements
      */
-    public static Date[] getMinMaxTimeForTrack(IGpxTrack trk) {
+    public static Instant[] getMinMaxTimeForTrack(IGpxTrack trk) {
         final LongSummaryStatistics statistics = trk.getSegments().stream()
                 .flatMap(seg -> seg.getWayPoints().stream())
@@ -727,5 +727,5 @@
         return statistics.getCount() == 0 || (statistics.getMin() == 0 && statistics.getMax() == 0)
                 ? null
-                : new Date[]{new Date(statistics.getMin()), new Date(statistics.getMax())};
+                : new Instant[]{Instant.ofEpochMilli(statistics.getMin()), Instant.ofEpochMilli(statistics.getMax())};
     }
 
@@ -737,5 +737,5 @@
     * @since 7319
     */
-    public synchronized Date[] getMinMaxTimeForAllTracks() {
+    public synchronized Instant[] getMinMaxTimeForAllTracks() {
         long now = System.currentTimeMillis();
         final LongSummaryStatistics statistics = tracks.stream()
@@ -746,6 +746,6 @@
                 .summaryStatistics();
         return statistics.getCount() == 0
-                ? new Date[0]
-                : new Date[]{new Date(statistics.getMin()), new Date(statistics.getMax())};
+                ? new Instant[0]
+                : new Instant[]{Instant.ofEpochMilli(statistics.getMin()), Instant.ofEpochMilli(statistics.getMax())};
     }
 
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java	(revision 17715)
@@ -3,5 +3,4 @@
 
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
@@ -226,5 +225,5 @@
                 final GpxImageEntry curImg = images.get(i);
                 final GpxImageEntry curTmp = curImg.getTmp();
-                final long time = curImg.getExifTime().getTime();
+                final long time = curImg.getExifInstant().toEpochMilli();
                 if ((!isLast && time > curWpTime) || time < prevWpTime) {
                     break;
@@ -239,5 +238,5 @@
                         curTmp.setPos(curWp.getCoor());
                     }
-                    curTmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
+                    curTmp.setGpsTime(curImg.getExifInstant().minusMillis(offset));
                     curTmp.flagNewGpsData();
                     curImg.tmpUpdated();
@@ -253,5 +252,5 @@
                 GpxImageEntry curImg = images.get(i);
                 GpxImageEntry curTmp = curImg.getTmp();
-                final long imgTime = curImg.getExifTime().getTime();
+                final long imgTime = curImg.getExifInstant().toEpochMilli();
                 if (imgTime < prevWpTime) {
                     break;
@@ -265,5 +264,5 @@
                         curTmp.setElevation(prevElevation + (curElevation - prevElevation) * timeDiff);
                     }
-                    curTmp.setGpsTime(new Date(curImg.getExifTime().getTime() - offset));
+                    curTmp.setGpsTime(curImg.getExifInstant().minusMillis(offset));
                     curTmp.flagNewGpsData();
                     curImg.tmpUpdated();
@@ -281,9 +280,9 @@
 
         // No photos or the first photo taken is later than the search period
-        if (lstSize == 0 || searchedTime < images.get(0).getExifTime().getTime())
+        if (lstSize == 0 || searchedTime < images.get(0).getExifInstant().toEpochMilli())
             return -1;
 
         // The search period is later than the last photo
-        if (searchedTime > images.get(lstSize - 1).getExifTime().getTime())
+        if (searchedTime > images.get(lstSize - 1).getExifInstant().toEpochMilli())
             return lstSize-1;
 
@@ -294,5 +293,5 @@
         while (endIndex - startIndex > 1) {
             curIndex = (endIndex + startIndex) / 2;
-            if (searchedTime > images.get(curIndex).getExifTime().getTime()) {
+            if (searchedTime > images.get(curIndex).getExifInstant().toEpochMilli()) {
                 startIndex = curIndex;
             } else {
@@ -300,10 +299,10 @@
             }
         }
-        if (searchedTime < images.get(endIndex).getExifTime().getTime())
+        if (searchedTime < images.get(endIndex).getExifInstant().toEpochMilli())
             return startIndex;
 
         // This final loop is to check if photos with the exact same EXIF time follows
-        while ((endIndex < (lstSize - 1)) && (images.get(endIndex).getExifTime().getTime()
-                == images.get(endIndex + 1).getExifTime().getTime())) {
+        while ((endIndex < (lstSize - 1)) && (images.get(endIndex).getExifInstant().toEpochMilli()
+                == images.get(endIndex + 1).getExifInstant().toEpochMilli())) {
             endIndex++;
         }
Index: trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java	(revision 17715)
@@ -6,4 +6,5 @@
 import java.io.File;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.Date;
 import java.util.List;
@@ -43,5 +44,5 @@
     private LatLon exifCoor;
     private Double exifImgDir;
-    private Date exifTime;
+    private Instant exifTime;
     /**
      * Flag isNewGpsData indicates that the GPS data of the image is new or has changed.
@@ -51,5 +52,5 @@
     private boolean isNewGpsData;
     /** Temporary source of GPS time if not correlated with GPX track. */
-    private Date exifGpsTime;
+    private Instant exifGpsTime;
 
     private String iptcCaption;
@@ -68,5 +69,5 @@
     private Double elevation;
     /** The time after correlation with a gpx track */
-    private Date gpsTime;
+    private Instant gpsTime;
 
     private int width;
@@ -173,5 +174,7 @@
      * is returned if that copy exists.
      * @return the GPS time value
-     */
+     * @deprecated Use {@link #getGpsInstant}
+     */
+    @Deprecated
     public Date getGpsTime() {
         if (tmp != null)
@@ -181,4 +184,13 @@
 
     /**
+     * Returns the GPS time value. The GPS time value from the temporary copy
+     * is returned if that copy exists.
+     * @return the GPS time value
+     */
+    public Instant getGpsInstant() {
+        return tmp != null ? tmp.gpsTime : gpsTime;
+    }
+
+    /**
      * Convenient way to determine if this entry has a GPS time, without the cost of building a defensive copy.
      * @return {@code true} if this entry has a GPS time
@@ -208,7 +220,17 @@
      * Returns EXIF time
      * @return EXIF time
-     */
+     * @deprecated Use {@link #getExifInstant}
+     */
+    @Deprecated
     public Date getExifTime() {
         return getDefensiveDate(exifTime);
+    }
+
+    /**
+     * Returns EXIF time
+     * @return EXIF time
+     */
+    public Instant getExifInstant() {
+        return exifTime;
     }
 
@@ -226,7 +248,17 @@
      * @return the EXIF GPS time
      * @since 6392
-     */
+     * @deprecated Use {@link #getExifGpsInstant}
+     */
+    @Deprecated
     public Date getExifGpsTime() {
         return getDefensiveDate(exifGpsTime);
+    }
+
+    /**
+     * Returns the EXIF GPS time.
+     * @return the EXIF GPS time
+     */
+    public Instant getExifGpsInstant() {
+        return exifGpsTime;
     }
 
@@ -240,8 +272,8 @@
     }
 
-    private static Date getDefensiveDate(Date date) {
+    private static Date getDefensiveDate(Instant date) {
         if (date == null)
             return null;
-        return new Date(date.getTime());
+        return Date.from(date);
     }
 
@@ -325,7 +357,9 @@
      * Sets EXIF time.
      * @param exifTime EXIF time
-     */
+     * @deprecated Use {@link #setExifTime(Instant)}
+     */
+    @Deprecated
     public void setExifTime(Date exifTime) {
-        this.exifTime = getDefensiveDate(exifTime);
+        this.exifTime = exifTime == null ? null : exifTime.toInstant();
     }
 
@@ -334,11 +368,43 @@
      * @param exifGpsTime the EXIF GPS time
      * @since 6392
-     */
+     * @deprecated Use {@link #setExifGpsTime(Instant)}
+     */
+    @Deprecated
     public void setExifGpsTime(Date exifGpsTime) {
-        this.exifGpsTime = getDefensiveDate(exifGpsTime);
-    }
-
+        this.exifGpsTime = exifGpsTime == null ? null : exifGpsTime.toInstant();
+    }
+
+    /**
+     * Sets the GPS time.
+     * @param gpsTime the GPS time
+     * @deprecated Use {@link #setGpsTime(Instant)}
+     */
+    @Deprecated
     public void setGpsTime(Date gpsTime) {
-        this.gpsTime = getDefensiveDate(gpsTime);
+        this.gpsTime = gpsTime == null ? null : gpsTime.toInstant();
+    }
+
+    /**
+     * Sets EXIF time.
+     * @param exifTime EXIF time
+     */
+    public void setExifTime(Instant exifTime) {
+        this.exifTime = exifTime;
+    }
+
+    /**
+     * Sets the EXIF GPS time.
+     * @param exifGpsTime the EXIF GPS time
+     */
+    public void setExifGpsTime(Instant exifGpsTime) {
+        this.exifGpsTime = exifGpsTime;
+    }
+
+    /**
+     * Sets the GPS time.
+     * @param gpsTime the GPS time
+     */
+    public void setGpsTime(Instant gpsTime) {
+        this.gpsTime = gpsTime;
     }
 
@@ -635,5 +701,5 @@
                         Logging.warn(topException);
                         Logging.info(tr("Can''t parse metadata for file \"{0}\". Using last modified date as timestamp.", fn));
-                        setExifTime(new Date(file.lastModified()));
+                        setExifTime(Instant.ofEpochMilli(file.lastModified()));
                         setExifCoor(null);
                         setPos(null);
@@ -646,7 +712,7 @@
         // Changed to silently cope with no time info in exif. One case
         // of person having time that couldn't be parsed, but valid GPS info
-        Date time = null;
+        Instant time = null;
         try {
-            time = ExifReader.readTime(metadata);
+            time = ExifReader.readInstant(metadata);
         } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException ex) {
             Logging.warn(ex);
@@ -655,5 +721,5 @@
         if (time == null) {
             Logging.info(tr("No EXIF time in file \"{0}\". Using last modified date as timestamp.", fn));
-            time = new Date(file.lastModified()); //use lastModified time if no EXIF time present
+            time = Instant.ofEpochMilli(file.lastModified()); //use lastModified time if no EXIF time present
         }
         setExifTime(time);
@@ -705,5 +771,5 @@
         }
 
-        ifNotNull(dirGps.getGpsDate(), this::setExifGpsTime);
+        ifNotNull(dirGps.getGpsDate(), d -> setExifGpsTime(d.toInstant()));
 
         IptcDirectory dirIptc = metadata.getFirstDirectoryOfType(IptcDirectory.class);
Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 17715)
@@ -3,4 +3,5 @@
 
 import java.awt.Color;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Date;
@@ -16,5 +17,4 @@
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.Utils;
-import org.openstreetmap.josm.tools.date.DateUtils;
 import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
 
@@ -66,7 +66,4 @@
         attr = new HashMap<>(0);
         attr.putAll(p.attr);
-        if (p.getDate() != null) {
-            attr.put(PT_TIME, p.getDate());
-        }
         lat = p.lat;
         lon = p.lon;
@@ -139,7 +136,9 @@
      * @param time the time to set
      * @since 9383
-     */
+     * @deprecated Use {@link #setInstant(Instant)}
+     */
+    @Deprecated
     public void setTime(Date time) {
-        setTimeInMillis(time.getTime());
+        setInstant(time.toInstant());
     }
 
@@ -149,7 +148,9 @@
      * @param ts seconds from the epoch
      * @since 13210
-     */
+     * @deprecated Use {@link #setInstant(Instant)}
+     */
+    @Deprecated
     public void setTime(long ts) {
-        setTimeInMillis(ts * 1000);
+        setInstant(Instant.ofEpochSecond(ts));
     }
 
@@ -161,5 +162,14 @@
      */
     public void setTimeInMillis(long ts) {
-        attr.put(PT_TIME, new Date(ts));
+        setInstant(Instant.ofEpochMilli(ts));
+    }
+
+    /**
+     * Sets the {@link #PT_TIME} attribute to the specified time.
+     *
+     * @param instant the time to set
+     */
+    public void setInstant(Instant instant) {
+        attr.put(PT_TIME, instant);
     }
 
@@ -185,6 +195,6 @@
      */
     public long getTimeInMillis() {
-        Date d = getDateImpl();
-        return d == null ? 0 : d.getTime();
+        Instant d = getInstant();
+        return d == null ? 0 : d.toEpochMilli();
     }
 
@@ -196,5 +206,5 @@
      */
     public boolean hasDate() {
-        return attr.get(PT_TIME) instanceof Date;
+        return attr.get(PT_TIME) instanceof Instant;
     }
 
@@ -204,20 +214,24 @@
      * @return a copy of the Date object associated with this waypoint
      * @since 14456
-     */
+     * @deprecated Use {@link #getInstant()}
+     */
+    @Deprecated
     public Date getDate() {
-        return DateUtils.cloneDate(getDateImpl());
-    }
-
-    /**
-     * Returns the waypoint time Date object.
-     *
-     * @return the Date object associated with this waypoint
-     */
-    private Date getDateImpl() {
+        Instant instant = getInstant();
+        return instant == null ? null : Date.from(instant);
+    }
+
+    /**
+     * Returns the waypoint instant.
+     *
+     * @return the instant associated with this waypoint
+     * @since 14456
+     */
+    public Instant getInstant() {
         if (attr != null) {
             final Object obj = attr.get(PT_TIME);
 
-            if (obj instanceof Date) {
-                return (Date) obj;
+            if (obj instanceof Instant) {
+                return (Instant) obj;
             } else if (obj == null) {
                 Logging.trace("Waypoint {0} value unset", PT_TIME);
Index: trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 17715)
@@ -10,5 +10,8 @@
 import java.awt.event.ActionEvent;
 import java.io.File;
-import java.text.DateFormat;
+import java.time.Instant;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -157,5 +160,5 @@
      */
     public static String getTimespanForTrack(IGpxTrack trk) {
-        Date[] bounds = GpxData.getMinMaxTimeForTrack(trk);
+        Instant[] bounds = GpxData.getMinMaxTimeForTrack(trk);
         return bounds != null ? formatTimespan(bounds) : "";
     }
@@ -166,20 +169,20 @@
      * @return The timespan as a string
      */
-    public static String formatTimespan(Date[] bounds) {
+    public static String formatTimespan(Instant[] bounds) {
         String ts = "";
-        DateFormat df = DateUtils.getDateFormat(DateFormat.SHORT);
+        DateTimeFormatter df = DateUtils.getDateFormatter(FormatStyle.SHORT);
         String earliestDate = df.format(bounds[0]);
         String latestDate = df.format(bounds[1]);
 
         if (earliestDate.equals(latestDate)) {
-            DateFormat tf = DateUtils.getTimeFormat(DateFormat.SHORT);
+            DateTimeFormatter tf = DateUtils.getTimeFormatter(FormatStyle.SHORT);
             ts += earliestDate + ' ';
             ts += tf.format(bounds[0]) + " - " + tf.format(bounds[1]);
         } else {
-            DateFormat dtf = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
+            DateTimeFormatter dtf = DateUtils.getDateTimeFormatter(FormatStyle.SHORT, FormatStyle.MEDIUM);
             ts += dtf.format(bounds[0]) + " - " + dtf.format(bounds[1]);
         }
 
-        int diff = (int) (bounds[1].getTime() - bounds[0].getTime()) / 1000;
+        long diff = ChronoUnit.SECONDS.between(bounds[1], bounds[0]);
         ts += String.format(" (%d:%02d)", diff / 3600, (diff % 3600) / 60);
         return ts;
@@ -355,8 +358,8 @@
         long to = toDate.getTime();
         for (IGpxTrack trk : data.getTracks()) {
-            Date[] t = GpxData.getMinMaxTimeForTrack(trk);
+            Instant[] t = GpxData.getMinMaxTimeForTrack(trk);
 
             if (t == null) continue;
-            long tm = t[1].getTime();
+            long tm = t[1].toEpochMilli();
             trackVisibility[i] = (tm == 0 && showWithoutDate) || (from <= tm && tm <= to);
             i++;
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 17715)
@@ -24,4 +24,5 @@
 import java.io.IOException;
 import java.time.DateTimeException;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -878,5 +879,5 @@
                 wpt.setTimeInMillis(DateUtils.tsFromString(v));
             } else if (!n.isTimestampEmpty()) {
-                wpt.setTime(Integer.toUnsignedLong(n.getRawTimestamp()));
+                wpt.setInstant(Instant.ofEpochSecond(Integer.toUnsignedLong(n.getRawTimestamp())));
             }
         } catch (UncheckedParseException | DateTimeException e) {
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 17715)
@@ -28,9 +28,12 @@
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Date;
 import java.util.Dictionary;
 import java.util.Hashtable;
@@ -768,8 +771,8 @@
         void updateExifComponents(ImageEntry img) {
             imgDisp.setImage(img);
-            Date date = img.getExifTime();
+            Instant date = img.getExifInstant();
             if (date != null) {
-                DateFormat df = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
-                df.setTimeZone(DateUtils.UTC); // EXIF data does not contain timezone information and is read as UTC
+                DateTimeFormatter df = DateUtils.getDateTimeFormatter(FormatStyle.SHORT, FormatStyle.MEDIUM)
+                        .withZone(ZoneOffset.UTC); // EXIF data does not contain timezone information and is read as UTC
                 lbExifTime.setText(df.format(date));
                 tfGpsTime.setText(df.format(date));
@@ -1260,5 +1263,5 @@
 
         // Init variables
-        long firstExifDate = imgs.get(0).getExifTime().getTime();
+        long firstExifDate = imgs.get(0).getExifInstant().toEpochMilli();
 
         // Finds first GPX point
@@ -1334,5 +1337,5 @@
                 .filter(e -> e.getExifCoor() == null || exif)
                 .filter(e -> tagged || !e.isTagged() || e.getExifCoor() != null)
-                .sorted(Comparator.comparing(ImageEntry::getExifTime))
+                .sorted(Comparator.comparing(ImageEntry::getExifInstant))
                 .collect(Collectors.toList());
     }
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java	(revision 17715)
@@ -13,6 +13,7 @@
 import java.awt.event.KeyEvent;
 import java.awt.event.WindowEvent;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
 import java.util.Collections;
 import java.util.List;
@@ -472,21 +473,14 @@
             }
 
-            DateFormat dtf = DateUtils.getDateTimeFormat(DateFormat.SHORT, DateFormat.MEDIUM);
-            // Make sure date/time format includes milliseconds
-            if (dtf instanceof SimpleDateFormat) {
-                String pattern = ((SimpleDateFormat) dtf).toPattern();
-                if (!pattern.contains(".SSS")) {
-                    dtf = new SimpleDateFormat(pattern.replace(":ss", ":ss.SSS"));
-                }
-            }
-            // Set timezone to UTC since UTC is assumed when parsing the EXIF timestamp,
-            // see see org.openstreetmap.josm.tools.ExifReader.readTime(com.drew.metadata.Metadata)
-            dtf.setTimeZone(DateUtils.UTC);
+            DateTimeFormatter dtf = DateUtils.getDateTimeFormatter(FormatStyle.SHORT, FormatStyle.MEDIUM)
+                    // Set timezone to UTC since UTC is assumed when parsing the EXIF timestamp,
+                    // see see org.openstreetmap.josm.tools.ExifReader.readTime(com.drew.metadata.Metadata)
+                    .withZone(ZoneOffset.UTC);
 
             if (entry.hasExifTime()) {
-                osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifTime())));
+                osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifInstant())));
             }
             if (entry.hasGpsTime()) {
-                osd.append(tr("\nGPS time: {0}", dtf.format(entry.getGpsTime())));
+                osd.append(tr("\nGPS time: {0}", dtf.format(entry.getGpsInstant())));
             }
             Optional.ofNullable(entry.getIptcCaption()).map(s -> tr("\nCaption: {0}", s)).ifPresent(osd::append);
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/ChooseTrackVisibilityAction.java	(revision 17715)
@@ -13,4 +13,5 @@
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Comparator;
@@ -88,5 +89,5 @@
             String name = (String) Optional.ofNullable(attr.get(GpxConstants.GPX_NAME)).orElse("");
             String desc = (String) Optional.ofNullable(attr.get(GpxConstants.GPX_DESC)).orElse("");
-            Date[] time = GpxData.getMinMaxTimeForTrack(trk);
+            Instant[] time = GpxData.getMinMaxTimeForTrack(trk);
             String url = (String) Optional.ofNullable(attr.get("url")).orElse("");
             tracks[i] = new Object[]{name, desc, time, trk.length(), url, trk};
@@ -140,5 +141,5 @@
         t.setRowSorter(rowSorter);
         rowSorter.setModel(model);
-        rowSorter.setComparator(2, Comparator.comparing((Date[] d) -> d == null ? Long.MIN_VALUE : d[0].getTime()));
+        rowSorter.setComparator(2, Comparator.comparing((Instant[] d) -> d == null ? Instant.MIN : d[0]));
         rowSorter.setComparator(3, Comparator.comparingDouble(length -> (double) length));
         // default column widths
@@ -150,6 +151,6 @@
             public Component getTableCellRendererComponent(
                     JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
-                if (value instanceof Date[]) {
-                    value = GpxLayer.formatTimespan(((Date[]) value));
+                if (value instanceof Instant[]) {
+                    value = GpxLayer.formatTimespan(((Instant[]) value));
                 }
                 return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 17715)
@@ -7,4 +7,5 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Date;
@@ -36,5 +37,4 @@
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.GBC;
-import org.openstreetmap.josm.tools.date.DateUtils;
 
 /**
@@ -123,5 +123,5 @@
             String key = entry.getKey();
             Object obj = entry.getValue();
-            if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Number || obj instanceof Date)) {
+            if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Number || obj instanceof Instant)) {
                 keys.add(key);
             }
@@ -129,11 +129,11 @@
                 // only convert when required
                 p.put(GpxConstants.GPX_PREFIX + key, obj.toString());
-            } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
+            } else if (obj instanceof Instant && GpxConstants.PT_TIME.equals(key)) {
                 // timestamps should always be converted
-                Date date = (Date) obj;
+                Instant date = (Instant) obj;
                 if (!none) { //... but the tag will only be set when required
-                    p.put(GpxConstants.GPX_PREFIX + key, DateUtils.fromDate(date));
-                }
-                p.setTimestamp(date);
+                    p.put(GpxConstants.GPX_PREFIX + key, String.valueOf(date));
+                }
+                p.setTimestamp(Date.from(date));
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java	(revision 17715)
@@ -7,4 +7,5 @@
 import java.awt.GridBagLayout;
 import java.awt.event.ActionListener;
+import java.time.Instant;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
@@ -52,7 +53,12 @@
 
         final Date startTime, endTime;
-        Date[] bounds = layer.data.getMinMaxTimeForAllTracks();
-        startTime = (bounds.length == 0) ? Date.from(ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()).toInstant()) : bounds[0];
-        endTime = (bounds.length == 0) ? new Date() : bounds[1];
+        Instant[] bounds = layer.data.getMinMaxTimeForAllTracks();
+        if (bounds.length == 0) {
+            startTime = Date.from(ZonedDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneId.systemDefault()).toInstant());
+            endTime = new Date();
+        } else {
+            startTime = Date.from(bounds[0]);
+            endTime = Date.from(bounds[1]);
+        }
 
         dateFrom.setDate(startTime);
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java	(revision 17715)
@@ -22,8 +22,8 @@
 import java.io.BufferedReader;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.Date;
 import java.util.LinkedList;
 import java.util.List;
@@ -565,8 +565,8 @@
         double now = System.currentTimeMillis()/1000.0;
         if (colored == ColorMode.TIME) {
-            Date[] bounds = data.getMinMaxTimeForAllTracks();
+            Instant[] bounds = data.getMinMaxTimeForAllTracks();
             if (bounds.length >= 2) {
-                minval = bounds[0].getTime()/1000.0;
-                maxval = bounds[1].getTime()/1000.0;
+                minval = bounds[0].getEpochSecond();
+                maxval = bounds[1].getEpochSecond();
             } else {
                 minval = 0;
Index: trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 17715)
@@ -366,5 +366,5 @@
                     // As this sentence has no complete time only use it
                     // if there is no time so far
-                    currentwp.setTime(d);
+                    currentwp.setInstant(d.toInstant());
                 }
                 // elevation
@@ -494,5 +494,5 @@
                 }
                 // time: this sentence has complete time so always use it.
-                currentwp.setTime(d);
+                currentwp.setInstant(d.toInstant());
                 // speed
                 accu = e[RMC.SPEED.position];
@@ -544,5 +544,5 @@
             if (ps.pWp != currentwp) {
                 if (ps.pWp != null) {
-                    ps.pWp.getDate();
+                    ps.pWp.getInstant();
                 }
                 ps.pWp = currentwp;
Index: trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/io/rtklib/RtkLibPosReader.java	(revision 17715)
@@ -91,5 +91,5 @@
                                     Double.parseDouble(fields[IDX_LON])));
                             currentwp.put(GpxConstants.PT_ELE, fields[IDX_HEIGHT]);
-                            currentwp.setTime(parseDate(fields[IDX_DATE]+" "+fields[IDX_TIME]));
+                            currentwp.setInstant(parseDate(fields[IDX_DATE]+" "+fields[IDX_TIME]).toInstant());
                             currentwp.put(GpxConstants.RTKLIB_Q, Integer.parseInt(fields[IDX_Q]));
                             currentwp.put(GpxConstants.PT_SAT, fields[IDX_NS]);
Index: trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionExporter.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionExporter.java	(revision 17715)
@@ -87,5 +87,5 @@
             }
             if (entry.hasGpsTime()) {
-                addAttr("gps-time", Long.toString(entry.getGpsTime().getTime()), imgElem, support);
+                addAttr("gps-time", Long.toString(entry.getGpsInstant().toEpochMilli()), imgElem, support);
             }
             if (entry.getExifOrientation() != null) {
@@ -93,8 +93,8 @@
             }
             if (entry.hasExifTime()) {
-                addAttr("exif-time", Long.toString(entry.getExifTime().getTime()), imgElem, support);
+                addAttr("exif-time", Long.toString(entry.getExifInstant().toEpochMilli()), imgElem, support);
             }
             if (entry.hasExifGpsTime()) {
-                addAttr("exif-gps-time", Long.toString(entry.getExifGpsTime().getTime()), imgElem, support);
+                addAttr("exif-gps-time", Long.toString(entry.getExifGpsInstant().toEpochMilli()), imgElem, support);
             }
             if (entry.getExifCoor() != null) {
Index: trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java	(revision 17715)
@@ -6,6 +6,6 @@
 import java.io.File;
 import java.io.IOException;
+import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 
@@ -90,5 +90,5 @@
                 break;
             case "gps-time":
-                entry.setGpsTime(new Date(Long.parseLong(attrElem.getTextContent())));
+                entry.setGpsTime(Instant.ofEpochMilli(Long.parseLong(attrElem.getTextContent())));
                 break;
             case "exif-orientation":
@@ -96,8 +96,8 @@
                 break;
             case "exif-time":
-                entry.setExifTime(new Date(Long.parseLong(attrElem.getTextContent())));
+                entry.setExifTime(Instant.ofEpochMilli(Long.parseLong(attrElem.getTextContent())));
                 break;
             case "exif-gps-time":
-                entry.setExifGpsTime(new Date(Long.parseLong(attrElem.getTextContent())));
+                entry.setExifGpsTime(Instant.ofEpochMilli(Long.parseLong(attrElem.getTextContent())));
                 break;
             case "exif-coordinates":
Index: trunk/src/org/openstreetmap/josm/tools/ExifReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 17715)
@@ -6,4 +6,5 @@
 import java.io.IOException;
 import java.time.DateTimeException;
+import java.time.Instant;
 import java.util.Date;
 import java.util.List;
@@ -42,9 +43,21 @@
      * @param filename The JPEG file to read
      * @return The date/time read in the EXIF section, or {@code null} if not found
-     */
+     * @deprecated Use {@link #readInstant(File)}
+     */
+    @Deprecated
     public static Date readTime(File filename) {
-        try {
-            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
-            return readTime(metadata);
+        Instant instant = readInstant(filename);
+        return instant == null ? null : Date.from(instant);
+    }
+
+    /**
+     * Returns the date/time from the given JPEG file.
+     * @param filename The JPEG file to read
+     * @return The date/time read in the EXIF section, or {@code null} if not found
+     */
+    public static Instant readInstant(File filename) {
+        try {
+            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
+            return readInstant(metadata);
         } catch (JpegProcessingException | IOException e) {
             Logging.error(e);
@@ -58,6 +71,18 @@
      * @return The date/time read in the EXIF section, or {@code null} if not found
      * @since 11745
-     */
+     * @deprecated Use {@link #readInstant(Metadata)}
+     */
+    @Deprecated
     public static Date readTime(Metadata metadata) {
+        Instant instant = readInstant(metadata);
+        return instant == null ? null : Date.from(instant);
+    }
+
+    /**
+     * Returns the date/time from the given JPEG file.
+     * @param metadata The EXIF metadata
+     * @return The date/time read in the EXIF section, or {@code null} if not found
+     */
+    public static Instant readInstant(Metadata metadata) {
         try {
             String dateTimeOrig = null;
@@ -109,8 +134,8 @@
             if (dateStr != null) {
                 dateStr = dateStr.replace('/', ':'); // workaround for HTC Sensation bug, see #7228
-                final Date date = DateUtils.fromString(dateStr);
+                Instant date = DateUtils.parseInstant(dateStr);
                 if (subSeconds != null) {
                     try {
-                        date.setTime(date.getTime() + (long) (TimeUnit.SECONDS.toMillis(1) * Double.parseDouble("0." + subSeconds)));
+                        date = date.plusMillis((long) (TimeUnit.SECONDS.toMillis(1) * Double.parseDouble("0." + subSeconds)));
                     } catch (NumberFormatException e) {
                         Logging.warn("Failed parsing sub seconds from [{0}]", subSeconds);
Index: trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 17714)
+++ trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 17715)
@@ -287,5 +287,7 @@
      * @return the date format used for GPX waypoints
      * @since 14055
-     */
+     * @deprecated Use {@link Instant#toString()}
+     */
+    @Deprecated
     public static DateFormat getGpxFormat() {
         SimpleDateFormat result = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
