| /* |
| * Copyright (C) 2013 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 libcore.icu; |
| |
| import java.util.Calendar; |
| import java.util.Locale; |
| import java.util.TimeZone; |
| |
| /** |
| * Exposes icu4c's DateIntervalFormat. |
| */ |
| public final class DateIntervalFormat { |
| |
| // 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 (like FORMAT_NO_YEAR). |
| 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_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_ALL = 0x80000; |
| |
| // TODO: check whether icu4c's DateIntervalFormat is expensive enough to warrant a native peer. |
| private DateIntervalFormat() { |
| } |
| |
| // This is public DateUtils API in frameworks/base. |
| public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) { |
| if ((flags & FORMAT_UTC) != 0) { |
| olsonId = "UTC"; |
| } |
| TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault(); |
| return formatDateRange(Locale.getDefault(), tz, startMs, endMs, flags); |
| } |
| |
| // This is our slightly more sensible internal API. (A truly sane replacement would take a |
| // skeleton instead of int flags.) |
| public static String formatDateRange(Locale locale, TimeZone tz, long startMs, long endMs, int flags) { |
| String skeleton = toSkeleton(tz, startMs, endMs, flags); |
| return formatDateInterval(skeleton, locale.toString(), tz.getID(), startMs, endMs); |
| } |
| |
| private static String toSkeleton(TimeZone tz, long startMs, long endMs, int flags) { |
| Calendar startCalendar = Calendar.getInstance(tz); |
| startCalendar.setTimeInMillis(startMs); |
| |
| Calendar endCalendar; |
| if (startMs == endMs) { |
| endCalendar = startCalendar; |
| } else { |
| endCalendar = Calendar.getInstance(tz); |
| endCalendar.setTimeInMillis(endMs); |
| } |
| |
| 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 ((flags & FORMAT_ABBREV_TIME) == 0 || !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; |
| } |
| |
| 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(); |
| } |
| |
| 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 native String formatDateInterval(String skeleton, String localeName, String timeZoneName, long fromDate, long toDate); |
| } |