/* * plist - An open source library to parse and generate property lists * Copyright (C) 2011 Daniel Dreibrodt, Keith Randall * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.dd.plist; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; /** * Represents a date. * * @author Daniel Dreibrodt */ public class NSDate extends NSObject { private Date date; // EPOCH = new SimpleDateFormat("yyyy MM dd zzz").parse("2001 01 01 GMT").getTime(); // ...but that's annoying in a static initializer because it can throw exceptions, ick. // So we just hardcode the correct value. private final static long EPOCH = 978307200000L; private static final SimpleDateFormat sdfDefault = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); private static final SimpleDateFormat sdfGnuStep = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); static { sdfDefault.setTimeZone(TimeZone.getTimeZone("GMT")); sdfGnuStep.setTimeZone(TimeZone.getTimeZone("GMT")); } /** * Parses the XML date string and creates a Java Date object from it. * This function is synchronized as SimpleDateFormat is not thread-safe. * * @param textRepresentation The date string as found in the XML property list * @return The parsed Date * @throws ParseException If the given string cannot be parsed. * @see SimpleDateFormat#parse(java.lang.String) */ private static synchronized Date parseDateString(String textRepresentation) throws ParseException { try { return sdfDefault.parse(textRepresentation); } catch (ParseException ex) { return sdfGnuStep.parse(textRepresentation); } } /** * Generates a String representation of a Java Date object. The string * is formatted according to the specification for XML property list dates. * * @param date The date which should be represented. * @return The string representation of the date. */ private static synchronized String makeDateString(Date date) { return sdfDefault.format(date); } /** * Generates a String representation of a Java Date object. The string * is formatted according to the specification for GnuStep ASCII property * list dates. * * @param date The date which should be represented. * @return The string representation of the date. */ private static synchronized String makeDateStringGnuStep(Date date) { return sdfGnuStep.format(date); } /** * Creates a date from its binary representation. * * @param bytes The date bytes */ public NSDate(byte[] bytes){ this(bytes, 0, bytes.length); } /** * Creates a date from its binary representation. * * @param bytes byte array with all information * @param startIndex int with the starting index of the date * @param endIndex int with the end index of the date */ public NSDate(byte[] bytes, final int startIndex, final int endIndex) { //dates are 8 byte big-endian double, seconds since the epoch date = new Date(EPOCH + (long) (1000 * BinaryPropertyListParser.parseDouble(bytes, startIndex, endIndex))); } /** * Parses a date from its textual representation. * That representation has the following pattern: <code>yyyy-MM-dd'T'HH:mm:ss'Z'</code> * * @param textRepresentation The textual representation of the date (ISO 8601 format) * @throws ParseException When the date could not be parsed, i.e. it does not match the expected pattern. */ public NSDate(String textRepresentation) throws ParseException { date = parseDateString(textRepresentation); } /** * Creates a NSDate from a Java Date * * @param d The date */ public NSDate(Date d) { if (d == null) throw new IllegalArgumentException("Date cannot be null"); date = d; } /** * Gets the date. * * @return The date. */ public Date getDate() { return date; } @Override public boolean equals(Object obj) { return obj.getClass().equals(getClass()) && date.equals(((NSDate) obj).getDate()); } @Override public int hashCode() { return date.hashCode(); } @Override void toXML(StringBuilder xml, int level) { indent(xml, level); xml.append("<date>"); xml.append(makeDateString(date)); xml.append("</date>"); } @Override public void toBinary(BinaryPropertyListWriter out) throws IOException { out.write(0x33); out.writeDouble((date.getTime() - EPOCH) / 1000.0); } /** * Generates a string representation of the date. * * @return A string representation of the date. * @see java.util.Date#toString() */ @Override public String toString() { return date.toString(); } @Override protected void toASCII(StringBuilder ascii, int level) { indent(ascii, level); ascii.append("\""); ascii.append(makeDateString(date)); ascii.append("\""); } @Override protected void toASCIIGnuStep(StringBuilder ascii, int level) { indent(ascii, level); ascii.append("<*D"); ascii.append(makeDateStringGnuStep(date)); ascii.append(">"); } }