Skip to content
This repository has been archived by the owner on Nov 8, 2023. It is now read-only.

Commit

Permalink
Use ICU for relative time formatting
Browse files Browse the repository at this point in the history
Rewrite the DateUtils' relative time formatting APIs
(getRelativeTimeSpanString, getRelativeDateTimeString) to use ICU ones.
Two APIs that take withPreposition parameter are not changed. Because
(a) ICU doesn't provide functionality to format preposition; (b) They
are not really computing relative time but instead calling
formatDateRange() to get the absolute time/date string.

Bug: 19146457
Bug: 5252772
Change-Id: Iea8d699d63cc4438513910da66d038912e44fb8d
  • Loading branch information
Tao Bao committed Feb 12, 2015
1 parent 1a24bb5 commit 67bfa0b
Show file tree
Hide file tree
Showing 78 changed files with 15 additions and 4,923 deletions.
154 changes: 15 additions & 139 deletions core/java/android/text/format/DateUtils.java
Expand Up @@ -28,9 +28,11 @@
import java.util.Formatter;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.TimeZone;

import libcore.icu.DateIntervalFormat;
import libcore.icu.LocaleData;
import libcore.icu.RelativeDateTimeFormatter;

/**
* This class contains various date-related utilities for creating text for things like
Expand Down Expand Up @@ -242,6 +244,8 @@ public static String getMonthString(int month, int abbrev) {

/**
* Returns a string describing the elapsed time since startTime.
* <p>
* The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}.
* @param startTime some time in the past.
* @return a String object containing the elapsed time.
* @see #getRelativeTimeSpanString(long, long, long)
Expand Down Expand Up @@ -289,69 +293,8 @@ public static CharSequence getRelativeTimeSpanString(long time, long now, long m
*/
public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution,
int flags) {
Resources r = Resources.getSystem();
boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0;

boolean past = (now >= time);
long duration = Math.abs(now - time);

int resId;
long count;
if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) {
count = duration / SECOND_IN_MILLIS;
if (past) {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_num_seconds_ago;
} else {
resId = com.android.internal.R.plurals.num_seconds_ago;
}
} else {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_in_num_seconds;
} else {
resId = com.android.internal.R.plurals.in_num_seconds;
}
}
} else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) {
count = duration / MINUTE_IN_MILLIS;
if (past) {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_num_minutes_ago;
} else {
resId = com.android.internal.R.plurals.num_minutes_ago;
}
} else {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_in_num_minutes;
} else {
resId = com.android.internal.R.plurals.in_num_minutes;
}
}
} else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) {
count = duration / HOUR_IN_MILLIS;
if (past) {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_num_hours_ago;
} else {
resId = com.android.internal.R.plurals.num_hours_ago;
}
} else {
if (abbrevRelative) {
resId = com.android.internal.R.plurals.abbrev_in_num_hours;
} else {
resId = com.android.internal.R.plurals.in_num_hours;
}
}
} else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) {
return getRelativeDayString(r, time, now);
} else {
// We know that we won't be showing the time, so it is safe to pass
// in a null context.
return formatDateRange(null, time, time, flags);
}

String format = r.getQuantityString(resId, (int) count);
return String.format(format, count);
return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(),
TimeZone.getDefault(), time, now, minResolution, flags);
}

/**
Expand All @@ -360,8 +303,8 @@ public static CharSequence getRelativeTimeSpanString(long time, long now, long m
* <p>
* Example output strings for the US date format.
* <ul>
* <li>3 mins ago, 10:15 AM</li>
* <li>yesterday, 12:20 PM</li>
* <li>3 min. ago, 10:15 AM</li>
* <li>Yesterday, 12:20 PM</li>
* <li>Dec 12, 4:12 AM</li>
* <li>11/14/2007, 8:20 AM</li>
* </ul>
Expand All @@ -374,86 +317,19 @@ public static CharSequence getRelativeTimeSpanString(long time, long now, long m
* @param transitionResolution the elapsed time (in milliseconds) at which
* to stop reporting relative measurements. Elapsed times greater
* than this resolution will default to normal date formatting.
* For example, will transition from "6 days ago" to "Dec 12"
* For example, will transition from "7 days ago" to "Dec 12"
* when using {@link #WEEK_IN_MILLIS}.
*/
public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
long transitionResolution, int flags) {
Resources r = Resources.getSystem();

long now = System.currentTimeMillis();
long duration = Math.abs(now - time);

// getRelativeTimeSpanString() doesn't correctly format relative dates
// above a week or exact dates below a day, so clamp
// transitionResolution as needed.
if (transitionResolution > WEEK_IN_MILLIS) {
transitionResolution = WEEK_IN_MILLIS;
} else if (transitionResolution < DAY_IN_MILLIS) {
transitionResolution = DAY_IN_MILLIS;
}

CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME);

String result;
if (duration < transitionResolution) {
CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags);
result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause);
} else {
CharSequence dateClause = getRelativeTimeSpanString(c, time, false);
result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause);
}

return result;
}

/**
* Returns a string describing a day relative to the current day. For example if the day is
* today this function returns "Today", if the day was a week ago it returns "7 days ago", and
* if the day is in 2 weeks it returns "in 14 days".
*
* @param r the resources
* @param day the relative day to describe in UTC milliseconds
* @param today the current time in UTC milliseconds
*/
private static final String getRelativeDayString(Resources r, long day, long today) {
Locale locale = r.getConfiguration().locale;
if (locale == null) {
locale = Locale.getDefault();
}

// TODO: use TimeZone.getOffset instead.
Time startTime = new Time();
startTime.set(day);
int startDay = Time.getJulianDay(day, startTime.gmtoff);

Time currentTime = new Time();
currentTime.set(today);
int currentDay = Time.getJulianDay(today, currentTime.gmtoff);

int days = Math.abs(currentDay - startDay);
boolean past = (today > day);

// TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2).
if (days == 1) {
if (past) {
return LocaleData.get(locale).yesterday;
} else {
return LocaleData.get(locale).tomorrow;
}
} else if (days == 0) {
return LocaleData.get(locale).today;
}

int resId;
if (past) {
resId = com.android.internal.R.plurals.num_days_ago;
} else {
resId = com.android.internal.R.plurals.in_num_days;
// Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format.
if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) {
flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR;
}

String format = r.getQuantityString(resId, days);
return String.format(format, days);
return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(),
TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution,
transitionResolution, flags);
}

private static void initFormatStrings() {
Expand Down
64 changes: 0 additions & 64 deletions core/res/res/values-af/strings.xml
Expand Up @@ -1059,75 +1059,11 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> wil Verken-met-raak aktiveer. Wanneer Verken-met-raak aangeskakel is, kan jy beskrywings van wat onder jou vinger is hoor of sien, of jy kan gebare uitvoer om interaksie met die foon te hê ."</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"1 maand gelede"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Voor 1 maand gelede"</string>
<plurals name="num_seconds_ago">
<item quantity="one" msgid="4869870056547896011">"1 sekonde gelede"</item>
<item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> sekondes gelede"</item>
</plurals>
<plurals name="num_minutes_ago">
<item quantity="one" msgid="3306787433088810191">"1 minuut gelede"</item>
<item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> minute gelede"</item>
</plurals>
<plurals name="num_hours_ago">
<item quantity="one" msgid="9150797944610821849">"1 uur gelede"</item>
<item quantity="other" msgid="2467273239587587569">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
</plurals>
<plurals name="last_num_days">
<item quantity="other" msgid="3069992808164318268">"Afgelope <xliff:g id="COUNT">%d</xliff:g> dae"</item>
</plurals>
<string name="last_month" msgid="3959346739979055432">"Verlede maand"</string>
<string name="older" msgid="5211975022815554840">"Ouer"</string>
<plurals name="num_days_ago">
<item quantity="one" msgid="861358534398115820">"gister"</item>
<item quantity="other" msgid="2479586466153314633">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
</plurals>
<plurals name="in_num_seconds">
<item quantity="one" msgid="2729745560954905102">"oor 1 sekonde"</item>
<item quantity="other" msgid="1241926116443974687">"oor <xliff:g id="COUNT">%d</xliff:g> sekondes"</item>
</plurals>
<plurals name="in_num_minutes">
<item quantity="one" msgid="8793095251325200395">"oor 1 minuut"</item>
<item quantity="other" msgid="3330713936399448749">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
</plurals>
<plurals name="in_num_hours">
<item quantity="one" msgid="7164353342477769999">"oor 1 uur"</item>
<item quantity="other" msgid="547290677353727389">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="in_num_days">
<item quantity="one" msgid="5413088743009839518">"môre"</item>
<item quantity="other" msgid="5109449375100953247">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
<item quantity="one" msgid="1849036840200069118">"1 sek. gelede"</item>
<item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> sek. gelede"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
<item quantity="one" msgid="6361490147113871545">"1 min. gelede"</item>
<item quantity="other" msgid="851164968597150710">"<xliff:g id="COUNT">%d</xliff:g> min. gelede"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
<item quantity="one" msgid="4796212039724722116">"1 uur gelede"</item>
<item quantity="other" msgid="6889970745748538901">"<xliff:g id="COUNT">%d</xliff:g> uur gelede"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
<item quantity="one" msgid="8463161711492680309">"gister"</item>
<item quantity="other" msgid="3453342639616481191">"<xliff:g id="COUNT">%d</xliff:g> dae gelede"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
<item quantity="one" msgid="5842225370795066299">"oor 1 sek."</item>
<item quantity="other" msgid="5495880108825805108">"oor <xliff:g id="COUNT">%d</xliff:g> sek."</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
<item quantity="one" msgid="562786149928284878">"oor 1 min."</item>
<item quantity="other" msgid="4216113292706568726">"oor <xliff:g id="COUNT">%d</xliff:g> minute"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
<item quantity="one" msgid="3274708118124045246">"oor 1 uur"</item>
<item quantity="other" msgid="3705373766798013406">"oor <xliff:g id="COUNT">%d</xliff:g> uur"</item>
</plurals>
<plurals name="abbrev_in_num_days">
<item quantity="one" msgid="2178576254385739855">"môre"</item>
<item quantity="other" msgid="2973062968038355991">"oor <xliff:g id="COUNT">%d</xliff:g> dae"</item>
</plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"op <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"by <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"in <xliff:g id="YEAR">%s</xliff:g>"</string>
Expand Down
64 changes: 0 additions & 64 deletions core/res/res/values-am/strings.xml
Expand Up @@ -1059,75 +1059,11 @@
<string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> ማሰስን በንኪ ማንቃት ይፈልጋል። አስስ በንኪ በሚበራበት ጊዜ፣ ከስልኩ ጋር ለመግባባት ምን በጣትዎ ስር ወይም ምልክቶችን ማከናወን እንዳለብዎ ማብራሪያ ሊመለከቱ ወይም ሊሰሙ ይችላሉ።"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"ከ1 ወር በፊት"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"ከ1 ወር በፊት"</string>
<plurals name="num_seconds_ago">
<item quantity="one" msgid="4869870056547896011">"ከ1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3903706804349556379">"<xliff:g id="COUNT">%d</xliff:g> ሰኮንዶች በፊት"</item>
</plurals>
<plurals name="num_minutes_ago">
<item quantity="one" msgid="3306787433088810191">"ከ 1 ደቂቃ በፊት"</item>
<item quantity="other" msgid="2176942008915455116">"<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
</plurals>
<plurals name="num_hours_ago">
<item quantity="one" msgid="9150797944610821849">"ከ1 ሰዓት በፊት"</item>
<item quantity="other" msgid="2467273239587587569">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
</plurals>
<plurals name="last_num_days">
<item quantity="other" msgid="3069992808164318268">"ቀኖች <xliff:g id="COUNT">%d</xliff:g> ያልቃል"</item>
</plurals>
<string name="last_month" msgid="3959346739979055432">" ያለፈው ወር"</string>
<string name="older" msgid="5211975022815554840">"የድሮ"</string>
<plurals name="num_days_ago">
<item quantity="one" msgid="861358534398115820">"ትላንትና"</item>
<item quantity="other" msgid="2479586466153314633">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="in_num_seconds">
<item quantity="one" msgid="2729745560954905102">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="1241926116443974687">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="in_num_minutes">
<item quantity="one" msgid="8793095251325200395">"በ1 ደቂቃ ውስጥ"</item>
<item quantity="other" msgid="3330713936399448749">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
</plurals>
<plurals name="in_num_hours">
<item quantity="one" msgid="7164353342477769999">"በ 1 ሰዓት"</item>
<item quantity="other" msgid="547290677353727389">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
</plurals>
<plurals name="in_num_days">
<item quantity="one" msgid="5413088743009839518">"ነገ"</item>
<item quantity="other" msgid="5109449375100953247">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
</plurals>
<plurals name="abbrev_num_seconds_ago">
<item quantity="one" msgid="1849036840200069118">"1 ሴኮንድ በፊት"</item>
<item quantity="other" msgid="3699169366650930415">"<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች በፊት"</item>
</plurals>
<plurals name="abbrev_num_minutes_ago">
<item quantity="one" msgid="6361490147113871545">"ከ 1 ደቂቃ በፊት"</item>
<item quantity="other" msgid="851164968597150710">"ከ <xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች በፊት"</item>
</plurals>
<plurals name="abbrev_num_hours_ago">
<item quantity="one" msgid="4796212039724722116">"ከ1 ሰዓት በፊት"</item>
<item quantity="other" msgid="6889970745748538901">"ከ <xliff:g id="COUNT">%d</xliff:g> ሰዓት በፊት"</item>
</plurals>
<plurals name="abbrev_num_days_ago">
<item quantity="one" msgid="8463161711492680309">"ትላንትና"</item>
<item quantity="other" msgid="3453342639616481191">"ከ <xliff:g id="COUNT">%d</xliff:g>ቀን በፊት"</item>
</plurals>
<plurals name="abbrev_in_num_seconds">
<item quantity="one" msgid="5842225370795066299">"በ1 ሴኮንድ"</item>
<item quantity="other" msgid="5495880108825805108">"በ<xliff:g id="COUNT">%d</xliff:g> ሰከንዶች ውስጥ"</item>
</plurals>
<plurals name="abbrev_in_num_minutes">
<item quantity="one" msgid="562786149928284878">"በ1 ደቂቃ ውስጥ"</item>
<item quantity="other" msgid="4216113292706568726">"በ<xliff:g id="COUNT">%d</xliff:g> ደቂቃዎች ውስጥ"</item>
</plurals>
<plurals name="abbrev_in_num_hours">
<item quantity="one" msgid="3274708118124045246">"በ 1 ሰዓት"</item>
<item quantity="other" msgid="3705373766798013406">"በ <xliff:g id="COUNT">%d</xliff:g> ሰዓቶች"</item>
</plurals>
<plurals name="abbrev_in_num_days">
<item quantity="one" msgid="2178576254385739855">"ነገ"</item>
<item quantity="other" msgid="2973062968038355991">"በ<xliff:g id="COUNT">%d</xliff:g> ቀኖች"</item>
</plurals>
<string name="preposition_for_date" msgid="9093949757757445117">"በ <xliff:g id="DATE">%s</xliff:g>"</string>
<string name="preposition_for_time" msgid="5506831244263083793">"በ <xliff:g id="TIME">%s</xliff:g>"</string>
<string name="preposition_for_year" msgid="5040395640711867177">"ውስጥ <xliff:g id="YEAR">%s</xliff:g>"</string>
Expand Down

0 comments on commit 67bfa0b

Please sign in to comment.