1 // ================================================================================================= 2 // ADOBE SYSTEMS INCORPORATED 3 // Copyright 2006 Adobe Systems Incorporated 4 // All Rights Reserved 5 // 6 // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms 7 // of the Adobe license agreement accompanying it. 8 // ================================================================================================= 9 10 package com.adobe.xmp.impl; 11 12 import java.util.Calendar; 13 import java.util.Date; 14 import java.util.GregorianCalendar; 15 import java.util.Locale; 16 import java.util.TimeZone; 17 18 import com.adobe.xmp.XMPDateTime; 19 import com.adobe.xmp.XMPException; 20 21 22 /** 23 * The implementation of <code>XMPDateTime</code>. Internally a <code>calendar</code> is used 24 * plus an additional nano seconds field, because <code>Calendar</code> supports only milli 25 * seconds. The <code>nanoSeconds</code> convers only the resolution beyond a milli second. 26 * 27 * @since 16.02.2006 28 */ 29 public class XMPDateTimeImpl implements XMPDateTime 30 { 31 /** */ 32 private int year = 0; 33 /** */ 34 private int month = 0; 35 /** */ 36 private int day = 0; 37 /** */ 38 private int hour = 0; 39 /** */ 40 private int minute = 0; 41 /** */ 42 private int second = 0; 43 /** Use the unversal time as default */ 44 private TimeZone timeZone = TimeZone.getTimeZone("UTC"); 45 /** 46 * The nano seconds take micro and nano seconds, while the milli seconds are in the calendar. 47 */ 48 private int nanoSeconds; 49 50 51 /** 52 * Creates an <code>XMPDateTime</code>-instance with the current time in the default time 53 * zone. 54 */ 55 public XMPDateTimeImpl() 56 { 57 // EMPTY 58 } 59 60 61 /** 62 * Creates an <code>XMPDateTime</code>-instance from a calendar. 63 * 64 * @param calendar a <code>Calendar</code> 65 */ 66 public XMPDateTimeImpl(Calendar calendar) 67 { 68 // extract the date and timezone from the calendar provided 69 Date date = calendar.getTime(); 70 TimeZone zone = calendar.getTimeZone(); 71 72 // put that date into a calendar the pretty much represents ISO8601 73 // I use US because it is close to the "locale" for the ISO8601 spec 74 GregorianCalendar intCalendar = 75 (GregorianCalendar) Calendar.getInstance(Locale.US); 76 intCalendar.setGregorianChange(new Date(Long.MIN_VALUE)); 77 intCalendar.setTimeZone(zone); 78 intCalendar.setTime(date); 79 80 this.year = intCalendar.get(Calendar.YEAR); 81 this.month = intCalendar.get(Calendar.MONTH) + 1; // cal is from 0..12 82 this.day = intCalendar.get(Calendar.DAY_OF_MONTH); 83 this.hour = intCalendar.get(Calendar.HOUR_OF_DAY); 84 this.minute = intCalendar.get(Calendar.MINUTE); 85 this.second = intCalendar.get(Calendar.SECOND); 86 this.nanoSeconds = intCalendar.get(Calendar.MILLISECOND) * 1000000; 87 this.timeZone = intCalendar.getTimeZone(); 88 } 89 90 91 /** 92 * Creates an <code>XMPDateTime</code>-instance from 93 * a <code>Date</code> and a <code>TimeZone</code>. 94 * 95 * @param date a date describing an absolute point in time 96 * @param timeZone a TimeZone how to interpret the date 97 */ 98 public XMPDateTimeImpl(Date date, TimeZone timeZone) 99 { 100 GregorianCalendar calendar = new GregorianCalendar(timeZone); 101 calendar.setTime(date); 102 this.year = calendar.get(Calendar.YEAR); 103 this.month = calendar.get(Calendar.MONTH) + 1; // cal is from 0..12 104 this.day = calendar.get(Calendar.DAY_OF_MONTH); 105 this.hour = calendar.get(Calendar.HOUR_OF_DAY); 106 this.minute = calendar.get(Calendar.MINUTE); 107 this.second = calendar.get(Calendar.SECOND); 108 this.nanoSeconds = calendar.get(Calendar.MILLISECOND) * 1000000; 109 this.timeZone = timeZone; 110 } 111 112 113 /** 114 * Creates an <code>XMPDateTime</code>-instance from an ISO 8601 string. 115 * 116 * @param strValue an ISO 8601 string 117 * @throws XMPException If the string is a non-conform ISO 8601 string, an exception is thrown 118 */ 119 public XMPDateTimeImpl(String strValue) throws XMPException 120 { 121 ISO8601Converter.parse(strValue, this); 122 } 123 124 125 /** 126 * @see XMPDateTime#getYear() 127 */ 128 public int getYear() 129 { 130 return year; 131 } 132 133 134 /** 135 * @see XMPDateTime#setYear(int) 136 */ 137 public void setYear(int year) 138 { 139 this.year = Math.min(Math.abs(year), 9999); 140 } 141 142 143 /** 144 * @see XMPDateTime#getMonth() 145 */ 146 public int getMonth() 147 { 148 return month; 149 } 150 151 152 /** 153 * @see XMPDateTime#setMonth(int) 154 */ 155 public void setMonth(int month) 156 { 157 if (month < 1) 158 { 159 this.month = 1; 160 } 161 else if (month > 12) 162 { 163 this.month = 12; 164 } 165 else 166 { 167 this.month = month; 168 } 169 } 170 171 172 /** 173 * @see XMPDateTime#getDay() 174 */ 175 public int getDay() 176 { 177 return day; 178 } 179 180 181 /** 182 * @see XMPDateTime#setDay(int) 183 */ 184 public void setDay(int day) 185 { 186 if (day < 1) 187 { 188 this.day = 1; 189 } 190 else if (day > 31) 191 { 192 this.day = 31; 193 } 194 else 195 { 196 this.day = day; 197 } 198 } 199 200 201 /** 202 * @see XMPDateTime#getHour() 203 */ 204 public int getHour() 205 { 206 return hour; 207 } 208 209 210 /** 211 * @see XMPDateTime#setHour(int) 212 */ 213 public void setHour(int hour) 214 { 215 this.hour = Math.min(Math.abs(hour), 23); 216 } 217 218 219 /** 220 * @see XMPDateTime#getMinute() 221 */ 222 public int getMinute() 223 { 224 return minute; 225 } 226 227 228 /** 229 * @see XMPDateTime#setMinute(int) 230 */ 231 public void setMinute(int minute) 232 { 233 this.minute = Math.min(Math.abs(minute), 59); 234 } 235 236 237 /** 238 * @see XMPDateTime#getSecond() 239 */ 240 public int getSecond() 241 { 242 return second; 243 } 244 245 246 /** 247 * @see XMPDateTime#setSecond(int) 248 */ 249 public void setSecond(int second) 250 { 251 this.second = Math.min(Math.abs(second), 59); 252 } 253 254 255 /** 256 * @see XMPDateTime#getNanoSecond() 257 */ 258 public int getNanoSecond() 259 { 260 return nanoSeconds; 261 } 262 263 264 /** 265 * @see XMPDateTime#setNanoSecond(int) 266 */ 267 public void setNanoSecond(int nanoSecond) 268 { 269 this.nanoSeconds = nanoSecond; 270 } 271 272 273 /** 274 * @see Comparable#compareTo(Object) 275 */ 276 public int compareTo(Object dt) 277 { 278 long d = getCalendar().getTimeInMillis() 279 - ((XMPDateTime) dt).getCalendar().getTimeInMillis(); 280 if (d != 0) 281 { 282 return (int) (d % 2); 283 } 284 else 285 { 286 // if millis are equal, compare nanoseconds 287 d = nanoSeconds - ((XMPDateTime) dt).getNanoSecond(); 288 return (int) (d % 2); 289 } 290 } 291 292 293 /** 294 * @see XMPDateTime#getTimeZone() 295 */ 296 public TimeZone getTimeZone() 297 { 298 return timeZone; 299 } 300 301 302 /** 303 * @see XMPDateTime#setTimeZone(TimeZone) 304 */ 305 public void setTimeZone(TimeZone timeZone) 306 { 307 this.timeZone = timeZone; 308 } 309 310 311 /** 312 * @see XMPDateTime#getCalendar() 313 */ 314 public Calendar getCalendar() 315 { 316 GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance(Locale.US); 317 calendar.setGregorianChange(new Date(Long.MIN_VALUE)); 318 calendar.setTimeZone(timeZone); 319 calendar.set(Calendar.YEAR, year); 320 calendar.set(Calendar.MONTH, month - 1); 321 calendar.set(Calendar.DAY_OF_MONTH, day); 322 calendar.set(Calendar.HOUR_OF_DAY, hour); 323 calendar.set(Calendar.MINUTE, minute); 324 calendar.set(Calendar.SECOND, second); 325 calendar.set(Calendar.MILLISECOND, nanoSeconds / 1000000); 326 return calendar; 327 } 328 329 330 /** 331 * @see XMPDateTime#getISO8601String() 332 */ 333 public String getISO8601String() 334 { 335 return ISO8601Converter.render(this); 336 } 337 338 339 /** 340 * @return Returns the ISO string representation. 341 */ 342 public String toString() 343 { 344 return getISO8601String(); 345 } 346 }