diff --git a/src/org/openstreetmap/josm/tools/date/DateUtils.java b/src/org/openstreetmap/josm/tools/date/DateUtils.java
index c148194..c8a3245 100644
|
a
|
b
|
public final class DateUtils {
|
| 34 | 34 | */ |
| 35 | 35 | public static final TimeZone UTC = TimeZone.getTimeZone("UTC"); |
| 36 | 36 | |
| 37 | | protected DateUtils() { |
| 38 | | // Hide default constructor for utils classes |
| 39 | | } |
| 40 | | |
| 41 | 37 | /** |
| 42 | 38 | * Property to enable display of ISO dates globally. |
| 43 | 39 | * @since 7299 |
| … |
… |
public final class DateUtils {
|
| 51 | 47 | * with the timezone lookup, is very expensive. |
| 52 | 48 | */ |
| 53 | 49 | private static final GregorianCalendar calendar = new GregorianCalendar(UTC); |
| | 50 | /** |
| | 51 | * A shared instance to convert local times. The time zone should be set before every conversion. |
| | 52 | */ |
| 54 | 53 | private static final GregorianCalendar calendarLocale = new GregorianCalendar(TimeZone.getDefault()); |
| 55 | 54 | private static final DatatypeFactory XML_DATE; |
| 56 | 55 | |
| … |
… |
public final class DateUtils {
|
| 67 | 66 | XML_DATE = fact; |
| 68 | 67 | } |
| 69 | 68 | |
| | 69 | protected DateUtils() { |
| | 70 | // Hide default constructor for utils classes |
| | 71 | } |
| | 72 | |
| 70 | 73 | /** |
| 71 | 74 | * Parses XML date quickly, regardless of current locale. |
| 72 | 75 | * @param str The XML date as string |
| 73 | 76 | * @return The date |
| 74 | 77 | * @throws UncheckedParseException if the date does not match any of the supported date formats |
| 75 | 78 | */ |
| 76 | | public static synchronized Date fromString(String str) throws UncheckedParseException { |
| | 79 | public static synchronized Date fromString(String str) { |
| 77 | 80 | return new Date(tsFromString(str)); |
| 78 | 81 | } |
| 79 | 82 | |
| … |
… |
public final class DateUtils {
|
| 83 | 86 | * @return The date in milliseconds since epoch |
| 84 | 87 | * @throws UncheckedParseException if the date does not match any of the supported date formats |
| 85 | 88 | */ |
| 86 | | public static synchronized long tsFromString(String str) throws UncheckedParseException { |
| | 89 | public static synchronized long tsFromString(String str) { |
| 87 | 90 | // "2007-07-25T09:26:24{Z|{+|-}01[:00]}" |
| 88 | 91 | if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || |
| 89 | 92 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx") || |
| … |
… |
public final class DateUtils {
|
| 93 | 96 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx") || |
| 94 | 97 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") || |
| 95 | 98 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) { |
| 96 | | final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx") ? calendarLocale : calendar; // consider EXIF date in default timezone |
| | 99 | final Calendar c; // consider EXIF date in default timezone |
| | 100 | if (checkLayout(str, "xxxx:xx:xx xx:xx:xx")) { |
| | 101 | c = getLocalCalendar(); |
| | 102 | } else { |
| | 103 | c = calendar; |
| | 104 | } |
| 97 | 105 | c.set( |
| 98 | 106 | parsePart4(str, 0), |
| 99 | 107 | parsePart2(str, 5)-1, |
| … |
… |
public final class DateUtils {
|
| 115 | 123 | checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") || |
| 116 | 124 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") || |
| 117 | 125 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) { |
| 118 | | final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? calendarLocale : calendar; // consider EXIF date in default timezone |
| | 126 | // consider EXIF date in default timezone |
| | 127 | final Calendar c = checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") ? getLocalCalendar() : calendar; |
| 119 | 128 | c.set( |
| 120 | 129 | parsePart4(str, 0), |
| 121 | 130 | parsePart2(str, 5)-1, |
| … |
… |
public final class DateUtils {
|
| 133 | 142 | } else { |
| 134 | 143 | // example date format "18-AUG-08 13:33:03" |
| 135 | 144 | SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); |
| 136 | | f.setTimeZone(calendarLocale.getTimeZone()); |
| 137 | 145 | Date d = f.parse(str, new ParsePosition(0)); |
| 138 | 146 | if (d != null) |
| 139 | 147 | return d.getTime(); |
| … |
… |
public final class DateUtils {
|
| 146 | 154 | } |
| 147 | 155 | } |
| 148 | 156 | |
| | 157 | private static Calendar getLocalCalendar() { |
| | 158 | final Calendar c = calendarLocale; |
| | 159 | c.setTimeZone(TimeZone.getDefault()); |
| | 160 | return c; |
| | 161 | } |
| | 162 | |
| 149 | 163 | private static String toXmlFormat(GregorianCalendar cal) { |
| 150 | 164 | XMLGregorianCalendar xgc = XML_DATE.newXMLGregorianCalendar(cal); |
| 151 | 165 | if (cal.get(Calendar.MILLISECOND) == 0) { |
| … |
… |
public final class DateUtils {
|
| 315 | 329 | CheckParameterUtil.ensureParameterNotNull(datetime, "datetime"); |
| 316 | 330 | return getDateTimeFormat(dateStyle, timeStyle).format(datetime); |
| 317 | 331 | } |
| 318 | | |
| 319 | | /** |
| 320 | | * Allows to override the timezone for unit tests. |
| 321 | | * @param zone the timezone to use |
| 322 | | */ |
| 323 | | protected static synchronized void setTimeZone(TimeZone zone) { |
| 324 | | calendarLocale.setTimeZone(zone); |
| 325 | | } |
| 326 | 332 | } |
diff --git a/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java b/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java
index 7ae3e3a..658ba4f 100644
|
a
|
b
|
import java.util.Date;
|
| 14 | 14 | import java.util.GregorianCalendar; |
| 15 | 15 | import java.util.TimeZone; |
| 16 | 16 | |
| 17 | | import org.junit.After; |
| 18 | 17 | import org.junit.Before; |
| 19 | 18 | import org.junit.Rule; |
| 20 | 19 | import org.junit.Test; |
| … |
… |
import org.openstreetmap.josm.TestUtils;
|
| 22 | 21 | import org.openstreetmap.josm.data.coor.LatLon; |
| 23 | 22 | import org.openstreetmap.josm.testutils.JOSMTestRules; |
| 24 | 23 | import org.openstreetmap.josm.tools.date.DateUtils; |
| 25 | | import org.openstreetmap.josm.tools.date.DateUtilsTest; |
| 26 | 24 | |
| 27 | 25 | import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; |
| 28 | 26 | |
| … |
… |
public class ExifReaderTest {
|
| 36 | 34 | */ |
| 37 | 35 | @Rule |
| 38 | 36 | @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD") |
| 39 | | public JOSMTestRules test = new JOSMTestRules(); |
| | 37 | public JOSMTestRules test = new JOSMTestRules().timeout(60000); |
| 40 | 38 | |
| 41 | 39 | private File orientationSampleFile, directionSampleFile; |
| 42 | 40 | |
| … |
… |
public class ExifReaderTest {
|
| 47 | 45 | public void setUp() { |
| 48 | 46 | directionSampleFile = new File("data_nodist/exif-example_direction.jpg"); |
| 49 | 47 | orientationSampleFile = new File("data_nodist/exif-example_orientation=6.jpg"); |
| 50 | | DateUtilsTest.setTimeZone(TimeZone.getTimeZone("Europe/Berlin")); |
| 51 | | } |
| 52 | | |
| 53 | | /** |
| 54 | | * Clean {@link DateUtils} state |
| 55 | | */ |
| 56 | | @After |
| 57 | | public void done() { |
| 58 | | DateUtilsTest.setTimeZone(DateUtils.UTC); |
| 59 | 48 | } |
| 60 | 49 | |
| 61 | 50 | /** |
| … |
… |
public class ExifReaderTest {
|
| 65 | 54 | @Test |
| 66 | 55 | public void testReadTime() throws ParseException { |
| 67 | 56 | Date date = ExifReader.readTime(directionSampleFile); |
| | 57 | assertEquals(new GregorianCalendar(2010, Calendar.MAY, 15, 17, 12, 05).getTime(), date); |
| | 58 | |
| | 59 | TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin")); |
| | 60 | date = ExifReader.readTime(directionSampleFile); |
| | 61 | TimeZone.setDefault(DateUtils.UTC); |
| 68 | 62 | assertEquals(new GregorianCalendar(2010, Calendar.MAY, 15, 15, 12, 05).getTime(), date); |
| 69 | 63 | } |
| 70 | 64 | |
| … |
… |
public class ExifReaderTest {
|
| 76 | 70 | public void testReadTimeSubSecond1() throws ParseException { |
| 77 | 71 | Date date = ExifReader.readTime(new File("data_nodist/IMG_20150711_193419.jpg")); |
| 78 | 72 | String dateStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(date); |
| | 73 | assertEquals("2015-07-11T19:34:19.100", dateStr); |
| | 74 | |
| | 75 | TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin")); |
| | 76 | date = ExifReader.readTime(new File("data_nodist/IMG_20150711_193419.jpg")); |
| | 77 | TimeZone.setDefault(DateUtils.UTC); |
| | 78 | dateStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(date); |
| 79 | 79 | assertEquals("2015-07-11T17:34:19.100", dateStr); |
| 80 | 80 | } |
| 81 | 81 | |
| … |
… |
public class ExifReaderTest {
|
| 116 | 116 | public void testTicket11685() throws IOException { |
| 117 | 117 | File file = new File(TestUtils.getRegressionDataFile(11685, "2015-11-08_15-33-27-Xiaomi_YI-Y0030832.jpg")); |
| 118 | 118 | String dateStr = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS").format(ExifReader.readTime(file)); |
| 119 | | assertEquals("2015-11-08T14:33:27.500", dateStr); |
| | 119 | assertEquals("2015-11-08T15:33:27.500", dateStr); |
| 120 | 120 | } |
| 121 | 121 | } |
diff --git a/test/unit/org/openstreetmap/josm/tools/UtilsTest.java b/test/unit/org/openstreetmap/josm/tools/UtilsTest.java
index bffa099..cbe2b8b 100644
|
a
|
b
|
import java.util.Locale;
|
| 12 | 12 | import org.junit.Assert; |
| 13 | 13 | import org.junit.Test; |
| 14 | 14 | import org.openstreetmap.josm.Main; |
| | 15 | import org.openstreetmap.josm.testutils.JOSMTestRules; |
| 15 | 16 | |
| 16 | 17 | /** |
| 17 | 18 | * Unit tests of {@link Utils} class. |
| 18 | 19 | */ |
| 19 | 20 | public class UtilsTest { |
| | 21 | /** |
| | 22 | * Use default, basic test rules. |
| | 23 | */ |
| | 24 | public JOSMTestRules rules = new JOSMTestRules(); |
| 20 | 25 | |
| 21 | 26 | /** |
| 22 | 27 | * Test of {@link Utils#strip} method. |
diff --git a/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java b/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
index 9e55379..06803a7 100644
|
a
|
b
|
public class DateUtilsTest {
|
| 33 | 33 | * @param zone the timezone to use |
| 34 | 34 | */ |
| 35 | 35 | public static void setTimeZone(TimeZone zone) { |
| 36 | | DateUtils.setTimeZone(zone); |
| 37 | 36 | TimeZone.setDefault(zone); |
| 38 | 37 | } |
| 39 | 38 | |