1 | /*
|
---|
2 | * Copyright 2002-2005 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.tools.ant.util;
|
---|
18 |
|
---|
19 | import java.text.ChoiceFormat;
|
---|
20 | import java.text.DateFormat;
|
---|
21 | import java.text.MessageFormat;
|
---|
22 | import java.text.ParseException;
|
---|
23 | import java.text.SimpleDateFormat;
|
---|
24 | import java.util.Calendar;
|
---|
25 | import java.util.Date;
|
---|
26 | import java.util.Locale;
|
---|
27 | import java.util.TimeZone;
|
---|
28 |
|
---|
29 | /**
|
---|
30 | * Helper methods to deal with date/time formatting with a specific
|
---|
31 | * defined format (<a href="http://www.w3.org/TR/NOTE-datetime">ISO8601</a>)
|
---|
32 | * or a plurialization correct elapsed time in minutes and seconds.
|
---|
33 | *
|
---|
34 | *
|
---|
35 | * @since Ant 1.5
|
---|
36 | *
|
---|
37 | */
|
---|
38 | public final class DateUtils {
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * ISO8601-like pattern for date-time. It does not support timezone.
|
---|
42 | * <tt>yyyy-MM-ddTHH:mm:ss</tt>
|
---|
43 | */
|
---|
44 | public static final String ISO8601_DATETIME_PATTERN
|
---|
45 | = "yyyy-MM-dd'T'HH:mm:ss";
|
---|
46 |
|
---|
47 | /**
|
---|
48 | * ISO8601-like pattern for date. <tt>yyyy-MM-dd</tt>
|
---|
49 | */
|
---|
50 | public static final String ISO8601_DATE_PATTERN
|
---|
51 | = "yyyy-MM-dd";
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * ISO8601-like pattern for time. <tt>HH:mm:ss</tt>
|
---|
55 | */
|
---|
56 | public static final String ISO8601_TIME_PATTERN
|
---|
57 | = "HH:mm:ss";
|
---|
58 |
|
---|
59 | /**
|
---|
60 | * Format used for SMTP (and probably other) Date headers.
|
---|
61 | */
|
---|
62 | public static final DateFormat DATE_HEADER_FORMAT
|
---|
63 | = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
|
---|
64 |
|
---|
65 |
|
---|
66 | // code from Magesh moved from DefaultLogger and slightly modified
|
---|
67 | private static final MessageFormat MINUTE_SECONDS
|
---|
68 | = new MessageFormat("{0}{1}");
|
---|
69 |
|
---|
70 | private static final double[] LIMITS = {0, 1, 2};
|
---|
71 |
|
---|
72 | private static final String[] MINUTES_PART = {"", "1 minute ", "{0,number} minutes "};
|
---|
73 |
|
---|
74 | private static final String[] SECONDS_PART = {"0 seconds", "1 second", "{1,number} seconds"};
|
---|
75 |
|
---|
76 | private static final ChoiceFormat MINUTES_FORMAT =
|
---|
77 | new ChoiceFormat(LIMITS, MINUTES_PART);
|
---|
78 |
|
---|
79 | private static final ChoiceFormat SECONDS_FORMAT =
|
---|
80 | new ChoiceFormat(LIMITS, SECONDS_PART);
|
---|
81 |
|
---|
82 | static {
|
---|
83 | MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
|
---|
84 | MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
|
---|
85 | }
|
---|
86 |
|
---|
87 | /** private constructor */
|
---|
88 | private DateUtils() {
|
---|
89 | }
|
---|
90 |
|
---|
91 |
|
---|
92 | /**
|
---|
93 | * Format a date/time into a specific pattern.
|
---|
94 | * @param date the date to format expressed in milliseconds.
|
---|
95 | * @param pattern the pattern to use to format the date.
|
---|
96 | * @return the formatted date.
|
---|
97 | */
|
---|
98 | public static String format(long date, String pattern) {
|
---|
99 | return format(new Date(date), pattern);
|
---|
100 | }
|
---|
101 |
|
---|
102 |
|
---|
103 | /**
|
---|
104 | * Format a date/time into a specific pattern.
|
---|
105 | * @param date the date to format expressed in milliseconds.
|
---|
106 | * @param pattern the pattern to use to format the date.
|
---|
107 | * @return the formatted date.
|
---|
108 | */
|
---|
109 | public static String format(Date date, String pattern) {
|
---|
110 | DateFormat df = createDateFormat(pattern);
|
---|
111 | return df.format(date);
|
---|
112 | }
|
---|
113 |
|
---|
114 |
|
---|
115 | /**
|
---|
116 | * Format an elapsed time into a plurialization correct string.
|
---|
117 | * It is limited only to report elapsed time in minutes and
|
---|
118 | * seconds and has the following behavior.
|
---|
119 | * <ul>
|
---|
120 | * <li>minutes are not displayed when 0. (ie: "45 seconds")</li>
|
---|
121 | * <li>seconds are always displayed in plural form (ie "0 seconds" or
|
---|
122 | * "10 seconds") except for 1 (ie "1 second")</li>
|
---|
123 | * </ul>
|
---|
124 | * @param millis the elapsed time to report in milliseconds.
|
---|
125 | * @return the formatted text in minutes/seconds.
|
---|
126 | */
|
---|
127 | public static String formatElapsedTime(long millis) {
|
---|
128 | long seconds = millis / 1000;
|
---|
129 | long minutes = seconds / 60;
|
---|
130 | Object[] args = {new Long(minutes), new Long(seconds % 60)};
|
---|
131 | return MINUTE_SECONDS.format(args);
|
---|
132 | }
|
---|
133 |
|
---|
134 | /**
|
---|
135 | * return a lenient date format set to GMT time zone.
|
---|
136 | * @param pattern the pattern used for date/time formatting.
|
---|
137 | * @return the configured format for this pattern.
|
---|
138 | */
|
---|
139 | private static DateFormat createDateFormat(String pattern) {
|
---|
140 | SimpleDateFormat sdf = new SimpleDateFormat(pattern);
|
---|
141 | TimeZone gmt = TimeZone.getTimeZone("GMT");
|
---|
142 | sdf.setTimeZone(gmt);
|
---|
143 | sdf.setLenient(true);
|
---|
144 | return sdf;
|
---|
145 | }
|
---|
146 |
|
---|
147 | /**
|
---|
148 | * Calculate the phase of the moon for a given date.
|
---|
149 | *
|
---|
150 | * <p>Code heavily influenced by hacklib.c in <a
|
---|
151 | * href="http://www.nethack.org/">Nethack</a></p>
|
---|
152 | *
|
---|
153 | * <p>The Algorithm:
|
---|
154 | *
|
---|
155 | * <pre>
|
---|
156 | * moon period = 29.53058 days ~= 30, year = 365.2422 days
|
---|
157 | *
|
---|
158 | * days moon phase advances on first day of year compared to preceding year
|
---|
159 | * = 365.2422 - 12*29.53058 ~= 11
|
---|
160 | *
|
---|
161 | * years in Metonic cycle (time until same phases fall on the same days of
|
---|
162 | * the month) = 18.6 ~= 19
|
---|
163 | *
|
---|
164 | * moon phase on first day of year (epact) ~= (11*(year%19) + 18) % 30
|
---|
165 | * (18 as initial condition for 1900)
|
---|
166 | *
|
---|
167 | * current phase in days = first day phase + days elapsed in year
|
---|
168 | *
|
---|
169 | * 6 moons ~= 177 days
|
---|
170 | * 177 ~= 8 reported phases * 22
|
---|
171 | * + 11/22 for rounding
|
---|
172 | * </pre>
|
---|
173 | *
|
---|
174 | * @return The phase of the moon as a number between 0 and 7 with
|
---|
175 | * 0 meaning new moon and 4 meaning full moon.
|
---|
176 | *
|
---|
177 | * @since 1.2, Ant 1.5
|
---|
178 | */
|
---|
179 | public static int getPhaseOfMoon(Calendar cal) {
|
---|
180 | int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
|
---|
181 | int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
|
---|
182 | int epact = (11 * yearInMetonicCycle + 18) % 30;
|
---|
183 | if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
|
---|
184 | epact++;
|
---|
185 | }
|
---|
186 | return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
|
---|
187 | }
|
---|
188 |
|
---|
189 | /**
|
---|
190 | * Returns the current Date in a format suitable for a SMTP date
|
---|
191 | * header.
|
---|
192 | *
|
---|
193 | * @since Ant 1.5.2
|
---|
194 | */
|
---|
195 | public static String getDateForHeader() {
|
---|
196 | Calendar cal = Calendar.getInstance();
|
---|
197 | TimeZone tz = cal.getTimeZone();
|
---|
198 | int offset = tz.getOffset(cal.get(Calendar.ERA),
|
---|
199 | cal.get(Calendar.YEAR),
|
---|
200 | cal.get(Calendar.MONTH),
|
---|
201 | cal.get(Calendar.DAY_OF_MONTH),
|
---|
202 | cal.get(Calendar.DAY_OF_WEEK),
|
---|
203 | cal.get(Calendar.MILLISECOND));
|
---|
204 | StringBuffer tzMarker = new StringBuffer(offset < 0 ? "-" : "+");
|
---|
205 | offset = Math.abs(offset);
|
---|
206 | int hours = offset / (60 * 60 * 1000);
|
---|
207 | int minutes = offset / (60 * 1000) - 60 * hours;
|
---|
208 | if (hours < 10) {
|
---|
209 | tzMarker.append("0");
|
---|
210 | }
|
---|
211 | tzMarker.append(hours);
|
---|
212 | if (minutes < 10) {
|
---|
213 | tzMarker.append("0");
|
---|
214 | }
|
---|
215 | tzMarker.append(minutes);
|
---|
216 | return DATE_HEADER_FORMAT.format(cal.getTime()) + tzMarker.toString();
|
---|
217 | }
|
---|
218 |
|
---|
219 | /**
|
---|
220 | * Parse a string as a datetime using the ISO8601_DATETIME format which is
|
---|
221 | * <code>yyyy-MM-dd'T'HH:mm:ss</code>
|
---|
222 | *
|
---|
223 | * @param datestr string to be parsed
|
---|
224 | *
|
---|
225 | * @return a java.util.Date object as parsed by the format.
|
---|
226 | * @exception ParseException if the supplied string cannot be parsed by
|
---|
227 | * this pattern.
|
---|
228 | * @since Ant 1.6
|
---|
229 | */
|
---|
230 | public static Date parseIso8601DateTime(String datestr)
|
---|
231 | throws ParseException {
|
---|
232 | return new SimpleDateFormat(ISO8601_DATETIME_PATTERN).parse(datestr);
|
---|
233 | }
|
---|
234 |
|
---|
235 | /**
|
---|
236 | * Parse a string as a date using the ISO8601_DATE format which is
|
---|
237 | * <code>yyyy-MM-dd</code>
|
---|
238 | *
|
---|
239 | * @param datestr string to be parsed
|
---|
240 | *
|
---|
241 | * @return a java.util.Date object as parsed by the format.
|
---|
242 | * @exception ParseException if the supplied string cannot be parsed by
|
---|
243 | * this pattern.
|
---|
244 | * @since Ant 1.6
|
---|
245 | */
|
---|
246 | public static Date parseIso8601Date(String datestr) throws ParseException {
|
---|
247 | return new SimpleDateFormat(ISO8601_DATE_PATTERN).parse(datestr);
|
---|
248 | }
|
---|
249 |
|
---|
250 | /**
|
---|
251 | * Parse a string as a date using the either the ISO8601_DATETIME
|
---|
252 | * or ISO8601_DATE formats.
|
---|
253 | *
|
---|
254 | * @param datestr string to be parsed
|
---|
255 | *
|
---|
256 | * @return a java.util.Date object as parsed by the formats.
|
---|
257 | * @exception ParseException if the supplied string cannot be parsed by
|
---|
258 | * either of these patterns.
|
---|
259 | * @since Ant 1.6
|
---|
260 | */
|
---|
261 | public static Date parseIso8601DateTimeOrDate(String datestr)
|
---|
262 | throws ParseException {
|
---|
263 | try {
|
---|
264 | return parseIso8601DateTime(datestr);
|
---|
265 | } catch (ParseException px) {
|
---|
266 | return parseIso8601Date(datestr);
|
---|
267 | }
|
---|
268 | }
|
---|
269 | }
|
---|