Merge changes from topic "DateUtilsBridge"
* changes: Move/Copy some libcore.icu classes to android.text.format Copy some libcore.icu classes to android.text.format
This commit is contained in:
60
core/java/android/text/format/DateTimeFormat.java
Normal file
60
core/java/android/text/format/DateTimeFormat.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.text.format;
|
||||||
|
|
||||||
|
import android.icu.text.DateFormat;
|
||||||
|
import android.icu.text.DateTimePatternGenerator;
|
||||||
|
import android.icu.text.DisplayContext;
|
||||||
|
import android.icu.text.SimpleDateFormat;
|
||||||
|
import android.icu.util.Calendar;
|
||||||
|
import android.icu.util.ULocale;
|
||||||
|
import android.util.LruCache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A formatter that outputs a single date/time.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
class DateTimeFormat {
|
||||||
|
private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
|
||||||
|
|
||||||
|
static class FormatterCache extends LruCache<String, DateFormat> {
|
||||||
|
FormatterCache() {
|
||||||
|
super(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTimeFormat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String format(ULocale icuLocale, Calendar time, int flags,
|
||||||
|
DisplayContext displayContext) {
|
||||||
|
String skeleton = DateUtilsBridge.toSkeleton(time, flags);
|
||||||
|
String key = skeleton + "\t" + icuLocale + "\t" + time.getTimeZone();
|
||||||
|
synchronized (CACHED_FORMATTERS) {
|
||||||
|
DateFormat formatter = CACHED_FORMATTERS.get(key);
|
||||||
|
if (formatter == null) {
|
||||||
|
DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(
|
||||||
|
icuLocale);
|
||||||
|
formatter = new SimpleDateFormat(generator.getBestPattern(skeleton), icuLocale);
|
||||||
|
CACHED_FORMATTERS.put(key, formatter);
|
||||||
|
}
|
||||||
|
formatter.setContext(displayContext);
|
||||||
|
return formatter.format(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,7 +29,6 @@ import com.android.internal.R;
|
|||||||
|
|
||||||
import libcore.icu.DateIntervalFormat;
|
import libcore.icu.DateIntervalFormat;
|
||||||
import libcore.icu.LocaleData;
|
import libcore.icu.LocaleData;
|
||||||
import libcore.icu.RelativeDateTimeFormatter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
|||||||
198
core/java/android/text/format/DateUtilsBridge.java
Normal file
198
core/java/android/text/format/DateUtilsBridge.java
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.text.format;
|
||||||
|
|
||||||
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
|
||||||
|
|
||||||
|
import android.icu.util.Calendar;
|
||||||
|
import android.icu.util.GregorianCalendar;
|
||||||
|
import android.icu.util.TimeZone;
|
||||||
|
import android.icu.util.ULocale;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common methods and constants for the various ICU formatters used to support {@link
|
||||||
|
* android.text.format.DateUtils}.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(visibility = PACKAGE)
|
||||||
|
public final class DateUtilsBridge {
|
||||||
|
// These are all public API in DateUtils. There are others, but they're either for use with
|
||||||
|
// other methods (like FORMAT_ABBREV_RELATIVE), don't internationalize (like FORMAT_CAP_AMPM),
|
||||||
|
// or have never been implemented anyway.
|
||||||
|
public static final int FORMAT_SHOW_TIME = 0x00001;
|
||||||
|
public static final int FORMAT_SHOW_WEEKDAY = 0x00002;
|
||||||
|
public static final int FORMAT_SHOW_YEAR = 0x00004;
|
||||||
|
public static final int FORMAT_NO_YEAR = 0x00008;
|
||||||
|
public static final int FORMAT_SHOW_DATE = 0x00010;
|
||||||
|
public static final int FORMAT_NO_MONTH_DAY = 0x00020;
|
||||||
|
public static final int FORMAT_12HOUR = 0x00040;
|
||||||
|
public static final int FORMAT_24HOUR = 0x00080;
|
||||||
|
public static final int FORMAT_UTC = 0x02000;
|
||||||
|
public static final int FORMAT_ABBREV_TIME = 0x04000;
|
||||||
|
public static final int FORMAT_ABBREV_WEEKDAY = 0x08000;
|
||||||
|
public static final int FORMAT_ABBREV_MONTH = 0x10000;
|
||||||
|
public static final int FORMAT_NUMERIC_DATE = 0x20000;
|
||||||
|
public static final int FORMAT_ABBREV_RELATIVE = 0x40000;
|
||||||
|
public static final int FORMAT_ABBREV_ALL = 0x80000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an immutable ICU timezone backed by the specified libcore timezone data. At the time
|
||||||
|
* of writing the libcore implementation is faster but restricted to 1902 - 2038. Callers must
|
||||||
|
* not modify the {@code tz} after calling this method.
|
||||||
|
*/
|
||||||
|
public static TimeZone icuTimeZone(java.util.TimeZone tz) {
|
||||||
|
TimeZone icuTimeZone = TimeZone.getTimeZone(tz.getID());
|
||||||
|
icuTimeZone.freeze(); // Optimization - allows the timezone to be copied cheaply.
|
||||||
|
return icuTimeZone;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a GregorianCalendar based on the arguments
|
||||||
|
*/
|
||||||
|
public static Calendar createIcuCalendar(TimeZone icuTimeZone, ULocale icuLocale,
|
||||||
|
long timeInMillis) {
|
||||||
|
Calendar calendar = new GregorianCalendar(icuTimeZone, icuLocale);
|
||||||
|
calendar.setTimeInMillis(timeInMillis);
|
||||||
|
return calendar;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toSkeleton(Calendar calendar, int flags) {
|
||||||
|
return toSkeleton(calendar, calendar, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String toSkeleton(Calendar startCalendar, Calendar endCalendar, int flags) {
|
||||||
|
if ((flags & FORMAT_ABBREV_ALL) != 0) {
|
||||||
|
flags |= FORMAT_ABBREV_MONTH | FORMAT_ABBREV_TIME | FORMAT_ABBREV_WEEKDAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
String monthPart = "MMMM";
|
||||||
|
if ((flags & FORMAT_NUMERIC_DATE) != 0) {
|
||||||
|
monthPart = "M";
|
||||||
|
} else if ((flags & FORMAT_ABBREV_MONTH) != 0) {
|
||||||
|
monthPart = "MMM";
|
||||||
|
}
|
||||||
|
|
||||||
|
String weekPart = "EEEE";
|
||||||
|
if ((flags & FORMAT_ABBREV_WEEKDAY) != 0) {
|
||||||
|
weekPart = "EEE";
|
||||||
|
}
|
||||||
|
|
||||||
|
String timePart = "j"; // "j" means choose 12 or 24 hour based on current locale.
|
||||||
|
if ((flags & FORMAT_24HOUR) != 0) {
|
||||||
|
timePart = "H";
|
||||||
|
} else if ((flags & FORMAT_12HOUR) != 0) {
|
||||||
|
timePart = "h";
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've not been asked to abbreviate times, or we're using the 24-hour clock (where it
|
||||||
|
// never makes sense to leave out the minutes), include minutes. This gets us times like
|
||||||
|
// "4 PM" while avoiding times like "16" (for "16:00").
|
||||||
|
if ((flags & FORMAT_ABBREV_TIME) == 0 || (flags & FORMAT_24HOUR) != 0) {
|
||||||
|
timePart += "m";
|
||||||
|
} else {
|
||||||
|
// Otherwise, we're abbreviating a 12-hour time, and should only show the minutes
|
||||||
|
// if they're not both "00".
|
||||||
|
if (!(onTheHour(startCalendar) && onTheHour(endCalendar))) {
|
||||||
|
timePart = timePart + "m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallOnDifferentDates(startCalendar, endCalendar)) {
|
||||||
|
flags |= FORMAT_SHOW_DATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fallInSameMonth(startCalendar, endCalendar) && (flags & FORMAT_NO_MONTH_DAY) != 0) {
|
||||||
|
flags &= (~FORMAT_SHOW_WEEKDAY);
|
||||||
|
flags &= (~FORMAT_SHOW_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & (FORMAT_SHOW_DATE | FORMAT_SHOW_TIME | FORMAT_SHOW_WEEKDAY)) == 0) {
|
||||||
|
flags |= FORMAT_SHOW_DATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've been asked to show the date, work out whether we think we should show the year.
|
||||||
|
if ((flags & FORMAT_SHOW_DATE) != 0) {
|
||||||
|
if ((flags & FORMAT_SHOW_YEAR) != 0) {
|
||||||
|
// The caller explicitly wants us to show the year.
|
||||||
|
} else if ((flags & FORMAT_NO_YEAR) != 0) {
|
||||||
|
// The caller explicitly doesn't want us to show the year, even if we otherwise
|
||||||
|
// would.
|
||||||
|
} else if (!fallInSameYear(startCalendar, endCalendar) || !isThisYear(startCalendar)) {
|
||||||
|
flags |= FORMAT_SHOW_YEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
if ((flags & (FORMAT_SHOW_DATE | FORMAT_NO_MONTH_DAY)) != 0) {
|
||||||
|
if ((flags & FORMAT_SHOW_YEAR) != 0) {
|
||||||
|
builder.append("y");
|
||||||
|
}
|
||||||
|
builder.append(monthPart);
|
||||||
|
if ((flags & FORMAT_NO_MONTH_DAY) == 0) {
|
||||||
|
builder.append("d");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((flags & FORMAT_SHOW_WEEKDAY) != 0) {
|
||||||
|
builder.append(weekPart);
|
||||||
|
}
|
||||||
|
if ((flags & FORMAT_SHOW_TIME) != 0) {
|
||||||
|
builder.append(timePart);
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int dayDistance(Calendar c1, Calendar c2) {
|
||||||
|
return c2.get(Calendar.JULIAN_DAY) - c1.get(Calendar.JULIAN_DAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the argument will be displayed as if it were midnight, using any of the
|
||||||
|
* skeletons provided by {@link #toSkeleton}.
|
||||||
|
*/
|
||||||
|
public static boolean isDisplayMidnightUsingSkeleton(Calendar c) {
|
||||||
|
// All the skeletons returned by toSkeleton have minute precision (they may abbreviate
|
||||||
|
// 4:00 PM to 4 PM but will still show the following minute as 4:01 PM).
|
||||||
|
return c.get(Calendar.HOUR_OF_DAY) == 0 && c.get(Calendar.MINUTE) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean onTheHour(Calendar c) {
|
||||||
|
return c.get(Calendar.MINUTE) == 0 && c.get(Calendar.SECOND) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean fallOnDifferentDates(Calendar c1, Calendar c2) {
|
||||||
|
return c1.get(Calendar.YEAR) != c2.get(Calendar.YEAR)
|
||||||
|
|| c1.get(Calendar.MONTH) != c2.get(Calendar.MONTH)
|
||||||
|
|| c1.get(Calendar.DAY_OF_MONTH) != c2.get(Calendar.DAY_OF_MONTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean fallInSameMonth(Calendar c1, Calendar c2) {
|
||||||
|
return c1.get(Calendar.MONTH) == c2.get(Calendar.MONTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean fallInSameYear(Calendar c1, Calendar c2) {
|
||||||
|
return c1.get(Calendar.YEAR) == c2.get(Calendar.YEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isThisYear(Calendar c) {
|
||||||
|
Calendar now = (Calendar) c.clone();
|
||||||
|
now.setTimeInMillis(System.currentTimeMillis());
|
||||||
|
return c.get(Calendar.YEAR) == now.get(Calendar.YEAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
359
core/java/android/text/format/RelativeDateTimeFormatter.java
Normal file
359
core/java/android/text/format/RelativeDateTimeFormatter.java
Normal file
@@ -0,0 +1,359 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.text.format;
|
||||||
|
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_MONTH;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_SHOW_DATE;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_SHOW_TIME;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR;
|
||||||
|
|
||||||
|
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
|
||||||
|
|
||||||
|
import android.icu.text.DisplayContext;
|
||||||
|
import android.icu.util.Calendar;
|
||||||
|
import android.icu.util.ULocale;
|
||||||
|
import android.util.LruCache;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes icu4j's RelativeDateTimeFormatter.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
@VisibleForTesting(visibility = PACKAGE)
|
||||||
|
public final class RelativeDateTimeFormatter {
|
||||||
|
|
||||||
|
public static final long SECOND_IN_MILLIS = 1000;
|
||||||
|
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
|
||||||
|
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
|
||||||
|
public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
|
||||||
|
public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
|
||||||
|
// YEAR_IN_MILLIS considers 364 days as a year. However, since this
|
||||||
|
// constant comes from public API in DateUtils, it cannot be fixed here.
|
||||||
|
public static final long YEAR_IN_MILLIS = WEEK_IN_MILLIS * 52;
|
||||||
|
|
||||||
|
private static final int DAY_IN_MS = 24 * 60 * 60 * 1000;
|
||||||
|
private static final int EPOCH_JULIAN_DAY = 2440588;
|
||||||
|
|
||||||
|
private static final FormatterCache CACHED_FORMATTERS = new FormatterCache();
|
||||||
|
|
||||||
|
static class FormatterCache
|
||||||
|
extends LruCache<String, android.icu.text.RelativeDateTimeFormatter> {
|
||||||
|
FormatterCache() {
|
||||||
|
super(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RelativeDateTimeFormatter() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the internal API that implements the functionality of DateUtils
|
||||||
|
* .getRelativeTimeSpanString(long,
|
||||||
|
* long, long, int), which is to return a string describing 'time' as a time relative to 'now'
|
||||||
|
* such as '5 minutes ago', or 'In 2 days'. More examples can be found in DateUtils' doc.
|
||||||
|
* <p>
|
||||||
|
* In the implementation below, it selects the appropriate time unit based on the elapsed time
|
||||||
|
* between time' and 'now', e.g. minutes, days and etc. Callers may also specify the desired
|
||||||
|
* minimum resolution to show in the result. For example, '45 minutes ago' will become '0 hours
|
||||||
|
* ago' when minResolution is HOUR_IN_MILLIS. Once getting the quantity and unit to display, it
|
||||||
|
* calls icu4j's RelativeDateTimeFormatter to format the actual string according to the given
|
||||||
|
* locale.
|
||||||
|
* <p>
|
||||||
|
* Note that when minResolution is set to DAY_IN_MILLIS, it returns the result depending on the
|
||||||
|
* actual date difference. For example, it will return 'Yesterday' even if 'time' was less than
|
||||||
|
* 24 hours ago but falling onto a different calendar day.
|
||||||
|
* <p>
|
||||||
|
* It takes two additional parameters of Locale and TimeZone than the DateUtils' API. Caller
|
||||||
|
* must specify the locale and timezone. FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set
|
||||||
|
* in 'flags' to get the abbreviated forms when available. When 'time' equals to 'now', it
|
||||||
|
* always // returns a string like '0 seconds/minutes/... ago' according to minResolution.
|
||||||
|
*/
|
||||||
|
public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
|
||||||
|
long now, long minResolution, int flags) {
|
||||||
|
// Android has been inconsistent about capitalization in the past. e.g. bug
|
||||||
|
// http://b/20247811.
|
||||||
|
// Now we capitalize everything consistently.
|
||||||
|
final DisplayContext displayContext =
|
||||||
|
DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE;
|
||||||
|
return getRelativeTimeSpanString(locale, tz, time, now, minResolution, flags,
|
||||||
|
displayContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getRelativeTimeSpanString(Locale locale, java.util.TimeZone tz, long time,
|
||||||
|
long now, long minResolution, int flags, DisplayContext displayContext) {
|
||||||
|
if (locale == null) {
|
||||||
|
throw new NullPointerException("locale == null");
|
||||||
|
}
|
||||||
|
if (tz == null) {
|
||||||
|
throw new NullPointerException("tz == null");
|
||||||
|
}
|
||||||
|
ULocale icuLocale = ULocale.forLocale(locale);
|
||||||
|
android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
|
||||||
|
return getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution, flags,
|
||||||
|
displayContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getRelativeTimeSpanString(ULocale icuLocale,
|
||||||
|
android.icu.util.TimeZone icuTimeZone, long time, long now, long minResolution,
|
||||||
|
int flags,
|
||||||
|
DisplayContext displayContext) {
|
||||||
|
|
||||||
|
long duration = Math.abs(now - time);
|
||||||
|
boolean past = (now >= time);
|
||||||
|
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.Style style;
|
||||||
|
if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
|
||||||
|
style = android.icu.text.RelativeDateTimeFormatter.Style.SHORT;
|
||||||
|
} else {
|
||||||
|
style = android.icu.text.RelativeDateTimeFormatter.Style.LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.Direction direction;
|
||||||
|
if (past) {
|
||||||
|
direction = android.icu.text.RelativeDateTimeFormatter.Direction.LAST;
|
||||||
|
} else {
|
||||||
|
direction = android.icu.text.RelativeDateTimeFormatter.Direction.NEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'relative' defaults to true as we are generating relative time span
|
||||||
|
// string. It will be set to false when we try to display strings without
|
||||||
|
// a quantity, such as 'Yesterday', etc.
|
||||||
|
boolean relative = true;
|
||||||
|
int count;
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.RelativeUnit unit;
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit aunit = null;
|
||||||
|
|
||||||
|
if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
|
||||||
|
count = (int) (duration / SECOND_IN_MILLIS);
|
||||||
|
unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.SECONDS;
|
||||||
|
} else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
|
||||||
|
count = (int) (duration / MINUTE_IN_MILLIS);
|
||||||
|
unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.MINUTES;
|
||||||
|
} else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
|
||||||
|
// Even if 'time' actually happened yesterday, we don't format it as
|
||||||
|
// "Yesterday" in this case. Unless the duration is longer than a day,
|
||||||
|
// or minResolution is specified as DAY_IN_MILLIS by user.
|
||||||
|
count = (int) (duration / HOUR_IN_MILLIS);
|
||||||
|
unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.HOURS;
|
||||||
|
} else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
|
||||||
|
count = Math.abs(dayDistance(icuTimeZone, time, now));
|
||||||
|
unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.DAYS;
|
||||||
|
|
||||||
|
if (count == 2) {
|
||||||
|
// Some locales have special terms for "2 days ago". Return them if
|
||||||
|
// available. Note that we cannot set up direction and unit here and
|
||||||
|
// make it fall through to use the call near the end of the function,
|
||||||
|
// because for locales that don't have special terms for "2 days ago",
|
||||||
|
// icu4j returns an empty string instead of falling back to strings
|
||||||
|
// like "2 days ago".
|
||||||
|
String str;
|
||||||
|
if (past) {
|
||||||
|
synchronized (CACHED_FORMATTERS) {
|
||||||
|
str = getFormatter(icuLocale, style, displayContext).format(
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.Direction.LAST_2,
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
synchronized (CACHED_FORMATTERS) {
|
||||||
|
str = getFormatter(icuLocale, style, displayContext).format(
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.Direction.NEXT_2,
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (str != null && !str.isEmpty()) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
// Fall back to show something like "2 days ago".
|
||||||
|
} else if (count == 1) {
|
||||||
|
// Show "Yesterday / Tomorrow" instead of "1 day ago / In 1 day".
|
||||||
|
aunit = android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
|
||||||
|
relative = false;
|
||||||
|
} else if (count == 0) {
|
||||||
|
// Show "Today" if time and now are on the same day.
|
||||||
|
aunit = android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit.DAY;
|
||||||
|
direction = android.icu.text.RelativeDateTimeFormatter.Direction.THIS;
|
||||||
|
relative = false;
|
||||||
|
}
|
||||||
|
} else if (minResolution == WEEK_IN_MILLIS) {
|
||||||
|
count = (int) (duration / WEEK_IN_MILLIS);
|
||||||
|
unit = android.icu.text.RelativeDateTimeFormatter.RelativeUnit.WEEKS;
|
||||||
|
} else {
|
||||||
|
Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
|
||||||
|
// The duration is longer than a week and minResolution is not
|
||||||
|
// WEEK_IN_MILLIS. Return the absolute date instead of relative time.
|
||||||
|
|
||||||
|
// Bug 19822016:
|
||||||
|
// If user doesn't supply the year display flag, we need to explicitly
|
||||||
|
// set that to show / hide the year based on time and now. Otherwise
|
||||||
|
// formatDateRange() would determine that based on the current system
|
||||||
|
// time and may give wrong results.
|
||||||
|
if ((flags & (FORMAT_NO_YEAR | FORMAT_SHOW_YEAR)) == 0) {
|
||||||
|
Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale,
|
||||||
|
now);
|
||||||
|
|
||||||
|
if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
|
||||||
|
flags |= FORMAT_SHOW_YEAR;
|
||||||
|
} else {
|
||||||
|
flags |= FORMAT_NO_YEAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DateTimeFormat.format(icuLocale, timeCalendar, flags, displayContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (CACHED_FORMATTERS) {
|
||||||
|
android.icu.text.RelativeDateTimeFormatter formatter =
|
||||||
|
getFormatter(icuLocale, style, displayContext);
|
||||||
|
if (relative) {
|
||||||
|
return formatter.format(count, direction, unit);
|
||||||
|
} else {
|
||||||
|
return formatter.format(direction, aunit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the internal API that implements DateUtils.getRelativeDateTimeString(long, long,
|
||||||
|
* long, long, int), which is to return a string describing 'time' as a time relative to 'now',
|
||||||
|
* formatted like '[relative time/date], [time]'. More examples can be found in DateUtils' doc.
|
||||||
|
* <p>
|
||||||
|
* The function is similar to getRelativeTimeSpanString, but it always appends the absolute time
|
||||||
|
* to the relative time string to return '[relative time/date clause], [absolute time clause]'.
|
||||||
|
* It also takes an extra parameter transitionResolution to determine the format of the date
|
||||||
|
* clause. When the elapsed time is less than the transition resolution, it displays the
|
||||||
|
* relative time string. Otherwise, it gives the absolute numeric date string as the date
|
||||||
|
* clause. With the date and time clauses, it relies on icu4j's
|
||||||
|
* RelativeDateTimeFormatter::combineDateAndTime()
|
||||||
|
* to concatenate the two.
|
||||||
|
* <p>
|
||||||
|
* It takes two additional parameters of Locale and TimeZone than the DateUtils' API. Caller
|
||||||
|
* must specify the locale and timezone. FORMAT_ABBREV_RELATIVE or FORMAT_ABBREV_ALL can be set
|
||||||
|
* in 'flags' to get the abbreviated forms when they are available.
|
||||||
|
* <p>
|
||||||
|
* Bug 5252772: Since the absolute time will always be part of the result, minResolution will be
|
||||||
|
* set to at least DAY_IN_MILLIS to correctly indicate the date difference. For example, when
|
||||||
|
* it's 1:30 AM, it will return 'Yesterday, 11:30 PM' for getRelativeDateTimeString(null, null,
|
||||||
|
* now - 2 hours, now, HOUR_IN_MILLIS, DAY_IN_MILLIS, 0), instead of '2 hours ago, 11:30 PM'
|
||||||
|
* even with minResolution being HOUR_IN_MILLIS.
|
||||||
|
*/
|
||||||
|
public static String getRelativeDateTimeString(Locale locale, java.util.TimeZone tz, long time,
|
||||||
|
long now, long minResolution, long transitionResolution, int flags) {
|
||||||
|
|
||||||
|
if (locale == null) {
|
||||||
|
throw new NullPointerException("locale == null");
|
||||||
|
}
|
||||||
|
if (tz == null) {
|
||||||
|
throw new NullPointerException("tz == null");
|
||||||
|
}
|
||||||
|
ULocale icuLocale = ULocale.forLocale(locale);
|
||||||
|
android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
|
||||||
|
|
||||||
|
long duration = Math.abs(now - time);
|
||||||
|
// It doesn't make much sense to have results like: "1 week ago, 10:50 AM".
|
||||||
|
if (transitionResolution > WEEK_IN_MILLIS) {
|
||||||
|
transitionResolution = WEEK_IN_MILLIS;
|
||||||
|
}
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.Style style;
|
||||||
|
if ((flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0) {
|
||||||
|
style = android.icu.text.RelativeDateTimeFormatter.Style.SHORT;
|
||||||
|
} else {
|
||||||
|
style = android.icu.text.RelativeDateTimeFormatter.Style.LONG;
|
||||||
|
}
|
||||||
|
|
||||||
|
Calendar timeCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, time);
|
||||||
|
Calendar nowCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, now);
|
||||||
|
|
||||||
|
int days = Math.abs(DateUtilsBridge.dayDistance(timeCalendar, nowCalendar));
|
||||||
|
|
||||||
|
// Now get the date clause, either in relative format or the actual date.
|
||||||
|
String dateClause;
|
||||||
|
if (duration < transitionResolution) {
|
||||||
|
// This is to fix bug 5252772. If there is any date difference, we should
|
||||||
|
// promote the minResolution to DAY_IN_MILLIS so that it can display the
|
||||||
|
// date instead of "x hours/minutes ago, [time]".
|
||||||
|
if (days > 0 && minResolution < DAY_IN_MILLIS) {
|
||||||
|
minResolution = DAY_IN_MILLIS;
|
||||||
|
}
|
||||||
|
dateClause = getRelativeTimeSpanString(icuLocale, icuTimeZone, time, now, minResolution,
|
||||||
|
flags, DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
|
||||||
|
} else {
|
||||||
|
// We always use fixed flags to format the date clause. User-supplied
|
||||||
|
// flags are ignored.
|
||||||
|
if (timeCalendar.get(Calendar.YEAR) != nowCalendar.get(Calendar.YEAR)) {
|
||||||
|
// Different years
|
||||||
|
flags = FORMAT_SHOW_DATE | FORMAT_SHOW_YEAR | FORMAT_NUMERIC_DATE;
|
||||||
|
} else {
|
||||||
|
// Default
|
||||||
|
flags = FORMAT_SHOW_DATE | FORMAT_NO_YEAR | FORMAT_ABBREV_MONTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
dateClause = DateTimeFormat.format(icuLocale, timeCalendar, flags,
|
||||||
|
DisplayContext.CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
String timeClause = DateTimeFormat.format(icuLocale, timeCalendar, FORMAT_SHOW_TIME,
|
||||||
|
DisplayContext.CAPITALIZATION_NONE);
|
||||||
|
|
||||||
|
// icu4j also has other options available to control the capitalization. We are currently
|
||||||
|
// using
|
||||||
|
// the _NONE option only.
|
||||||
|
DisplayContext capitalizationContext = DisplayContext.CAPITALIZATION_NONE;
|
||||||
|
|
||||||
|
// Combine the two clauses, such as '5 days ago, 10:50 AM'.
|
||||||
|
synchronized (CACHED_FORMATTERS) {
|
||||||
|
return getFormatter(icuLocale, style, capitalizationContext)
|
||||||
|
.combineDateAndTime(dateClause, timeClause);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getFormatter() caches the RelativeDateTimeFormatter instances based on the combination of
|
||||||
|
* localeName, sytle and capitalizationContext. It should always be used along with the action
|
||||||
|
* of the formatter in a synchronized block, because otherwise the formatter returned by
|
||||||
|
* getFormatter() may have been evicted by the time of the call to formatter->action().
|
||||||
|
*/
|
||||||
|
private static android.icu.text.RelativeDateTimeFormatter getFormatter(
|
||||||
|
ULocale locale, android.icu.text.RelativeDateTimeFormatter.Style style,
|
||||||
|
DisplayContext displayContext) {
|
||||||
|
String key = locale + "\t" + style + "\t" + displayContext;
|
||||||
|
android.icu.text.RelativeDateTimeFormatter formatter = CACHED_FORMATTERS.get(key);
|
||||||
|
if (formatter == null) {
|
||||||
|
formatter = android.icu.text.RelativeDateTimeFormatter.getInstance(
|
||||||
|
locale, null, style, displayContext);
|
||||||
|
CACHED_FORMATTERS.put(key, formatter);
|
||||||
|
}
|
||||||
|
return formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the date difference for the two times in a given timezone.
|
||||||
|
private static int dayDistance(android.icu.util.TimeZone icuTimeZone, long startTime,
|
||||||
|
long endTime) {
|
||||||
|
return julianDay(icuTimeZone, endTime) - julianDay(icuTimeZone, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int julianDay(android.icu.util.TimeZone icuTimeZone, long time) {
|
||||||
|
long utcMs = time + icuTimeZone.getOffset(time);
|
||||||
|
return (int) (utcMs / DAY_IN_MS) + EPOCH_JULIAN_DAY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,762 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.text.format;
|
||||||
|
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_ALL;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_ABBREV_RELATIVE;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_NO_YEAR;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_NUMERIC_DATE;
|
||||||
|
import static android.text.format.DateUtilsBridge.FORMAT_SHOW_YEAR;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.DAY_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.HOUR_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.MINUTE_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.SECOND_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.WEEK_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.YEAR_IN_MILLIS;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.getRelativeDateTimeString;
|
||||||
|
import static android.text.format.RelativeDateTimeFormatter.getRelativeTimeSpanString;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.TimeZone;
|
||||||
|
|
||||||
|
@Presubmit
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class RelativeDateTimeFormatterTest {
|
||||||
|
|
||||||
|
// Tests adopted from CTS tests for DateUtils.getRelativeTimeSpanString.
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeTimeSpanStringCTS() throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("GMT");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, en_US);
|
||||||
|
// Feb 5, 2015 at 10:50 GMT
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
final long baseTime = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
assertEquals("0 minutes ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime - SECOND_IN_MILLIS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("In 0 minutes",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime + SECOND_IN_MILLIS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
assertEquals("1 minute ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, 0, MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("In 1 minute",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, MINUTE_IN_MILLIS, 0, MINUTE_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
assertEquals("42 minutes ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime - 42 * MINUTE_IN_MILLIS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("In 42 minutes",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime + 42 * MINUTE_IN_MILLIS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
final long TWO_HOURS_IN_MS = 2 * HOUR_IN_MILLIS;
|
||||||
|
assertEquals("2 hours ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime - TWO_HOURS_IN_MS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
|
||||||
|
assertEquals("In 2 hours",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime + TWO_HOURS_IN_MS, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, FORMAT_NUMERIC_DATE));
|
||||||
|
|
||||||
|
assertEquals("In 42 min.",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime + (42 * MINUTE_IN_MILLIS), baseTime,
|
||||||
|
MINUTE_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
|
||||||
|
assertEquals("Tomorrow",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("In 2 days",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, 2 * DAY_IN_MILLIS, 0, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("Yesterday",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, 0, DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("2 days ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, 0, 2 * DAY_IN_MILLIS, DAY_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
|
||||||
|
assertEquals("5 days ago",
|
||||||
|
getRelativeTimeSpanString(en_US, tz, baseTime - DAY_DURATION, baseTime,
|
||||||
|
DAY_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void test_getRelativeTimeSpanString_helper(long delta, long minResolution, int flags,
|
||||||
|
String expectedInPast,
|
||||||
|
String expectedInFuture) throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, en_US);
|
||||||
|
// Feb 5, 2015 at 10:50 PST
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
final long base = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
assertEquals(expectedInPast,
|
||||||
|
getRelativeTimeSpanString(en_US, tz, base - delta, base, minResolution, flags));
|
||||||
|
assertEquals(expectedInFuture,
|
||||||
|
getRelativeTimeSpanString(en_US, tz, base + delta, base, minResolution, flags));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void test_getRelativeTimeSpanString_helper(long delta, long minResolution,
|
||||||
|
String expectedInPast,
|
||||||
|
String expectedInFuture) throws Exception {
|
||||||
|
test_getRelativeTimeSpanString_helper(delta, minResolution, 0, expectedInPast,
|
||||||
|
expectedInFuture);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeTimeSpanString() throws Exception {
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, "0 seconds ago",
|
||||||
|
"0 seconds ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago",
|
||||||
|
"In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, "1 minute ago",
|
||||||
|
"In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, "5 days ago", "In 5 days");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"0 seconds ago",
|
||||||
|
"0 seconds ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"1 second ago",
|
||||||
|
"In 1 second");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"2 seconds ago",
|
||||||
|
"In 2 seconds");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"25 seconds ago",
|
||||||
|
"In 25 seconds");
|
||||||
|
test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"1 minute ago",
|
||||||
|
"In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS,
|
||||||
|
"1 hour ago",
|
||||||
|
"In 1 hour");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"0 minutes ago",
|
||||||
|
"0 minutes ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"1 minute ago",
|
||||||
|
"In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"2 minutes ago",
|
||||||
|
"In 2 minutes");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"25 minutes ago",
|
||||||
|
"In 25 minutes");
|
||||||
|
test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, "1 hour ago",
|
||||||
|
"In 1 hour");
|
||||||
|
test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"12 hours ago",
|
||||||
|
"In 12 hours");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
|
||||||
|
"0 hours ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
|
||||||
|
"In 1 hour");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "2 hours ago",
|
||||||
|
"In 2 hours");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "5 hours ago",
|
||||||
|
"In 5 hours");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, "20 hours ago",
|
||||||
|
"In 20 hours");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
|
||||||
|
"Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
|
||||||
|
"Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
|
||||||
|
"In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, "January 11",
|
||||||
|
"March 2");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
|
||||||
|
"0 weeks ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
|
||||||
|
"In 1 week");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "2 weeks ago",
|
||||||
|
"In 2 weeks");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, "25 weeks ago",
|
||||||
|
"In 25 weeks");
|
||||||
|
|
||||||
|
// duration >= minResolution
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, "30 seconds ago",
|
||||||
|
"In 30 seconds");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"30 minutes ago", "In 30 minutes");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, "Yesterday",
|
||||||
|
"Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, "5 days ago",
|
||||||
|
"In 5 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"July 10, 2014",
|
||||||
|
"September 3");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"February 6, 2010", "February 4, 2020");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"1 minute ago",
|
||||||
|
"In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS,
|
||||||
|
"1 minute ago", "In 1 minute");
|
||||||
|
test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "1 hour ago",
|
||||||
|
"In 1 hour");
|
||||||
|
test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS,
|
||||||
|
"1 hour ago",
|
||||||
|
"In 1 hour");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Today", "Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
|
||||||
|
"Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "Yesterday",
|
||||||
|
"Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
|
||||||
|
"In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, "2 days ago",
|
||||||
|
"In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, "1 week ago",
|
||||||
|
"In 1 week");
|
||||||
|
test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, "1 week ago",
|
||||||
|
"In 1 week");
|
||||||
|
|
||||||
|
// duration < minResolution
|
||||||
|
test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS,
|
||||||
|
"0 minutes ago",
|
||||||
|
"In 0 minutes");
|
||||||
|
test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, "0 hours ago",
|
||||||
|
"In 0 hours");
|
||||||
|
test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, "0 hours ago",
|
||||||
|
"In 0 hours");
|
||||||
|
test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, "Yesterday",
|
||||||
|
"Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, "0 weeks ago",
|
||||||
|
"In 0 weeks");
|
||||||
|
test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, "0 weeks ago",
|
||||||
|
"In 0 weeks");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeTimeSpanStringAbbrev() throws Exception {
|
||||||
|
int flags = FORMAT_ABBREV_RELATIVE;
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, 0, flags, "0 sec. ago",
|
||||||
|
"0 sec. ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, 0, flags, "1 min. ago",
|
||||||
|
"In 1 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, 0, flags, "5 days ago",
|
||||||
|
"In 5 days");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"0 sec. ago", "0 sec. ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"1 sec. ago", "In 1 sec.");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"2 sec. ago", "In 2 sec.");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"25 sec. ago", "In 25 sec.");
|
||||||
|
test_getRelativeTimeSpanString_helper(75 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"1 min. ago", "In 1 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(5000 * SECOND_IN_MILLIS, SECOND_IN_MILLIS, flags,
|
||||||
|
"1 hr. ago", "In 1 hr.");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"0 min. ago", "0 min. ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"1 min. ago", "In 1 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"2 min. ago", "In 2 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"25 min. ago", "In 25 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(75 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"1 hr. ago", "In 1 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(720 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"12 hr. ago", "In 12 hr.");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"0 hr. ago", "0 hr. ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"1 hr. ago", "In 1 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"2 hr. ago", "In 2 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"5 hr. ago", "In 5 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"20 hr. ago", "In 20 hr.");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
|
||||||
|
"Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"2 days ago", "In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * DAY_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"January 11", "March 2");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(0 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"0 wk. ago", "0 wk. ago");
|
||||||
|
test_getRelativeTimeSpanString_helper(1 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"1 wk. ago", "In 1 wk.");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"2 wk. ago", "In 2 wk.");
|
||||||
|
test_getRelativeTimeSpanString_helper(25 * WEEK_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"25 wk. ago", "In 25 wk.");
|
||||||
|
|
||||||
|
// duration >= minResolution
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * SECOND_IN_MILLIS, 0, flags, "30 sec. ago",
|
||||||
|
"In 30 sec.");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * MINUTE_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"30 min. ago", "In 30 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * HOUR_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"5 days ago", "In 5 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(30 * WEEK_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"July 10, 2014", "September 3");
|
||||||
|
test_getRelativeTimeSpanString_helper(5 * 365 * DAY_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"February 6, 2010", "February 4, 2020");
|
||||||
|
|
||||||
|
test_getRelativeTimeSpanString_helper(60 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"1 min. ago", "In 1 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(120 * SECOND_IN_MILLIS - 1, MINUTE_IN_MILLIS, flags,
|
||||||
|
"1 min. ago", "In 1 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(60 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"1 hr. ago", "In 1 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(120 * MINUTE_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
|
||||||
|
"1 hr. ago", "In 1 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(2 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags, "Today",
|
||||||
|
"Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(12 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Today");
|
||||||
|
test_getRelativeTimeSpanString_helper(24 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(48 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"2 days ago", "In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(45 * HOUR_IN_MILLIS, DAY_IN_MILLIS, flags,
|
||||||
|
"2 days ago", "In 2 days");
|
||||||
|
test_getRelativeTimeSpanString_helper(7 * DAY_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"1 wk. ago", "In 1 wk.");
|
||||||
|
test_getRelativeTimeSpanString_helper(14 * DAY_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
|
||||||
|
"1 wk. ago", "In 1 wk.");
|
||||||
|
|
||||||
|
// duration < minResolution
|
||||||
|
test_getRelativeTimeSpanString_helper(59 * SECOND_IN_MILLIS, MINUTE_IN_MILLIS, flags,
|
||||||
|
"0 min. ago", "In 0 min.");
|
||||||
|
test_getRelativeTimeSpanString_helper(59 * MINUTE_IN_MILLIS, HOUR_IN_MILLIS, flags,
|
||||||
|
"0 hr. ago", "In 0 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(HOUR_IN_MILLIS - 1, HOUR_IN_MILLIS, flags,
|
||||||
|
"0 hr. ago", "In 0 hr.");
|
||||||
|
test_getRelativeTimeSpanString_helper(DAY_IN_MILLIS - 1, DAY_IN_MILLIS, flags,
|
||||||
|
"Yesterday", "Tomorrow");
|
||||||
|
test_getRelativeTimeSpanString_helper(20 * SECOND_IN_MILLIS, WEEK_IN_MILLIS, flags,
|
||||||
|
"0 wk. ago", "In 0 wk.");
|
||||||
|
test_getRelativeTimeSpanString_helper(WEEK_IN_MILLIS - 1, WEEK_IN_MILLIS, flags,
|
||||||
|
"0 wk. ago", "In 0 wk.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeTimeSpanStringGerman() throws Exception {
|
||||||
|
// Bug: 19744876
|
||||||
|
// We need to specify the timezone and the time explicitly. Otherwise it
|
||||||
|
// may not always give a correct answer of "tomorrow" by using
|
||||||
|
// (now + DAY_IN_MILLIS).
|
||||||
|
Locale de_DE = new Locale("de", "DE");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("Europe/Berlin");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, de_DE);
|
||||||
|
// Feb 5, 2015 at 10:50 CET
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
final long now = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
// 42 minutes ago
|
||||||
|
assertEquals("Vor 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now - 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
|
||||||
|
// In 42 minutes
|
||||||
|
assertEquals("In 42 Minuten", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now + 42 * MINUTE_IN_MILLIS, now, MINUTE_IN_MILLIS, 0));
|
||||||
|
// Yesterday
|
||||||
|
assertEquals("Gestern", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// The day before yesterday
|
||||||
|
assertEquals("Vorgestern", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// Tomorrow
|
||||||
|
assertEquals("Morgen", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// The day after tomorrow
|
||||||
|
assertEquals("Übermorgen", getRelativeTimeSpanString(de_DE, tz,
|
||||||
|
now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeTimeSpanStringFrench() throws Exception {
|
||||||
|
Locale fr_FR = new Locale("fr", "FR");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("Europe/Paris");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, fr_FR);
|
||||||
|
// Feb 5, 2015 at 10:50 CET
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
final long now = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
// 42 minutes ago
|
||||||
|
assertEquals("Il y a 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now - (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
|
||||||
|
// In 42 minutes
|
||||||
|
assertEquals("Dans 42 minutes", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now + (42 * MINUTE_IN_MILLIS), now, MINUTE_IN_MILLIS, 0));
|
||||||
|
// Yesterday
|
||||||
|
assertEquals("Hier", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now - DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// The day before yesterday
|
||||||
|
assertEquals("Avant-hier", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now - 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// Tomorrow
|
||||||
|
assertEquals("Demain", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now + DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
// The day after tomorrow
|
||||||
|
assertEquals("Après-demain", getRelativeTimeSpanString(fr_FR, tz,
|
||||||
|
now + 2 * DAY_IN_MILLIS, now, DAY_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests adopted from CTS tests for DateUtils.getRelativeDateTimeString.
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeDateTimeStringCTS() throws Exception {
|
||||||
|
Locale en_US = Locale.getDefault();
|
||||||
|
TimeZone tz = TimeZone.getDefault();
|
||||||
|
final long baseTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
final long DAY_DURATION = 5 * 24 * 60 * 60 * 1000;
|
||||||
|
assertNotNull(getRelativeDateTimeString(en_US, tz, baseTime - DAY_DURATION, baseTime,
|
||||||
|
MINUTE_IN_MILLIS, DAY_IN_MILLIS,
|
||||||
|
FORMAT_NUMERIC_DATE));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeDateTimeString() throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, en_US);
|
||||||
|
// Feb 5, 2015 at 10:50 PST
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
final long base = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
assertEquals("5 seconds ago, 10:49 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("5 min. ago, 10:45 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
|
||||||
|
HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("0 hr. ago, 10:45 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * MINUTE_IN_MILLIS, base,
|
||||||
|
HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("5 hours ago, 5:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base,
|
||||||
|
HOUR_IN_MILLIS, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("Yesterday, 7:50 PM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 15 * HOUR_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("5 days ago, 10:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * DAY_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("Jan 29, 10:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 7 * DAY_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("11/27/2014, 10:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("11/27/2014, 10:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
|
||||||
|
YEAR_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// User-supplied flags should be ignored when formatting the date clause.
|
||||||
|
final int FORMAT_SHOW_WEEKDAY = 0x00002;
|
||||||
|
assertEquals("11/27/2014, 10:50 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS,
|
||||||
|
FORMAT_ABBREV_ALL | FORMAT_SHOW_WEEKDAY));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeDateTimeStringDST() throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, en_US);
|
||||||
|
|
||||||
|
// DST starts on Mar 9, 2014 at 2:00 AM.
|
||||||
|
// So 5 hours before 3:15 AM should be formatted as 'Yesterday, 9:15 PM'.
|
||||||
|
cal.set(2014, Calendar.MARCH, 9, 3, 15, 0);
|
||||||
|
long base = cal.getTimeInMillis();
|
||||||
|
assertEquals("Yesterday, 9:15 PM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 5 * HOUR_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// 1 hour after 2:00 AM should be formatted as 'In 1 hour, 4:00 AM'.
|
||||||
|
cal.set(2014, Calendar.MARCH, 9, 2, 0, 0);
|
||||||
|
base = cal.getTimeInMillis();
|
||||||
|
assertEquals("In 1 hour, 4:00 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base + 1 * HOUR_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// DST ends on Nov 2, 2014 at 2:00 AM. Clocks are turned backward 1 hour to
|
||||||
|
// 1:00 AM. 8 hours before 5:20 AM should be 'Yesterday, 10:20 PM'.
|
||||||
|
cal.set(2014, Calendar.NOVEMBER, 2, 5, 20, 0);
|
||||||
|
base = cal.getTimeInMillis();
|
||||||
|
assertEquals("Yesterday, 10:20 PM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base - 8 * HOUR_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
cal.set(2014, Calendar.NOVEMBER, 2, 0, 45, 0);
|
||||||
|
base = cal.getTimeInMillis();
|
||||||
|
// 45 minutes after 0:45 AM should be 'In 45 minutes, 1:30 AM'.
|
||||||
|
assertEquals("In 45 minutes, 1:30 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base + 45 * MINUTE_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
// 45 minutes later, it should be 'In 45 minutes, 1:15 AM'.
|
||||||
|
assertEquals("In 45 minutes, 1:15 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base + 90 * MINUTE_IN_MILLIS,
|
||||||
|
base + 45 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
// Another 45 minutes later, it should be 'In 45 minutes, 2:00 AM'.
|
||||||
|
assertEquals("In 45 minutes, 2:00 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, base + 135 * MINUTE_IN_MILLIS,
|
||||||
|
base + 90 * MINUTE_IN_MILLIS, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_getRelativeDateTimeStringItalian() throws Exception {
|
||||||
|
Locale it_IT = new Locale("it", "IT");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("Europe/Rome");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, it_IT);
|
||||||
|
// 05 febbraio 2015 20:15
|
||||||
|
cal.set(2015, Calendar.FEBRUARY, 5, 20, 15, 0);
|
||||||
|
final long base = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
assertEquals("5 secondi fa, 20:14",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 5 * SECOND_IN_MILLIS, base, 0,
|
||||||
|
MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("5 min fa, 20:10",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base, 0,
|
||||||
|
HOUR_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("0 h fa, 20:10",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 5 * MINUTE_IN_MILLIS, base,
|
||||||
|
HOUR_IN_MILLIS, DAY_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("Ieri, 22:15",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 22 * HOUR_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
assertEquals("5 giorni fa, 20:15",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 5 * DAY_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("27/11/2014, 20:15",
|
||||||
|
getRelativeDateTimeString(it_IT, tz, base - 10 * WEEK_IN_MILLIS, base, 0,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://b/5252772: detect the actual date difference
|
||||||
|
@Test
|
||||||
|
public void test5252772() throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
|
||||||
|
// Now is Sep 2, 2011, 10:23 AM PDT.
|
||||||
|
Calendar nowCalendar = Calendar.getInstance(tz, en_US);
|
||||||
|
nowCalendar.set(2011, Calendar.SEPTEMBER, 2, 10, 23, 0);
|
||||||
|
final long now = nowCalendar.getTimeInMillis();
|
||||||
|
|
||||||
|
// Sep 1, 2011, 10:24 AM
|
||||||
|
Calendar yesterdayCalendar1 = Calendar.getInstance(tz, en_US);
|
||||||
|
yesterdayCalendar1.set(2011, Calendar.SEPTEMBER, 1, 10, 24, 0);
|
||||||
|
long yesterday1 = yesterdayCalendar1.getTimeInMillis();
|
||||||
|
assertEquals("Yesterday, 10:24 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, yesterday1, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Sep 1, 2011, 10:22 AM
|
||||||
|
Calendar yesterdayCalendar2 = Calendar.getInstance(tz, en_US);
|
||||||
|
yesterdayCalendar2.set(2011, Calendar.SEPTEMBER, 1, 10, 22, 0);
|
||||||
|
long yesterday2 = yesterdayCalendar2.getTimeInMillis();
|
||||||
|
assertEquals("Yesterday, 10:22 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, yesterday2, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Aug 31, 2011, 10:24 AM
|
||||||
|
Calendar twoDaysAgoCalendar1 = Calendar.getInstance(tz, en_US);
|
||||||
|
twoDaysAgoCalendar1.set(2011, Calendar.AUGUST, 31, 10, 24, 0);
|
||||||
|
long twoDaysAgo1 = twoDaysAgoCalendar1.getTimeInMillis();
|
||||||
|
assertEquals("2 days ago, 10:24 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, twoDaysAgo1, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Aug 31, 2011, 10:22 AM
|
||||||
|
Calendar twoDaysAgoCalendar2 = Calendar.getInstance(tz, en_US);
|
||||||
|
twoDaysAgoCalendar2.set(2011, Calendar.AUGUST, 31, 10, 22, 0);
|
||||||
|
long twoDaysAgo2 = twoDaysAgoCalendar2.getTimeInMillis();
|
||||||
|
assertEquals("2 days ago, 10:22 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, twoDaysAgo2, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Sep 3, 2011, 10:22 AM
|
||||||
|
Calendar tomorrowCalendar1 = Calendar.getInstance(tz, en_US);
|
||||||
|
tomorrowCalendar1.set(2011, Calendar.SEPTEMBER, 3, 10, 22, 0);
|
||||||
|
long tomorrow1 = tomorrowCalendar1.getTimeInMillis();
|
||||||
|
assertEquals("Tomorrow, 10:22 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, tomorrow1, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Sep 3, 2011, 10:24 AM
|
||||||
|
Calendar tomorrowCalendar2 = Calendar.getInstance(tz, en_US);
|
||||||
|
tomorrowCalendar2.set(2011, Calendar.SEPTEMBER, 3, 10, 24, 0);
|
||||||
|
long tomorrow2 = tomorrowCalendar2.getTimeInMillis();
|
||||||
|
assertEquals("Tomorrow, 10:24 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, tomorrow2, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Sep 4, 2011, 10:22 AM
|
||||||
|
Calendar twoDaysLaterCalendar1 = Calendar.getInstance(tz, en_US);
|
||||||
|
twoDaysLaterCalendar1.set(2011, Calendar.SEPTEMBER, 4, 10, 22, 0);
|
||||||
|
long twoDaysLater1 = twoDaysLaterCalendar1.getTimeInMillis();
|
||||||
|
assertEquals("In 2 days, 10:22 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, twoDaysLater1, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
// Sep 4, 2011, 10:24 AM
|
||||||
|
Calendar twoDaysLaterCalendar2 = Calendar.getInstance(tz, en_US);
|
||||||
|
twoDaysLaterCalendar2.set(2011, Calendar.SEPTEMBER, 4, 10, 24, 0);
|
||||||
|
long twoDaysLater2 = twoDaysLaterCalendar2.getTimeInMillis();
|
||||||
|
assertEquals("In 2 days, 10:24 AM",
|
||||||
|
getRelativeDateTimeString(en_US, tz, twoDaysLater2, now, MINUTE_IN_MILLIS,
|
||||||
|
WEEK_IN_MILLIS, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// b/19822016: show / hide the year based on the dates in the arguments.
|
||||||
|
@Test
|
||||||
|
public void test_bug19822016() throws Exception {
|
||||||
|
Locale en_US = new Locale("en", "US");
|
||||||
|
TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
|
||||||
|
Calendar cal = Calendar.getInstance(tz, en_US);
|
||||||
|
// Feb 5, 2012 at 10:50 PST
|
||||||
|
cal.set(2012, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
long base = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("11/27/2011, 10:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
|
||||||
|
assertEquals("January 6, 2012", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
|
||||||
|
assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("December 7, 2011", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
|
||||||
|
assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
|
||||||
|
|
||||||
|
// Feb 5, 2018 at 10:50 PST
|
||||||
|
cal.set(2018, Calendar.FEBRUARY, 5, 10, 50, 0);
|
||||||
|
base = cal.getTimeInMillis();
|
||||||
|
assertEquals("Feb 5, 5:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 5 * HOUR_IN_MILLIS, base, 0, MINUTE_IN_MILLIS, 0));
|
||||||
|
assertEquals("Jan 29, 10:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 7 * DAY_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
assertEquals("11/27/2017, 10:50 AM", getRelativeDateTimeString(en_US, tz,
|
||||||
|
base - 10 * WEEK_IN_MILLIS, base, 0, WEEK_IN_MILLIS, 0));
|
||||||
|
|
||||||
|
assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("January 6", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
|
||||||
|
assertEquals("January 6, 2018", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 30 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
|
||||||
|
assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, 0));
|
||||||
|
assertEquals("December 7, 2017", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_SHOW_YEAR));
|
||||||
|
assertEquals("December 7", getRelativeTimeSpanString(en_US, tz,
|
||||||
|
base - 60 * DAY_IN_MILLIS, base, DAY_IN_MILLIS, FORMAT_NO_YEAR));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for missing ICU data. http://b/25821045
|
||||||
|
@Test
|
||||||
|
public void test_bug25821045() {
|
||||||
|
final TimeZone tz = TimeZone.getDefault();
|
||||||
|
final long now = System.currentTimeMillis();
|
||||||
|
final long time = now + 1000;
|
||||||
|
final int minResolution = 1000 * 60;
|
||||||
|
final int transitionResolution = minResolution;
|
||||||
|
final int flags = FORMAT_ABBREV_RELATIVE;
|
||||||
|
// Exercise all available locales, forcing the ICU implementation to pre-cache the data.
|
||||||
|
// This
|
||||||
|
// highlights data issues. It can take a while.
|
||||||
|
for (Locale locale : Locale.getAvailableLocales()) {
|
||||||
|
// In (e.g.) ICU56 an exception is thrown on the first use for a locale if required
|
||||||
|
// data for
|
||||||
|
// the "other" plural is missing. It doesn't matter what is actually formatted.
|
||||||
|
try {
|
||||||
|
RelativeDateTimeFormatter.getRelativeDateTimeString(
|
||||||
|
locale, tz, time, now, minResolution, transitionResolution, flags);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
fail("Failed to format for " + locale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for ICU data lookup fallback failure. http://b/25883157
|
||||||
|
@Test
|
||||||
|
public void test_bug25883157() {
|
||||||
|
final Locale locale = new Locale("en", "GB");
|
||||||
|
final TimeZone tz = TimeZone.getTimeZone("GMT");
|
||||||
|
|
||||||
|
final Calendar cal = Calendar.getInstance(tz, locale);
|
||||||
|
cal.set(2015, Calendar.JUNE, 19, 12, 0, 0);
|
||||||
|
|
||||||
|
final long base = cal.getTimeInMillis();
|
||||||
|
final long time = base + 2 * WEEK_IN_MILLIS;
|
||||||
|
|
||||||
|
assertEquals("In 2 wk", getRelativeTimeSpanString(
|
||||||
|
locale, tz, time, base, WEEK_IN_MILLIS, FORMAT_ABBREV_RELATIVE));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://b/63745717
|
||||||
|
@Test
|
||||||
|
public void test_combineDateAndTime_apostrophe() {
|
||||||
|
final Locale locale = new Locale("fr");
|
||||||
|
android.icu.text.RelativeDateTimeFormatter icuFormatter =
|
||||||
|
android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
|
||||||
|
assertEquals("D à T", icuFormatter.combineDateAndTime("D", "T"));
|
||||||
|
// Ensure single quote ' and curly braces {} are not interpreted in input values.
|
||||||
|
assertEquals("D'x' à T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user