Home | History | Annotate | Download | only in icu
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.icu;
     18 
     19 import android.icu.util.Calendar;
     20 import android.icu.util.ULocale;
     21 
     22 import java.text.FieldPosition;
     23 import java.util.TimeZone;
     24 import libcore.util.BasicLruCache;
     25 
     26 import static libcore.icu.DateUtilsBridge.FORMAT_UTC;
     27 
     28 /**
     29  * Exposes icu4j's DateIntervalFormat.
     30  */
     31 public final class DateIntervalFormat {
     32 
     33   private static final BasicLruCache<String, android.icu.text.DateIntervalFormat> CACHED_FORMATTERS
     34           = new BasicLruCache<>(8);
     35 
     36   private DateIntervalFormat() {
     37   }
     38 
     39   // This is public DateUtils API in frameworks/base.
     40   public static String formatDateRange(long startMs, long endMs, int flags, String olsonId) {
     41     if ((flags & FORMAT_UTC) != 0) {
     42       olsonId = "UTC";
     43     }
     44     // We create a java.util.TimeZone here to use libcore's data and libcore's olson ID / pseudo-tz
     45     // logic.
     46     TimeZone tz = (olsonId != null) ? TimeZone.getTimeZone(olsonId) : TimeZone.getDefault();
     47     android.icu.util.TimeZone icuTimeZone = DateUtilsBridge.icuTimeZone(tz);
     48     ULocale icuLocale = ULocale.getDefault();
     49     return formatDateRange(icuLocale, icuTimeZone, startMs, endMs, flags);
     50   }
     51 
     52   // This is our slightly more sensible internal API. (A truly sane replacement would take a
     53   // skeleton instead of int flags.)
     54   public static String formatDateRange(ULocale icuLocale, android.icu.util.TimeZone icuTimeZone,
     55       long startMs, long endMs, int flags) {
     56     Calendar startCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, startMs);
     57     Calendar endCalendar;
     58     if (startMs == endMs) {
     59       endCalendar = startCalendar;
     60     } else {
     61       endCalendar = DateUtilsBridge.createIcuCalendar(icuTimeZone, icuLocale, endMs);
     62     }
     63 
     64     boolean endsAtMidnight = isMidnight(endCalendar);
     65 
     66     // If we're not showing the time or the start and end times are on the same day, and the
     67     // end time is midnight, fudge the end date so we don't count the day that's about to start.
     68     // This is not the behavior of icu4j's DateIntervalFormat, but it's the historical behavior
     69     // of Android's DateUtils.formatDateRange.
     70     if (startMs != endMs && endsAtMidnight &&
     71         ((flags & DateUtilsBridge.FORMAT_SHOW_TIME) == 0
     72             || DateUtilsBridge.dayDistance(startCalendar, endCalendar) <= 1)) {
     73       endCalendar.add(Calendar.DAY_OF_MONTH, -1);
     74     }
     75 
     76     String skeleton = DateUtilsBridge.toSkeleton(startCalendar, endCalendar, flags);
     77     synchronized (CACHED_FORMATTERS) {
     78       android.icu.text.DateIntervalFormat formatter =
     79           getFormatter(skeleton, icuLocale, icuTimeZone);
     80       return formatter.format(startCalendar, endCalendar, new StringBuffer(),
     81           new FieldPosition(0)).toString();
     82     }
     83   }
     84 
     85   private static android.icu.text.DateIntervalFormat getFormatter(String skeleton, ULocale locale,
     86       android.icu.util.TimeZone icuTimeZone) {
     87     String key = skeleton + "\t" + locale + "\t" + icuTimeZone;
     88     android.icu.text.DateIntervalFormat formatter = CACHED_FORMATTERS.get(key);
     89     if (formatter != null) {
     90       return formatter;
     91     }
     92     formatter = android.icu.text.DateIntervalFormat.getInstance(skeleton, locale);
     93     formatter.setTimeZone(icuTimeZone);
     94     CACHED_FORMATTERS.put(key, formatter);
     95     return formatter;
     96   }
     97 
     98   private static boolean isMidnight(Calendar c) {
     99     return c.get(Calendar.HOUR_OF_DAY) == 0 &&
    100         c.get(Calendar.MINUTE) == 0 &&
    101         c.get(Calendar.SECOND) == 0 &&
    102         c.get(Calendar.MILLISECOND) == 0;
    103   }
    104 
    105 }
    106