Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 17749)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Date;
@@ -112,11 +113,11 @@
                 // A changeset does not contain all referred primitives, this is the map of incomplete ones
                 // For each incomplete primitive, we'll have to get its state at date it was referred
-                Map<OsmPrimitive, Date> toLoad = new HashMap<>();
+                Map<OsmPrimitive, Instant> toLoad = new HashMap<>();
                 for (OsmPrimitive p : downloadedData.allNonDeletedPrimitives()) {
                     if (p.isIncomplete()) {
-                        Date timestamp = p.getReferrers().stream()
+                        Instant timestamp = p.getReferrers().stream()
                                 .filter(ref -> !ref.isTimestampEmpty())
                                 .findFirst()
-                                .map(AbstractPrimitive::getTimestamp)
+                                .map(AbstractPrimitive::getInstant)
                                 .orElse(null);
                         toLoad.put(p, timestamp);
@@ -138,7 +139,7 @@
     private static final class HistoryLoaderAndListener extends HistoryLoadTask implements HistoryDataSetListener {
 
-        private final Map<OsmPrimitive, Date> toLoad;
-
-        private HistoryLoaderAndListener(Map<OsmPrimitive, Date> toLoad) {
+        private final Map<OsmPrimitive, Instant> toLoad;
+
+        private HistoryLoaderAndListener(Map<OsmPrimitive, Instant> toLoad) {
             this.toLoad = toLoad;
             this.setChangesetDataNeeded(false);
@@ -150,14 +151,14 @@
         @Override
         public void historyUpdated(HistoryDataSet source, PrimitiveId id) {
-            Map<OsmPrimitive, Date> toLoadNext = new HashMap<>();
-            for (Iterator<Entry<OsmPrimitive, Date>> it = toLoad.entrySet().iterator(); it.hasNext();) {
-                Entry<OsmPrimitive, Date> entry = it.next();
+            Map<OsmPrimitive, Instant> toLoadNext = new HashMap<>();
+            for (Iterator<Entry<OsmPrimitive, Instant>> it = toLoad.entrySet().iterator(); it.hasNext();) {
+                Entry<OsmPrimitive, Instant> entry = it.next();
                 OsmPrimitive p = entry.getKey();
                 History history = source.getHistory(p.getPrimitiveId());
-                Date date = entry.getValue();
+                Instant date = entry.getValue();
                 // If the history has been loaded and a timestamp is known
                 if (history != null && date != null) {
                     // Lookup for the primitive version at the specified timestamp
-                    HistoryOsmPrimitive hp = history.getByDate(date);
+                    HistoryOsmPrimitive hp = history.getByDate(Date.from(date));
                     if (hp != null) {
                         PrimitiveData data;
Index: /trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/AbstractPrimitive.java	(revision 17749)
@@ -5,4 +5,5 @@
 
 import java.text.MessageFormat;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collection;
@@ -297,4 +298,5 @@
     }
 
+    @Deprecated
     @Override
     public void setTimestamp(Date timestamp) {
@@ -303,11 +305,22 @@
 
     @Override
+    public void setInstant(Instant timestamp) {
+        this.timestamp = (int) timestamp.getEpochSecond();
+    }
+
+    @Override
     public void setRawTimestamp(int timestamp) {
         this.timestamp = timestamp;
     }
 
+    @Deprecated
     @Override
     public Date getTimestamp() {
-        return new Date(TimeUnit.SECONDS.toMillis(Integer.toUnsignedLong(timestamp)));
+        return Date.from(getInstant());
+    }
+
+    @Override
+    public Instant getInstant() {
+        return Instant.ofEpochSecond(Integer.toUnsignedLong(timestamp));
     }
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 17749)
@@ -103,5 +103,5 @@
         final Changeset changeset = new Changeset(primitive.getChangesetId());
         changeset.setUser(primitive.getUser());
-        changeset.setCreatedAt(primitive.getTimestamp().toInstant()); // not accurate in all cases
+        changeset.setCreatedAt(primitive.getInstant()); // not accurate in all cases
         return changeset;
     }
Index: /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/IPrimitive.java	(revision 17749)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.data.osm;
 
+import java.time.Instant;
 import java.util.Date;
 import java.util.List;
@@ -276,5 +277,7 @@
      * @return date of last modification
      * @see #setTimestamp
-     */
+     * @deprecated Use {@link #getInstant}
+     */
+    @Deprecated
     Date getTimestamp();
 
@@ -284,4 +287,14 @@
      * used to check against edit conflicts.
      *
+     * @return date of last modification
+     * @see #getInstant
+     */
+    Instant getInstant();
+
+    /**
+     * Time of last modification to this object. This is not set by JOSM but
+     * read from the server and delivered back to the server unmodified. It is
+     * used to check against edit conflicts.
+     *
      * @return last modification as timestamp
      * @see #setRawTimestamp
@@ -293,6 +306,15 @@
      * @param timestamp date of last modification
      * @see #getTimestamp
-     */
+     * @deprecated Use {@link #setInstant}
+     */
+    @Deprecated
     void setTimestamp(Date timestamp);
+
+    /**
+     * Sets time of last modification to this object
+     * @param timestamp date of last modification
+     * @see #getInstant
+     */
+    void setInstant(Instant timestamp);
 
     /**
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 17749)
@@ -301,4 +301,5 @@
     }
 
+    @Deprecated
     @Override
     public void setTimestamp(Date timestamp) {
Index: /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java	(revision 17749)
@@ -96,5 +96,5 @@
      */
     protected HistoryOsmPrimitive(OsmPrimitive p) {
-        this(p.getId(), p.getVersion(), p.isVisible(), p.getUser(), p.getChangesetId(), p.getTimestamp());
+        this(p.getId(), p.getVersion(), p.isVisible(), p.getUser(), p.getChangesetId(), Date.from(p.getInstant()));
     }
 
@@ -364,5 +364,5 @@
             Logging.log(Logging.LEVEL_ERROR, "Cannot change visibility for "+data+':', e);
         }
-        data.setTimestamp(timestamp);
+        data.setInstant(timestamp.toInstant());
         data.setKeys(tags);
         data.setOsmId(id, (int) version);
Index: /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/data/osm/search/SearchCompiler.java	(revision 17749)
@@ -741,5 +741,5 @@
             String mv;
             if ("timestamp".equals(key) && osm instanceof OsmPrimitive) {
-                mv = DateUtils.fromTimestamp(((OsmPrimitive) osm).getRawTimestamp());
+                mv = ((OsmPrimitive) osm).getInstant().toString();
             } else {
                 mv = osm.get(key);
@@ -1493,5 +1493,5 @@
             try {
                 // if min timestamp is empty: use lowest possible date
-                minDate = DateUtils.fromString(rangeA1.isEmpty() ? "1980" : rangeA1).getTime();
+                minDate = DateUtils.parseInstant(rangeA1.isEmpty() ? "1980" : rangeA1).toEpochMilli();
             } catch (UncheckedParseException | DateTimeException ex) {
                 throw new SearchParseError(tr("Cannot parse timestamp ''{0}''", rangeA1), ex);
@@ -1499,5 +1499,5 @@
             try {
                 // if max timestamp is empty: use "now"
-                maxDate = rangeA2.isEmpty() ? System.currentTimeMillis() : DateUtils.fromString(rangeA2).getTime();
+                maxDate = rangeA2.isEmpty() ? System.currentTimeMillis() : DateUtils.parseInstant(rangeA2).toEpochMilli();
             } catch (UncheckedParseException | DateTimeException ex) {
                 throw new SearchParseError(tr("Cannot parse timestamp ''{0}''", rangeA2), ex);
@@ -1508,5 +1508,5 @@
         @Override
         protected Long getNumber(OsmPrimitive osm) {
-            return osm.getTimestamp().getTime();
+            return osm.getInstant().toEpochMilli();
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDataText.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDataText.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDataText.java	(revision 17749)
@@ -154,5 +154,5 @@
         add(tr("Data Set: "), Integer.toHexString(o.getDataSet().hashCode()));
         add(tr("Edited at: "), o.isTimestampEmpty() ? tr("<new object>")
-                : DateUtils.fromTimestamp(o.getRawTimestamp()));
+                : o.getInstant().toString());
         add(tr("Edited by: "), o.getUser() == null ? tr("<new object>")
                 : getNameAndId(o.getUser().getName(), o.getUser().getId()));
Index: /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java	(revision 17749)
@@ -236,5 +236,6 @@
      */
     public void update(final OsmPrimitive primitive, final boolean isLatest) {
-        update(Changeset.fromPrimitive(primitive), isLatest, primitive.getTimestamp(), primitive.getVersion(), primitive.getPrimitiveId());
+        Date timestamp = Date.from(primitive.getInstant());
+        update(Changeset.fromPrimitive(primitive), isLatest, timestamp, primitive.getVersion(), primitive.getPrimitiveId());
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 17749)
@@ -24,5 +24,4 @@
 import java.io.IOException;
 import java.time.DateTimeException;
-import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -877,7 +876,7 @@
                 wpt.setTimeInMillis(time);
             } else if ((v = gpxVal(n, GpxConstants.PT_TIME)) != null) {
-                wpt.setTimeInMillis(DateUtils.tsFromString(v));
+                wpt.setInstant(DateUtils.parseInstant(v));
             } else if (!n.isTimestampEmpty()) {
-                wpt.setInstant(Instant.ofEpochSecond(Integer.toUnsignedLong(n.getRawTimestamp())));
+                wpt.setInstant(n.getInstant());
             }
         } catch (UncheckedParseException | DateTimeException e) {
Index: /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java	(revision 17749)
@@ -9,5 +9,4 @@
 import java.time.Instant;
 import java.util.ArrayList;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -135,5 +134,5 @@
                     p.put(GpxConstants.GPX_PREFIX + key, String.valueOf(date));
                 }
-                p.setTimestamp(Date.from(date));
+                p.setInstant(date);
             }
         }
Index: /trunk/src/org/openstreetmap/josm/io/AbstractReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/io/AbstractReader.java	(revision 17749)
@@ -431,5 +431,5 @@
         }
         try {
-            int timestamp = timestampCache.computeIfAbsent(time, t -> (int) (DateUtils.tsFromString(t) / 1000));
+            int timestamp = timestampCache.computeIfAbsent(time, t -> (int) (DateUtils.parseInstant(t).getEpochSecond()));
             current.setRawTimestamp(timestamp);
         } catch (UncheckedParseException | DateTimeException e) {
Index: /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 17749)
@@ -9,5 +9,4 @@
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -153,5 +152,5 @@
                     // TODO is there a way to obtain the timestamp for non-closed changesets?
                     Instant instant = Utils.firstNonNull(cs.getClosedAt(), Instant.now());
-                    p.setTimestamp(Date.from(instant));
+                    p.setInstant(instant);
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 17748)
+++ /trunk/src/org/openstreetmap/josm/io/OsmWriter.java	(revision 17749)
@@ -366,5 +366,5 @@
             }
             if (!osm.isTimestampEmpty()) {
-                out.print(" timestamp='"+DateUtils.fromTimestamp(osm.getRawTimestamp())+'\'');
+                out.print(" timestamp='"+osm.getInstant()+'\'');
             }
             // user and visible added with 0.4 API
Index: /trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java	(revision 17748)
+++ /trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java	(revision 17749)
@@ -14,5 +14,4 @@
 import java.time.Instant;
 import java.util.Arrays;
-import java.util.Date;
 
 import org.junit.jupiter.api.AfterEach;
@@ -25,5 +24,4 @@
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
-import org.openstreetmap.josm.tools.date.DateUtils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -307,5 +305,5 @@
         n.put("key1", "value1");
         n.setUser(myUser);
-        n.setTimestamp(new Date());
+        n.setInstant(Instant.now());
 
         my.addPrimitive(n);
@@ -314,5 +312,5 @@
         n1.setCoor(LatLon.ZERO);
         n1.put("key1", "value1");
-        n1.setTimestamp(Date.from(Instant.now().plusSeconds(3600)));
+        n1.setInstant(Instant.now().plusSeconds(3600));
         n1.setUser(theirUser);
         their.addPrimitive(n1);
@@ -346,5 +344,5 @@
         n1.setOsmId(1, 1);
         n1.put("key1", "value1");
-        n1.setTimestamp(new Date());
+        n1.setInstant(Instant.now());
         their.addPrimitive(n1);
 
@@ -646,5 +644,5 @@
         User user = User.createOsmUser(1111, "their");
         theirWay.setUser(user);
-        theirWay.setTimestamp(new Date());
+        theirWay.setInstant(Instant.now());
         their.addPrimitive(theirWay);
 
@@ -699,5 +697,5 @@
         User user = User.createOsmUser(1111, "their");
         theirWay.setUser(user);
-        theirWay.setTimestamp(new Date());
+        theirWay.setInstant(Instant.now());
         their.addPrimitive(theirWay);
 
@@ -754,5 +752,5 @@
         theirWay.addNode(tn3);
         theirWay.setUser(User.createOsmUser(1111, "their"));
-        theirWay.setTimestamp(new Date());
+        theirWay.setInstant(Instant.now());
         their.addPrimitive(theirWay);
 
@@ -1182,5 +1180,5 @@
         Node nA = new Node(2848219691L, 1);
         nA.setCoor(LatLon.ZERO);
-        nA.setTimestamp(DateUtils.fromString("2014-05-10T14:25:40Z"));
+        nA.setInstant(Instant.parse("2014-05-10T14:25:40Z"));
         nA.setChangesetId(22251108);
         nA.setUser(User.createOsmUser(385987, "yaho"));
Index: /trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(revision 17748)
+++ /trunk/test/unit/org/openstreetmap/josm/data/osm/search/SearchCompilerTest.java	(revision 17749)
@@ -13,4 +13,5 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
+import java.time.Instant;
 import java.util.Arrays;
 import java.util.Collection;
@@ -44,5 +45,4 @@
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 import org.openstreetmap.josm.tools.Logging;
-import org.openstreetmap.josm.tools.date.DateUtils;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@@ -449,5 +449,5 @@
     void testTimestamp() throws SearchParseError {
         final Node n1 = new Node();
-        n1.setTimestamp(DateUtils.fromString("2010-01-22"));
+        n1.setInstant(Instant.parse("2010-01-22T00:00:00Z"));
         assertTrue(SearchCompiler.compile("timestamp:2010/2011").match(n1));
         assertTrue(SearchCompiler.compile("timestamp:2010-01/2011").match(n1));
@@ -455,5 +455,5 @@
         assertFalse(SearchCompiler.compile("timestamp:2010-01-23/2011").match(n1));
         assertFalse(SearchCompiler.compile("timestamp:2010/2010-01-21").match(n1));
-        n1.setTimestamp(DateUtils.fromString("2016-01-22"));
+        n1.setInstant(Instant.parse("2016-01-22T00:00:00Z"));
         assertFalse(SearchCompiler.compile("timestamp:2010/2011").match(n1));
     }
Index: /trunk/test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java	(revision 17748)
+++ /trunk/test/unit/org/openstreetmap/josm/io/OsmJsonReaderTest.java	(revision 17749)
@@ -9,4 +9,5 @@
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
+import java.time.Instant;
 import java.util.Iterator;
 
@@ -131,5 +132,5 @@
         assertEquals(1, n.getUniqueId());
         assertEquals(new LatLon(2.0, -3.0), n.getCoor());
-        assertEquals("2018-01-01T00:00:00Z", DateUtils.newIsoDateTimeFormat().format(n.getTimestamp()));
+        assertEquals(Instant.parse("2018-01-01T00:00:00Z"), n.getInstant());
         assertEquals(4, n.getVersion());
         assertEquals(5, n.getChangesetId());
Index: /trunk/test/unit/org/openstreetmap/josm/io/OsmWriterTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/OsmWriterTest.java	(revision 17748)
+++ /trunk/test/unit/org/openstreetmap/josm/io/OsmWriterTest.java	(revision 17749)
@@ -24,4 +24,6 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.DownloadPolicy;
+import org.openstreetmap.josm.data.osm.INode;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.NodeData;
 import org.openstreetmap.josm.data.osm.UploadPolicy;
@@ -127,3 +129,20 @@
         }
     }
+
+    /**
+     * Unit test of {@link OsmWriter#visit(INode)}.
+     * @throws IOException if an I/O error occurs
+     */
+    @Test
+    void testNode() throws IOException {
+        Node node = new Node(1, 42);
+        node.setCoor(new LatLon(12., 34.));
+        node.setInstant(Instant.parse("2006-05-10T18:27:47Z"));
+        try (StringWriter stringWriter = new StringWriter();
+             OsmWriter osmWriter = OsmWriterFactory.createOsmWriter(new PrintWriter(stringWriter), true, OsmWriter.DEFAULT_API_VERSION)) {
+            osmWriter.visit(node);
+            assertEquals("  <node id='1' timestamp='2006-05-10T18:27:47Z' visible='true' version='42' lat='12.0' lon='34.0' />\n",
+                    stringWriter.toString().replace("\r", ""));
+        }
+    }
 }
