View Javadoc
1   /*
2    * Copyright 1999,2006 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.commons.feedparser.tools;
18  
19  import java.text.SimpleDateFormat;
20  import java.util.Date;
21  import java.util.Locale;
22  import java.util.TimeZone;
23  
24  /**
25   * ISO 8601 date parsing utility.  Designed for parsing the ISO subset used in
26   * Dublin Core, RSS 1.0, and Atom.
27   * 
28   * @author <a href="mailto:burton@apache.org">Kevin A. Burton (burtonator)</a>
29   * @version $Id: ISO8601DateParser.java 373572 2006-01-30 19:28:41Z mvdb $
30   */
31  public class ISO8601DateParser {
32  
33      // 2004-06-14T19:GMT20:30Z
34      // 2004-06-20T06:GMT22:01Z
35  
36      private static SimpleDateFormat df
37          = new SimpleDateFormat( "yyyy-MM-dd'T'hh:mm:ssz", Locale.ENGLISH );
38  
39      // http://www.cl.cam.ac.uk/~mgk25/iso-time.html
40      //    
41      // http://www.intertwingly.net/wiki/pie/DateTime
42      //
43      // http://www.w3.org/TR/NOTE-datetime
44      //
45      // Different standards may need different levels of granularity in the date and
46      // time, so this profile defines six levels. Standards that reference this
47      // profile should specify one or more of these granularities. If a given
48      // standard allows more than one granularity, it should specify the meaning of
49      // the dates and times with reduced precision, for example, the result of
50      // comparing two dates with different precisions.
51  
52      // The formats are as follows. Exactly the components shown here must be
53      // present, with exactly this punctuation. Note that the "T" appears literally
54      // in the string, to indicate the beginning of the time element, as specified in
55      // ISO 8601.
56  
57      //    Year:
58      //       YYYY (eg 1997)
59      //    Year and month:
60      //       YYYY-MM (eg 1997-07)
61      //    Complete date:
62      //       YYYY-MM-DD (eg 1997-07-16)
63      //    Complete date plus hours and minutes:
64      //       YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00)
65      //    Complete date plus hours, minutes and seconds:
66      //       YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00)
67      //    Complete date plus hours, minutes, seconds and a decimal fraction of a
68      // second
69      //       YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00)
70  
71      // where:
72  
73      //      YYYY = four-digit year
74      //      MM   = two-digit month (01=January, etc.)
75      //      DD   = two-digit day of month (01 through 31)
76      //      hh   = two digits of hour (00 through 23) (am/pm NOT allowed)
77      //      mm   = two digits of minute (00 through 59)
78      //      ss   = two digits of second (00 through 59)
79      //      s    = one or more digits representing a decimal fraction of a second
80      //      TZD  = time zone designator (Z or +hh:mm or -hh:mm)
81      public static Date parse( String input ) throws java.text.ParseException {
82  
83          //NOTE: SimpleDateFormat uses GMT[-+]hh:mm for the TZ which breaks
84          //things a bit.  Before we go on we have to repair this.
85  
86          //this is zero time so we need to add that TZ indicator for 
87          if ( input.endsWith( "Z" ) ) {
88              input = input.substring( 0, input.length() - 1) + "GMT-00:00";
89          } else {
90              int inset = 6;
91          
92              String s0 = input.substring( 0, input.length() - inset );
93              String s1 = input.substring( input.length() - inset, input.length() );
94  
95              input = s0 + "GMT" + s1;
96          }
97          
98          return df.parse( input );
99          
100     }
101 
102     public static String toString( Date date ) {
103 
104         TimeZone tz = TimeZone.getTimeZone( "UTC" );
105         
106         df.setTimeZone( tz );
107 
108         String output = df.format( date );
109 
110         int inset0 = 9;
111         int inset1 = 6;
112         
113         String s0 = output.substring( 0, output.length() - inset0 );
114         String s1 = output.substring( output.length() - inset1, output.length() );
115 
116         String result = s0 + s1;
117 
118         result = result.replaceAll( "UTC", "+00:00" );
119         
120         return result;
121         
122     }
123 
124     public static void main( String[] args ) throws Exception {
125 
126         System.out.println( parse( "2004-05-31T09:19:31-06:00" ) );
127         System.out.println( parse( "2004-06-23T17:25:31-00:00" ) );
128         System.out.println( parse( "2004-06-23T17:25:31Z" ) );
129 
130         //2002-10-02T10:00:00-05:00
131         System.out.println( "v: " + toString( new Date( System.currentTimeMillis() ) ) );
132 
133     }
134 
135 }
136