Changeset 18735 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/tools/date/DateUtils.java
r18013 r18735 12 12 import java.time.format.DateTimeFormatter; 13 13 import java.time.format.DateTimeFormatterBuilder; 14 import java.time.format.DateTimeParseException;15 14 import java.time.format.FormatStyle; 16 15 import java.util.Date; … … 81 80 public static Instant parseInstant(String str) { 82 81 // "2007-07-25T09:26:24{Z|{+|-}01[:00]}" 83 if (checkLayout(str, "xxxx-xx-xx") || 84 checkLayout(str, "xxxx-xx") || 85 checkLayout(str, "xxxx")) { 86 final ZonedDateTime local = ZonedDateTime.of( 87 parsePart4(str, 0), 88 str.length() > 5 ? parsePart2(str, 5) : 1, 89 str.length() > 8 ? parsePart2(str, 8) : 1, 90 0, 0, 0, 0, ZoneOffset.UTC); 91 return local.toInstant(); 92 } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || 93 checkLayout(str, "xxxx-xx-xxTxx:xx:xx") || 94 checkLayout(str, "xxxx:xx:xx xx:xx:xx") || 95 checkLayout(str, "xxxx/xx/xx xx:xx:xx") || 96 checkLayout(str, "xxxx-xx-xx xx:xx:xxZ") || 97 checkLayout(str, "xxxx-xx-xx xx:xx:xx UTC") || 98 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx") || 99 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx") || 100 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") || 101 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) { 102 final ZonedDateTime local = ZonedDateTime.of( 103 parsePart4(str, 0), 104 parsePart2(str, 5), 105 parsePart2(str, 8), 106 parsePart2(str, 11), 107 parsePart2(str, 14), 108 parsePart2(str, 17), 109 0, 110 ZoneOffset.UTC 111 ); 112 if (str.length() == 22 || str.length() == 25) { 113 final int plusHr = parsePart2(str, 20); 114 return local.plusHours(str.charAt(19) == '+' ? -plusHr : plusHr).toInstant(); 82 try { 83 if (checkLayout(str, "xxxx-xx-xx") || 84 checkLayout(str, "xxxx-xx") || 85 checkLayout(str, "xxxx")) { 86 final ZonedDateTime local = ZonedDateTime.of( 87 parsePart4(str, 0), 88 str.length() > 5 ? parsePart2(str, 5) : 1, 89 str.length() > 8 ? parsePart2(str, 8) : 1, 90 0, 0, 0, 0, ZoneOffset.UTC); 91 return local.toInstant(); 92 } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xxZ") || 93 checkLayout(str, "xxxx-xx-xxTxx:xx:xx") || 94 checkLayout(str, "xxxx:xx:xx xx:xx:xx") || 95 checkLayout(str, "xxxx/xx/xx xx:xx:xx") || 96 checkLayout(str, "xxxx-xx-xx xx:xx:xxZ") || 97 checkLayout(str, "xxxx-xx-xx xx:xx:xx UTC") || 98 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx") || 99 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx") || 100 checkLayout(str, "xxxx-xx-xxTxx:xx:xx+xx:00") || 101 checkLayout(str, "xxxx-xx-xxTxx:xx:xx-xx:00")) { 102 final ZonedDateTime local = ZonedDateTime.of( 103 parsePart4(str, 0), 104 parsePart2(str, 5), 105 parsePart2(str, 8), 106 parsePart2(str, 11), 107 parsePart2(str, 14), 108 parsePart2(str, 17), 109 0, 110 ZoneOffset.UTC 111 ); 112 if (str.length() == 22 || str.length() == 25) { 113 final int plusHr = parsePart2(str, 20); 114 return local.plusHours(str.charAt(19) == '+' ? -plusHr : plusHr).toInstant(); 115 } 116 return local.toInstant(); 117 } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxxZ") || 118 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx") || 119 checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") || 120 checkLayout(str, "xxxx/xx/xx xx:xx:xx.xxx") || 121 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") || 122 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) { 123 final ZonedDateTime local = ZonedDateTime.of( 124 parsePart4(str, 0), 125 parsePart2(str, 5), 126 parsePart2(str, 8), 127 parsePart2(str, 11), 128 parsePart2(str, 14), 129 parsePart2(str, 17), 130 parsePart3(str, 20) * 1_000_000, 131 ZoneOffset.UTC 132 ); 133 if (str.length() == 29) { 134 final int plusHr = parsePart2(str, 24); 135 return local.plusHours(str.charAt(23) == '+' ? -plusHr : plusHr).toInstant(); 136 } 137 return local.toInstant(); 138 } else if (checkLayout(str, "xxxx/xx/xx xx:xx:xx.xxxxxx")) { 139 return ZonedDateTime.of( 140 parsePart4(str, 0), 141 parsePart2(str, 5), 142 parsePart2(str, 8), 143 parsePart2(str, 11), 144 parsePart2(str, 14), 145 parsePart2(str, 17), 146 parsePart6(str, 20) * 1_000, 147 ZoneOffset.UTC 148 ).toInstant(); 149 } else { 150 // example date format "18-AUG-08 13:33:03" 151 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); 152 Date d = f.parse(str, new ParsePosition(0)); 153 if (d != null) 154 return d.toInstant(); 115 155 } 116 return local.toInstant(); 117 } else if (checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxxZ") || 118 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx") || 119 checkLayout(str, "xxxx:xx:xx xx:xx:xx.xxx") || 120 checkLayout(str, "xxxx/xx/xx xx:xx:xx.xxx") || 121 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx+xx:00") || 122 checkLayout(str, "xxxx-xx-xxTxx:xx:xx.xxx-xx:00")) { 123 final ZonedDateTime local = ZonedDateTime.of( 124 parsePart4(str, 0), 125 parsePart2(str, 5), 126 parsePart2(str, 8), 127 parsePart2(str, 11), 128 parsePart2(str, 14), 129 parsePart2(str, 17), 130 parsePart3(str, 20) * 1_000_000, 131 ZoneOffset.UTC 132 ); 133 if (str.length() == 29) { 134 final int plusHr = parsePart2(str, 24); 135 return local.plusHours(str.charAt(23) == '+' ? -plusHr : plusHr).toInstant(); 136 } 137 return local.toInstant(); 138 } else if (checkLayout(str, "xxxx/xx/xx xx:xx:xx.xxxxxx")) { 139 return ZonedDateTime.of( 140 parsePart4(str, 0), 141 parsePart2(str, 5), 142 parsePart2(str, 8), 143 parsePart2(str, 11), 144 parsePart2(str, 14), 145 parsePart2(str, 17), 146 parsePart6(str, 20) * 1_000, 147 ZoneOffset.UTC 148 ).toInstant(); 149 } else { 150 // example date format "18-AUG-08 13:33:03" 151 SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yy HH:mm:ss"); 152 Date d = f.parse(str, new ParsePosition(0)); 153 if (d != null) 154 return d.toInstant(); 155 } 156 157 try { 156 158 157 // slow path for fractional seconds different from millisecond precision 159 158 return ZonedDateTime.parse(str).toInstant(); 160 } catch (IllegalArgumentException | DateTime ParseException ex) {159 } catch (IllegalArgumentException | DateTimeException ex) { 161 160 throw new UncheckedParseException("The date string (" + str + ") could not be parsed.", ex); 162 161 } … … 213 212 } 214 213 214 /** 215 * Check text for a specified layout 216 * @param text The text to check 217 * @param pattern The pattern to use 218 * @return {@code true} if the layout matches, otherwise {@code false} 219 */ 215 220 private static boolean checkLayout(String text, String pattern) { 216 221 if (text.length() != pattern.length()) … … 244 249 245 250 private static int parsePart6(String str, int off) { 246 return 100 000 * num(str.charAt(off))247 + 10 000 * num(str.charAt(off + 1))248 + 1 000 * num(str.charAt(off + 2))249 + 100 * num(str.charAt(off + 3))250 + 10 * num(str.charAt(off + 4))251 + num(str.charAt(off + 5));251 return 100_000 * num(str.charAt(off)) 252 + 10_000 * num(str.charAt(off + 1)) 253 + 1_000 * num(str.charAt(off + 2)) 254 + 100 * num(str.charAt(off + 3)) 255 + 10 * num(str.charAt(off + 4)) 256 + num(str.charAt(off + 5)); 252 257 } 253 258 … … 268 273 */ 269 274 public static DateFormat getDateFormat(int dateStyle) { 270 if ( PROP_ISO_DATES.get()) {275 if (Boolean.TRUE.equals(PROP_ISO_DATES.get())) { 271 276 return newIsoDateFormat(); 272 277 } else { … … 281 286 */ 282 287 public static DateTimeFormatter getDateFormatter(FormatStyle dateStyle) { 283 DateTimeFormatter formatter = PROP_ISO_DATES.get()288 DateTimeFormatter formatter = Boolean.TRUE.equals(PROP_ISO_DATES.get()) 284 289 ? DateTimeFormatter.ISO_LOCAL_DATE 285 290 : DateTimeFormatter.ofLocalizedDate(dateStyle); … … 306 311 */ 307 312 public static DateFormat getTimeFormat(int timeStyle) { 308 if ( PROP_ISO_DATES.get()) {313 if (Boolean.TRUE.equals(PROP_ISO_DATES.get())) { 309 314 // This is not strictly conform to ISO 8601. We just want to avoid US-style times such as 3.30pm 310 315 return new SimpleDateFormat("HH:mm:ss"); … … 320 325 */ 321 326 public static DateTimeFormatter getTimeFormatter(FormatStyle timeStyle) { 322 DateTimeFormatter formatter = PROP_ISO_DATES.get()327 DateTimeFormatter formatter = Boolean.TRUE.equals(PROP_ISO_DATES.get()) 323 328 ? DateTimeFormatter.ISO_LOCAL_TIME 324 329 : DateTimeFormatter.ofLocalizedTime(timeStyle); … … 346 351 */ 347 352 public static DateFormat getDateTimeFormat(int dateStyle, int timeStyle) { 348 if ( PROP_ISO_DATES.get()) {353 if (Boolean.TRUE.equals(PROP_ISO_DATES.get())) { 349 354 // This is not strictly conform to ISO 8601. We just want to avoid US-style times such as 3.30pm 350 355 // and we don't want to use the 'T' separator as a space character is much more readable … … 372 377 */ 373 378 public static DateTimeFormatter getDateTimeFormatter(FormatStyle dateStyle, FormatStyle timeStyle) { 374 DateTimeFormatter formatter = PROP_ISO_DATES.get()379 DateTimeFormatter formatter = Boolean.TRUE.equals(PROP_ISO_DATES.get()) 375 380 ? ISO_LOCAL_DATE_TIME 376 381 : DateTimeFormatter.ofLocalizedDateTime(dateStyle, timeStyle); -
trunk/test/unit/org/openstreetmap/josm/tools/date/DateUtilsTest.java
r17987 r18735 17 17 import java.util.concurrent.ForkJoinPool; 18 18 19 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 20 import net.trajano.commons.testing.UtilityClassTestUtil; 19 21 import org.junit.jupiter.api.Disabled; 20 22 import org.junit.jupiter.api.Test; 21 23 import org.junit.jupiter.api.extension.RegisterExtension; 24 import org.junit.jupiter.params.ParameterizedTest; 25 import org.junit.jupiter.params.provider.ValueSource; 22 26 import org.openstreetmap.josm.testutils.JOSMTestRules; 23 27 import org.openstreetmap.josm.tools.UncheckedParseException; 24 25 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;26 import net.trajano.commons.testing.UtilityClassTestUtil;27 28 28 29 /** … … 116 117 * Verifies that parsing an illegal date throws a {@link UncheckedParseException} 117 118 */ 118 @Test 119 void testIllegalDate() { 120 assertThrows(UncheckedParseException.class, () -> DateUtils.fromString("2014-")); 119 @ParameterizedTest 120 @ValueSource(strings = {"2014-", "2014-01-", "2014-01-01T", "2014-00-01", "2014-01-00"}) 121 void testIllegalDate(String date) { 122 assertThrows(UncheckedParseException.class, () -> DateUtils.fromString(date)); 121 123 } 122 124
Note:
See TracChangeset
for help on using the changeset viewer.