// ================================================================================================= // ADOBE SYSTEMS INCORPORATED // Copyright 2006 Adobe Systems Incorporated // All Rights Reserved // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms // of the Adobe license agreement accompanying it. // ================================================================================================= package com.adobe.xmp.impl; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.TimeZone; import com.adobe.xmp.XMPDateTime; import com.adobe.xmp.XMPException; /** * The implementation of XMPDateTime. Internally a calendar is used * plus an additional nano seconds field, because Calendar supports only milli * seconds. The nanoSeconds convers only the resolution beyond a milli second. * * @since 16.02.2006 */ public class XMPDateTimeImpl implements XMPDateTime { /** */ private int year = 0; /** */ private int month = 0; /** */ private int day = 0; /** */ private int hour = 0; /** */ private int minute = 0; /** */ private int second = 0; /** Use the unversal time as default */ private TimeZone timeZone = TimeZone.getTimeZone("UTC"); /** * The nano seconds take micro and nano seconds, while the milli seconds are in the calendar. */ private int nanoSeconds; /** * Creates an XMPDateTime-instance with the current time in the default time * zone. */ public XMPDateTimeImpl() { // EMPTY } /** * Creates an XMPDateTime-instance from a calendar. * * @param calendar a Calendar */ public XMPDateTimeImpl(Calendar calendar) { // extract the date and timezone from the calendar provided Date date = calendar.getTime(); TimeZone zone = calendar.getTimeZone(); // put that date into a calendar the pretty much represents ISO8601 // I use US because it is close to the "locale" for the ISO8601 spec GregorianCalendar intCalendar = (GregorianCalendar) Calendar.getInstance(Locale.US); intCalendar.setGregorianChange(new Date(Long.MIN_VALUE)); intCalendar.setTimeZone(zone); intCalendar.setTime(date); this.year = intCalendar.get(Calendar.YEAR); this.month = intCalendar.get(Calendar.MONTH) + 1; // cal is from 0..12 this.day = intCalendar.get(Calendar.DAY_OF_MONTH); this.hour = intCalendar.get(Calendar.HOUR_OF_DAY); this.minute = intCalendar.get(Calendar.MINUTE); this.second = intCalendar.get(Calendar.SECOND); this.nanoSeconds = intCalendar.get(Calendar.MILLISECOND) * 1000000; this.timeZone = intCalendar.getTimeZone(); } /** * Creates an XMPDateTime-instance from * a Date and a TimeZone. * * @param date a date describing an absolute point in time * @param timeZone a TimeZone how to interpret the date */ public XMPDateTimeImpl(Date date, TimeZone timeZone) { GregorianCalendar calendar = new GregorianCalendar(timeZone); calendar.setTime(date); this.year = calendar.get(Calendar.YEAR); this.month = calendar.get(Calendar.MONTH) + 1; // cal is from 0..12 this.day = calendar.get(Calendar.DAY_OF_MONTH); this.hour = calendar.get(Calendar.HOUR_OF_DAY); this.minute = calendar.get(Calendar.MINUTE); this.second = calendar.get(Calendar.SECOND); this.nanoSeconds = calendar.get(Calendar.MILLISECOND) * 1000000; this.timeZone = timeZone; } /** * Creates an XMPDateTime-instance from an ISO 8601 string. * * @param strValue an ISO 8601 string * @throws XMPException If the string is a non-conform ISO 8601 string, an exception is thrown */ public XMPDateTimeImpl(String strValue) throws XMPException { ISO8601Converter.parse(strValue, this); } /** * @see XMPDateTime#getYear() */ public int getYear() { return year; } /** * @see XMPDateTime#setYear(int) */ public void setYear(int year) { this.year = Math.min(Math.abs(year), 9999); } /** * @see XMPDateTime#getMonth() */ public int getMonth() { return month; } /** * @see XMPDateTime#setMonth(int) */ public void setMonth(int month) { if (month < 1) { this.month = 1; } else if (month > 12) { this.month = 12; } else { this.month = month; } } /** * @see XMPDateTime#getDay() */ public int getDay() { return day; } /** * @see XMPDateTime#setDay(int) */ public void setDay(int day) { if (day < 1) { this.day = 1; } else if (day > 31) { this.day = 31; } else { this.day = day; } } /** * @see XMPDateTime#getHour() */ public int getHour() { return hour; } /** * @see XMPDateTime#setHour(int) */ public void setHour(int hour) { this.hour = Math.min(Math.abs(hour), 23); } /** * @see XMPDateTime#getMinute() */ public int getMinute() { return minute; } /** * @see XMPDateTime#setMinute(int) */ public void setMinute(int minute) { this.minute = Math.min(Math.abs(minute), 59); } /** * @see XMPDateTime#getSecond() */ public int getSecond() { return second; } /** * @see XMPDateTime#setSecond(int) */ public void setSecond(int second) { this.second = Math.min(Math.abs(second), 59); } /** * @see XMPDateTime#getNanoSecond() */ public int getNanoSecond() { return nanoSeconds; } /** * @see XMPDateTime#setNanoSecond(int) */ public void setNanoSecond(int nanoSecond) { this.nanoSeconds = nanoSecond; } /** * @see Comparable#compareTo(Object) */ public int compareTo(Object dt) { long d = getCalendar().getTimeInMillis() - ((XMPDateTime) dt).getCalendar().getTimeInMillis(); if (d != 0) { return (int) (d % 2); } else { // if millis are equal, compare nanoseconds d = nanoSeconds - ((XMPDateTime) dt).getNanoSecond(); return (int) (d % 2); } } /** * @see XMPDateTime#getTimeZone() */ public TimeZone getTimeZone() { return timeZone; } /** * @see XMPDateTime#setTimeZone(TimeZone) */ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } /** * @see XMPDateTime#getCalendar() */ public Calendar getCalendar() { GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance(Locale.US); calendar.setGregorianChange(new Date(Long.MIN_VALUE)); calendar.setTimeZone(timeZone); calendar.set(Calendar.YEAR, year); calendar.set(Calendar.MONTH, month - 1); calendar.set(Calendar.DAY_OF_MONTH, day); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); calendar.set(Calendar.MILLISECOND, nanoSeconds / 1000000); return calendar; } /** * @see XMPDateTime#getISO8601String() */ public String getISO8601String() { return ISO8601Converter.render(this); } /** * @return Returns the ISO string representation. */ public String toString() { return getISO8601String(); } }