/** * Copyright 2010 Google Inc. * * 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 org.waveprotocol.wave.client.common.util; import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.GWT; import com.google.gwt.i18n.client.DateTimeFormat; import java.util.Date; /** * Date formatting utilities. * */ @SuppressWarnings("deprecation") // GWT supports Date.getXXX, but java doesn't anymore public final class DateUtils { private final static long SEC_MS = 1000; private final static long MIN_MS = 60 * SEC_MS; private final static long HOUR_MS = 60 * MIN_MS; // Singleton class. private DateUtils() { } private static final DateUtils INSTANCE = new DateUtils(); /** * Please avoid invoking getInstance() inside methods but rather inject the * instance into the class through the constructor. This will * - make it easier to move to GIN in the future, and * - make the class easier to test since DateUtils needs to be mocked out * in non-GWT tests. * * @return the shared DateUtils instance */ public static DateUtils getInstance() { return INSTANCE; } /** * Formats a date in the past, taking into account how long ago it was * * @param time The date to format, in ms since whenever * @return The formatted date */ public String formatPastDate(long time) { return formatPastDate(new Date(time), new Date()); } private static DateTimeFormat monthDayFormat; private static DateTimeFormat getMonthDayFormat() { if (monthDayFormat == null) { monthDayFormat = DateTimeFormat.getFormat(DateTimeFormat.PredefinedFormat.MONTH_ABBR_DAY); } return monthDayFormat; } /** * Package-private version, takes a fixed "now" time - used for testing */ String formatPastDate(Date date, Date now) { // NOTE(zdwang): For now skip it for junit code; also see formatDateTime() if (!GWT.isClient()) { return "formatPastDate is not yet implemented in unit test code"; } if (!isValid(date, now)) { GWT.log("formatPastDate can only format time in the past, trying anyway", null); } if (isRecent(date, now) || onSameDay(date, now)) { return DateTimeFormat.getShortTimeFormat().format(date).toLowerCase(); // AM/PM -> am/pm } else if (isSameYear(date, now)) { return getMonthDayFormat().format(date); } else { return DateTimeFormat.getMediumDateFormat().format(date); } } /** * Formats the specified date and time as a String. */ public String formatDateTime(Date date) { // NOTE(zdwang): For now skip it for junit code; also see formatPastDate() if (!GWT.isClient()) { return "formatDateTime is not yet implemented in unit test code"; } // AM/PM -> am/pm for consistency with formatPastDate() return DateTimeFormat.getShortDateTimeFormat().format(date).toLowerCase(); } /** * @return true if a date is approximately in the past (i.e., before a * minute in the future). */ private boolean isValid(Date date, Date now) { long diff = (now.getTime() + MIN_MS) - date.getTime(); return diff >= 0; } /** * @return true if a duration is less than six hours. */ private boolean isRecent(Date date, Date now) { return (now.getTime() - date.getTime()) < 6 * HOUR_MS; } /** * @return true if a date occurs on the same day as today. */ private boolean onSameDay(Date date, Date now) { return (date.getDate() == now.getDate()) && (date.getMonth() == now.getMonth()) && (date.getYear() == now.getYear()); } /** * @return true if a date occurs in the same year as this year. */ private boolean isSameYear(Date date, Date now) { return date.getYear() == now.getYear(); } /** * This is used to get a efficient time for JS. * Warning! Use TimerService if you want to actually test and control the time. */ public double currentTimeMillis() { // Use an optimised time for JS when running in JS. if (!GWT.isClient()) { return System.currentTimeMillis(); } else { return Duration.currentTimeMillis(); } } }