diff --git a/src/org/openstreetmap/josm/tools/date/DateUtils.java b/src/org/openstreetmap/josm/tools/date/DateUtils.java
index 9cd7cc82e..09ba101a7 100644
|
a
|
b
|
|
| 14 | 14 | import java.util.TimeZone; |
| 15 | 15 | import java.util.concurrent.TimeUnit; |
| 16 | 16 | |
| 17 | | import javax.xml.datatype.DatatypeConfigurationException; |
| 18 | | import javax.xml.datatype.DatatypeFactory; |
| 19 | | |
| 20 | 17 | import org.openstreetmap.josm.data.preferences.BooleanProperty; |
| 21 | 18 | import org.openstreetmap.josm.tools.CheckParameterUtil; |
| 22 | | import org.openstreetmap.josm.tools.Logging; |
| 23 | 19 | import org.openstreetmap.josm.tools.UncheckedParseException; |
| 24 | 20 | |
| 25 | 21 | /** |
| … |
… |
|
| 43 | 39 | */ |
| 44 | 40 | public static final BooleanProperty PROP_ISO_DATES = new BooleanProperty("iso.dates", false); |
| 45 | 41 | |
| 46 | | private static final DatatypeFactory XML_DATE; |
| 47 | | |
| 48 | | static { |
| 49 | | DatatypeFactory fact = null; |
| 50 | | try { |
| 51 | | fact = DatatypeFactory.newInstance(); |
| 52 | | } catch (DatatypeConfigurationException e) { |
| 53 | | Logging.error(e); |
| 54 | | } |
| 55 | | XML_DATE = fact; |
| 56 | | } |
| 57 | | |
| 58 | 42 | /** |
| 59 | 43 | * Constructs a new {@code DateUtils}. |
| 60 | 44 | */ |
| … |
… |
private DateUtils() {
|
| 69 | 53 | * @throws UncheckedParseException if the date does not match any of the supported date formats |
| 70 | 54 | * @throws DateTimeException if the value of any field is out of range, or if the day-of-month is invalid for the month-year |
| 71 | 55 | */ |
| 72 | | public static synchronized Date fromString(String str) { |
| | 56 | public static Date fromString(String str) { |
| 73 | 57 | return new Date(tsFromString(str)); |
| 74 | 58 | } |
| 75 | 59 | |
| … |
… |
public static synchronized Date fromString(String str) {
|
| 80 | 64 | * @throws UncheckedParseException if the date does not match any of the supported date formats |
| 81 | 65 | * @throws DateTimeException if the value of any field is out of range, or if the day-of-month is invalid for the month-year |
| 82 | 66 | */ |
| 83 | | public static synchronized long tsFromString(String str) { |
| | 67 | public static long tsFromString(String str) { |
| 84 | 68 | // "2007-07-25T09:26:24{Z|{+|-}01[:00]}" |
| 85 | | if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || |
| | 69 | if (checkLayout(str, "xxxx-xx-xx")) { |
| | 70 | final ZonedDateTime local = ZonedDateTime.of( |
| | 71 | parsePart4(str, 0), |
| | 72 | parsePart2(str, 5), |
| | 73 | parsePart2(str, 8), |
| | 74 | 0,0,0, 0, ZoneOffset.UTC); |
| | 75 | return local.toInstant().toEpochMilli(); |
| | 76 | } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || |
| 86 | 77 | checkLayout(str, "xxxx-xx-xxTxx:xx:xx") || |
| 87 | 78 | checkLayout(str, "xxxx:xx:xx xx:xx:xx") || |
| 88 | 79 | checkLayout(str, "xxxx-xx-xx xx:xx:xxZ") || |
| … |
… |
public static synchronized long tsFromString(String str) {
|
| 133 | 124 | if (d != null) |
| 134 | 125 | return d.getTime(); |
| 135 | 126 | } |
| 136 | | |
| 137 | | try { |
| 138 | | return XML_DATE.newXMLGregorianCalendar(str).toGregorianCalendar().getTimeInMillis(); |
| 139 | | } catch (IllegalArgumentException ex) { |
| 140 | | throw new UncheckedParseException("The date string (" + str + ") could not be parsed.", ex); |
| 141 | | } |
| | 127 | throw new UncheckedParseException("The date string (" + str + ") could not be parsed."); |
| 142 | 128 | } |
| 143 | 129 | |
| 144 | 130 | /** |
| … |
… |
public static String fromTimestamp(long timestamp) {
|
| 157 | 143 | * @return The formatted date |
| 158 | 144 | * @since 14434 |
| 159 | 145 | */ |
| 160 | | public static synchronized String fromTimestampInMillis(long timestamp) { |
| | 146 | public static String fromTimestampInMillis(long timestamp) { |
| 161 | 147 | final ZonedDateTime temporal = Instant.ofEpochMilli(timestamp).atZone(ZoneOffset.UTC); |
| 162 | 148 | return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(temporal); |
| 163 | 149 | } |
| … |
… |
public static synchronized String fromTimestampInMillis(long timestamp) {
|
| 167 | 153 | * @param timestamp number of seconds since the epoch |
| 168 | 154 | * @return The formatted date |
| 169 | 155 | */ |
| 170 | | public static synchronized String fromTimestamp(int timestamp) { |
| | 156 | public static String fromTimestamp(int timestamp) { |
| 171 | 157 | return fromTimestamp(Integer.toUnsignedLong(timestamp)); |
| 172 | 158 | } |
| 173 | 159 | |
| … |
… |
public static synchronized String fromTimestamp(int timestamp) {
|
| 176 | 162 | * @param date The date to format |
| 177 | 163 | * @return The formatted date |
| 178 | 164 | */ |
| 179 | | public static synchronized String fromDate(Date date) { |
| | 165 | public static String fromDate(Date date) { |
| 180 | 166 | final ZonedDateTime temporal = date.toInstant().atZone(ZoneOffset.UTC); |
| 181 | 167 | return DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(temporal); |
| 182 | 168 | } |
diff --git a/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java b/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
index 3e9efe675..d6bcc949c 100644
|
a
|
b
|
|
| 9 | 9 | |
| 10 | 10 | import java.text.DateFormat; |
| 11 | 11 | import java.util.Date; |
| | 12 | import java.util.Random; |
| 12 | 13 | import java.util.TimeZone; |
| | 14 | import java.util.concurrent.ForkJoinPool; |
| 13 | 15 | |
| | 16 | import org.junit.Ignore; |
| 14 | 17 | import org.junit.Rule; |
| 15 | 18 | import org.junit.Test; |
| 16 | 19 | import org.openstreetmap.josm.testutils.JOSMTestRules; |
| … |
… |
public void testTsFromString() {
|
| 191 | 194 | assertEquals(1459695600123L + 5 * 3600 * 1000, DateUtils.tsFromString("2016-04-03T15:00:00.123-05:00")); |
| 192 | 195 | |
| 193 | 196 | // Local time |
| 194 | | TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin")); |
| | 197 | setTimeZone(TimeZone.getTimeZone("Europe/Berlin")); |
| 195 | 198 | assertEquals(1459688400000L, DateUtils.tsFromString("03-APR-16 15:00:00")); |
| 196 | 199 | } |
| 197 | 200 | |
| | 201 | @Test |
| | 202 | @Ignore("slow, for thread safety testing") |
| | 203 | public void testTsFromString800k() throws Exception { |
| | 204 | new ForkJoinPool(64).submit(() -> new Random() |
| | 205 | .longs(800_000) |
| | 206 | .parallel() |
| | 207 | .forEach(ignore -> testTsFromString())).get(); |
| | 208 | // 13.992s → 2.213s |
| | 209 | } |
| | 210 | |
| 198 | 211 | /** |
| 199 | 212 | * Unit test of {@link DateUtils#tsFromString} method. |
| 200 | 213 | */ |