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 }