View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  
19  package org.apache.oodt.commons.date;
20  
21  //JDK imports
22  import java.text.DecimalFormat;
23  import java.text.ParseException;
24  import java.text.SimpleDateFormat;
25  import java.util.Calendar;
26  import java.util.GregorianCalendar;
27  import java.util.SimpleTimeZone;
28  import java.util.TimeZone;
29  
30  /**
31   * 
32   * @author bfoster
33   * @version $Revision$
34   * 
35   */
36  public class DateUtils {
37  
38      public static enum FormatType { UTC_FORMAT, LOCAL_FORMAT, TAI_FORMAT };
39      
40      public static Calendar tai93epoch = new GregorianCalendar(1993, GregorianCalendar.JANUARY, 1);
41      
42      public static Calendar julianEpoch = new GregorianCalendar(1970, GregorianCalendar.JANUARY, 1);
43      
44      private static SimpleDateFormat utcFormat = new SimpleDateFormat(
45              "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
46      private static SimpleDateFormat taiFormat = new SimpleDateFormat(
47              "yyyy-MM-dd'T'HH:mm:ss.SSS");
48      private static SimpleDateFormat localFormat = new SimpleDateFormat(
49              "yyyy-MM-dd'T'HH:mm:ss.SSSZ");    
50      
51      static {
52          utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
53          taiFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
54      }
55      
56      static enum IndexType {
57          DATE(0),
58          LEAP_SECS(1);
59          
60          public int index;
61          
62          IndexType(int index) {
63              this.index = index;
64          }
65      }
66      
67      //Info taken from ftp://oceans.gsfc.nasa.gov/COMMON/leapsec.dat
68      static long[][] dateAndLeapSecs = {
69          { 0 , 10 },
70          { new GregorianCalendar(1972, GregorianCalendar.JULY,    1).getTimeInMillis() , 11 },
71          { new GregorianCalendar(1973, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 12 },
72          { new GregorianCalendar(1974, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 13 },
73          { new GregorianCalendar(1975, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 14 },
74          { new GregorianCalendar(1976, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 15 },
75          { new GregorianCalendar(1977, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 16 },
76          { new GregorianCalendar(1978, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 17 },
77          { new GregorianCalendar(1979, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 18 },
78          { new GregorianCalendar(1980, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 19 },
79          { new GregorianCalendar(1981, GregorianCalendar.JULY,    1).getTimeInMillis() , 20 },
80          { new GregorianCalendar(1982, GregorianCalendar.JULY,    1).getTimeInMillis() , 21 },
81          { new GregorianCalendar(1983, GregorianCalendar.JULY,    1).getTimeInMillis() , 22 },
82          { new GregorianCalendar(1985, GregorianCalendar.JULY,    1).getTimeInMillis() , 23 },
83          { new GregorianCalendar(1988, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 24 },
84          { new GregorianCalendar(1990, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 25 },
85          { new GregorianCalendar(1991, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 26 },
86          { new GregorianCalendar(1992, GregorianCalendar.JULY,    1).getTimeInMillis() , 27 },
87          { new GregorianCalendar(1993, GregorianCalendar.JULY,    1).getTimeInMillis() , 28 },
88          { new GregorianCalendar(1994, GregorianCalendar.JULY,    1).getTimeInMillis() , 29 },
89          { new GregorianCalendar(1996, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 30 },
90          { new GregorianCalendar(1997, GregorianCalendar.JULY,    1).getTimeInMillis() , 31 },
91          { new GregorianCalendar(1999, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 32 },
92          { new GregorianCalendar(2006, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 33 },
93          { new GregorianCalendar(2009, GregorianCalendar.JANUARY, 1).getTimeInMillis() , 34 },
94      };
95      
96      private DateUtils() {}
97      
98      public static int getLeapSecsForDate(Calendar utcCal) throws Exception {
99          long timeInMillis = utcCal.getTimeInMillis();
100         for (int i = dateAndLeapSecs.length - 1; i >= 0; i--) {
101             if (dateAndLeapSecs[i][IndexType.DATE.index] < timeInMillis)
102                 return (int) dateAndLeapSecs[i][IndexType.LEAP_SECS.index];
103         }
104         throw new Exception("No Leap Second found for given date!");
105     }
106     
107     public static synchronized Calendar toTai(Calendar cal) throws Exception {
108         Calendar taiCal = Calendar.getInstance(createTaiTimeZone(getLeapSecsForDate(cal)));
109         taiCal.setTimeInMillis(cal.getTimeInMillis() + getLeapSecsForDate(cal) * 1000);
110         return taiCal;
111     }
112     
113     private static synchronized Calendar taiToUtc(Calendar taiCal) throws Exception {
114         Calendar calUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
115         calUtc.setTimeInMillis(taiCal.getTimeInMillis() - taiCal.getTimeZone().getRawOffset());
116         return calUtc;
117     }
118     
119     private static Calendar taiToLocal(Calendar taiCal) throws Exception {
120         return toLocal(taiToUtc(taiCal));
121     }
122 
123     public static synchronized Calendar toLocal(Calendar cal) throws Exception {
124         if (cal.getTimeZone().getID().equals("TAI")) {
125             return taiToLocal(cal);
126         } else {
127             Calendar calLocal = Calendar.getInstance();
128             calLocal.setTimeInMillis(cal.getTimeInMillis());
129             return calLocal;
130         }
131     }
132 
133     public static synchronized Calendar toUtc(Calendar cal) throws Exception {
134         if (cal.getTimeZone().getID().equals("TAI")) {
135             return taiToUtc(cal);
136         } else {
137             Calendar calUtc = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
138             calUtc.setTimeInMillis(cal.getTimeInMillis());
139             return calUtc;   
140         }
141     }
142     
143     public static Calendar getCurrentUtcTime() throws Exception {
144         return toUtc(getCurrentLocalTime());
145     }
146     
147     public static Calendar getCurrentLocalTime() throws Exception {
148         return Calendar.getInstance();
149     }
150     
151     public static Calendar getCurrentTaiTime() throws Exception {
152         return toTai(getCurrentUtcTime());
153     }
154     
155     public static String toCustomLocalFormat(Calendar cal, String format) {
156         return new SimpleDateFormat(format).format(cal.getTime());
157     }
158     
159     public static String toString(Calendar cal) {
160         String timeZoneId = cal.getTimeZone().getID();
161         if (timeZoneId.equals("UTC")) {
162             return utcFormat.format(cal.getTime());
163         }else if (timeZoneId.equals("TAI")) {
164             return taiFormat.format(cal.getTime()) + "-0000" 
165                 + (cal.getTimeZone().getRawOffset() / 1000);
166         }else {
167             return localFormat.format(cal.getTime());
168         }
169     }
170     
171     public static synchronized Calendar toLocalCustomFormatCalendar(String calString, String format) throws ParseException {
172         Calendar localCal = Calendar.getInstance();
173         localCal.setTime(new SimpleDateFormat(format).parse(calString));
174         return localCal;
175     }
176     
177     public static synchronized Calendar toCalendar(String calString, FormatType formatType)
178             throws ParseException {
179         Calendar cal = Calendar.getInstance();
180         switch (formatType) {
181             case LOCAL_FORMAT:
182                 cal.setTimeInMillis(localFormat.parse(calString).getTime());
183                 break;
184             case TAI_FORMAT:
185                 cal.setTimeZone(createTaiTimeZone(Integer.parseInt(calString
186                     .substring(calString.length() - 2))));
187                 calString = calString.substring(0, calString.length() - 5);
188                 cal.setTimeInMillis(taiFormat.parse(calString).getTime());
189                 break;
190             case UTC_FORMAT:
191                 cal.setTimeZone(TimeZone.getTimeZone("UTC"));
192                 cal.setTimeInMillis(utcFormat.parse(calString).getTime());
193                 break;
194             default:
195                 cal.setTimeInMillis(localFormat.parse(calString).getTime());
196         }
197         return cal;
198     }
199     
200     public static double getTimeInSecs(Calendar cal, Calendar epoch) throws Exception {
201         return getTimeInMillis(cal, epoch) / 1000.0;
202     }
203     
204     public static String toString(double seconds) {
205         return new DecimalFormat("#.000").format(seconds);
206     }
207     
208     public static long getTimeInMillis(Calendar cal, Calendar epoch) throws Exception {
209         long epochDiffInMilli;
210         /**
211          * Fixes date conversion issues preventing tests passing in the UK but working elsewhere in the world.
212          */
213         if(julianEpoch.getTimeZone().getID().equals("Europe/London")){
214             epochDiffInMilli = epoch.getTimeInMillis() - (julianEpoch.getTimeInMillis()+julianEpoch.getTimeZone().getOffset(julianEpoch.getTimeInMillis())) ;
215         }else {
216             epochDiffInMilli = epoch.getTimeInMillis() - julianEpoch.getTimeInMillis() ;
217         }
218         if (cal.getTimeZone().getID().equals("TAI"))
219             epochDiffInMilli += getLeapSecsForDate(epoch) * 1000;
220         long milliseconds = cal.getTimeInMillis();
221         return milliseconds - epochDiffInMilli;
222     }
223     
224     private static TimeZone createTaiTimeZone(int leapSecs) {
225         return new SimpleTimeZone(leapSecs * 1000, "TAI");
226     }
227     
228     public static void main(String[] args) throws Exception {
229         Calendar curTime = getCurrentLocalTime();
230         System.out.println("Test Time: " + toString(toCalendar(toString(toTai(toCalendar("2008-01-20T16:29:55.000Z", 
231                 FormatType.UTC_FORMAT))), FormatType.TAI_FORMAT)));
232         System.out.println("Current Local Time: " + toString(curTime) + " " + curTime.getTimeInMillis());
233         System.out.println("Current UTC Time: " + toString((curTime = toCalendar("2008-01-20T16:29:55.000Z", 
234                 FormatType.UTC_FORMAT))) + " " + toString(getTimeInSecs(curTime, tai93epoch)));
235         System.out.println("Current TAI Time: " + toString((curTime = toTai(toCalendar("2008-01-20T16:29:55.000Z", 
236                 FormatType.UTC_FORMAT)))) + " " + toString(getTimeInSecs(curTime, tai93epoch)));
237         System.out.println("Current UTC Time: " + toString(taiToUtc(curTime)));
238     }
239     
240 }