Index: /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 14066)
+++ /trunk/src/org/openstreetmap/josm/io/nmea/NmeaReader.java	(revision 14067)
@@ -15,5 +15,6 @@
 import java.util.Locale;
 import java.util.Objects;
-import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.openstreetmap.josm.data.coor.LatLon;
@@ -45,4 +46,9 @@
 public class NmeaReader implements IGpxReader {
 
+    /**
+     * Course Over Ground and Ground Speed.
+     * <p>
+     * The actual course and speed relative to the ground
+     */
     enum VTG {
         COURSE(1), COURSE_REF(2), // true course
@@ -59,4 +65,12 @@
     }
 
+    /**
+     * Recommended Minimum Specific GNSS Data.
+     * <p>
+     * Time, date, position, course and speed data provided by a GNSS navigation receiver.
+     * This sentence is transmitted at intervals not exceeding 2-seconds.
+     * RMC is the recommended minimum data to be provided by a GNSS receiver.
+     * All data fields must be provided, null fields used only when data is temporarily unavailable.
+     */
     enum RMC {
         TIME(1),
@@ -81,4 +95,9 @@
     }
 
+    /**
+     * Global Positioning System Fix Data.
+     * <p>
+     * Time, position and fix related data for a GPS receiver.
+     */
     enum GGA {
         TIME(1), LATITUDE(2), LATITUDE_NAME(3), LONGITUDE(4), LONGITUDE_NAME(5),
@@ -99,4 +118,16 @@
     }
 
+    /**
+     * GNSS DOP and Active Satellites.
+     * <p>
+     * GNSS receiver operating mode, satellites used in the navigation solution reported by the GGA or GNS sentence,
+     * and DOP values.
+     * If only GPS, GLONASS, etc. is used for the reported position solution the talker ID is GP, GL, etc.
+     * and the DOP values pertain to the individual system. If GPS, GLONASS, etc. are combined to obtain the
+     * reported position solution multiple GSA sentences are produced, one with the GPS satellites, another with
+     * the GLONASS satellites, etc. Each of these GSA sentences shall have talker ID GN, to indicate that the
+     * satellites are used in a combined solution and each shall have the PDOP, HDOP and VDOP for the
+     * combined satellites used in the position.
+     */
     enum GSA {
         AUTOMATIC(1),
@@ -115,4 +146,9 @@
     }
 
+    /**
+     * Geographic Position - Latitude/Longitude.
+     * <p>
+     * Latitude and Longitude of vessel position, time of position fix and status.
+     */
     enum GLL {
         LATITUDE(1), LATITUDE_NS(2), // Latitude, NS
@@ -135,13 +171,25 @@
     GpxData data;
 
+    private static final Pattern DATE_TIME_PATTERN = Pattern.compile("(\\d{12})(\\.\\d+)?");
+
     private final SimpleDateFormat rmcTimeFmt = new SimpleDateFormat("ddMMyyHHmmss.SSS", Locale.ENGLISH);
-    private final SimpleDateFormat rmcTimeFmtStd = new SimpleDateFormat("ddMMyyHHmmss", Locale.ENGLISH);
 
     private Date readTime(String p) throws IllegalDataException {
-        Date d = Optional.ofNullable(rmcTimeFmt.parse(p, new ParsePosition(0)))
-                .orElseGet(() -> rmcTimeFmtStd.parse(p, new ParsePosition(0)));
-        if (d == null)
-            throw new IllegalDataException("Date is malformed: '" + p + "'");
-        return d;
+        // NMEA defines time with "a variable number of digits for decimal-fraction of seconds"
+        // This variable decimal fraction cannot be parsed by SimpleDateFormat
+        Matcher m = DATE_TIME_PATTERN.matcher(p);
+        if (m.matches()) {
+            String date = m.group(1);
+            double milliseconds = 0d;
+            if (m.groupCount() > 1 && m.group(2) != null) {
+                milliseconds = 1000d * Double.parseDouble("0" + m.group(2));
+            }
+            // Add milliseconds on three digits to match SimpleDateFormat pattern
+            date += String.format(".%03d", (int) milliseconds);
+            Date d = rmcTimeFmt.parse(date, new ParsePosition(0));
+            if (d != null)
+                return d;
+        }
+        throw new IllegalDataException("Date is malformed: '" + p + "'");
     }
 
@@ -177,5 +225,4 @@
         this.source = Objects.requireNonNull(source);
         rmcTimeFmt.setTimeZone(DateUtils.UTC);
-        rmcTimeFmtStd.setTimeZone(DateUtils.UTC);
     }
 
Index: /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java	(revision 14066)
+++ /trunk/test/unit/org/openstreetmap/josm/io/nmea/NmeaReaderTest.java	(revision 14067)
@@ -6,11 +6,15 @@
 import static org.junit.Assert.assertTrue;
 
+import java.io.ByteArrayInputStream;
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.List;
 import java.util.TimeZone;
 
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -40,4 +44,14 @@
     public JOSMTestRules test = new JOSMTestRules();
 
+    private final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
+
+    /**
+     * Forces the timezone.
+     */
+    @Before
+    public void setUp() {
+        iso8601.setTimeZone(TimeZone.getTimeZone("UTC"));
+    }
+
     /**
      * Tests reading a nmea file.
@@ -58,8 +72,7 @@
         assertEquals(wayPoints.get(0).getTime(), DateUtils.fromString(wayPoints.get(0).get(GpxConstants.PT_TIME).toString()));
 
-        final SimpleDateFormat iso8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
-        assertEquals("2016-01-25T06:05:09.200+01", iso8601.format(wayPoints.get(0).getTime()));
-        assertEquals("2016-01-25T06:05:09.400+01", iso8601.format(wayPoints.get(1).getTime()));
-        assertEquals("2016-01-25T06:05:09.600+01", iso8601.format(wayPoints.get(2).getTime()));
+        assertEquals("2016-01-25T05:05:09.200Z", iso8601.format(wayPoints.get(0).getTime()));
+        assertEquals("2016-01-25T05:05:09.400Z", iso8601.format(wayPoints.get(1).getTime()));
+        assertEquals("2016-01-25T05:05:09.600Z", iso8601.format(wayPoints.get(2).getTime()));
 
         assertEquals(new LatLon(46.98807, -1.400525), wayPoints.get(0).getCoor());
@@ -146,3 +159,20 @@
         compareWithReference(14924, "input", 0);
     }
+
+    private static Date readDate(String nmeaLine) throws IOException, SAXException {
+        NmeaReader in = new NmeaReader(new ByteArrayInputStream(nmeaLine.getBytes(StandardCharsets.UTF_8)));
+        in.parse(true);
+        return in.data.tracks.iterator().next().getSegments().iterator().next().getWayPoints().iterator().next().getTime();
+    }
+
+    /**
+     * Non-regression test for <a href="https://josm.openstreetmap.de/ticket/16496">Bug #16496</a>.
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testTicket16496() throws Exception {
+        assertEquals("2018-05-30T16:28:59.400Z", iso8601.format(readDate("$GNRMC,162859.400,A,4543.03388,N,00058.19870,W,45.252,209.07,300518,,,D,V*13")));
+        assertEquals("2018-05-30T16:28:59.400Z", iso8601.format(readDate("$GNRMC,162859.40,A,4543.03388,N,00058.19870,W,45.252,209.07,300518,,,D,V*23")));
+        assertEquals("2018-05-30T16:28:59.400Z", iso8601.format(readDate("$GNRMC,162859.4,A,4543.03388,N,00058.19870,W,45.252,209.07,300518,,,D,V*13")));
+    }
 }
