1 /* 2 * Copyright (C) 2012 Google Inc. 3 * Licensed to The Android Open Source Project. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package com.android.mail; 18 19 import android.content.Context; 20 import android.text.format.DateUtils; 21 22 import java.util.Calendar; 23 import java.util.Formatter; 24 25 /** 26 * Convenience class to efficiently make multiple short date strings. Instantiating and reusing 27 * one of these builders is faster than repeatedly bringing up all the locale stuff. 28 * 29 */ 30 public class FormattedDateBuilder { 31 32 private final StringBuilder sb; 33 private final Formatter dateFormatter; 34 private final Context mContext; 35 36 public FormattedDateBuilder(Context context) { 37 mContext = context; 38 sb = new StringBuilder(); 39 dateFormatter = new Formatter(sb); 40 } 41 42 /** 43 * This is used in the conversation list, and headers of collapsed messages in 44 * threaded conversations. 45 * Times on today's date will just display time, e.g. 8:15 AM 46 * Times not today, but within the same calendar year will display absolute date, e.g. Nov 6 47 * Times not in the same year display a numeric absolute date, e.g. 11/18/12 48 * 49 * @param when The time to generate a formatted date for 50 * @return The formatted date 51 */ 52 public CharSequence formatShortDateTime(long when) { 53 if (DateUtils.isToday(when)) { 54 return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME); 55 } else if (isCurrentYear(when)) { 56 return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH); 57 } else { 58 return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE); 59 } 60 } 61 62 /** 63 * This is used in regular message headers. 64 * Times on today's date will just display time, e.g. 8:15 AM 65 * Times not today, but within two weeks ago will display relative date and time, 66 * e.g. 6 days ago, 8:15 AM 67 * Times more than two weeks ago but within the same calendar year will display 68 * absolute date and time, e.g. Nov 6, 8:15 AM 69 * Times not in the same year display a numeric absolute date, e.g. 11/18/12 70 * 71 * @param when The time to generate a formatted date for 72 * @return The formatted date 73 */ 74 public CharSequence formatLongDateTime(long when) { 75 if (DateUtils.isToday(when)) { 76 return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME); 77 } else if (isCurrentYear(when)) { 78 return getRelativeDateTimeString(mContext, when, DateUtils.DAY_IN_MILLIS, 79 2 * DateUtils.WEEK_IN_MILLIS, 80 DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH); 81 } else { 82 return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE); 83 } 84 } 85 86 /** 87 * This is used in expanded details headers. 88 * Displays full date and time e.g. Tue, Nov 18, 2012, 8:15 AM, or 89 * Yesterday, Nov 18, 2012, 8:15 AM 90 * 91 * @param when The time to generate a formatted date for 92 * @return The formatted date 93 */ 94 public CharSequence formatFullDateTime(long when) { 95 sb.setLength(0); 96 DateUtils.formatDateRange(mContext, dateFormatter, when, when, 97 DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | 98 DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL); 99 return sb.toString(); 100 } 101 102 /** 103 * This is used for displaying dates when printing. 104 * Displays the full date, e.g. Tue, Nov 18, 2012 at 8:15 PM 105 * 106 * @param when The time to generate a formatted date for 107 * @return The formatted date 108 */ 109 public String formatDateTimeForPrinting(long when) { 110 return mContext.getString(R.string.date_message_received_print, 111 formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY | 112 DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL), 113 formatDateTime(when, DateUtils.FORMAT_SHOW_TIME)); 114 } 115 116 private boolean isCurrentYear(long when) { 117 final Calendar nowCal = Calendar.getInstance(); 118 final Calendar whenCal = Calendar.getInstance(); 119 whenCal.setTimeInMillis(when); 120 return (nowCal.get(Calendar.YEAR) == whenCal.get(Calendar.YEAR)); 121 } 122 123 private CharSequence formatDateTime(long when, int flags) { 124 sb.setLength(0); 125 DateUtils.formatDateRange(mContext, dateFormatter, when, when, flags); 126 return sb.toString(); 127 } 128 129 /** 130 * A port of 131 * {@link DateUtils#getRelativeDateTimeString(android.content.Context, long, long, long, int)} 132 * that does not include the time in strings like "2 days ago". 133 */ 134 private static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, 135 long transitionResolution, int flags) { 136 final long now = System.currentTimeMillis(); 137 final long duration = Math.abs(now - time); 138 139 // getRelativeTimeSpanString() doesn't correctly format relative dates 140 // above a week or exact dates below a day, so clamp 141 // transitionResolution as needed. 142 if (transitionResolution > DateUtils.WEEK_IN_MILLIS) { 143 transitionResolution = DateUtils.WEEK_IN_MILLIS; 144 } else if (transitionResolution < DateUtils.DAY_IN_MILLIS) { 145 transitionResolution = DateUtils.DAY_IN_MILLIS; 146 } 147 148 if (duration < transitionResolution) { 149 return DateUtils.getRelativeTimeSpanString(time, now, minResolution, flags); 150 } else { 151 return DateUtils.getRelativeTimeSpanString(c, time, false); 152 } 153 } 154 } 155