195 lines
7.6 KiB
Java
195 lines
7.6 KiB
Java
/*
|
|
* 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.DateUtils.FORMAT_12HOUR;
|
|
import static android.text.format.DateUtils.FORMAT_24HOUR;
|
|
import static android.text.format.DateUtils.FORMAT_ABBREV_ALL;
|
|
import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
|
|
import static android.text.format.DateUtils.FORMAT_ABBREV_TIME;
|
|
import static android.text.format.DateUtils.FORMAT_ABBREV_WEEKDAY;
|
|
import static android.text.format.DateUtils.FORMAT_NO_MONTH_DAY;
|
|
import static android.text.format.DateUtils.FORMAT_NO_YEAR;
|
|
import static android.text.format.DateUtils.FORMAT_NUMERIC_DATE;
|
|
import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
|
|
import static android.text.format.DateUtils.FORMAT_SHOW_TIME;
|
|
import static android.text.format.DateUtils.FORMAT_SHOW_WEEKDAY;
|
|
import static android.text.format.DateUtils.FORMAT_SHOW_YEAR;
|
|
|
|
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 {
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
}
|