Index: trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java	(revision 9383)
@@ -12,14 +12,8 @@
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.projection.Projections;
-import org.openstreetmap.josm.tools.date.PrimaryDateParser;
+import org.openstreetmap.josm.tools.date.DateUtils;
 import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
 
 public class WayPoint extends WithAttributes implements Comparable<WayPoint>, TemplateEngineDataProvider {
-
-    private static ThreadLocal<PrimaryDateParser> dateParser = new ThreadLocal<PrimaryDateParser>() {
-        @Override protected PrimaryDateParser initialValue() {
-            return new PrimaryDateParser();
-        }
-    };
 
     public double time;
@@ -99,14 +93,38 @@
 
     /**
+     * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time
+     *
+     * @param time the time to set
+     * @since 9383
+     */
+    public void setTime(Date time) {
+        this.time = time.getTime() / 1000.;
+        this.attr.put(PT_TIME, DateUtils.fromDate(time));
+    }
+
+    /**
      * Convert the time stamp of the waypoint into seconds from the epoch
      */
     public void setTime() {
+        setTimeFromAttribute();
+    }
+
+    /**
+     * Convert the time stamp of the waypoint into seconds from the epoch
+     * @return The parsed time if successful, or {@code null}
+     * @since 9383
+     */
+    public Date setTimeFromAttribute() {
         if (attr.containsKey(PT_TIME)) {
             try {
-                time = dateParser.get().parse(get(PT_TIME).toString()).getTime() / 1000.; /* ms => seconds */
+                final Date time = DateUtils.fromString(get(PT_TIME).toString());
+                setTime(time);
+                return time;
             } catch (Exception e) {
+                Main.warn(e);
                 time = 0;
             }
         }
+        return null;
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java	(revision 9383)
@@ -81,5 +81,4 @@
 import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.date.DateUtils;
-import org.openstreetmap.josm.tools.date.PrimaryDateParser;
 import org.xml.sax.SAXException;
 
@@ -1014,5 +1013,4 @@
 
             List<ImageEntry> imgs = getSortedImgList();
-            PrimaryDateParser dateParser = new PrimaryDateParser();
 
             // no images found, exit
@@ -1032,12 +1030,10 @@
                 for (GpxTrackSegment segment : trk.getSegments()) {
                     for (WayPoint curWp : segment.getWayPoints()) {
-                        String curDateWpStr = curWp.getString(GpxConstants.PT_TIME);
-                        if (curDateWpStr == null) {
-                            continue;
-                        }
-
                         try {
-                            firstGPXDate = dateParser.parse(curDateWpStr).getTime()/1000;
-                            break outer;
+                            final Date parsedTime = curWp.setTimeFromAttribute();
+                            if (parsedTime != null) {
+                                firstGPXDate = parsedTime.getTime();
+                                break outer;
+                            }
                         } catch (Exception e) {
                             Main.warn(e);
@@ -1153,6 +1149,4 @@
         int ret = 0;
 
-        PrimaryDateParser dateParser = new PrimaryDateParser();
-
         for (GpxTrack trk : selectedGpx.tracks) {
             for (GpxTrackSegment segment : trk.getSegments()) {
@@ -1162,25 +1156,19 @@
 
                 for (WayPoint curWp : segment.getWayPoints()) {
-
-                    String curWpTimeStr = curWp.getString(GpxConstants.PT_TIME);
-                    if (curWpTimeStr != null) {
-
-                        try {
-                            long curWpTime = dateParser.parse(curWpTimeStr).getTime() + offset;
+                    try {
+                        final Date parsedTime = curWp.setTimeFromAttribute();
+                        if (parsedTime != null) {
+                            final long curWpTime = parsedTime.getTime() + offset;
                             ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset);
 
                             prevWp = curWp;
                             prevWpTime = curWpTime;
-
-                        } catch (ParseException e) {
-                            Main.error("Error while parsing date \"" + curWpTimeStr + '"');
-                            Main.error(e);
-                            prevWp = null;
-                            prevWpTime = 0;
+                            continue;
                         }
-                    } else {
-                        prevWp = null;
-                        prevWpTime = 0;
+                    } catch (Exception e) {
+                        Main.warn(e);
                     }
+                    prevWp = null;
+                    prevWpTime = 0;
                 }
             }
Index: trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageEntry.java	(revision 9383)
@@ -5,5 +5,4 @@
 import java.io.File;
 import java.io.IOException;
-import java.text.ParseException;
 import java.util.Calendar;
 import java.util.Collections;
@@ -449,5 +448,5 @@
         try {
             setExifTime(ExifReader.readTime(file));
-        } catch (ParseException ex) {
+        } catch (RuntimeException ex) {
             setExifTime(null);
         }
Index: trunk/src/org/openstreetmap/josm/tools/ExifReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/tools/ExifReader.java	(revision 9383)
@@ -5,10 +5,9 @@
 import java.io.File;
 import java.io.IOException;
-import java.text.ParseException;
 import java.util.Date;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.coor.LatLon;
-import org.openstreetmap.josm.tools.date.PrimaryDateParser;
+import org.openstreetmap.josm.tools.date.DateUtils;
 
 import com.drew.imaging.jpeg.JpegMetadataReader;
@@ -38,7 +37,6 @@
      * @param filename The JPEG file to read
      * @return The date/time read in the EXIF section, or {@code null} if not found
-     * @throws ParseException if {@link PrimaryDateParser#parse} fails to parse date/time
-     */
-    public static Date readTime(File filename) throws ParseException {
+     */
+    public static Date readTime(File filename) {
         try {
             Metadata metadata = JpegMetadataReader.readMetadata(filename);
@@ -60,8 +58,6 @@
             if (dateStr != null) {
                 dateStr = dateStr.replace('/', ':'); // workaround for HTC Sensation bug, see #7228
-                return new PrimaryDateParser().parse(dateStr);
-            }
-        } catch (ParseException e) {
-            throw e;
+                return DateUtils.fromString(dateStr);
+            }
         } catch (Exception e) {
             Main.error(e);
Index: trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 9383)
@@ -45,9 +45,11 @@
      * with the timezone lookup, is very expensive.
      */
-    private static GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    private static final GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    private static final GregorianCalendar calendarLocale = new GregorianCalendar(TimeZone.getDefault());
     private static final DatatypeFactory XML_DATE;
 
     static {
         calendar.setTimeInMillis(0);
+        calendarLocale.setTimeInMillis(0);
 
         DatatypeFactory fact = null;
@@ -78,8 +80,10 @@
         if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx") ||
+                checkLayout(str, "xxxx:xx:xx xx:xx:xx") ||
                 checkLayout(str, "xxxx-xx-xx xx:xx:xx UTC") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) {
-            calendar.set(
+            final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx") ? calendarLocale : calendar; // consider EXIF date in default timezone
+            c.set(
                 parsePart4(str, 0),
                 parsePart2(str, 5)-1,
@@ -92,13 +96,15 @@
                 int plusHr = parsePart2(str, 20);
                 int mul = str.charAt(19) == '+' ? -3600000 : 3600000;
-                return calendar.getTimeInMillis()+plusHr*mul;
+                return c.getTimeInMillis()+plusHr*mul;
             }
 
-            return calendar.getTimeInMillis();
+            return c.getTimeInMillis();
         } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxxZ") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx") ||
+                checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) {
-            calendar.set(
+            final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? calendarLocale : calendar; // consider EXIF date in default timezone
+            c.set(
                 parsePart4(str, 0),
                 parsePart2(str, 5)-1,
@@ -112,5 +118,5 @@
             }
 
-            return calendar.getTimeInMillis() + millis;
+            return c.getTimeInMillis() + millis;
         } else {
             // example date format "18-AUG-08 13:33:03"
Index: trunk/src/org/openstreetmap/josm/tools/date/PrimaryDateParser.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/date/PrimaryDateParser.java	(revision 9382)
+++ trunk/src/org/openstreetmap/josm/tools/date/PrimaryDateParser.java	(revision 9383)
@@ -17,5 +17,7 @@
  *
  * @author Brett Henderson
+ * @deprecated Use {@link DateUtils} instead!
  */
+@Deprecated
 public class PrimaryDateParser {
     private DatatypeFactory datatypeFactory;
Index: trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImagesTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImagesTest.java	(revision 9383)
+++ trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImagesTest.java	(revision 9383)
@@ -0,0 +1,19 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer.geoimage;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.openstreetmap.josm.data.gpx.GpxData;
+import org.openstreetmap.josm.io.GpxReaderTest;
+
+public class CorrelateGpxWithImagesTest {
+
+    @Test
+    public void testMatchGpxTrack() throws Exception {
+        final GpxData munich = GpxReaderTest.parseGpxData("data_nodist/munich.gpx");
+        final ImageEntry i1 = new ImageEntry();
+        i1.setExifGpsTime();
+        CorrelateGpxWithImages.matchGpxTrack(null, munich, 0);
+    }
+}
Index: trunk/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java	(revision 9382)
+++ trunk/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java	(revision 9383)
@@ -4,4 +4,7 @@
 import static org.junit.Assert.assertEquals;
 
+import java.util.TimeZone;
+
+import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -10,4 +13,12 @@
  */
 public class DateUtilsTest {
+
+    /**
+     * Setup test.
+     */
+    @BeforeClass
+    public static void setUp() {
+        TimeZone.setDefault(TimeZone.getTimeZone("GMT+8:00"));
+    }
 
     /**
@@ -26,3 +37,31 @@
         assertEquals(1417298930000L, DateUtils.fromString("2014-11-29 22:08:50 UTC").getTime());
     }
+
+    /**
+     * Test to parse date as used in EXIF structures.
+     */
+    @Test
+    public void testExifDate() {
+        assertEquals(1443038712000L - 8 * 3600 * 1000, DateUtils.fromString("2015:09:23 20:05:12").getTime());
+        assertEquals(1443038712888L - 8 * 3600 * 1000, DateUtils.fromString("2015:09:23 20:05:12.888").getTime());
+    }
+
+    /**
+     * Test to parse date as used in GPX files
+     */
+    @Test
+    public void testGPXDate() {
+        assertEquals(1277465405000L, DateUtils.fromString("2010-06-25T11:30:05.000Z").getTime());
+    }
+
+    /**
+     * Test to parse date as defined in <a href="https://tools.ietf.org/html/rfc3339">RFC 3339</a>
+     */
+    @Test
+    public void testRfc3339() {
+        // examples taken from RFC
+        assertEquals(482196050520L, DateUtils.fromString("1985-04-12T23:20:50.52Z").getTime());
+        assertEquals(851042397000L, DateUtils.fromString("1996-12-19T16:39:57-08:00").getTime());
+        assertEquals(-1041337172130L, DateUtils.fromString("1937-01-01T12:00:27.87+00:20").getTime());
+    }
 }
