Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/query/AdvancedChangesetQueryPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/query/AdvancedChangesetQueryPanel.java	(revision 11034)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/query/AdvancedChangesetQueryPanel.java	(revision 11035)
@@ -11,9 +11,12 @@
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
-import java.text.DateFormat;
-import java.text.ParseException;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.time.format.FormatStyle;
 import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Locale;
 
 import javax.swing.BorderFactory;
@@ -842,20 +845,16 @@
                 throw new IllegalStateException(tr("Cannot build changeset query with time based restrictions. Input is not valid."));
             if (rbClosedAfter.isSelected()) {
-                GregorianCalendar cal = new GregorianCalendar();
-                Date d1 = valClosedAfterDate1.getDate();
-                Date d2 = valClosedAfterTime1.getDate();
-                cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
-                query.closedAfter(cal.getTime());
+                LocalDate d1 = valClosedAfterDate1.getDate();
+                LocalTime d2 = valClosedAfterTime1.getDate();
+                final Date d3 = new Date(d1.atTime(d2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
+                query.closedAfter(d3);
             } else if (rbClosedAfterAndCreatedBefore.isSelected()) {
-                GregorianCalendar cal = new GregorianCalendar();
-                Date d1 = valClosedAfterDate2.getDate();
-                Date d2 = valClosedAfterTime2.getDate();
-                cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
-                Date d3 = cal.getTime();
+                LocalDate d1 = valClosedAfterDate2.getDate();
+                LocalTime d2 = valClosedAfterTime2.getDate();
+                Date d3 = new Date(d1.atTime(d2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
 
                 d1 = valCreatedBeforeDate.getDate();
                 d2 = valCreatedBeforeTime.getDate();
-                cal.setTimeInMillis(d1.getTime() + (d2 == null ? 0 : d2.getTime()));
-                Date d4 = cal.getTime();
+                Date d4 = new Date(d1.atTime(d2).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
 
                 query.closedAfterAndCreatedBefore(d3, d4);
@@ -1042,5 +1041,5 @@
 
         public String getStandardTooltipText() {
-            Date date = new Date();
+            final ZonedDateTime now = ZonedDateTime.now();
             return tr(
                     "Please enter a date in the usual format for your locale.<br>"
@@ -1049,8 +1048,8 @@
                     + "Example: {2}<br>"
                     + "Example: {3}<br>",
-                    DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()).format(date),
-                    DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()).format(date),
-                    DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()).format(date),
-                    DateFormat.getDateInstance(DateFormat.FULL, Locale.getDefault()).format(date)
+                    DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT).format(now),
+                    DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).format(now),
+                    DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG).format(now),
+                    DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL).format(now)
             );
         }
@@ -1068,10 +1067,10 @@
         }
 
-        public Date getDate() {
-            for (int format: new int[] {DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL}) {
-                DateFormat df = DateFormat.getDateInstance(format);
+        public LocalDate getDate() {
+            for (final FormatStyle format: FormatStyle.values()) {
+                DateTimeFormatter df = DateTimeFormatter.ofLocalizedDate(format);
                 try {
-                    return df.parse(getComponent().getText());
-                } catch (ParseException e) {
+                    return LocalDate.parse(getComponent().getText(), df);
+                } catch (DateTimeParseException e) {
                     // Try next format
                     Main.trace(e);
@@ -1109,5 +1108,5 @@
 
         public String getStandardTooltipText() {
-            Date date = new Date();
+            final ZonedDateTime now = ZonedDateTime.now();
             return tr(
                     "Please enter a valid time in the usual format for your locale.<br>"
@@ -1116,8 +1115,8 @@
                     + "Example: {2}<br>"
                     + "Example: {3}<br>",
-                    DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()).format(date),
-                    DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.getDefault()).format(date),
-                    DateFormat.getTimeInstance(DateFormat.LONG, Locale.getDefault()).format(date),
-                    DateFormat.getTimeInstance(DateFormat.FULL, Locale.getDefault()).format(date)
+                    DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT).format(now),
+                    DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM).format(now),
+                    DateTimeFormatter.ofLocalizedTime(FormatStyle.LONG).format(now),
+                    DateTimeFormatter.ofLocalizedTime(FormatStyle.FULL).format(now)
             );
         }
@@ -1135,16 +1134,18 @@
         }
 
-        public Date getDate() {
+        public LocalTime getDate() {
             if (getComponent().getText().trim().isEmpty())
-                return null;
-
-            for (int style : new int[]{DateFormat.SHORT, DateFormat.MEDIUM, DateFormat.LONG, DateFormat.FULL}) {
+                return LocalTime.MIDNIGHT;
+
+            for (final FormatStyle format: FormatStyle.values()) {
+                DateTimeFormatter df = DateTimeFormatter.ofLocalizedTime(format);
                 try {
-                    return DateFormat.getTimeInstance(style, Locale.getDefault()).parse(getComponent().getText());
-                } catch (ParseException e) {
-                    continue;
+                    return LocalTime.parse(getComponent().getText(), df);
+                } catch (DateTimeParseException e) {
+                    // Try next format
+                    Main.trace(e);
                 }
             }
-            return null;
+            return LocalTime.MIDNIGHT;
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java	(revision 11034)
+++ trunk/src/org/openstreetmap/josm/gui/layer/gpx/DateFilterPanel.java	(revision 11035)
@@ -7,6 +7,7 @@
 import java.awt.GridBagLayout;
 import java.awt.event.ActionListener;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Date;
-import java.util.GregorianCalendar;
 
 import javax.swing.JCheckBox;
@@ -49,5 +50,5 @@
         final Date startTime, endTime;
         Date[] bounds = layer.data.getMinMaxTimeForAllTracks();
-        startTime = (bounds.length == 0) ? new GregorianCalendar(2000, 1, 1).getTime() : bounds[0];
+        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];
 
Index: trunk/src/org/openstreetmap/josm/io/GpxExporter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/GpxExporter.java	(revision 11034)
+++ trunk/src/org/openstreetmap/josm/io/GpxExporter.java	(revision 11035)
@@ -12,5 +12,5 @@
 import java.io.OutputStream;
 import java.text.MessageFormat;
-import java.util.Calendar;
+import java.time.Year;
 
 import javax.swing.JButton;
@@ -225,5 +225,5 @@
                 String sCopyrightYear = data.getString(META_COPYRIGHT_YEAR);
                 if (sCopyrightYear == null) {
-                    sCopyrightYear = Integer.toString(Calendar.getInstance().get(Calendar.YEAR));
+                    sCopyrightYear = Year.now().toString();
                 }
                 copyrightYear.setText(sCopyrightYear);
Index: trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 11034)
+++ trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java	(revision 11035)
@@ -5,7 +5,10 @@
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
 import java.util.Date;
-import java.util.GregorianCalendar;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -13,5 +16,4 @@
 import javax.xml.datatype.DatatypeConfigurationException;
 import javax.xml.datatype.DatatypeFactory;
-import javax.xml.datatype.XMLGregorianCalendar;
 
 import org.openstreetmap.josm.Main;
@@ -41,21 +43,7 @@
     public static final BooleanProperty PROP_ISO_DATES = new BooleanProperty("iso.dates", false);
 
-    /**
-     * A shared instance used for conversion between individual date fields
-     * and long millis time. It is guarded against conflict by the class lock.
-     * The shared instance is used because the construction, together
-     * with the timezone lookup, is very expensive.
-     */
-    private static final GregorianCalendar calendar = new GregorianCalendar(UTC);
-    /**
-     * A shared instance to convert local times. The time zone should be set before every conversion.
-     */
-    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;
         try {
@@ -97,26 +85,21 @@
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) {
-            final Calendar c; // consider EXIF date in default timezone
-            if (checkLayout(str, "xxxx:xx:xx xx:xx:xx")) {
-                c = getLocalCalendar();
-            } else {
-                c = calendar;
-            }
-            c.set(
+            final ZonedDateTime local = ZonedDateTime.of(
                 parsePart4(str, 0),
-                parsePart2(str, 5)-1,
+                parsePart2(str, 5),
                 parsePart2(str, 8),
                 parsePart2(str, 11),
                 parsePart2(str, 14),
-                parsePart2(str, 17));
-            c.set(Calendar.MILLISECOND, 0);
-
+                parsePart2(str, 17),
+                0,
+                // consider EXIF date in default timezone
+                checkLayout(str, "xxxx:xx:xx xx:xx:xx") ? ZoneId.systemDefault() : ZoneOffset.UTC
+            );
             if (str.length() == 22 || str.length() == 25) {
-                int plusHr = parsePart2(str, 20);
-                int mul = str.charAt(19) == '+' ? -3600000 : 3600000;
-                return c.getTimeInMillis()+plusHr*mul;
+                final int plusHr = parsePart2(str, 20);
+                final int mul = str.charAt(19) == '+' ? -1 : 1;
+                return local.plusHours(plusHr * mul).toInstant().toEpochMilli();
             }
-
-            return c.getTimeInMillis();
+            return local.toInstant().toEpochMilli();
         } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxxZ") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx") ||
@@ -124,20 +107,21 @@
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") ||
                 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) {
-            // consider EXIF date in default timezone
-            final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? getLocalCalendar() : calendar;
-            c.set(
+            final ZonedDateTime local = ZonedDateTime.of(
                 parsePart4(str, 0),
-                parsePart2(str, 5)-1,
+                parsePart2(str, 5),
                 parsePart2(str, 8),
                 parsePart2(str, 11),
                 parsePart2(str, 14),
-                parsePart2(str, 17));
-            c.set(Calendar.MILLISECOND, 0);
-            long millis = parsePart3(str, 20);
+                parsePart2(str, 17),
+                parsePart3(str, 20) * 1_000_000,
+                // consider EXIF date in default timezone
+                checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? ZoneId.systemDefault() : ZoneOffset.UTC
+            );
             if (str.length() == 29) {
-                millis += parsePart2(str, 24) * (str.charAt(23) == '+' ? -3600000 : 3600000);
+                final int plusHr = parsePart2(str, 24);
+                final int mul = str.charAt(23) == '+' ? -1 : 1;
+                return local.plusHours(plusHr * mul).toInstant().toEpochMilli();
             }
-
-            return c.getTimeInMillis() + millis;
+            return local.toInstant().toEpochMilli();
         } else {
             // example date format "18-AUG-08 13:33:03"
@@ -155,18 +139,4 @@
     }
 
-    private static Calendar getLocalCalendar() {
-        final Calendar c = calendarLocale;
-        c.setTimeZone(TimeZone.getDefault());
-        return c;
-    }
-
-    private static String toXmlFormat(GregorianCalendar cal) {
-        XMLGregorianCalendar xgc = XML_DATE.newXMLGregorianCalendar(cal);
-        if (cal.get(Calendar.MILLISECOND) == 0) {
-            xgc.setFractionalSecond(null);
-        }
-        return xgc.toXMLFormat();
-    }
-
     /**
      * Formats a date to the XML UTC format regardless of current locale.
@@ -175,6 +145,6 @@
      */
     public static synchronized String fromTimestamp(int timestamp) {
-        calendar.setTimeInMillis(timestamp * 1000L);
-        return toXmlFormat(calendar);
+        final ZonedDateTime temporal = Instant.ofEpochMilli(timestamp * 1000L).atZone(ZoneOffset.UTC);
+        return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(temporal);
     }
 
@@ -185,6 +155,6 @@
      */
     public static synchronized String fromDate(Date date) {
-        calendar.setTime(date);
-        return toXmlFormat(calendar);
+        final ZonedDateTime temporal = date.toInstant().atZone(ZoneOffset.UTC);
+        return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(temporal);
     }
 
Index: trunk/test/unit/org/openstreetmap/josm/data/AutosaveTaskTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/AutosaveTaskTest.java	(revision 11034)
+++ trunk/test/unit/org/openstreetmap/josm/data/AutosaveTaskTest.java	(revision 11035)
@@ -14,5 +14,6 @@
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.Calendar;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Date;
 import java.util.List;
@@ -87,8 +88,5 @@
         Files.createDirectories(task.getAutosaveDir());
         AutosaveLayerInfo info = new AutosaveLayerInfo(new OsmDataLayer(new DataSet(), "layer", null));
-        Calendar cal = Calendar.getInstance();
-        cal.set(2016, 0, 1, 1, 2, 3);
-        cal.set(Calendar.MILLISECOND, 456);
-        Date fixed = cal.getTime();
+        Date fixed = Date.from(ZonedDateTime.of(2016, 1, 1, 1, 2, 3, 456_000_000, ZoneId.systemDefault()).toInstant());
 
         AutosaveTask.PROP_INDEX_LIMIT.put(5);
Index: trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java	(revision 11034)
+++ trunk/test/unit/org/openstreetmap/josm/data/osm/DataSetMergerTest.java	(revision 11035)
@@ -11,8 +11,7 @@
 
 import java.io.StringWriter;
+import java.time.Instant;
 import java.util.Arrays;
-import java.util.Calendar;
 import java.util.Date;
-import java.util.GregorianCalendar;
 
 import org.junit.After;
@@ -26,5 +25,4 @@
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * Unit tests for class {@link DataSetMerger}.
@@ -298,5 +296,4 @@
     public void testNodeSimpleNoIdSemanticallyEqual() {
 
-        Calendar cal = GregorianCalendar.getInstance();
         User myUser = User.createOsmUser(1111, "my");
 
@@ -307,5 +304,5 @@
         n.put("key1", "value1");
         n.setUser(myUser);
-        n.setTimestamp(cal.getTime());
+        n.setTimestamp(new Date());
 
         my.addPrimitive(n);
@@ -314,7 +311,5 @@
         n1.setCoor(LatLon.ZERO);
         n1.put("key1", "value1");
-        cal.add(Calendar.HOUR, 1);
-        Date timestamp = cal.getTime();
-        n1.setTimestamp(timestamp);
+        n1.setTimestamp(Date.from(Instant.now().plusSeconds(3600)));
         n1.setUser(theirUser);
         their.addPrimitive(n1);
Index: trunk/test/unit/org/openstreetmap/josm/io/ChangesetQueryUrlParserTest.groovy
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/io/ChangesetQueryUrlParserTest.groovy	(revision 11034)
+++ trunk/test/unit/org/openstreetmap/josm/io/ChangesetQueryUrlParserTest.groovy	(revision 11035)
@@ -1,6 +1,4 @@
 // License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.io;
-
-import static org.junit.Assert.*
+package org.openstreetmap.josm.io
 
 import org.junit.Test
@@ -8,4 +6,7 @@
 import org.openstreetmap.josm.io.ChangesetQuery.ChangesetQueryUrlParser
 
+import java.time.OffsetDateTime
+import java.time.ZoneOffset
+
 class ChangesetQueryUrlParserTest {
     final shouldFail = new GroovyTestCase().&shouldFail
@@ -127,12 +128,6 @@
         assert q != null
         assert q.@closedAfter != null
-        Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));
-        cal.setTime(q.@closedAfter);
-        assert cal.get(Calendar.YEAR) == 2009
-        assert cal.get(Calendar.MONTH) == 11 // calendar is 0-based
-        assert cal.get(Calendar.DAY_OF_MONTH) == 25
-        assert cal.get(Calendar.HOUR_OF_DAY) == 10
-        assert cal.get(Calendar.MINUTE) == 0
-        assert cal.get(Calendar.SECOND) == 0
+        def cal = q.@closedAfter.toInstant().atOffset(ZoneOffset.UTC)
+        assert cal == OffsetDateTime.of(2009, 12, 25, 10, 0, 0, 0, ZoneOffset.UTC)
 
         // OK
Index: trunk/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java
===================================================================
--- trunk/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java	(revision 11034)
+++ trunk/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java	(revision 11035)
@@ -10,7 +10,7 @@
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.Calendar;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.util.Date;
-import java.util.GregorianCalendar;
 import java.util.TimeZone;
 
@@ -24,5 +24,4 @@
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
 /**
  * EXIF metadata extraction test
@@ -55,10 +54,11 @@
     public void testReadTime() throws ParseException {
         Date date = ExifReader.readTime(directionSampleFile);
-        assertEquals(new GregorianCalendar(2010, Calendar.MAY, 15, 17, 12, 05).getTime(), date);
+        assertEquals(ZonedDateTime.of(2010, 5, 15, 17, 12, 5, 0, ZoneId.systemDefault()).toInstant(), date.toInstant());
 
-        TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
+        final TimeZone zone = TimeZone.getTimeZone("Europe/Berlin");
+        TimeZone.setDefault(zone);
         date = ExifReader.readTime(directionSampleFile);
         TimeZone.setDefault(DateUtils.UTC);
-        assertEquals(new GregorianCalendar(2010, Calendar.MAY, 15, 15, 12, 05).getTime(), date);
+        assertEquals(ZonedDateTime.of(2010, 5, 15, 17, 12, 5, 0, zone.toZoneId()).toInstant(), date.toInstant());
     }
 
