Date parser for the ISO 8601 format. : Date Format « Data Type « Java






Date parser for the ISO 8601 format.

      
//package com.adobe.epubcheck.util;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.StringTokenizer;
import java.util.TimeZone;

/**
 * Date parser for the ISO 8601 format.
 * 
 * Initial code taken from the jigsaw project (W3C license [1]) and modified consistently to
 * apply further checks that were missing, for example the initial code reported 
 * <code>2011-</code> as valid date. 
 * See also:
 * http://www.w3.org/TR/1998/NOTE-datetime-19980827
 * 
 * @author mircea@oxygenxml.com Initial version and fixes.
 * @author mihaela@sync.ro Initial version and fixes.
 * 
 * @author george@oxygenxml.com Additional fixes.
 */
 
/** 
 ***** [1] W3C license (jigsaw license) *****
 * 
 * Jigsaw Copying Conditions
 * 
 * W3C IPR SOFTWARE NOTICE
 * 
 * Copyright  1995-1998 World Wide Web Consortium, (Massachusetts Institute of
 * Technology, Institut National de Recherche en Informatique et en
 * Automatique, Keio University). All Rights Reserved.
 * http://www.w3.org/Consortium/Legal/
 * 
 * This W3C work (including software, documents, or other related items) is
 * being provided by the copyright holders under the following license. By
 * obtaining, using and/or copying this work, you (the licensee) agree that you
 * have read, understood, and will comply with the following terms and
 * conditions:
 * 
 * Permission to use, copy, and modify this software and its documentation,
 * with or without modification,  for any purpose and without fee or royalty is
 * hereby granted, provided that you include the following on ALL copies of the
 * software and documentation or portions thereof, including modifications,
 * that you make:
 * 
 *   1. The full text of this NOTICE in a location viewable to users of the
 *      redistributed or derivative work.
 *   2. Any pre-existing intellectual property disclaimers, notices, or terms
 *      and conditions. If none exist, a short notice of the following form
 *      (hypertext is preferred, text is permitted) should be used within the
 *      body of any redistributed or derivative code: "Copyright  World Wide
 *      Web Consortium, (Massachusetts Institute of Technology, Institut
 *      National de Recherche en Informatique et en Automatique, Keio
 *      University). All Rights Reserved. http://www.w3.org/Consortium/Legal/"
 *   3. Notice of any changes or modifications to the W3C files, including the
 *      date changes were made. (We recommend you provide URIs to the location
 *      from which the code is derived).
 * 
 * In addition, creators of derivitive works must include the full text of this
 * NOTICE in a location viewable to users of the derivitive work.
 * 
 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS
 * MAKE NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
 * LIMITED TO, WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR
 * PURPOSE OR THAT THE USE OF THE SOFTWARE OR DOCUMENTATION WILL NOT INFRINGE
 * ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS.
 * 
 * COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR
 * CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR
 * DOCUMENTATION.
 * 
 * The name and trademarks of copyright holders may NOT be used in advertising
 * or publicity pertaining to the software without specific, written prior
 * permission. Title to copyright in this software and any associated
 * documentation will at all times remain with copyright holders.
 * 
 * ____________________________________
 * 
 * This formulation of W3C's notice and license became active on August 14
 * 1998. See the older formulation for the policy prior to this date. Please
 * see our Copyright FAQ for common questions about using materials from our
 * site, including specific terms and conditions for packages like libwww,
 * Amaya, and Jigsaw. Other questions about this notice can be directed to
 * site-policy@w3.org .
 * 
 * 
 * 
 * 
 * webmaster
 * (last updated 14-Aug-1998)
 ***** end W3C license (jigsaw license) *****
 */
public class DateParser {

  /**
   * Check if the next token, if exists, has a given value and that the 
   * provided string tokenizer has more tokens after that. It consumes 
   * the token checked against the expected value from the string tokenizer.
   * 
   * @param st            The StringTokenizer to check. 
   * @param token         The value expected for the next token.
   * @return 
   *   <code>true</code> if the token matches the value and there are more tokens.
   *   <code>false</code> if there are no more tokens and we do not have a token to check.
   * @throws InvalidDateException If the token does not match the value or if there are no 
   * more tokens after the token that matches the expected value.
   */
  private boolean checkValueAndNext(StringTokenizer st, String token) throws InvalidDateException {
    if (!st.hasMoreTokens()) {
      return false;
    }
    String t = st.nextToken();
    if (!t.equals(token)) {
      throw new InvalidDateException("Unexpected: " + t);
    }
    if (!st.hasMoreTokens()) {
      throw new InvalidDateException("Incomplete date.");
    }
    return true;
  }

  /**
   * Check if a given date is an iso8601 date.
   * 
   * @param iso8601Date The date to be checked.
   * @return <code>true</code> if the date is an iso8601 date.
   * @throws InvalidDateException 
   */
  private Calendar getCalendar(String iso8601Date) throws InvalidDateException {
    // YYYY-MM-DDThh:mm:ss.sTZD
    StringTokenizer st = new StringTokenizer(iso8601Date, "-T:.+Z", true);
    if (!st.hasMoreTokens()) {
      throw new InvalidDateException("Empty Date");
    }
    Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
    calendar.clear();
    try {
      // Year
      if (st.hasMoreTokens()) {
        int year = Integer.parseInt(st.nextToken());
        calendar.set(Calendar.YEAR, year);
      } else {
        return calendar;
      }
      // Month
      if (checkValueAndNext(st, "-")) {
        int month = Integer.parseInt(st.nextToken()) -1;
        calendar.set(Calendar.MONTH, month);
      } else {
        return calendar;
      }
      // Day
      if (checkValueAndNext(st, "-")) {
        int day = Integer.parseInt(st.nextToken());
        calendar.set(Calendar.DAY_OF_MONTH, day);
      } else {
        return calendar;
      }
      // Hour
      if (checkValueAndNext(st, "T")) {
        int hour = Integer.parseInt(st.nextToken());
        calendar.set(Calendar.HOUR_OF_DAY, hour);
      } else {
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
      }
      // Minutes
      if (checkValueAndNext(st, ":")) {
        int minutes = Integer.parseInt(st.nextToken());
        calendar.set(Calendar.MINUTE, minutes);
      } else {
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar;
      }
      if (! st.hasMoreTokens()) {
        return calendar;
      }
      // Not mandatory now
      // Seconds
      String tok = st.nextToken();
      if (tok.equals(":")) { // seconds
        if (st.hasMoreTokens()) {
          int secondes = Integer.parseInt(st.nextToken());
          calendar.set(Calendar.SECOND, secondes);
          if (! st.hasMoreTokens()) {
            return calendar;
          }
          // decimal fraction of a second
          tok = st.nextToken();
          if (tok.equals(".")) {
            String nt = st.nextToken();
            while(nt.length() < 3) {
              nt += "0";
            }
            if (nt.length() > 3) {
              // check the other part from the decimal fraction to be formed only from digits
              for (int i=3; i<nt.length(); i++) {
                if (!Character.isDigit(nt.charAt(i))) {
                  throw new InvalidDateException("Invalid digit in the decimal fraction of a second: " + nt.charAt(i));
                }
              }
            }
            nt = nt.substring( 0, 3 ); //Cut trailing chars..
            int millisec = Integer.parseInt(nt);
            calendar.set(Calendar.MILLISECOND, millisec);
            if (! st.hasMoreTokens()) {
              return calendar;
            }
            tok = st.nextToken();
          } else {
            calendar.set(Calendar.MILLISECOND, 0);
          }
        } else {
          throw new InvalidDateException("No secondes specified");
        }
      } else {
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
      }
      // Time zone
      if (! tok.equals("Z")) { // UTC
        if (! (tok.equals("+") || tok.equals("-"))) {
          throw new InvalidDateException("only Z, + or - allowed");
        }
        boolean plus = tok.equals("+");
        if (! st.hasMoreTokens()) {
          throw new InvalidDateException("Missing hour field");
        }
        int tzhour = Integer.parseInt(st.nextToken());
        int tzmin  = 0;
        if (checkValueAndNext(st, ":")) {
          tzmin = Integer.parseInt(st.nextToken());
        } else {
          throw new InvalidDateException("Missing minute field");
        }
        if (plus) {
          calendar.add(Calendar.HOUR, -tzhour);
          calendar.add(Calendar.MINUTE, -tzmin);
        } else {
          calendar.add(Calendar.HOUR, tzhour);
          calendar.add(Calendar.MINUTE, tzmin);
        }
      } else {
        if (st.hasMoreTokens()) {
          throw new InvalidDateException("Unexpected field at the end of the date field: " + st.nextToken());
        }
      }
    } catch (NumberFormatException ex) {
      throw new InvalidDateException("[" + ex.getMessage() + "] is not an integer");
    }
    return calendar;
  }
 
  /**
   * 
   * @param iso8601DateAsString The date parameter as a String.
   * @return The corresponding Date object representing the result of parsing the date parameter.
   * @throws InvalidDateException In case of an invalid date.
   */
  public Date parse(String iso8601DateAsString) throws InvalidDateException  {
      Calendar calendar = getCalendar(iso8601DateAsString);
      try {
        calendar.setLenient(false);
        return calendar.getTime();
      } catch (Exception e) {
        throw new InvalidDateException(iso8601DateAsString + " " + e.getClass().toString() + " " + e.getMessage());
      }
  }
}
class InvalidDateException extends Exception {
  /**
   * Creates an exception to signal an invalid date.
   * @param message
   */
  public InvalidDateException(String message) {
    super(message);
  }
}
  /**
   * Test the ISO8601 date. 
   * Date grammar: 
   *   Year: 
   *     YYYY (eg 1997) 
   *   Year and month: 
   *     YYYY-MM (eg 1997-07) 
   *   Complete date: 
   *     YYYY-MM-DD (eg 1997-07-16) 
   *   Complete date plus hours and minutes: 
   *     YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) 
   *   Complete date plus hours, minutes and seconds:
   *     YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) 
   *   Complete date plus hours, minutes, seconds and a decimal fraction of a second
   *     YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 
   * where:
   * 
   * YYYY = four-digit year 
   * MM = two-digit month (01=January, etc.) 
   * DD = two-digit day of month (01 through 31) 
   * hh = two digits of hour (00 through 23) (am/pm NOT allowed) 
   * mm = two digits of minute (00 through 59)
   * ss = two digits of second (00 through 59) 
   * s = one or more digits representing a decimal fraction of a second 
   * TZD = time zone designator (Z or +hh:mm or -hh:mm)
   * 
   * @throws Exception
   */

/*
package com.adobe.epubcheck.util;

public class DateParserTest {
  public void testisISO8601Date() throws Exception {
    DateParser p = new DateParser();
    p.parse(  "2011"            );
    p.parse(  "2011-02"          );
    p.parse(  "2011-02-12"        );
    p.parse(  "2011-03-01T13"        );
    p.parse(  "2011-02-01T13:00"      );
    p.parse(  "2011-02-01T13:00:00"    );
    p.parse(  "2011-02-01T13:00:00Z"    );
    p.parse(  "2011-02-01T13:00:00+01:00"  );
    p.parse(  "2011-02-01T13:00:00-03:00"  );

    try {  
      p.parse(  ""              );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-"            );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-"          );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  "2011-02-01T"        );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:"      );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:"      );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:00T"    );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:00+01"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:00+01:"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:00-03"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-01T13:00:00-03:"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  "2011-02-01T13:00:00-03:AA"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  "20a1"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  " 2"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    try {  
      p.parse(  "2011-02-29"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  "2011-02-01T13:00:00.123aqb"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    try {  
      p.parse(  "1994-11-05T13:15:30Zab"  );
      throw new Exception("Invaid date passed!");
    } catch (InvalidDateException e) {}
    
    
  }

  public static void main(String[] args) {
    try {
      new DateParserTest().testisISO8601Date();
      System.out.println("Passed all tests!");
    } catch (Exception e) {
      System.out.println("Fail:");
      e.printStackTrace();
    }
  }
}
*/

   
    
    
    
    
    
  








Related examples in the same category

1.Date Era changeDate Era change
2.Date Format
3.The Time and Date Format Suffixes
4.Display standard 12-hour time format
5.Display complete time and date information
6.Display just hour and minute
7.Display month by name and number
8.DateFormat.getDateInstance(DateFormat.SHORT)
9.Use relative indexes to simplify the creation of a custom time and date format.
10.Date Format with LocaleDate Format with Locale
11.Date Format SymbolsDate Format Symbols
12.Decimal Format with different SymbolsDecimal Format with different Symbols
13.Date format: "dd.MM.yy", "yyyy.MM.dd G 'at' hh:mm:ss z","EEE, MMM d, ''yy", "h:mm a", "H:mm", "H:mm:ss:SSS", "K:mm a,z","yyyy.MMMMM.dd GGG hh:mm aaa"Date format:
14.SimpleDateFormat.getAvailableLocalesSimpleDateFormat.getAvailableLocales
15.DateFormat.SHORT
16.This is same as MEDIUM: DateFormat.getDateInstance().format(new Date())
17.This is same as MEDIUM: DateFormat.getDateInstance(DateFormat.DEFAULT).format(new Date())
18.DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.CANADA).format(new Date())
19.DateFormat.getTimeInstance(DateFormat.LONG, Locale.CANADA).format(new Date())
20.DateFormat.getTimeInstance(DateFormat.FULL, Locale.CANADA).format(new Date())
21.DateFormat.getTimeInstance(DateFormat.DEFAULT, Locale.CANADA).format(new Date())
22.DateFormat.getDateInstance(DateFormat.LONG)
23.DateFormat.getTimeInstance(DateFormat.SHORT)
24.DateFormat.getTimeInstance(DateFormat.LONG)
25.Parse date string input with DateFormat.getTimeInstance(DateFormat.DEFAULT, Locale.CANADA)
26.Simple Date Format DemoSimple Date Format Demo
27.Format date in Medium format
28.Format date in Long format
29.Format date in Full format
30.Format date in Default format
31.Formatting day of week using SimpleDateFormat
32.Formatting day of week in EEEE format like Sunday, Monday etc.
33.Formatting day in d format like 1,2 etc
34.Formatting day in dd format like 01, 02 etc.
35.Format hour in h (1-12 in AM/PM) format like 1, 2..12.
36.Format hour in hh (01-12 in AM/PM) format like 01, 02..12.
37.Format hour in H (0-23) format like 0, 1...23.
38.Format hour in HH (00-23) format like 00, 01..23.
39.Format hour in k (1-24) format like 1, 2..24.
40.Format hour in kk (01-24) format like 01, 02..24.
41.Format hour in K (0-11 in AM/PM) format like 0, 1..11.
42.Format hour in KK (00-11) format like 00, 01,..11.
43.Formatting minute in m format like 1,2 etc.
44.Format minutes in mm format like 01, 02 etc.
45.Format month in M format like 1,2 etc
46.Format Month in MM format like 01, 02 etc.
47.Format Month in MMM format like Jan, Feb etc.
48.Format Month in MMMM format like January, February etc.
49.Format seconds in s format like 1,2 etc.
50.Format seconds in ss format like 01, 02 etc.
51.Format date in dd/mm/yyyy format
52.Format date in mm-dd-yyyy hh:mm:ss format
53.Format year in yy format like 07, 08 etc
54.Format year in yyyy format like 2007, 2008 etc.
55.new SimpleDateFormat("hh")
56.new SimpleDateFormat("H") // The hour (0-23)
57.new SimpleDateFormat("m"): The minutes
58.new SimpleDateFormat("mm")
59.SimpleDateFormat("MM"): number based month value
60.new SimpleDateFormat("s"): The seconds
61.new SimpleDateFormat("ss")
62.new SimpleDateFormat("a"): The am/pm marker
63.new SimpleDateFormat("z"): The time zone
64.new SimpleDateFormat("zzzz")
65.new SimpleDateFormat("Z")
66.new SimpleDateFormat("hh:mm:ss a")
67.new SimpleDateFormat("HH.mm.ss")
68.new SimpleDateFormat("HH:mm:ss Z")
69.SimpleDateFormat("MM/dd/yy")
70.SimpleDateFormat("dd-MMM-yy")
71.SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z")
72.SimpleDateFormat("yyyy")
73.The month: SimpleDateFormat("M")
74.Three letter-month value: SimpleDateFormat("MMM")
75.Full length of month name: SimpleDateFormat("MMMM")
76.The day number: SimpleDateFormat("d")
77.Two digits day number: SimpleDateFormat("dd")
78.The day in week: SimpleDateFormat("E")
79.Full day name: SimpleDateFormat("EEEE")
80.Add AM PM to time using SimpleDateFormat
81.Simply format a date as "YYYYMMDD"
82.Java SimpleDateFormat Class Example("MM/dd/yyyy")
83.The format used is EEE, dd MMM yyyy HH:mm:ss Z in US locale.
84.Date Formatting and Localization
85.Get a List of Short Month Names
86.Get a List of Weekday Names
87.Get a List of Short Weekday Names
88.Change date formatting symbols
89.An alternate way to get week days symbols
90.ISO8601 formatter for date-time without time zone.The format used is yyyy-MM-dd'T'HH:mm:ss.
91.ISO8601 formatter for date-time with time zone. The format used is yyyy-MM-dd'T'HH:mm:ssZZ.
92.Parsing custom formatted date string into Date object using SimpleDateFormat
93.Parse with a custom format
94.Parsing the Time Using a Custom Format
95.Parse with a default format
96.Parse a date and time
97.Parse string date value input with SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z")
98.Parse string date value input with SimpleDateFormat("dd-MMM-yy")
99.Parse string date value with default format: DateFormat.getDateInstance(DateFormat.DEFAULT)
100.Find the current date format
101.Time format viewer
102.Date format viewer
103.Returns a String in the format Xhrs, Ymins, Z sec, for the time difference between two times
104.format Duration
105.Get Date Suffix
106.Date Format Cache
107.ISO8601 Date Format
108.Explode a date in 8 digit format into the three components.
109.Date To Iso Date Time
110.Iso Date Time To Date
111.Gets formatted time
112.Format Time To 2 Digits
113.Time formatting utility.
114.ISO 8601 BASIC date format
115.Format As MySQL Datetime
116.new SimpleDateFormat( "EEE MMM d HH:mm:ss z yyyy", Locale.UK )
117.Parse W3C Date format
118.Pack/Unpacks date stored in kdb format
119.Provides preset formatting for Dates. All dates are returned as GMT
120.Parse RSS date format to Date object.
121.Date format for face book
122.FastDateFormat is a fast and thread-safe version of java.text.SimpleDateFormat.
123.Date format and parse Util
124.XSD Date Time
125.Return a String value of Now() in a specify format
126.Format data to string with specified style.
127.extends Formatter