blob: 89127c93ac3afb978e6e73bc6fd281299c2e5d2c [file] [log] [blame]
/*
* Copyright (C) 2010 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.contacts.util;
import android.content.Context;
import android.text.format.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* Utility methods for processing dates.
*/
public class DateUtils {
public static final TimeZone UTC_TIMEZONE = TimeZone.getTimeZone("UTC");
// All the SimpleDateFormats in this class use the UTC timezone
public static final SimpleDateFormat NO_YEAR_DATE_FORMAT =
new SimpleDateFormat("--MM-dd", Locale.US);
/**
* When parsing a date without a year, the system assumes 1970, which wasn't a leap-year.
* Let's add a one-off hack for that day of the year
*/
public static final String NO_YEAR_DATE_FEB29TH = "--02-29";
public static final SimpleDateFormat FULL_DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd", Locale.US);
public static final SimpleDateFormat DATE_AND_TIME_FORMAT =
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
public static final SimpleDateFormat NO_YEAR_DATE_AND_TIME_FORMAT =
new SimpleDateFormat("--MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
// Variations of ISO 8601 date format. Do not change the order - it does affect the
// result in ambiguous cases.
private static final SimpleDateFormat[] DATE_FORMATS = {
FULL_DATE_FORMAT,
DATE_AND_TIME_FORMAT,
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'", Locale.US),
new SimpleDateFormat("yyyyMMdd", Locale.US),
new SimpleDateFormat("yyyyMMdd'T'HHmmssSSS'Z'", Locale.US),
new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'", Locale.US),
new SimpleDateFormat("yyyyMMdd'T'HHmm'Z'", Locale.US),
};
private static final java.text.DateFormat FORMAT_WITHOUT_YEAR_MONTH_FIRST =
new SimpleDateFormat("MMMM dd");
private static final java.text.DateFormat FORMAT_WITHOUT_YEAR_DAY_FIRST =
new SimpleDateFormat("dd MMMM");
static {
for (SimpleDateFormat format : DATE_FORMATS) {
format.setLenient(true);
format.setTimeZone(UTC_TIMEZONE);
}
NO_YEAR_DATE_FORMAT.setTimeZone(UTC_TIMEZONE);
FORMAT_WITHOUT_YEAR_MONTH_FIRST.setTimeZone(UTC_TIMEZONE);
FORMAT_WITHOUT_YEAR_DAY_FIRST.setTimeZone(UTC_TIMEZONE);
}
/**
* Parses the supplied string to see if it looks like a date. If so,
* returns the date. Otherwise, returns null.
*/
public static Date parseDate(String string) {
ParsePosition parsePosition = new ParsePosition(0);
for (int i = 0; i < DATE_FORMATS.length; i++) {
SimpleDateFormat f = DATE_FORMATS[i];
synchronized (f) {
parsePosition.setIndex(0);
Date date = f.parse(string, parsePosition);
if (parsePosition.getIndex() == string.length()) {
return date;
}
}
}
return null;
}
private static final Date getUtcDate(int year, int month, int dayOfMonth) {
final Calendar calendar = Calendar.getInstance(UTC_TIMEZONE, Locale.US);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
return calendar.getTime();
}
/**
* Parses the supplied string to see if it looks like a date. If so,
* returns the same date in a cleaned-up format for the user. Otherwise, returns
* the supplied string unchanged.
*/
public static String formatDate(Context context, String string) {
if (string == null) {
return null;
}
string = string.trim();
if (string.length() == 0) {
return string;
}
ParsePosition parsePosition = new ParsePosition(0);
final boolean noYearParsed;
Date date;
// Unfortunately, we can't parse Feb 29th correctly, so let's handle this day seperately
if (NO_YEAR_DATE_FEB29TH.equals(string)) {
date = getUtcDate(0, Calendar.FEBRUARY, 29);
noYearParsed = true;
} else {
synchronized (NO_YEAR_DATE_FORMAT) {
date = NO_YEAR_DATE_FORMAT.parse(string, parsePosition);
}
noYearParsed = parsePosition.getIndex() == string.length();
}
if (noYearParsed) {
java.text.DateFormat outFormat = isMonthBeforeDay(context)
? FORMAT_WITHOUT_YEAR_MONTH_FIRST
: FORMAT_WITHOUT_YEAR_DAY_FIRST;
synchronized (outFormat) {
return outFormat.format(date);
}
}
for (int i = 0; i < DATE_FORMATS.length; i++) {
SimpleDateFormat f = DATE_FORMATS[i];
synchronized (f) {
parsePosition.setIndex(0);
date = f.parse(string, parsePosition);
if (parsePosition.getIndex() == string.length()) {
java.text.DateFormat outFormat = DateFormat.getDateFormat(context);
outFormat.setTimeZone(UTC_TIMEZONE);
return outFormat.format(date);
}
}
}
return string;
}
public static boolean isMonthBeforeDay(Context context) {
char[] dateFormatOrder = DateFormat.getDateFormatOrder(context);
for (int i = 0; i < dateFormatOrder.length; i++) {
if (dateFormatOrder[i] == DateFormat.DATE) {
return false;
}
if (dateFormatOrder[i] == DateFormat.MONTH) {
return true;
}
}
return false;
}
}