Index: src/org/openstreetmap/josm/tools/DateContainer.java
===================================================================
--- src/org/openstreetmap/josm/tools/DateContainer.java	(revision 0)
+++ src/org/openstreetmap/josm/tools/DateContainer.java	(revision 0)
@@ -0,0 +1,59 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import java.text.ParseException;
+import java.util.Date;
+
+/**
+ * Holds date in unparsed and parsed form. Date is parsed from string only if necessary
+ *
+ */
+public class DateContainer {
+
+    private String asString;
+    private Date asDate;
+    
+    public DateContainer(String asString) {
+        this.asString = asString;
+    }
+    
+    /**
+     * 
+     * @return Unparsed date
+     */
+    public String getAsString() {
+        return asString;
+    }
+
+    /**
+     * 
+     * @return Parsed date
+     */
+    public Date getAsDate() {
+        if (asDate == null && asString != null) {
+            try {
+                asDate = DateParser.parse(asString);
+            } catch (ParseException ex) {
+                asDate = new Date();
+            }
+        }
+        return asDate;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof DateContainer) {
+            DateContainer other = (DateContainer) o;
+            // TODO Is it enough to compare string representation? Dates can be in different format but are they in real life?
+            return getAsDate().equals(other.getAsDate());
+        }
+
+        return false;
+    }
+    
+    @Override
+    public int hashCode() {
+        return getAsDate().hashCode();
+    }
+
+}
Index: src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 1471)
+++ src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(working copy)
@@ -405,9 +405,9 @@
                     doneNodes.add(n);
                 }
                 WayPoint wpt = new WayPoint(n.coor);
-                if (n.timestamp != null)
+                if (n.getTimestamp().getAsString() != null)
                 {
-                    wpt.attr.put("time", n.timestamp);
+                    wpt.attr.put("time", n.getTimestamp().getAsString());
                     wpt.setTime();
                 }
                 trkseg.add(wpt);
@@ -419,8 +419,8 @@
         for (Node n : data.nodes) {
             if (n.incomplete || n.deleted || doneNodes.contains(n)) continue;
             WayPoint wpt = new WayPoint(n.coor);
-            if (n.timestamp != null) {
-                wpt.attr.put("time", n.timestamp);
+            if (n.getTimestamp().getAsString() != null) {
+                wpt.attr.put("time", n.getTimestamp().getAsString());
                 wpt.setTime();
             }
             if (n.keys != null && n.keys.containsKey("name")) {
Index: src/org/openstreetmap/josm/gui/layer/GpxLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(revision 1471)
+++ src/org/openstreetmap/josm/gui/layer/GpxLayer.java	(working copy)
@@ -67,6 +67,7 @@
 import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
 import org.openstreetmap.josm.gui.layer.markerlayer.AudioMarker;
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
+import org.openstreetmap.josm.tools.DateContainer;
 import org.openstreetmap.josm.tools.DontShowAgainInfo;
 import org.openstreetmap.josm.tools.GBC;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -659,8 +660,7 @@
                         String timestr = p.getString("time");
                         if(timestr != null)
                         {
-                            timestr = timestr.replace("Z","+00:00");
-                            n.timestamp = timestr;
+                            n.setTimestamp(new DateContainer(timestr.replace("Z","+00:00")));
                         }
                         ds.nodes.add(n);
                         w.nodes.add(n);
Index: src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 1471)
+++ src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(working copy)
@@ -66,7 +66,7 @@
         boolean visible;
 
         public int compareTo(HistoryItem o) {
-            return unifyDate(osm.getTimestamp()).compareTo(unifyDate(o.osm.getTimestamp()));
+            return unifyDate(osm.getTimestamp().getAsDate()).compareTo(unifyDate(o.osm.getTimestamp().getAsDate()));
         }
     }
 
@@ -170,7 +170,7 @@
                 orderedHistory.addAll(cache.get(osm));
             data.setRowCount(0);
             for (HistoryItem i : orderedHistory)
-                data.addRow(new Object[]{i.osm, i.osm.timestamp, i.visible});
+                data.addRow(new Object[]{i.osm, i.osm.getTimestamp().getAsString(), i.visible});
             historyPane.setVisible(true);
             notLoaded.setVisible(false);
         }
Index: src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmReader.java	(revision 1471)
+++ src/org/openstreetmap/josm/io/OsmReader.java	(working copy)
@@ -32,6 +32,7 @@
 import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.gui.PleaseWaitDialog;
+import org.openstreetmap.josm.tools.DateContainer;
 import org.xml.sax.Attributes;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
@@ -100,7 +101,7 @@
                osm.modified = modified;
                osm.selected = selected;
                osm.deleted = deleted;
-               osm.timestamp = timestamp;
+               osm.setTimestamp(timestamp);
                osm.user = user;
                osm.visible = visible;
                osm.version = version;
@@ -305,7 +306,7 @@
                     throw new SAXException(tr("Couldn''t read time format \"{0}\".",time));
                }
                */
-               current.timestamp = time;
+               current.setTimestamp(new DateContainer(time));
           }
 
           // user attribute added in 0.4 API
Index: src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmWriter.java	(revision 1471)
+++ src/org/openstreetmap/josm/io/OsmWriter.java	(working copy)
@@ -200,8 +200,8 @@
             if (action != null)
                 out.print(" action='"+action+"'");
         }
-        if (osm.timestamp != null) {
-            out.print(" timestamp='"+osm.timestamp+"'");
+        if (osm.getTimestamp().getAsString() != null) {
+            out.print(" timestamp='"+osm.getTimestamp().getAsString()+"'");
         }
         // user and visible added with 0.4 API
         if (osm.user != null) {
Index: src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(revision 1471)
+++ src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java	(working copy)
@@ -234,20 +234,32 @@
                 return true; // no merge needed.
             }
             if (my.realEqual(other, true)) {
-                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
-                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
+                Date myd = my.getTimestamp().getAsDate();
+                if (myd == null) {
+                    myd = new Date(0);
+                }
+                Date otherd = other.getTimestamp().getAsDate();
+                if (otherd == null) {
+                    otherd = new Date(0);
+                }
 
                 // they differ in modified/timestamp combination only. Auto-resolve it.
                 merged.put(other, my);
                 if (myd.before(otherd)) {
                     my.modified = other.modified;
-                    my.timestamp = other.timestamp;
+                    my.setTimestamp(other.getTimestamp());
                 }
                 return true; // merge done.
             }
             if (my.id == other.id && my.id != 0) {
-                Date myd = my.timestamp == null ? new Date(0) : my.getTimestamp();
-                Date otherd = other.timestamp == null ? new Date(0) : other.getTimestamp();
+                Date myd = my.getTimestamp().getAsDate();
+                if (myd == null) {
+                    myd = new Date(0);
+                }
+                Date otherd = other.getTimestamp().getAsDate();
+                if (otherd == null) {
+                    otherd = new Date(0);
+                }
 
                 if (my.incomplete || other.incomplete) {
                     if (my.incomplete) {
Index: src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 1471)
+++ src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(working copy)
@@ -3,22 +3,19 @@
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Date;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 
-import org.openstreetmap.josm.data.osm.visitor.Visitor;
-import org.openstreetmap.josm.tools.DateParser;
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.visitor.Visitor;
 import org.openstreetmap.josm.gui.mappaint.ElemStyle;
+import org.openstreetmap.josm.tools.DateContainer;
 
 
 /**
@@ -128,21 +125,24 @@
      * show which ways/nodes will connect 
      */
     public volatile boolean highlighted = false;
-
+    
+    protected DateContainer timestamp;
     /**
      * 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.
-     */
-    public String timestamp = null;
+     * 
+     * Returned value is never null (though the date itself can be null)
+     */    
+    public DateContainer getTimestamp() {
+        return timestamp;
+    }
+    
+    public void setTimestamp(DateContainer timestamp) {
+        this.timestamp = timestamp;
+    }
 
     /**
-     * The timestamp is only parsed when this is really necessary, and this
-     * is the cache for the result.
-     */
-    public Date parsedTimestamp = null;
-
-    /**
      * If set to true, this object is incomplete, which means only the id
      * and type is known (type is the objects instance class)
      */
@@ -182,22 +182,6 @@
     }
 
     /**
-     * Returns the timestamp for this object, or the current time if none is set.
-     * Internally, parses the timestamp from XML into a Date object and caches it
-     * for possible repeated calls.
-     */
-    public Date getTimestamp() {
-        if (parsedTimestamp == null) {
-            try {
-                parsedTimestamp = DateParser.parse(timestamp);
-            } catch (ParseException ex) {
-                parsedTimestamp = new Date();
-            }
-        }
-        return parsedTimestamp;
-    }
-
-    /**
      * Equal, if the id (and class) is equal.
      *
      * An primitive is equal to its incomplete counter part.
