Java/GWT/Date Utilities

Материал из Java эксперт
Перейти к: навигация, поиск

A simple regular expression based parser for date notations

   <source lang="java">

package org.gwtwidgets.client.util; import java.util.Date; import org.gwtwidgets.client.util.regex.Pattern; /**

* This is a simple regular expression based parser for date notations.
* While our aim is to fully support in the future the JDK date parser, currently
* only numeric notations and literals are supported such as dd/MM/yyyy HH:mm:ss.SSSS.
* Each entity is parsed with the same number of digits, i.e. for dd two digits will be
* parsed while for d only one will be parsed.
* @author 
*
*/

public class SimpleDateParser {

 private final static String DAY_IN_MONTH = "d";
 private final static String MONTH = "M";
 private final static String YEAR = "y";
 private final static String LITERAL = "\\";
 private final static int DATE_PATTERN = 0;
 private final static int REGEX_PATTERN = 1;
 private final static int COMPONENT = 2;
 private final static int REGEX = 0;
 private final static int INSTRUCTION = 1;
 private final static String[] TOKENS[] = {
 { "SSSS", "(\\d\\d\\d\\d)",DateLocale.TOKEN_MILLISECOND }, 
 { "SSS", "(\\d\\d\\d)", DateLocale.TOKEN_MILLISECOND },
 { "SS", "(\\d\\d)", DateLocale.TOKEN_MILLISECOND }, 
 { "S", "(\\d)", DateLocale.TOKEN_MILLISECOND },
 { "ss", "(\\d\\d)", DateLocale.TOKEN_SECOND }, 
 { "s", "(\\d)", DateLocale.TOKEN_SECOND },
 { "mm", "(\\d\\d)", DateLocale.TOKEN_MINUTE }, 
 { "m", "(\\d)", DateLocale.TOKEN_MINUTE},
 { "HH", "(\\d\\d)", DateLocale.TOKEN_HOUR_24},
 { "H", "(\\d)", DateLocale.TOKEN_HOUR_24 },
 { "dd", "(\\d\\d)", DateLocale.TOKEN_DAY_OF_MONTH }, 
 { "d", "(\\d)", DateLocale.TOKEN_DAY_OF_MONTH },
 { "MM", "(\\d\\d)", DateLocale.TOKEN_MONTH }, 
 { "M", "(\\d)", DateLocale.TOKEN_MONTH },
 { "yyyy", "(\\d\\d\\d\\d)", DateLocale.TOKEN_YEAR }, 
 { "yyy", "(\\d\\d\\d)", DateLocale.TOKEN_YEAR },
 { "yy", "(\\d\\d)", DateLocale.TOKEN_YEAR }, 
 { "y", "(\\d)", DateLocale.TOKEN_YEAR }
 };
 private Pattern regularExpression;;
 private String instructions = "";
 private static void _parse(String format, String[] args) {
   if (format.length() == 0)
     return;
   if (format.startsWith(""")){
     format = format.substring(1);
     int end = format.indexOf(""");
     if (end == -1)
       throw new IllegalArgumentException("Unmatched single quotes.");
     args[REGEX]+=Pattern.quote(format.substring(0,end));
     format = format.substring(end+1);
   }
   for (int i = 0; i < TOKENS.length; i++) {
     String[] row = TOKENS[i];
     String datePattern = row[DATE_PATTERN];
     if (!format.startsWith(datePattern))
       continue;
     format = format.substring(datePattern.length());
     args[REGEX] += row[REGEX_PATTERN];
     args[INSTRUCTION] += row[COMPONENT];
     _parse(format, args);
     return;
   }
   args[REGEX] += Pattern.quote(""+format.charAt(0));
   format = format.substring(1);
   _parse(format, args);
 }
 private static void load(Date date, String text, String component) {
   if (component.equals(DateLocale.TOKEN_MILLISECOND)) {
     //TODO: implement
   }
   if (component.equals(DateLocale.TOKEN_SECOND)) {
     date.setSeconds(Integer.parseInt(text));
   }
   if (component.equals(DateLocale.TOKEN_MINUTE)) {
     date.setMinutes(Integer.parseInt(text));
   }
   if (component.equals(DateLocale.TOKEN_HOUR_24)) {
     date.setHours(Integer.parseInt(text));
   }
   if (component.equals(DateLocale.TOKEN_DAY_OF_MONTH)) {
     date.setDate(Integer.parseInt(text));
   }
   if (component.equals(DateLocale.TOKEN_MONTH)) {
     date.setMonth(Integer.parseInt(text)-1);
   }
   if (component.equals(DateLocale.TOKEN_YEAR)) {
     //TODO: fix for short patterns
     date.setYear(Integer.parseInt(text)-1900);
   }
 }
 public SimpleDateParser(String format) {
   String[] args = new String[] { "", "" };
   _parse(format, args);
   regularExpression = new Pattern(args[REGEX]);
   instructions = args[INSTRUCTION];
 }
 public Date parse(String input) {
   Date date = new Date(0, 0, 0, 0, 0, 0);
   String matches[] = regularExpression.match(input);
   if (matches == null)
     throw new IllegalArgumentException(input+" does not match "+regularExpression.pattern());
   if (matches.length-1!=instructions.length())
     throw new IllegalArgumentException("Different group count - "+input+" does not match "+regularExpression.pattern());
   for (int group = 0; group < instructions.length(); group++) {
     String match = matches[group + 1];
     load(date, match, ""+instructions.charAt(group));
   }
   return date;
 }
 
 public static Date parse(String input, String pattern){
   return new SimpleDateParser(pattern).parse(input);
 }

}

      </source>
   
  
 
  



Date locale support for the SimpleDateParser

   <source lang="java">

package org.gwtwidgets.client.util; import java.util.Arrays; import java.util.List; /**

* Date locale support for the {@link SimpleDateParser}. You are encouraged to
* extend this class and provide implementations for other locales. 
* @author 
*
*/

public class DateLocale {

 public final static String TOKEN_DAY_OF_WEEK = "E";
 public final static String TOKEN_DAY_OF_MONTH = "d";
 public final static String TOKEN_MONTH = "M";
 public final static String TOKEN_YEAR = "y";
 public final static String TOKEN_HOUR_12 = "h";
 public final static String TOKEN_HOUR_24 = "H";
 public final static String TOKEN_MINUTE = "m";
 public final static String TOKEN_SECOND = "s";
 
 public final static String TOKEN_MILLISECOND = "S";
 
 public final static String TOKEN_AM_PM = "a";
 public final static String AM = "AM";
 public final static String PM = "PM";
 public final static List SUPPORTED_DF_TOKENS = Arrays.asList(new String[] {
         TOKEN_DAY_OF_WEEK, TOKEN_DAY_OF_MONTH, TOKEN_MONTH, TOKEN_YEAR,
         TOKEN_HOUR_12, TOKEN_HOUR_24, TOKEN_MINUTE, TOKEN_SECOND,
         TOKEN_AM_PM });
 public String[] MONTH_LONG = { "January", "February", "March", "April",
         "May", "June", "July", "August", "September", "October",
         "November", "December" };
 public String[] MONTH_SHORT = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
         "Jul", "Aug", "Sept", "Oct", "Nov", "Dec" };
 public String[] WEEKDAY_LONG = { "Sunday", "Monday", "Tuesday",
         "Wednesday", "Thursday", "Friday", "Saturday" };
 public String[] WEEKDAY_SHORT = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri",
         "Sat" };
 public static String getAM() {
     return AM;
   }
 public static String getPM() {
     return PM;
   }
 public String[] getWEEKDAY_LONG() {
   return WEEKDAY_LONG;
 }
 public String[] getWEEKDAY_SHORT() {
   return WEEKDAY_SHORT;
 }

}


      </source>
   
  
 
  



Implement SimpleDateFormat for GWT

   <source lang="java">

/*

* Copyright 2006 Robert Hanson <iamroberthanson AT gmail.ru>
* 
* 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.gwtwidgets.client.util; import java.util.Date; /**

*
*
Title: *
SimpleDateFormat
*

*

Description: *
GWT does not implement any of the java.text package, so this class tries * to fill the void of the missing java.text.SimpleDateFormat class. This * version however only supports a subset of the date and time patterns * supported by its java.text counterpart. The pattern symbols supported by this * class are: *
*
E
*
Day in a week
*
d
*
Day of the month
*
y
*
Year
*
M
*
Month January, Jan, 01, 1
*
H
*
Hour in 24 hour format (0-23)
*
h
*
Hour in 12 hour format (1-12)
*
m
*
Minute of the hour
*
s
*
Seconds of the minute
*
a
*
am/pm
*
* All characters that are not recognised as a date format character are
* translated literally into the output string. 
* <p> * </dl> *

* A simple date parsing facility has also been implemented resembling the java * prototype. You can currently parse most numeric patterns but no temporal * literals (such as day or month names). *

* 
* @author 
* @version $Revision: 0.0 $
*/

public class SimpleDateFormat {

 private String format;
 private DateLocale locale = new DateLocale();
 /**
  * Gets the support locale for formatting and parsing dates
  * @return
  */
 public DateLocale getLocale() {
     return locale;
   }
 public void setLocale(DateLocale locale) {
     this.locale = locale;
   }
 public SimpleDateFormat(String pattern) {
   format = pattern;
 }
 public String format(Date date) {
   String f = "";
   if (format != null && format.length() > 0) {
     String lastTokenType = null;
     String currentToken = "";
     for (int i = 0; i < format.length(); i++) {
       String thisChar = format.substring(i, i + 1);
       String currentTokenType = DateLocale.SUPPORTED_DF_TOKENS
               .contains(thisChar) ? thisChar : "";
       if (currentTokenType.equals(lastTokenType) || i == 0) {
         currentToken += thisChar;
         lastTokenType = currentTokenType;
       } else {
         if ("".equals(lastTokenType))
           f += currentToken;
         else
           f += handleToken(currentToken, date);
         currentToken = thisChar;
         lastTokenType = currentTokenType;
       }
     }
     if ("".equals(lastTokenType))
       f += currentToken;
     else
       f += handleToken(currentToken, date);
   }
   return f;
 }
 /**
  * takes a date format string and returns the formatted portion of the date.
  * For instance if the token is MMMM then the full month name is returned.
  * 
  * @param token
  *            date format token
  * @param date
  *            date to format
  * @return formatted portion of the date
  */
 private String handleToken(String token, Date date) {
   String response = token;
   String tc = token.substring(0, 1);
   if (DateLocale.TOKEN_DAY_OF_WEEK.equals(tc)) {
     if (token.length() > 3)
       response = locale.getWEEKDAY_LONG()[date.getDay()];
     else
       response = locale.getWEEKDAY_SHORT()[date.getDay()];
   } else if (DateLocale.TOKEN_DAY_OF_MONTH.equals(tc)) {
     if (token.length() == 1)
       response = Integer.toString(date.getDate());
     else
       response = twoCharDateField(date.getDate());
   } else if (DateLocale.TOKEN_MONTH.equals(tc)) {
     switch (token.length()) {
     case 1:
       response = Integer.toString(date.getMonth() + 1);
       break;
     case 2:
       response = twoCharDateField(date.getMonth() + 1);
       break;
     case 3:
       response = locale.MONTH_SHORT[date.getMonth()];
       break;
     default:
       response = locale.MONTH_LONG[date.getMonth()];
       break;
     }
   } else if (DateLocale.TOKEN_YEAR.equals(tc)) {
     if (token.length() > 2)
       response = Integer.toString(date.getYear() + 1900);
     else
       response = twoCharDateField(date.getYear());
   } else if (DateLocale.TOKEN_HOUR_12.equals(tc)) {
     int h = date.getHours();
     if (h == 0)
       h = 12;
     else if (h > 12)
       h -= 12;
     if (token.length() > 1)
       response = twoCharDateField(h);
     else
       response = Integer.toString(h);
   } else if (DateLocale.TOKEN_HOUR_24.equals(tc)) {
     if (token.length() > 1)
       response = twoCharDateField(date.getHours());
     else
       response = Integer.toString(date.getHours());
   } else if (DateLocale.TOKEN_MINUTE.equals(tc)) {
     if (token.length() > 1)
       response = twoCharDateField(date.getMinutes());
     else
       response = Integer.toString(date.getMinutes());
   } else if (DateLocale.TOKEN_SECOND.equals(tc)) {
     if (token.length() > 1)
       response = twoCharDateField(date.getSeconds());
     else
       response = Integer.toString(date.getSeconds());
   } else if (DateLocale.TOKEN_AM_PM.equals(tc)) {
     int hour = date.getHours();
     if (hour > 11)
       response = DateLocale.getPM();
     else
       response = DateLocale.getAM();
   }
   return response;
 }
 /**
  * This is basically just a sneaky way to guarantee that our 1 or 2 digit
  * numbers come out as a 2 character string. we add an arbitrary number
  * larger than 100, convert this new number to a string, then take the right
  * most 2 characters.
  * 
  * @param num
  * @return
  */
 private String twoCharDateField(int num) {
   String res = Integer.toString(num + 1900);
   res = res.substring(res.length() - 2);
   return res;
 }
 private static Date newDate(long time) {
   return new Date(time);
 }
 /**
  * Parses text and returns the corresponding date object. 
  * 
  * @param source
  * @return java.util.Date
  */
 public Date parse(String source){
   return SimpleDateParser.parse(source, format);
 };

}


      </source>