1326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira/* 2326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Copyright (C) 2012 Google Inc. 3326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Licensed to The Android Open Source Project. 4326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * 5326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 6326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * you may not use this file except in compliance with the License. 7326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * You may obtain a copy of the License at 8326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * 9326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 10326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * 11326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Unless required by applicable law or agreed to in writing, software 12326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 13326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * See the License for the specific language governing permissions and 15326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * limitations under the License. 16326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 1730e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail; 18326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 19326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.content.Context; 20326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport android.text.format.DateUtils; 21326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 22b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdonimport java.util.Calendar; 23326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereiraimport java.util.Formatter; 24326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 25326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira/** 26326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * Convenience class to efficiently make multiple short date strings. Instantiating and reusing 27326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * one of these builders is faster than repeatedly bringing up all the locale stuff. 28326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira * 29326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira */ 30326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereirapublic class FormattedDateBuilder { 31326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 32b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon private final StringBuilder sb; 33b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon private final Formatter dateFormatter; 34b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon private final Context mContext; 35326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 36326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira public FormattedDateBuilder(Context context) { 37326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira mContext = context; 38326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira sb = new StringBuilder(); 39326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira dateFormatter = new Formatter(sb); 40326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 41326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 42b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon /** 43b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * This is used in the conversation list, and headers of collapsed messages in 44b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * threaded conversations. 45b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times on today's date will just display time, e.g. 8:15 AM 46b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times not today, but within the same calendar year will display absolute date, e.g. Nov 6 47b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times not in the same year display a numeric absolute date, e.g. 11/18/12 48b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * 49b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @param when The time to generate a formatted date for 50b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @return The formatted date 51b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon */ 52b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon public CharSequence formatShortDateTime(long when) { 53b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon if (DateUtils.isToday(when)) { 54b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME); 55b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } else if (isCurrentYear(when)) { 56b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH); 57b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } else { 58b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE); 59b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } 60326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 61326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 62b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon /** 63b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * This is used in regular message headers. 64b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times on today's date will just display time, e.g. 8:15 AM 65b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times not today, but within two weeks ago will display relative date and time, 66b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * e.g. 6 days ago, 8:15 AM 67b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times more than two weeks ago but within the same calendar year will display 68b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * absolute date and time, e.g. Nov 6, 8:15 AM 69b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Times not in the same year display a numeric absolute date, e.g. 11/18/12 70b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * 71b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @param when The time to generate a formatted date for 72b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @return The formatted date 73b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon */ 7435c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein public CharSequence formatLongDateTime(long when) { 7535c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein if (DateUtils.isToday(when)) { 76b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME); 77b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } else if (isCurrentYear(when)) { 78f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein return getRelativeDateTimeString(mContext, when, DateUtils.DAY_IN_MILLIS, 79b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon 2 * DateUtils.WEEK_IN_MILLIS, 80de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH); 8135c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein } else { 82b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE); 8335c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein } 8435c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein } 8535c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein 86b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon /** 87b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * This is used in expanded details headers. 88b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Displays full date and time e.g. Tue, Nov 18, 2012, 8:15 AM, or 89b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Yesterday, Nov 18, 2012, 8:15 AM 90b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * 91b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @param when The time to generate a formatted date for 92b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @return The formatted date 93b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon */ 94b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon public CharSequence formatFullDateTime(long when) { 9535c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein sb.setLength(0); 96de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein DateUtils.formatDateRange(mContext, dateFormatter, when, when, 97de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | 98de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL); 99de40dd3a292531c7dd8a5741eb0980f666a88b84Andrew Sapperstein return sb.toString(); 100326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira } 101326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira 10235c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein /** 103b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * This is used for displaying dates when printing. 104b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * Displays the full date, e.g. Tue, Nov 18, 2012 at 8:15 PM 105b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * 106b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @param when The time to generate a formatted date for 107b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon * @return The formatted date 10835c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein */ 109b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon public String formatDateTimeForPrinting(long when) { 110b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return mContext.getString(R.string.date_message_received_print, 111b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY | 112b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL), 113b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon formatDateTime(when, DateUtils.FORMAT_SHOW_TIME)); 114b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } 115b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon 116b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon private boolean isCurrentYear(long when) { 117b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon final Calendar nowCal = Calendar.getInstance(); 118b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon final Calendar whenCal = Calendar.getInstance(); 119b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon whenCal.setTimeInMillis(when); 120b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return (nowCal.get(Calendar.YEAR) == whenCal.get(Calendar.YEAR)); 121b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon } 12235c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein 123b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon private CharSequence formatDateTime(long when, int flags) { 124b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon sb.setLength(0); 125b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon DateUtils.formatDateRange(mContext, dateFormatter, when, when, flags); 126b7eac4739e2180b68d5d428438393581a3b5cfa7Martin Hibdon return sb.toString(); 12735c3bb793ac3ea8f63ff73d282c0dabfee5a49ceAndrew Sapperstein } 128f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein 129f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein /** 130f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein * A port of 131f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein * {@link DateUtils#getRelativeDateTimeString(android.content.Context, long, long, long, int)} 132f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein * that does not include the time in strings like "2 days ago". 133f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein */ 134f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein private static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, 135f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein long transitionResolution, int flags) { 136f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein final long now = System.currentTimeMillis(); 137f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein final long duration = Math.abs(now - time); 138f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein 139f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein // getRelativeTimeSpanString() doesn't correctly format relative dates 140f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein // above a week or exact dates below a day, so clamp 141f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein // transitionResolution as needed. 142f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein if (transitionResolution > DateUtils.WEEK_IN_MILLIS) { 143f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein transitionResolution = DateUtils.WEEK_IN_MILLIS; 144f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein } else if (transitionResolution < DateUtils.DAY_IN_MILLIS) { 145f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein transitionResolution = DateUtils.DAY_IN_MILLIS; 146f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein } 147f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein 148f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein if (duration < transitionResolution) { 149f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein return DateUtils.getRelativeTimeSpanString(time, now, minResolution, flags); 150f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein } else { 151f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein return DateUtils.getRelativeTimeSpanString(c, time, false); 152f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein } 153f290ba322a5d6d60496650ed37d65c3af758d354Andrew Sapperstein } 154326c660df0a0a36a52ae74d8bafaa22d6f253561Mindy Pereira} 155