//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You 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 mx.formatters { import mx.core.mx_internal; import mx.managers.ISystemManager; import mx.managers.SystemManager; use namespace mx_internal; [ResourceBundle("SharedResources")] [Alternative(replacement="spark.formatters.DateTimeFormatter", since="4.5")] /** * The DateFormatter class uses a format String to return a formatted date and time String * from an input String or a Date object. * You can create many variations easily, including international formats. * *

If an error occurs, an empty String is returned and a String describing * the error is saved to the error property. The error * property can have one of the following values:

* * * *

The parseDateString() method uses the mx.formatters.DateBase class * to define the localized string information required to convert * a date that is formatted as a String into a Date object.

* * @mxml * *

You use the <mx:DateFormatter> tag * to render date and time Strings from a Date object.

* *

The <mx:DateFormatter> tag * inherits all of the tag attributes of its superclass, * and adds the following tag attributes:

* *
 *  <mx:DateFormatter
 *    formatString="Y|M|D|A|E|H|J|K|L|N|S|Q"
 *   /> 
 *  
* * @includeExample examples/DateFormatterExample.mxml * * @see mx.formatters.DateBase * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public class DateFormatter extends Formatter { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- /** * @private */ private static const VALID_PATTERN_CHARS:String = "Y,M,D,A,E,H,J,K,L,N,S,Q"; //-------------------------------------------------------------------------- // // Class methods // //-------------------------------------------------------------------------- /** * Converts a date that is formatted as a String into a Date object. * Month and day names must match the names in mx.formatters.DateBase. * * The hour value in the String must be between 0 and 23, inclusive. * The minutes and seconds value must be between 0 and 59, inclusive. * The following example uses this method to create a Date object: * *
     *  var myDate:Date = DateFormatter.parseDateString("2009-12-02 23:45:30"); 
* * @see mx.formatters.DateBase * * @param str Date that is formatted as a String. * * @return Date object. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public static function parseDateString (str:String):Date { if (!str || str == "") return null; var year:int = -1; var mon:int = -1; var day:int = -1; var hour:int = -1; var min:int = -1; var sec:int = -1; var letter:String = ""; var marker:Object = 0; var count:int = 0; var len:int = str.length; // Strip out the Timezone. It is not used by the DateFormatter var timezoneRegEx:RegExp = /(GMT|UTC)((\+|-)\d\d\d\d )?/ig; str = str.replace(timezoneRegEx, ""); while (count < len) { letter = str.charAt(count); count++; // If the letter is a blank space or a comma, // continue to the next character if (letter <= " " || letter == ",") continue; // If the letter is a key punctuation character, // cache it for the next time around. if (letter == "/" || letter == ":" || letter == "+" || letter == "-") { marker = letter; continue; } // Scan for groups of numbers and letters // and match them to Date parameters if ("a" <= letter && letter <= "z" || "A" <= letter && letter <= "Z") { // Scan for groups of letters var word:String = letter; while (count < len) { letter = str.charAt(count); if (!("a" <= letter && letter <= "z" || "A" <= letter && letter <= "Z")) { break; } word += letter; count++; } // Allow for an exact match // or a match to the first 3 letters as a prefix. var n:int = DateBase.defaultStringKey.length; for (var i:int = 0; i < n; i++) { var s:String = String(DateBase.defaultStringKey[i]); if (s.toLowerCase() == word.toLowerCase() || s.toLowerCase().substr(0,3) == word.toLowerCase()) { if (i == 13) { // pm if (hour > 12 || hour < 1) break; // error else if (hour < 12) hour += 12; } else if (i == 12) { // am if (hour > 12 || hour < 1) break; // error else if (hour == 12) hour = 0; } else if (i < 12) { // month if (mon < 0) mon = i; else break; // error } break; } } marker = 0; } else if ("0" <= letter && letter <= "9") { // Scan for groups of numbers var numbers:String = letter; while ("0" <= (letter = str.charAt(count)) && letter <= "9" && count < len) { numbers += letter; count++; } var num:int = int(numbers); // If num is a number greater than 70, assign num to year. if (num >= 70) { if (year != -1) { break; // error } else if (letter <= " " || letter == "," || letter == "." || letter == "/" || letter == "-" || count >= len) { year = num; } else { break; //error } } // If the current letter is a slash or a dash, // assign num to month or day. else if (letter == "/" || letter == "-" || letter == ".") { if (mon < 0) mon = (num - 1); else if (day < 0) day = num; else break; //error } // If the current letter is a colon, // assign num to hour or minute. else if (letter == ":") { if (hour < 0) hour = num; else if (min < 0) min = num; else break; //error } // If hours are defined and minutes are not, // assign num to minutes. else if (hour >= 0 && min < 0) { min = num; } // If minutes are defined and seconds are not, // assign num to seconds. else if (min >= 0 && sec < 0) { sec = num; } // If day is not defined, assign num to day. else if (day < 0) { day = num; } // If month and day are defined and year is not, // assign num to year. else if (year < 0 && mon >= 0 && day >= 0) { year = 2000 + num; } // Otherwise, break the loop else { break; //error } marker = 0 } } if (year < 0 || mon < 0 || mon > 11 || day < 1 || day > 31) return null; // error - needs to be a date // Time is set to 0 if null. if (sec < 0) sec = 0; if (min < 0) min = 0; if (hour < 0) hour = 0; // create a date object and check the validity of the input date // by comparing the result with input values. var newDate:Date = new Date(year, mon, day, hour, min, sec); if (day != newDate.getDate() || mon != newDate.getMonth()) return null; return newDate; } //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function DateFormatter() { super(); } //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // formatString //---------------------------------- /** * @private * Storage for the formatString property. */ private var _formatString:String; /** * @private */ private var formatStringOverride:String; [Inspectable(category="General", defaultValue="null")] /** * The mask pattern. * *

You compose a pattern String using specific uppercase letters, * for example: YYYY/MM.

* *

The DateFormatter pattern String can contain other text * in addition to pattern letters. * To form a valid pattern String, you only need one pattern letter.

* *

The following table describes the valid pattern letters:

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Pattern letterDescription
Y Year. If the number of pattern letters is two, the year is * truncated to two digits; otherwise, it appears as four digits. * The year can be zero-padded, as the third example shows in the * following set of examples: *
    *
  • YY = 05
  • *
  • YYYY = 2005
  • *
  • YYYYY = 02005
  • *
M Month in year. The format depends on the following criteria: *
    *
  • If the number of pattern letters is one, the format is * interpreted as numeric in one or two digits.
  • *
  • If the number of pattern letters is two, the format * is interpreted as numeric in two digits.
  • *
  • If the number of pattern letters is three, * the format is interpreted as short text.
  • *
  • If the number of pattern letters is four, the format * is interpreted as full text.
  • *
* Examples: *
    *
  • M = 7
  • *
  • MM= 07
  • *
  • MMM=Jul
  • *
  • MMMM= July
  • *
DDay in month. While a single-letter pattern string for day is valid, * you typically use a two-letter pattern string. * *

Examples:

*
    *
  • D=4
  • *
  • DD=04
  • *
  • DD=10
  • *
EDay in week. The format depends on the following criteria: *
    *
  • If the number of pattern letters is one, the format is * interpreted as numeric in one or two digits.
  • *
  • If the number of pattern letters is two, the format is interpreted * as numeric in two digits.
  • *
  • If the number of pattern letters is three, the format is interpreted * as short text.
  • *
  • If the number of pattern letters is four, the format is interpreted * as full text.
  • *
* Examples: *
    *
  • E = 1
  • *
  • EE = 01
  • *
  • EEE = Mon
  • *
  • EEEE = Monday
  • *
A am/pm indicator.
JHour in day (0-23).
HHour in day (1-24).
KHour in am/pm (0-11).
LHour in am/pm (1-12).
NMinute in hour. * *

Examples:

*
    *
  • N = 3
  • *
  • NN = 03
  • *
SSecond in minute. * *

Example:

*
    *
  • SS = 30
  • *
QMillisecond in second * *

Example:

*
    *
  • QQ = 78
  • *
  • QQQ = 078
  • *
Other textYou can add other text into the pattern string to further * format the string. You can use punctuation, numbers, * and all lowercase letters. You should avoid uppercase letters * because they may be interpreted as pattern letters. * *

Example:

*
    *
  • EEEE, MMM. D, YYYY at L:NN:QQQ A = Tuesday, Sept. 8, 2005 at 1:26:012 PM
  • *
* * @default "MM/DD/YYYY" * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ public function get formatString():String { return _formatString; } /** * @private */ public function set formatString(value:String):void { formatStringOverride = value; _formatString = value != null ? value : resourceManager.getString( "SharedResources", "dateFormat"); } //-------------------------------------------------------------------------- // // Overridden methods // //-------------------------------------------------------------------------- /** * @private */ override protected function resourcesChanged():void { super.resourcesChanged(); formatString = formatStringOverride; } /** * Generates a date-formatted String from either a date-formatted String or a Date object. * The formatString property * determines the format of the output String. * If value cannot be formatted, return an empty String * and write a description of the error to the error property. * * @param value Date to format. This can be a Date object, * or a date-formatted String such as "Thursday, April 22, 2004". * * @return Formatted String. Empty if an error occurs. A description * of the error condition is written to the error property. * * @langversion 3.0 * @playerversion Flash 9 * @playerversion AIR 1.1 * @productversion Flex 3 */ override public function format(value:Object):String { // Reset any previous errors. if (error) error = null; // If value is null, or empty String just return "" // but treat it as an error for consistency. // Users will ignore it anyway. if (!value || (value is String && value == "")) { error = defaultInvalidValueError; return ""; } // -- value -- if (value is String) { value = DateFormatter.parseDateString(String(value)); if (!value) { error = defaultInvalidValueError; return ""; } } else if (!(value is Date)) { error = defaultInvalidValueError; return ""; } // -- format -- var letter:String; var nTokens:int = 0; var tokens:String = ""; var n:int = formatString.length; for (var i:int = 0; i < n; i++) { letter = formatString.charAt(i); if (VALID_PATTERN_CHARS.indexOf(letter) != -1 && letter != ",") { nTokens++; if (tokens.indexOf(letter) == -1) { tokens += letter; } else { if (letter != formatString.charAt(Math.max(i - 1, 0))) { error = defaultInvalidFormatError; return ""; } } } } if (nTokens < 1) { error = defaultInvalidFormatError; return ""; } var dataFormatter:StringFormatter = new StringFormatter( formatString, VALID_PATTERN_CHARS, DateBase.extractTokenDate); return dataFormatter.formatValue(value); } } }