Package ariba.util.formatter

Source Code of ariba.util.formatter.UserDateFormatter

/*
    Copyright 1996-2008 Ariba, 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.

    $Id: //ariba/platform/util/core/ariba/util/formatter/UserDateFormatter.java#8 $
*/

package ariba.util.formatter;

import ariba.util.core.Assert;
import ariba.util.core.Constants;
import ariba.util.core.Date;
import ariba.util.core.ResourceService;
import ariba.util.core.StringUtil;
import java.text.DateFormatSymbols;
import java.text.ParseException;
import java.util.Locale;
import java.util.TimeZone;

/**
    <code>UserDateFormatter</code> is a subclass of <code>DateFormatter</code>
    which is responsible for parsing user date strings, i.e. string typed in
    or selected by the user.  Additional natural language processing is done
    to make date input more user-friendly.  The localized strings for "today",
    "tomorrow", and "yesterday" are recognized and converted to the
    appropriate date relative to the current date.  Day of week strings
    (e.g. "monday", "sunday", etc.)  are also supported for input.

    @aribaapi documented
*/
public class UserDateFormatter extends DateFormatter
{
    /*-----------------------------------------------------------------------
        Constants
      -----------------------------------------------------------------------*/

    /**
        Our Java class name.

        @aribaapi private
    */
    public static final String ClassName = "ariba.util.formatter.UserDateFormatter";

        // localized string resource key for our list of date formats
    private static final String UserFormatsKey   = "UserFormats";

        // resource tags for date format strings for today
    private static final String TodayTimeFormatKey = "TodayTimeFmt";
    private static final String TodayFormatKey     = "TodayFmt";


    /*-----------------------------------------------------------------------
        Constructor
      -----------------------------------------------------------------------*/

    /**
        Creates a new <code>UserDateFormatter</code>.

        @aribaapi private
    */
    public UserDateFormatter ()
    {
    }


    /*-----------------------------------------------------------------------
        Static User Date Formatting
      -----------------------------------------------------------------------*/

    /**
        Returns a formatted string for the given <code>Date</code> in the
        default locale.  Recognizes if the given <code>Date</code> is today
        and formats the output accordingly.

        @param  date the <code>Date</code> to format into a string
        @return      a string representation of the <code>Date</code>
        @aribaapi documented
    */
    public static String getStringValue (Date date)
    {
        return getStringValue(date, getDefaultLocale(), getDefaultTimeZone());
    }

    /**
        Returns a formatted string for the given <code>Date</code> in the
        given <code>timeZone</code> using the default locale.  Recognizes if
        the given <code>Date</code> is today and formats the output
        accordingly.

        @param  date     the <code>Date</code> to format into a string
        @param  timeZone the <code>TimeZone</code> to use for formatting
        @return          a string representation of the <code>Date</code>
        @aribaapi documented
    */
    public static String getStringValue (Date date, TimeZone timeZone)
    {
        return getStringValue(date, getDefaultLocale(), timeZone);
    }

    /**
        Returns a formatted string for the given <code>Date</code> in the
        given locale.  Recognizes if the given <code>Date</code> is today and
        formats the output accordingly.

        @param  date     the <code>Date</code> to format into a string
        @param  locale   the <code>Locale</code> to use for formatting
        @param  timeZone the <code>TimeZone</code> to use for formatting
        @return          a string representation of the <code>Date</code>
        @aribaapi documented
    */
    public static String getStringValue (Date date, Locale locale, TimeZone timeZone)
    {
            // format dates for today with "Today" string
        if (Date.sameDay(date, new Date(date.calendarDate()), timeZone)) {
            String format;
            if (Date.timeIsMidnight(date, timeZone)) {
                format = TodayFormatKey;
            }
            else {
                format = TodayTimeFormatKey;
            }
            String pattern = lookupLocalizedFormat(format, locale);
            return DateFormatter.getStringValue(date, pattern, locale, timeZone);
        }
            // format other dates in the usual way
        else {
            return DateFormatter.getStringValue(date, locale, timeZone);
        }
    }

    public String getDateString (Date date, Locale locale, TimeZone timeZone)
    {
        return getStringValue(date, locale, timeZone);
    }

    /*-----------------------------------------------------------------------
        Static User Date Parsing
      -----------------------------------------------------------------------*/

    /**
        Tries to parse the given user string as a <code>Date</code> in the
        default locale.  In addition to the default date parsing, this method
        will also try to handle a number of more natural date strings,
        e.g. the string "today", "tomorrow", "monday", etc.  It also handles
        cases where the string is incomplete, e.g. "2/21".  In this case, the
        current year is used as the default.

        @param     string the string to parse as a <code>Date</code>
        @param calendarDate if true, a calendar date will be created
        @return           a <code>Date</code> derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code>
        @aribaapi documented
    */
    public static Date parseUserDate (String string, boolean calendarDate)
      throws ParseException
    {
        return parseUserDate(string, getDefaultLocale(), calendarDate);
    }

    /**
        Tries to parse the given user string as a <code>Date</code> in the
        default locale.  In addition to the default date parsing, this method
        will also try to handle a number of more natural date strings,
        e.g. the string "today", "tomorrow", "monday", etc.  It also handles
        cases where the string is incomplete, e.g. "2/21".  In this case, the
        current year is used as the default.

        @param     string the string to parse as a <code>Date</code>
        @return           a <code>Date</code> derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code>
        @aribaapi documented
    */
    public static Date parseUserDate (String string)
      throws ParseException
    {
        return parseUserDate(string, getDefaultLocale(), false);
    }

    /**
        Tries to parse the given user string as a <code>Date</code> in the
        given locale.  In addition to the default date parsing, this method
        will also try to handle a number of more natural date strings,
        e.g. the string "today", "tomorrow", "monday", etc.  It also handles
        cases where the string is incomplete, e.g. "2/21".  In this case, the
        current year is used as the default.

        @param     string the string to parse as a <code>Date</code>
        @param     locale the <code>Locale</code> to use for parsing
        @return           a <code>Date</code> derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code>
        @aribaapi documented
    */
    public static Date parseUserDate (String string,
                                      Locale locale)
      throws ParseException
    {
        return parseUserDate(string, locale, false);
    }

    /**
        Tries to parse the given user string as a <code>Date</code> in the
        given locale.  In addition to the default date parsing, this method
        will also try to handle a number of more natural date strings,
        e.g. the string "today", "tomorrow", "monday", etc.  It also handles
        cases where the string is incomplete, e.g. "2/21".  In this case, the
        current year is used as the default.

        @param     string the string to parse as a <code>Date</code>
        @param     locale the <code>Locale</code> to use for parsing
        @param calendarDate if true, a calendar date will be created
        @return           a <code>Date</code> derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code>
        @aribaapi documented
    */
    public static Date parseUserDate (String  string,
                                      Locale  locale,
                                      boolean calendarDate)
      throws ParseException
    {
        return parseUserDate(string, locale, getDefaultTimeZone(), calendarDate);
    }

    /**
        Tries to parse the given user string as a <code>Date</code> in the
        given locale.  In addition to the default date parsing, this method
        will also try to handle a number of more natural date strings,
        e.g. the string "today", "tomorrow", "monday", etc.  It also handles
        cases where the string is incomplete, e.g. "2/21".  In this case, the
        current year is used as the default.

        @param     string the string to parse as a <code>Date</code>
        @param     locale the <code>Locale</code> to use for parsing
        @param tz     the <code>TimeZone</code> to use for parsing
        @param calendarDate if true, a calendar date will be created
        @return           a <code>Date</code> derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code>
        @aribaapi documented
    */
    public static Date parseUserDate (String   string,
                                      Locale   locale,
                                      TimeZone tz,
                                      boolean  calendarDate)
      throws ParseException
    {
            // try the default date parsing first
        try {
            return parseDate(string, locale, tz, calendarDate);
        }
        catch (ParseException e)
        {
        }

            // attempt to parse strings like "today", "saturday", etc.
        Date result = parseNaturalDate(string, locale, tz,calendarDate);
        if (result != null) {
            return result;
        }

            // try the localized list of user date formats
        result = parseDateUsingFormats(string, locale,
                            UserFormatsKey, tz, calendarDate);

        if (result != null) {
            return result;
        }

            // attempt to parse strings like "1/21"
        result = parseRelativeDate(string, locale, tz, calendarDate);
        if (result != null) {
            return result;
        }

        throw makeParseException(DateFormatter.CannotParseDateKey, string, 0);
    }

        // resource tags for date format strings used by parseNaturalDate()
    private static final String YesterdayStringKey = "Yesterday";
    private static final String TodayStringKey     = "Today";
    private static final String TomorrowStringKey  = "Tomorrow";

        // array of these keys for convenience below (order is important)
    private static final String[] RelativeDayKeys = {
        YesterdayStringKey, TodayStringKey, TomorrowStringKey
    };

    /**
        Handles natural language strings like days of the week or "today",
        "tomorrow", and "yesterday".  For example, if today is Thursday,
        December 17, 1998, and the user types in "Sun", it will return a Date
        for Sunday, December 20, 1998, 00:00:00.
        @aribaapi private
    */
    private static Date parseNaturalDate (String string, Locale locale,
                                          TimeZone timeZone,
                                          boolean calendarDate)
    {
        if (StringUtil.nullOrEmptyString(string)) {
            return null;
        }

        /*
            "now" doesn't need to be calendarDate-aware,
            since this is just a temp to find out
            what year, month, and day today is.
        */
        Date now = new Date();

        int thisYear = Date.getYear(now, timeZone, locale);
        int thisMonth = Date.getMonth(now, timeZone, locale);
        int thisDayOfMonth = Date.getDayOfMonth(now, timeZone, locale);
        int thisDayOfWeek = Date.getDayOfWeek(now, timeZone, locale);

        Integer daysToAdd = null;

            // if the user entered a day name, offset into the future to the
            // appropriate day of the month, month, and year
        int dayOfWeek = findDay(string);
        if (dayOfWeek >= 0) {
            int add = ((7 + dayOfWeek) - thisDayOfWeek) % 7;
            if (add == 0) {
                add = 7;
            }
            daysToAdd = Constants.getInteger(add);
        }
            // otherwise, check if the string is a prefix for strings
            // like "today", "tomorrow", etc.
        else {
            for (int i = -1, len = string.length(); i <= 1; i++) {
                String key = RelativeDayKeys[i+1];
                String test = lookupLocalizedFormat(key, locale);
                if (!StringUtil.nullOrEmptyString(test)) {
                    if (test.length() >= len) {
                        String sub = test.substring(0, len);
                        if (sub.equalsIgnoreCase(string)) {
                            daysToAdd = Constants.getInteger(i);
                            break;
                        }
                    }
                }
            }
        }
        Date result = null;
        if (daysToAdd != null) {
            result = new Date(thisYear, thisMonth, thisDayOfMonth,
                                   calendarDate, timeZone, locale);
            Date.addDays(result, daysToAdd.intValue(), timeZone, locale);
            return result;
        }
        else {
                // lastly, try TodayTimeFormatKey.  Get the number of milisecs
                // that the time represent with respect to GMT. Then add on to
                // today's.
            result = parseDateUsingFormats(string, locale,
                     TodayTimeFormatKey, TimeZone.getTimeZone("GMT"), calendarDate);
            if (result != null) {
                Date today = new Date(thisYear, thisMonth, thisDayOfMonth,
                                   calendarDate, timeZone, locale);
                if (result.getTime() < Date.MillisPerDay) {
                    result.setTime(result.getTime() + today.getTime());
                }
            }
            return result;
        }
    }

    /**
        Determines whether the given string is a prefix for one of the
        localized day of the week words, e.g. "monday", "thursday", etc.
        Returns the day of the week (Sunday = 0) that matches, or -1 if the
        string doesn't match.

        @aribaapi private
    */
    private static int findDay (String string)
    {
            // use the locale specified by the resource service
        Locale locale = ResourceService.getService().getLocale();
        DateFormatSymbols symbols = new DateFormatSymbols(locale);

        String[] days = symbols.getWeekdays();
        int length = string.length();

        for (int i = 0; i < days.length; i++) {
            if ((days[i].length() >= length) &&
                (days[i].substring(0, length).equalsIgnoreCase(string)))
            {
                return i;
            }
        }

        return -1;
    }

        // resource tag for date format string used by parseRelativeDate()
    private static final String YearRelativeFormat = "YearRelativeFmt";

    /**
        Attempts to parse the given string as a relative date, i.e. a month
        and date with no year.  If the string is in this form, the current
        year is used as the default.
    */
    private static Date parseRelativeDate (String string, Locale locale,
                                           TimeZone timeZone,
                                           boolean calendarDate)
    {
            // parse the date given the year-relative format
        String format = lookupLocalizedFormat(YearRelativeFormat, locale);
        Date date = null;
        try {
            date = parseDate(string, format, locale, timeZone, calendarDate);
        }
        catch (ParseException e) {
            return null;
        }

            // set the year for the date to this year
        Date.setYear(date, Date.getYear(new Date(calendarDate)));

        return date;
    }

    /*-- User Date Values ---------------------------------------------------*/

    /**
        Returns a new <code>Date</code> derived from the given object in the
        default locale.  If the object is not a <code>Date</code>, it is
        converted to a string and parsed as a user string.  Returns null if
        the object can't be converted to a <code>Date</code>.

        @param  object the object to convert to a <code>Date</code>
        @param calendarDate if true, a calendar date will be created
        @return        a <code>Date</code> derived from the given object
        @aribaapi documented
    */
    public static Date userDateValue (Object object, boolean calendarDate)
    {
        return userDateValue(object, getDefaultLocale(), calendarDate);
    }

    /**
        Returns a new <code>Date</code> derived from the given object in the
        default locale.  If the object is not a <code>Date</code>, it is
        converted to a string and parsed as a user string.  Returns null if
        the object can't be converted to a <code>Date</code>.

        @param  object the object to convert to a <code>Date</code>
        @return        a <code>Date</code> derived from the given object
        @aribaapi documented
    */
    public static Date userDateValue (Object object)
    {
        return userDateValue(object, getDefaultLocale(), false);
    }

    /**
        Returns a new <code>Date</code> derived from the given object in the
        given locale.  If the object is not a <code>Date</code>, it is
        converted to a string and parsed as a user string.  Returns null if
        the object can't be converted to a <code>Date</code>.

        @param  object the object to convert to a <code>Date</code>
        @param  locale the <code>Locale</code> to use for conversion
        @return        a <code>Date</code> derived from the given object
        @aribaapi documented
    */
    public static Date userDateValue (Object object, Locale locale)
    {
        return userDateValue(object, locale, false);
    }

    /**
        Returns a new <code>Date</code> derived from the given object in the
        given locale.  If the object is not a <code>Date</code>, it is
        converted to a string and parsed as a user string.  Returns null if
        the object can't be converted to a <code>Date</code>.

        @param  object the object to convert to a <code>Date</code>
        @param  locale the <code>Locale</code> to use for conversion
        @param calendarDate if true, a calendar date will be created
        @return        a <code>Date</code> derived from the given object
        @aribaapi documented
    */
    public static Date userDateValue (Object object, Locale locale,
                                      boolean calendarDate)
    {
        if (object == null) {
            return null;
        }
        else if (object instanceof Date) {
            return ((Date)object);
        }
        else {
            try {
                return parseUserDate(object.toString(), locale, calendarDate);
            }
            catch (ParseException e) {
            }
            return null;
        }
    }


    /*-----------------------------------------------------------------------
        Formatting
      -----------------------------------------------------------------------*/

    /**
        Returns a string representation of the given object in the given
        locale.  The object must be a non-null <code>Date</code>.

        @param  object the <code>Date</code> to format into a string
        @param  locale the <code>Locale</code> to use for formatting
        @return        a string representation of the <code>Date</code>
        @aribaapi documented
    */
    protected String formatObject (Object object, Locale locale)
    {
        Assert.that(object instanceof Date, "invalid type");
        return getStringValue((Date)object, locale);
    }


    /*-----------------------------------------------------------------------
        Parsing
      -----------------------------------------------------------------------*/

    /**
        Parse the given string as a <code>Date</code> in the given
        locale and time zone.  The <code>locale</code> and
        <code>timeZone</code> parameters must be non-null.

        @param     string the string to parse
        @param     locale the <code>Locale</code> to use for parsing
        @param tz           the <code>TimeZone</code> to use for parsing
        @return           a <code>Date</code> object derived from the string
        @exception        ParseException if the string can't be parsed as a
                          <code>Date</code> object in the given locale
        @aribaapi documented
    */
    public Object parseString (String string, Locale locale, TimeZone tz)
        throws ParseException
    {
        return parseString(string, locale, tz, false);
    }

    /**
        Parse the given string as a <code>Date</code> in the given
        locale and time zone.  The <code>locale</code> and
        <code>timeZone</code> parameters must be non-null.

        @param string       the string to parse as a <code>Date</code>
        @param locale       the <code>Locale</code> to use for parsing
        @param tz     the <code>TimeZone</code> to use for parsing
        @param calendarDate if true, a calendar date will be created
        @return             a <code>Date</code> derived from the string
        @exception          ParseException if the string can't be parsed as a
                            <code>Date</code>
        @aribaapi documented
    */
    public Object parseString (
                        String string,
                        Locale locale,
                        TimeZone tz,
                        boolean calendarDate)
      throws ParseException
    {
        return parseUserDate(string, locale, tz, calendarDate);
    }

    /**
        Overrides DateFormatter.parseString() to call our static method for
        converting an object into a date.
        @param  object the object to convert to a <code>Date</code>
        @param  locale the <code>Locale</code> to use for conversion
        @return             a <code>Date</code> derived from the string
        @aribaapi documented
    */
    public Object getValue (Object object, Locale locale)
    {
        return userDateValue(object, locale, false);
    }
}
TOP

Related Classes of ariba.util.formatter.UserDateFormatter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.