Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 64 additions & 8 deletions CodenameOne/src/com/codename1/l10n/SimpleDateFormat.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ public class SimpleDateFormat extends DateFormat {
* Pattern character for RFC 822-style timezone.
*/
private static final char TIMEZONE822_LETTER = 'Z';
/**
* Pattern character for ISO 8601 timezone.
*/
private static final char ISO_TIMEZONE_LETTER = 'X';
/**
* Pattern character for week year.
*/
private static final char WEEK_YEAR_LETTER = 'Y';
/**
* Pattern character for day number of week.
*/
private static final char DAY_NUMBER_OF_WEEK_LETTER = 'u';
/**
* Internally used character for literal text.
*/
Expand All @@ -141,7 +153,7 @@ public class SimpleDateFormat extends DateFormat {
/**
* Pattern characters recognized by this implementation (same as JDK 1.6).
*/
private static final String PATTERN_LETTERS = "adDEFGHhKkMmsSwWyzZ";
private static final String PATTERN_LETTERS = "adDEFGHhKkMmsSwWyzZXYu";
/**
* TimeZone ID for Greenwich Mean Time
*/
Expand Down Expand Up @@ -371,7 +383,24 @@ String format(Date source, StringBuilder toAppendTo) {
toAppendTo.append(leftPad(v / 60, 2));
toAppendTo.append(leftPad(v % 60, 2));
break;
case ISO_TIMEZONE_LETTER:
v = getOffsetInMinutes(calendar, calendar.getTimeZone());
if (v < 0) {
toAppendTo.append(SIGN_NEGATIVE);
v = -v;
} else {
toAppendTo.append(SIGN_POSITIVE);
}
toAppendTo.append(leftPad(v / 60, 2));
if (len >= 2) {
if (len == 3) {
toAppendTo.append(':');
}
toAppendTo.append(leftPad(v % 60, 2));
}
break;
case YEAR_LETTER:
case WEEK_YEAR_LETTER:
v = calendar.get(Calendar.YEAR);
if (len == 2) {
v %= 100;
Expand Down Expand Up @@ -441,6 +470,10 @@ String format(Date source, StringBuilder toAppendTo) {
v = calendar.get(DAY_OF_WEEK_IN_MONTH);
toAppendTo.append(leftPad(v, len));
break;
case DAY_NUMBER_OF_WEEK_LETTER:
v = ((calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7) + 1;
toAppendTo.append(leftPad(v, len));
break;
}
}
return toAppendTo.toString();
Expand Down Expand Up @@ -515,6 +548,7 @@ public Date parse(String source) throws ParseException {
break;
case TIMEZONE_LETTER:
case TIMEZONE822_LETTER:
case ISO_TIMEZONE_LETTER:
s = readTimeZone(source, startIndex);
TimeZoneResult res = new TimeZoneResult();
if (s == null || (v = parseTimeZone(s, startIndex, res)) == -1) {
Expand All @@ -525,6 +559,7 @@ public Date parse(String source) throws ParseException {
tzMinutes = ((tzMinutes == -1) ? 0 : tzMinutes) + v;
break;
case YEAR_LETTER:
case WEEK_YEAR_LETTER:
s = readNumber(source, startIndex, token, adjacent);
calendar.set(Calendar.YEAR, parseYear(s, token, startIndex));
break;
Expand Down Expand Up @@ -572,6 +607,14 @@ public Date parse(String source) throws ParseException {
calendar.set(DAY_OF_WEEK_IN_MONTH,
parseNumber(s, startIndex, "day of week in month", -5, 5));
break;
case DAY_NUMBER_OF_WEEK_LETTER:
s = readNumber(source, startIndex, token, adjacent);
v = parseNumber(s, startIndex, "day number of week", 1, 7);
// Map 1(Mon)-7(Sun) to Calendar 2(Mon)..1(Sun)
// Mon=1 -> 2. Tue=2 -> 3. ... Sat=6 -> 7. Sun=7 -> 1.
// v % 7 + 1
calendar.set(Calendar.DAY_OF_WEEK, (v % 7) + 1);
break;
}
if (s != null) {
startIndex += s.length();
Expand Down Expand Up @@ -1186,14 +1229,27 @@ List<String> parseDatePattern(String pattern) {
char ch = pattern.charAt(i);
// Handle literal text enclosed in quotes
if (ch == EXPLICIT_LITERAL) {
int n = pattern.indexOf(EXPLICIT_LITERAL, i + 1);
if (n != -1) {
if (tmp != null) {
tokens.add(tmp.charAt(0) + tmp);
tmp = null;
if (tmp != null) {
tokens.add(tmp.charAt(0) + tmp);
tmp = null;
}
StringBuilder sb = new StringBuilder();
int n = i + 1;
while (n < plen) {
char c = pattern.charAt(n);
if (c == EXPLICIT_LITERAL) {
if (n + 1 < plen && pattern.charAt(n + 1) == EXPLICIT_LITERAL) {
sb.append(EXPLICIT_LITERAL);
n += 2;
continue;
} else {
break;
}
}
tokens.add(LITERAL_LETTER + pattern.substring(i + 1, n));
sb.append(c);
n++;
}
tokens.add(LITERAL_LETTER + sb.toString());
i = n;
continue;
}
Expand All @@ -1208,7 +1264,7 @@ List<String> parseDatePattern(String pattern) {
int n;
for (n = i; n < plen; n++) {
ch = pattern.charAt(n);
if (PATTERN_LETTERS.indexOf(ch) != -1) {
if (PATTERN_LETTERS.indexOf(ch) != -1 || ch == EXPLICIT_LITERAL) {
break;
}
if (isAlpha(ch)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,58 @@ void cloneCopiesPatternAndSymbols() {
assertSame(symbols, clone.getDateFormatSymbols());
}

@Test
void testQuotedStringLiteral() {
// "formats like yyyy.MM.dd G 'at' HH:mm:ss z yield illegal argument exception on the t char."
assertDoesNotThrow(() -> {
new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z");
}, "Should not throw exception for quoted literal 'at'");
}

@Test
void testEscapedSingleQuoteFormat() {
// "Also formats like: hh 'o''clock' yield exception for the c char."
SimpleDateFormat sdf = new SimpleDateFormat("hh 'o''clock'");
Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR, 5);
String result = sdf.format(cal.getTime());
// Expected: 05 o'clock
assertTrue(result.contains("o'clock"), "Should contain single quote: " + result);
}

@Test
void testXXXFormat() {
// "yyyy-MM-dd'T'HH:mm:ss.SSSXXX (exception for X char, recent API level prerequisite)"
assertDoesNotThrow(() -> {
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
}, "Should not throw exception for XXX format");

SimpleDateFormat sdf = new SimpleDateFormat("XXX");
// We cannot reliably test exact timezone string without controlling default timezone,
// but we can check it doesn't crash and produces something reasonable.
String result = sdf.format(new Date());
assertNotNull(result);
assertFalse(result.isEmpty());
}

@Test
void testYYYYAnduFormat() {
// "YYYY-'W'ww-u (exception for Y char)"
assertDoesNotThrow(() -> {
new SimpleDateFormat("YYYY-'W'ww-u");
}, "Should not throw exception for YYYY and u format");

SimpleDateFormat sdf = new SimpleDateFormat("u");
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
String result = sdf.format(cal.getTime());
assertEquals("1", result, "Monday should be 1");

cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
result = sdf.format(cal.getTime());
assertEquals("7", result, "Sunday should be 7");
}

private static class StubL10NManager extends L10NManager {
StubL10NManager() {
super("en", "US");
Expand Down
Loading