001 /*
002 * Zmanim Java API
003 * Copyright (C) 2004-2007 Eliyahu Hershfeld
004 *
005 * This program is free software; you can redistribute it and/or modify it under the terms of the
006 * GNU General Public License as published by the Free Software Foundation; either version 2 of the
007 * License, or (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
010 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011 * General Public License for more details.
012 *
013 * You should have received a copy of the GNU General Public License along with this program; if
014 * not, write to the Free Software Foundation, Inc. 59 Temple Place - Suite 330, Boston, MA
015 * 02111-1307, USA or connect to: http://www.fsf.org/copyleft/gpl.html
016 */
017 package net.sourceforge.zmanim.util;
018
019 import java.text.DecimalFormat;
020 import java.util.Date;
021 import java.util.Calendar;
022 import java.text.SimpleDateFormat;
023
024 /**
025 * A class used to format non {@link java.util.Date} times generated by the
026 * Zmanim package. For example the
027 * {@link net.sourceforge.zmanim.AstronomicalCalendar#getTemporalHour()} returns
028 * the length of the hour in milliseconds. This class can format this time.
029 *
030 * @author © Eliyahu Hershfeld 2004 - 2007
031 * @version 0.9.0
032 */
033 public class ZmanimFormatter {
034 private boolean prependZeroHours;
035
036 private boolean useSeconds;
037
038 private boolean useMillis;
039
040 boolean useDecimal;
041
042 private static DecimalFormat minuteSecondNF = new DecimalFormat("00");;
043
044 private DecimalFormat hourNF;
045
046 private static DecimalFormat milliNF = new DecimalFormat("000");
047
048 private SimpleDateFormat dateFormat;
049
050 // private DecimalFormat decimalNF;
051
052 /**
053 * Format using hours, minutes, seconds and milliseconds using the xsd:time
054 * format. This format will return 00.00.00.0 when formatting 0.
055 */
056 public static final int SEXAGESIMAL_XSD_FORMAT = 0;
057
058 private int timeFormat = SEXAGESIMAL_XSD_FORMAT;
059
060 /**
061 * Format using standard decimal format with 5 positions after the decimal.
062 */
063 public static final int DECIMAL_FORMAT = 1;
064
065 /** Format using hours and minutes. */
066 public static final int SEXAGESIMAL_FORMAT = 2;
067
068 /** Format using hours, minutes and seconds. */
069 public static final int SEXAGESIMAL_SECONDS_FORMAT = 3;
070
071 /** Format using hours, minutes, seconds and milliseconds. */
072 public static final int SEXAGESIMAL_MILLIS_FORMAT = 4;
073
074 /**
075 * Format using the XSD Duration format. This is in the format of
076 * PT1H6M7.869S (P for period (duration), T for time, H, M and S indicate
077 * hours, minutes and seconds.
078 */
079 public static final int XSD_DURATION_FORMAT = 5;
080
081 public ZmanimFormatter() {
082 this(0, new SimpleDateFormat("h:mm:ss"));
083 }
084
085 /**
086 * ZmanimFormatter constructor using a formatter
087 *
088 * @param format
089 * int The formatting style to use. Using
090 * ZmanimFormatter.SEXAGESIMAL_SECONDS_FORMAT will format the
091 * time time of 90*60*1000 + 1 as 1:30:00
092 */
093 public ZmanimFormatter(int format, SimpleDateFormat dateFormat) {
094 String hourFormat = "0";
095 if (prependZeroHours) {
096 hourFormat = "00";
097 }
098 hourNF = new DecimalFormat(hourFormat);
099 // decimalNF = new DecimalFormat("0.0####");
100 setTimeFormat(format);
101 this.setDateFormat(dateFormat);
102 }
103
104 /**
105 * Sets the format to use for formatting.
106 *
107 * @param format
108 * int the format constant to use.
109 */
110 public void setTimeFormat(int format) {
111 timeFormat = format;
112 switch (format) {
113 case SEXAGESIMAL_XSD_FORMAT:
114 setSettings(true, true, true);
115 break;
116 case SEXAGESIMAL_FORMAT:
117 setSettings(false, false, false);
118 break;
119 case SEXAGESIMAL_SECONDS_FORMAT:
120 setSettings(false, true, false);
121 break;
122 case SEXAGESIMAL_MILLIS_FORMAT:
123 setSettings(false, true, true);
124 break;
125 case DECIMAL_FORMAT:
126 default:
127 useDecimal = true;
128 }
129 }
130
131 public void setDateFormat(SimpleDateFormat sdf) {
132 dateFormat = sdf;
133 }
134
135 public SimpleDateFormat getDateFormat() {
136 return dateFormat;
137 }
138
139 private void setSettings(boolean prependZeroHours, boolean useSeconds,
140 boolean useMillis) {
141 this.prependZeroHours = prependZeroHours;
142 this.useSeconds = useSeconds;
143 this.useMillis = useMillis;
144 }
145
146 /**
147 * A method that formats milliseconds into a time format.
148 *
149 * @param milliseconds
150 * The time in milliseconds.
151 * @return String The formatted <code>String</code>
152 */
153 public String format(double milliseconds) {
154 return format((int) milliseconds);
155 }
156
157 /**
158 * A method that formats milliseconds into a time format.
159 *
160 * @param millis
161 * The time in milliseconds.
162 * @return String The formatted <code>String</code>
163 */
164 public String format(int millis) {
165 return format(new Time(millis));
166 }
167
168 /**
169 * A method that formats {@link Time}objects.
170 *
171 * @param time
172 * The time <code>Object</code> to be formatted.
173 * @return String The formatted <code>String</code>
174 */
175 public String format(Time time) {
176 if (timeFormat == XSD_DURATION_FORMAT) {
177 return formatXSDDurationTime(time);
178 }
179 StringBuffer sb = new StringBuffer();
180 sb.append(hourNF.format(time.getHours()));
181 sb.append(":");
182 sb.append(minuteSecondNF.format(time.getMinutes()));
183 if (useSeconds) {
184 sb.append(":");
185 sb.append(minuteSecondNF.format(time.getSeconds()));
186 }
187 if (useMillis) {
188 sb.append(".");
189 sb.append(milliNF.format(time.getMilliseconds()));
190 }
191 return sb.toString();
192 }
193
194 /**
195 * Formats a date using this classe's {@link #getDateFormat() date format}.
196 *
197 * @param dateTime
198 * the date to format
199 * @param calendar
200 * the {@link java.util.Calendar Calendar} used to help format
201 * based on the Calendar's DST and other settings.
202 * @return the formatted String
203 */
204 public String formatDateTime(Date dateTime, Calendar calendar) {
205 dateFormat.setCalendar(calendar);
206 if (this.dateFormat.toPattern().equals("yyyy-MM-dd'T'HH:mm:ss")) {
207 return getXSDateTime(dateTime, calendar);
208 } else {
209 return dateFormat.format(dateTime);
210 }
211
212 }
213
214 /**
215 * The date:date-time function returns the current date and time as a
216 * date/time string. The date/time string that's returned must be a string
217 * in the format defined as the lexical representation of xs:dateTime in <a
218 * href="http://www.w3.org/TR/xmlschema11-2/#dateTime">[3.3.8 dateTime]</a>
219 * of <a href="http://www.w3.org/TR/xmlschema11-2/">[XML Schema 1.1 Part 2:
220 * Datatypes]</a>. The date/time format is basically CCYY-MM-DDThh:mm:ss,
221 * although implementers should consult <a
222 * href="http://www.w3.org/TR/xmlschema11-2/">[XML Schema 1.1 Part 2:
223 * Datatypes]</a> and <a href="http://www.iso.ch/markete/8601.pdf">[ISO
224 * 8601]</a> for details. The date/time string format must include a time
225 * zone, either a Z to indicate Coordinated Universal Time or a + or -
226 * followed by the difference between the difference from UTC represented as
227 * hh:mm.
228 */
229 public String getXSDateTime(Date dateTime, Calendar cal) {
230 // Calendar cal = Calendar.getInstance();
231 // Date datetime = cal.getTime();
232 // Format for date and time.
233 String xsdDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss";
234 /*
235 * if (xmlDateFormat == null || xmlDateFormat.trim().equals("")) {
236 * xmlDateFormat = xsdDateTimeFormat; }
237 */
238 SimpleDateFormat dateFormat = new SimpleDateFormat(xsdDateTimeFormat);
239
240 StringBuffer buff = new StringBuffer(dateFormat.format(dateTime));
241 // Must also include offset from UTF.
242 // Get the offset (in milliseconds).
243 int offset = cal.get(Calendar.ZONE_OFFSET)
244 + cal.get(Calendar.DST_OFFSET);
245 // If there is no offset, we have "Coordinated
246 // Universal Time."
247 if (offset == 0)
248 buff.append("Z");
249 else {
250 // Convert milliseconds to hours and minutes
251 int hrs = offset / (60 * 60 * 1000);
252 // In a few cases, the time zone may be +/-hh:30.
253 int min = offset % (60 * 60 * 1000);
254 char posneg = hrs < 0 ? '-' : '+';
255 buff.append(posneg + formatDigits(hrs) + ':' + formatDigits(min));
256 }
257 return buff.toString();
258 }
259
260 /**
261 * Represent the hours and minutes with two-digit strings.
262 *
263 * @param digits hours or minutes.
264 * @return two-digit String representation of hrs or minutes.
265 */
266 private static String formatDigits(int digits) {
267 String dd = String.valueOf(Math.abs(digits));
268 return dd.length() == 1 ? '0' + dd : dd;
269 }
270
271 /**
272 * This returns the xml representation of an xsd:duration object.
273 *
274 * @param millis the duration in milliseconds
275 * @return the xsd:duration formatted String
276 */
277 public String formatXSDDurationTime(long millis) {
278 return formatXSDDurationTime(new Time(millis));
279 }
280
281 /**
282 * This returns the xml representation of an xsd:duration object.
283 *
284 * @param time the duration as a Time object
285 * @return the xsd:duration formatted String
286 */
287 public String formatXSDDurationTime(Time time) {
288 StringBuffer duration = new StringBuffer();
289
290 duration.append("P");
291
292 if (time.getHours() != 0 || time.getMinutes() != 0
293 || time.getSeconds() != 0 || time.getMilliseconds() != 0) {
294 duration.append("T");
295
296 if (time.getHours() != 0)
297 duration.append(time.getHours() + "H");
298
299 if (time.getMinutes() != 0)
300 duration.append(time.getMinutes() + "M");
301
302 if (time.getSeconds() != 0 || time.getMilliseconds() != 0) {
303 duration.append(time.getSeconds() + "."
304 + milliNF.format(time.getMilliseconds()));
305 duration.append("S");
306 }
307 if (duration.length() == 1) // zero seconds
308 duration.append("T0S");
309 if (time.isNegative())
310 duration.insert(0, "-");
311 }
312 return duration.toString();
313 }
314 }