summaryrefslogtreecommitdiffstats
path: root/src/com/android/mail/FormattedDateBuilder.java
blob: 40aa3c89062f697663d6d6b6985b8bbd23a390b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
 * Copyright (C) 2012 Google Inc.
 * Licensed to 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 com.android.mail;

import android.content.Context;
import android.text.format.DateUtils;

import java.util.Calendar;
import java.util.Formatter;

/**
 * Convenience class to efficiently make multiple short date strings. Instantiating and reusing
 * one of these builders is faster than repeatedly bringing up all the locale stuff.
 *
 */
public class FormattedDateBuilder {

    private final StringBuilder sb;
    private final Formatter dateFormatter;
    private final Context mContext;

    public FormattedDateBuilder(Context context) {
        mContext = context;
        sb = new StringBuilder();
        dateFormatter = new Formatter(sb);
    }

    /**
     * This is used in the conversation list, and headers of collapsed messages in
     * threaded conversations.
     * Times on today's date will just display time, e.g. 8:15 AM
     * Times not today, but within the same calendar year will display absolute date, e.g. Nov 6
     * Times not in the same year display a numeric absolute date, e.g. 11/18/12
     *
     * @param when The time to generate a formatted date for
     * @return The formatted date
     */
    public CharSequence formatShortDateTime(long when) {
        if (DateUtils.isToday(when)) {
            return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME);
        } else if (isCurrentYear(when)) {
            return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH);
        } else {
            return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE);
        }
    }

    /**
     * This is used in regular message headers.
     * Times on today's date will just display time, e.g. 8:15 AM
     * Times not today, but within two weeks ago will display relative date and time,
     * e.g. 6 days ago, 8:15 AM
     * Times more than two weeks ago but within the same calendar year will display
     * absolute date and time, e.g. Nov 6, 8:15 AM
     * Times not in the same year display a numeric absolute date, e.g. 11/18/12
     *
     * @param when The time to generate a formatted date for
     * @return The formatted date
     */
    public CharSequence formatLongDateTime(long when) {
        if (DateUtils.isToday(when)) {
            return formatDateTime(when, DateUtils.FORMAT_SHOW_TIME);
        } else if (isCurrentYear(when)) {
            return getRelativeDateTimeString(mContext, when, DateUtils.DAY_IN_MILLIS,
                    2 * DateUtils.WEEK_IN_MILLIS,
                    DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH);
        } else {
            return formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE);
        }
    }

    /**
     * This is used in expanded details headers.
     * Displays full date and time e.g. Tue, Nov 18, 2012, 8:15 AM, or
     * Yesterday, Nov 18, 2012, 8:15 AM
     *
     * @param when The time to generate a formatted date for
     * @return The formatted date
     */
    public CharSequence formatFullDateTime(long when) {
        sb.setLength(0);
        DateUtils.formatDateRange(mContext, dateFormatter, when, when,
                DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE |
                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL);
        return sb.toString();
    }

    /**
     * This is used for displaying dates when printing.
     * Displays the full date, e.g. Tue, Nov 18, 2012 at 8:15 PM
     *
     * @param when The time to generate a formatted date for
     * @return The formatted date
     */
    public String formatDateTimeForPrinting(long when) {
        return mContext.getString(R.string.date_message_received_print,
                formatDateTime(when, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY |
                        DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_ABBREV_ALL),
                        formatDateTime(when, DateUtils.FORMAT_SHOW_TIME));
    }

    private boolean isCurrentYear(long when) {
        final Calendar nowCal = Calendar.getInstance();
        final Calendar whenCal = Calendar.getInstance();
        whenCal.setTimeInMillis(when);
        return (nowCal.get(Calendar.YEAR) == whenCal.get(Calendar.YEAR));
    }

    private CharSequence formatDateTime(long when, int flags) {
        sb.setLength(0);
        DateUtils.formatDateRange(mContext, dateFormatter, when, when, flags);
        return sb.toString();
    }

    /**
     * A port of
     * {@link DateUtils#getRelativeDateTimeString(android.content.Context, long, long, long, int)}
     * that does not include the time in strings like "2 days ago".
     */
    private static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution,
            long transitionResolution, int flags) {
        final long now = System.currentTimeMillis();
        final long duration = Math.abs(now - time);

        // getRelativeTimeSpanString() doesn't correctly format relative dates
        // above a week or exact dates below a day, so clamp
        // transitionResolution as needed.
        if (transitionResolution > DateUtils.WEEK_IN_MILLIS) {
            transitionResolution = DateUtils.WEEK_IN_MILLIS;
        } else if (transitionResolution < DateUtils.DAY_IN_MILLIS) {
            transitionResolution = DateUtils.DAY_IN_MILLIS;
        }

        if (duration < transitionResolution) {
            return DateUtils.getRelativeTimeSpanString(time, now, minResolution, flags);
        } else {
            return DateUtils.getRelativeTimeSpanString(c, time, false);
        }
    }
}