예제 #1
0
 /// <summary>
 /// Make sure a time is UTC. If the time zone is not UTC, the time is
 /// adjusted and the time zone set to be UTC.
 /// </summary>
 /// <param name="dateTime">
 ///            the <code>XMPDateTime</code> variable containing the time to
 ///            be modified. </param>
 /// <returns> Returns an updated <code>XMPDateTime</code>-object. </returns>
 public static IXmpDateTime ConvertToUtcTime(IXmpDateTime dateTime) {
     long timeInMillis = dateTime.Calendar.TimeInMillis;
     XmpCalendar cal = new XmpCalendar();
     cal.TimeInMillis = timeInMillis;
     return new XmpDateTimeImpl(cal);
 }
예제 #2
0
        /// <param name="iso8601String"> a date string that is ISO 8601 conform. </param>
        /// <param name="binValue"> an existing XMPDateTime to set with the parsed date </param>
        /// <returns> Returns an XMPDateTime-object containing the ISO8601-date. </returns>
        /// <exception cref="XmpException"> Is thrown when the string is non-conform. </exception>
        public static IXmpDateTime Parse(string iso8601String, IXmpDateTime binValue) {
            if (iso8601String == null) {
                throw new XmpException("Parameter must not be null", XmpError.BADPARAM);
            }
            if (iso8601String.Length == 0) {
                return binValue;
            }

            ParseState input = new ParseState(iso8601String);

            if (input.Ch(0) == '-') {
                input.Skip();
            }

            // Extract the year.
            int value = input.GatherInt("Invalid year in date string", 9999);
            if (input.HasNext() && input.Ch() != '-') {
                throw new XmpException("Invalid date string, after year", XmpError.BADVALUE);
            }

            if (input.Ch(0) == '-') {
                value = -value;
            }
            binValue.Year = value;
            if (!input.HasNext()) {
                return binValue;
            }
            input.Skip();


            // Extract the month.
            value = input.GatherInt("Invalid month in date string", 12);
            if (input.HasNext() && input.Ch() != '-') {
                throw new XmpException("Invalid date string, after month", XmpError.BADVALUE);
            }
            binValue.Month = value;
            if (!input.HasNext()) {
                return binValue;
            }
            input.Skip();


            // Extract the day.
            value = input.GatherInt("Invalid day in date string", 31);
            if (input.HasNext() && input.Ch() != 'T') {
                throw new XmpException("Invalid date string, after day", XmpError.BADVALUE);
            }
            binValue.Day = value;
            if (!input.HasNext()) {
                return binValue;
            }
            input.Skip();

            // Extract the hour.
            value = input.GatherInt("Invalid hour in date string", 23);
            binValue.Hour = value;
            if (!input.HasNext()) {
                return binValue;
            }

            // Extract the minute.
            if (input.Ch() == ':') {
                input.Skip();
                value = input.GatherInt("Invalid minute in date string", 59);
                if (input.HasNext() && input.Ch() != ':' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-') {
                    throw new XmpException("Invalid date string, after minute", XmpError.BADVALUE);
                }
                binValue.Minute = value;
            }

            if (!input.HasNext()) {
                return binValue;
            }
            if (input.HasNext() && input.Ch() == ':') {
                input.Skip();
                value = input.GatherInt("Invalid whole seconds in date string", 59);
                if (input.HasNext() && input.Ch() != '.' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-') {
                    throw new XmpException("Invalid date string, after whole seconds", XmpError.BADVALUE);
                }
                binValue.Second = value;
                if (input.Ch() == '.') {
                    input.Skip();
                    int digits = input.Pos();
                    value = input.GatherInt("Invalid fractional seconds in date string", 999999999);
                    if (input.HasNext() && (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')) {
                        throw new XmpException("Invalid date string, after fractional second",
                                               XmpError.BADVALUE);
                    }
                    digits = input.Pos() - digits;
                    for (; digits > 9; --digits) {
                        value = value/10;
                    }
                    for (; digits < 9; ++digits) {
                        value = value*10;
                    }
                    binValue.NanoSecond = value;
                }
            }
            else if (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-') {
                throw new XmpException("Invalid date string, after time", XmpError.BADVALUE);
            }


            if (!input.HasNext()) {
                // no Timezone at all
                return binValue;
            }
            if (input.Ch() == 'Z') {
                input.Skip();
            }
            else if (input.HasNext()) {
                if (input.Ch() == '+') {
                }
                else if (input.Ch() == '-') {
                }
                else {
                    throw new XmpException("Time zone must begin with 'Z', '+', or '-'", XmpError.BADVALUE);
                }

                input.Skip();
                // Extract the time zone hour.
                if (input.HasNext()) {
                    if (input.Ch() == ':') {
                        input.Skip();
                    }
                    else {
                        throw new XmpException("Invalid date string, after time zone hour", XmpError.BADVALUE);
                    }
                }
            }

            // create a corresponding TZ and set it time zone
            binValue.TimeZone = TimeZone.CurrentTimeZone;

            if (input.HasNext()) {
                throw new XmpException("Invalid date string, extra chars at end", XmpError.BADVALUE);
            }

            return binValue;
        }
예제 #3
0
 /// <summary>
 /// Sets the local time zone without touching any other Any existing time zone value is replaced,
 /// the other date/time fields are not adjusted in any way.
 /// </summary>
 /// <param name="dateTime"> the <code>XMPDateTime</code> variable containing the value to be modified. </param>
 /// <returns> Returns an updated <code>XMPDateTime</code>-object. </returns>
 public static IXmpDateTime SetLocalTimeZone(IXmpDateTime dateTime) {
     XmpCalendar cal = dateTime.Calendar;
     cal.TimeZone = TimeZone.CurrentTimeZone;
     return new XmpDateTimeImpl(cal);
 }
예제 #4
0
        /// <param name="iso8601String">a date string that is ISO 8601 conform.</param>
        /// <param name="binValue">an existing XMPDateTime to set with the parsed date</param>
        /// <returns>Returns an XMPDateTime-object containing the ISO8601-date.</returns>
        /// <exception cref="XmpException">Is thrown when the string is non-conform.</exception>
        public static IXmpDateTime Parse(string iso8601String, IXmpDateTime binValue)
        {
            if (iso8601String == null)
            {
                throw new XmpException("Parameter must not be null", XmpErrorCode.BadParam);
            }
            if (iso8601String.Length == 0)
            {
                return binValue;
            }
            var input = new ParseState(iso8601String);
            if (input.Ch(0) == '-')
            {
                input.Skip();
            }
            // Extract the year.
            var value = input.GatherInt("Invalid year in date string", 9999);
            if (input.HasNext && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after year", XmpErrorCode.BadValue);
            }
            if (input.Ch(0) == '-')
            {
                value = -value;
            }
            binValue.Year = value;
            if (!input.HasNext)
            {
                return binValue;
            }
            input.Skip();
            // Extract the month.
            value = input.GatherInt("Invalid month in date string", 12);
            if (input.HasNext && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after month", XmpErrorCode.BadValue);
            }
            binValue.Month = value;
            if (!input.HasNext)
            {
                return binValue;
            }
            input.Skip();
            // Extract the day.
            value = input.GatherInt("Invalid day in date string", 31);
            if (input.HasNext && input.Ch() != 'T')
            {
                throw new XmpException("Invalid date string, after day", XmpErrorCode.BadValue);
            }
            binValue.Day = value;
            if (!input.HasNext)
            {
                return binValue;
            }
            input.Skip();
            // Extract the hour.
            value = input.GatherInt("Invalid hour in date string", 23);
            binValue.Hour = value;
            if (!input.HasNext)
            {
                return binValue;
            }
            // Extract the minute.
            if (input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid minute in date string", 59);
                if (input.HasNext && input.Ch() != ':' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after minute", XmpErrorCode.BadValue);
                }
                binValue.Minute = value;
            }
            if (!input.HasNext)
            {
                return binValue;
            }
            if (input.HasNext && input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid whole seconds in date string", 59);
                if (input.HasNext && input.Ch() != '.' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after whole seconds", XmpErrorCode.BadValue);
                }
                binValue.Second = value;
                if (input.Ch() == '.')
                {
                    input.Skip();
                    var digits = input.Pos();
                    value = input.GatherInt("Invalid fractional seconds in date string", 999999999);
                    if (input.HasNext && (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-'))
                    {
                        throw new XmpException("Invalid date string, after fractional second", XmpErrorCode.BadValue);
                    }
                    digits = input.Pos() - digits;
                    for (; digits > 9; --digits)
                    {
                        value = value / 10;
                    }
                    for (; digits < 9; ++digits)
                    {
                        value = value * 10;
                    }
                    binValue.Nanosecond = value;
                }
            }
            else
            {
                if (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after time", XmpErrorCode.BadValue);
                }
            }
            var tzSign = 0;
            var tzHour = 0;
            var tzMinute = 0;
            if (!input.HasNext)
            {
                // no Timezone at all
                return binValue;
            }
            if (input.Ch() == 'Z')
            {
                input.Skip();
            }
            else
            {
                if (input.HasNext)
                {
                    if (input.Ch() == '+')
                    {
                        tzSign = 1;
                    }
                    else
                    {
                        if (input.Ch() == '-')
                        {
                            tzSign = -1;
                        }
                        else
                        {
                            throw new XmpException("Time zone must begin with 'Z', '+', or '-'", XmpErrorCode.BadValue);
                        }
                    }
                    input.Skip();
                    // Extract the time zone hour.
                    tzHour = input.GatherInt("Invalid time zone hour in date string", 23);
                    if (input.HasNext)
                    {
                        if (input.Ch() == ':')
                        {
                            input.Skip();
                            // Extract the time zone minute.
                            tzMinute = input.GatherInt("Invalid time zone minute in date string", 59);
                        }
                        else
                        {
                            throw new XmpException("Invalid date string, after time zone hour", XmpErrorCode.BadValue);
                        }
                    }
                }
            }
            // create a corresponding TZ and set it time zone
            var offset = (TimeSpan.FromHours(tzHour) + TimeSpan.FromMinutes(tzMinute));
            if (tzSign < 0)
                offset = -offset;

#if PORTABLE
            binValue.TimeZone = TimeZoneInfo.Local;
            binValue.Offset = offset;
#else
            binValue.TimeZone = TimeZoneInfo.CreateCustomTimeZone("OFFSET" + offset, offset, string.Empty, string.Empty);
#endif

            if (input.HasNext)
                throw new XmpException("Invalid date string, extra chars at end", XmpErrorCode.BadValue);

            return binValue;
        }
예제 #5
0
 /// <summary>
 /// Converts a <code>Calendar</code> into an ISO 8601 string.
 /// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
 /// <ul>
 /// <li>YYYY
 /// <li>YYYY-MM
 /// <li>YYYY-MM-DD
 /// <li>YYYY-MM-DDThh:mmTZD
 /// <li>YYYY-MM-DDThh:mm:ssTZD
 /// <li>YYYY-MM-DDThh:mm:ss.sTZD
 /// </ul>
 /// 
 /// Data fields:
 /// <ul>
 /// <li>YYYY = four-digit year
 /// <li>MM	 = two-digit month (01=January, etc.)
 /// <li>DD	 = two-digit day of month (01 through 31)
 /// <li>hh	 = two digits of hour (00 through 23)
 /// <li>mm	 = two digits of minute (00 through 59)
 /// <li>ss	 = two digits of second (00 through 59)
 /// <li>s	 = one or more digits representing a decimal fraction of a second
 /// <li>TZD	 = time zone designator (Z or +hh:mm or -hh:mm)
 /// </ul>
 /// <p>
 /// <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999. 
 /// We allow any year, even negative ones. The year is formatted as "%.4d".<p>
 /// <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing.
 /// The quasi-bogus "time only" values from Photoshop CS are not supported.
 /// </summary>
 /// <param name="dateTime"> an XMPDateTime-object. </param>
 /// <returns> Returns an ISO 8601 string. </returns>
 public static string Render(IXmpDateTime dateTime) {
     return dateTime.Calendar.DateTime.ToString("s");
 }
예제 #6
0
 /// <seealso cref= XMPMeta#SetPropertyDate(String, String, XMPDateTime,
 ///      PropertyOptions) </seealso>
 public virtual void SetPropertyDate(string schemaNs, string propName, IXmpDateTime propValue,
                                     PropertyOptions options) {
     SetProperty(schemaNs, propName, propValue, options);
 }
예제 #7
0
        /// <summary>Converts a <c>Calendar</c> into an ISO 8601 string.</summary>
        /// <remarks>
        /// Converts a <c>Calendar</c> into an ISO 8601 string.
        /// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
        /// <list type="bullet">
        /// <item>YYYY</item>
        /// <item>YYYY-MM</item>
        /// <item>YYYY-MM-DD</item>
        /// <item>YYYY-MM-DDThh:mmTZD</item>
        /// <item>YYYY-MM-DDThh:mm:ssTZD</item>
        /// <item>YYYY-MM-DDThh:mm:ss.sTZD</item>
        /// </list>
        /// Data fields:
        /// <list type="bullet">
        /// <item>YYYY = four-digit year</item>
        /// <item>MM     = two-digit month (01=January, etc.)</item>
        /// <item>DD     = two-digit day of month (01 through 31)</item>
        /// <item>hh     = two digits of hour (00 through 23)</item>
        /// <item>mm     = two digits of minute (00 through 59)</item>
        /// <item>ss     = two digits of second (00 through 59)</item>
        /// <item>s     = one or more digits representing a decimal fraction of a second</item>
        /// <item>TZD     = time zone designator (Z or +hh:mm or -hh:mm)</item>
        /// </list>
        /// <para />
        /// <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999.
        /// We allow any year, even negative ones. The year is formatted as "%.4d".
        /// <para />
        /// <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing.
        /// The quasi-bogus "time only" values from Photoshop CS are not supported.
        /// </remarks>
        /// <param name="dateTime">an XMPDateTime-object.</param>
        /// <returns>Returns an ISO 8601 string.</returns>
        public static string Render(IXmpDateTime dateTime)
        {
            var buffer = new StringBuilder();

            if (dateTime.HasDate)
            {
                // year is rendered in any case, even 0000
                buffer.Append(dateTime.Year.ToString("0000"));
                if (dateTime.Month == 0)
                {
                    return(buffer.ToString());
                }

                // month
                buffer.Append('-');
                buffer.Append(dateTime.Month.ToString("00"));
                if (dateTime.Day == 0)
                {
                    return(buffer.ToString());
                }

                // day
                buffer.Append('-');
                buffer.Append(dateTime.Day.ToString("00"));

                // time, rendered if any time field is not zero
                if (dateTime.HasTime)
                {
                    // hours and minutes
                    buffer.Append('T');
                    buffer.Append(dateTime.Hour.ToString("00"));
                    buffer.Append(':');
                    buffer.Append(dateTime.Minute.ToString("00"));
                    // seconds and nanoseconds
                    if (dateTime.Second != 0 || dateTime.Nanosecond != 0)
                    {
                        buffer.Append(':');
                        var seconds = dateTime.Second + dateTime.Nanosecond / 1e9d;
                        buffer.AppendFormat("{0:00.#########}", seconds);
                    }
                    // time zone
                    if (dateTime.HasTimeZone)
                    {
                        // used to calculate the time zone offset incl. Daylight Savings
                        var timeInMillis = dateTime.Calendar.GetTimeInMillis();
                        var offset       = (int)dateTime.TimeZone.GetUtcOffset(XmpDateTime.UnixTimeToDateTimeOffset(timeInMillis).DateTime).TotalMilliseconds;
                        if (offset == 0)
                        {
                            // UTC
                            buffer.Append('Z');
                        }
                        else
                        {
                            var thours   = offset / 3600000;
                            var tminutes = Math.Abs(offset % 3600000 / 60000);
                            buffer.Append(thours.ToString("+00;-00"));
                            buffer.Append(tminutes.ToString(":00"));
                        }
                    }
                }
            }
            return(buffer.ToString());
        }
예제 #8
0
 /// <summary>
 /// Sets the local time zone without touching any other Any existing time zone value is replaced,
 /// the other date/time fields are not adjusted in any way.
 /// </summary>
 /// <param name="dateTime">the <c>XMPDateTime</c> variable containing the value to be modified.</param>
 /// <returns>Returns an updated <c>XMPDateTime</c>-object.</returns>
 public static IXmpDateTime SetLocalTimeZone(IXmpDateTime dateTime)
 {
     var cal = dateTime.Calendar;
     cal.SetTimeZone(TimeZoneInfo.Local);
     return new XmpDateTime(cal);
 }
예제 #9
0
 /// <summary>Make sure a time is UTC.</summary>
 /// <remarks>
 /// Make sure a time is UTC. If the time zone is not UTC, the time is
 /// adjusted and the time zone set to be UTC.
 /// </remarks>
 /// <param name="dateTime">
 /// the <c>XMPDateTime</c> variable containing the time to
 /// be modified.
 /// </param>
 /// <returns>Returns an updated <c>XMPDateTime</c>-object.</returns>
 public static IXmpDateTime ConvertToUtcTime(IXmpDateTime dateTime)
 {
     var timeInMillis = dateTime.Calendar.GetTimeInMillis();
     var cal = new GregorianCalendar(TimeZoneInfo.Utc);
     cal.SetGregorianChange(XmpDateTime.UnixTimeToDateTime(long.MinValue));
     cal.SetTimeInMillis(timeInMillis);
     return new XmpDateTime(cal);
 }
예제 #10
0
 /// <exception cref="XmpException" />
 public void SetPropertyDate(string schemaNs, string propName, IXmpDateTime propValue, PropertyOptions options)
 {
     SetProperty(schemaNs, propName, propValue, options);
 }
예제 #11
0
 /// <exception cref="XmpException" />
 public void SetPropertyDate(string schemaNs, string propName, IXmpDateTime propValue)
 {
     SetProperty(schemaNs, propName, propValue, null);
 }
        /// <param name="iso8601String"> a date string that is ISO 8601 conform. </param>
        /// <param name="binValue"> an existing XMPDateTime to set with the parsed date </param>
        /// <returns> Returns an XMPDateTime-object containing the ISO8601-date. </returns>
        /// <exception cref="XmpException"> Is thrown when the string is non-conform. </exception>
        public static IXmpDateTime Parse(string iso8601String, IXmpDateTime binValue)
        {
            if (iso8601String == null)
            {
                throw new XmpException("Parameter must not be null", XmpError.BADPARAM);
            }
            if (iso8601String.Length == 0)
            {
                return(binValue);
            }

            ParseState input = new ParseState(iso8601String);

            if (input.Ch(0) == '-')
            {
                input.Skip();
            }

            // Extract the year.
            int value = input.GatherInt("Invalid year in date string", 9999);

            if (input.HasNext() && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after year", XmpError.BADVALUE);
            }

            if (input.Ch(0) == '-')
            {
                value = -value;
            }
            binValue.Year = value;
            if (!input.HasNext())
            {
                return(binValue);
            }
            input.Skip();


            // Extract the month.
            value = input.GatherInt("Invalid month in date string", 12);
            if (input.HasNext() && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after month", XmpError.BADVALUE);
            }
            binValue.Month = value;
            if (!input.HasNext())
            {
                return(binValue);
            }
            input.Skip();


            // Extract the day.
            value = input.GatherInt("Invalid day in date string", 31);
            if (input.HasNext() && input.Ch() != 'T')
            {
                throw new XmpException("Invalid date string, after day", XmpError.BADVALUE);
            }
            binValue.Day = value;
            if (!input.HasNext())
            {
                return(binValue);
            }
            input.Skip();

            // Extract the hour.
            value         = input.GatherInt("Invalid hour in date string", 23);
            binValue.Hour = value;
            if (!input.HasNext())
            {
                return(binValue);
            }

            // Extract the minute.
            if (input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid minute in date string", 59);
                if (input.HasNext() && input.Ch() != ':' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after minute", XmpError.BADVALUE);
                }
                binValue.Minute = value;
            }

            if (!input.HasNext())
            {
                return(binValue);
            }
            if (input.HasNext() && input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid whole seconds in date string", 59);
                if (input.HasNext() && input.Ch() != '.' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after whole seconds", XmpError.BADVALUE);
                }
                binValue.Second = value;
                if (input.Ch() == '.')
                {
                    input.Skip();
                    int digits = input.Pos();
                    value = input.GatherInt("Invalid fractional seconds in date string", 999999999);
                    if (input.HasNext() && (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-'))
                    {
                        throw new XmpException("Invalid date string, after fractional second",
                                               XmpError.BADVALUE);
                    }
                    digits = input.Pos() - digits;
                    for (; digits > 9; --digits)
                    {
                        value = value / 10;
                    }
                    for (; digits < 9; ++digits)
                    {
                        value = value * 10;
                    }
                    binValue.NanoSecond = value;
                }
            }
            else if (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after time", XmpError.BADVALUE);
            }


            if (!input.HasNext())
            {
                // no Timezone at all
                return(binValue);
            }
            if (input.Ch() == 'Z')
            {
                input.Skip();
            }
            else if (input.HasNext())
            {
                if (input.Ch() == '+')
                {
                }
                else if (input.Ch() == '-')
                {
                }
                else
                {
                    throw new XmpException("Time zone must begin with 'Z', '+', or '-'", XmpError.BADVALUE);
                }

                input.Skip();
                // Extract the time zone hour.
                if (input.HasNext())
                {
                    if (input.Ch() == ':')
                    {
                        input.Skip();
                    }
                    else
                    {
                        throw new XmpException("Invalid date string, after time zone hour", XmpError.BADVALUE);
                    }
                }
            }

            // create a corresponding TZ and set it time zone
            binValue.TimeZone = TimeZone.CurrentTimeZone;

            if (input.HasNext())
            {
                throw new XmpException("Invalid date string, extra chars at end", XmpError.BADVALUE);
            }

            return(binValue);
        }
 /// <summary>
 /// Converts a <code>Calendar</code> into an ISO 8601 string.
 /// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
 /// <ul>
 /// <li>YYYY
 /// <li>YYYY-MM
 /// <li>YYYY-MM-DD
 /// <li>YYYY-MM-DDThh:mmTZD
 /// <li>YYYY-MM-DDThh:mm:ssTZD
 /// <li>YYYY-MM-DDThh:mm:ss.sTZD
 /// </ul>
 ///
 /// Data fields:
 /// <ul>
 /// <li>YYYY = four-digit year
 /// <li>MM	 = two-digit month (01=January, etc.)
 /// <li>DD	 = two-digit day of month (01 through 31)
 /// <li>hh	 = two digits of hour (00 through 23)
 /// <li>mm	 = two digits of minute (00 through 59)
 /// <li>ss	 = two digits of second (00 through 59)
 /// <li>s	 = one or more digits representing a decimal fraction of a second
 /// <li>TZD	 = time zone designator (Z or +hh:mm or -hh:mm)
 /// </ul>
 /// <p>
 /// <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999.
 /// We allow any year, even negative ones. The year is formatted as "%.4d".<p>
 /// <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing.
 /// The quasi-bogus "time only" values from Photoshop CS are not supported.
 /// </summary>
 /// <param name="dateTime"> an XMPDateTime-object. </param>
 /// <returns> Returns an ISO 8601 string. </returns>
 public static string Render(IXmpDateTime dateTime)
 {
     return(dateTime.Calendar.DateTime.ToString("s"));
 }
예제 #14
0
        /// <param name="iso8601String">a date string that is ISO 8601 conform.</param>
        /// <param name="binValue">an existing XMPDateTime to set with the parsed date</param>
        /// <returns>Returns an XMPDateTime-object containing the ISO8601-date.</returns>
        /// <exception cref="XmpException">Is thrown when the string is non-conform.</exception>
        public static IXmpDateTime Parse(string iso8601String, IXmpDateTime binValue)
        {
            if (iso8601String == null)
            {
                throw new XmpException("Parameter must not be null", XmpErrorCode.BadParam);
            }
            if (iso8601String.Length == 0)
            {
                return(binValue);
            }
            var input = new ParseState(iso8601String);

            if (input.Ch(0) == '-')
            {
                input.Skip();
            }
            // Extract the year.
            var value = input.GatherInt("Invalid year in date string", 9999);

            if (input.HasNext && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after year", XmpErrorCode.BadValue);
            }
            if (input.Ch(0) == '-')
            {
                value = -value;
            }
            binValue.Year = value;
            if (!input.HasNext)
            {
                return(binValue);
            }
            input.Skip();
            // Extract the month.
            value = input.GatherInt("Invalid month in date string", 12);
            if (input.HasNext && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after month", XmpErrorCode.BadValue);
            }
            binValue.Month = value;
            if (!input.HasNext)
            {
                return(binValue);
            }
            input.Skip();
            // Extract the day.
            value = input.GatherInt("Invalid day in date string", 31);
            if (input.HasNext && input.Ch() != 'T')
            {
                throw new XmpException("Invalid date string, after day", XmpErrorCode.BadValue);
            }
            binValue.Day = value;
            if (!input.HasNext)
            {
                return(binValue);
            }
            input.Skip();
            // Extract the hour.
            value         = input.GatherInt("Invalid hour in date string", 23);
            binValue.Hour = value;
            if (!input.HasNext)
            {
                return(binValue);
            }
            // Extract the minute.
            if (input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid minute in date string", 59);
                if (input.HasNext && input.Ch() != ':' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after minute", XmpErrorCode.BadValue);
                }
                binValue.Minute = value;
            }
            if (!input.HasNext)
            {
                return(binValue);
            }
            if (input.HasNext && input.Ch() == ':')
            {
                input.Skip();
                value = input.GatherInt("Invalid whole seconds in date string", 59);
                if (input.HasNext && input.Ch() != '.' && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                {
                    throw new XmpException("Invalid date string, after whole seconds", XmpErrorCode.BadValue);
                }
                binValue.Second = value;
                if (input.Ch() == '.')
                {
                    input.Skip();
                    var digits = input.Pos();
                    value = input.GatherInt("Invalid fractional seconds in date string", 999999999);
                    if (input.HasNext && input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
                    {
                        throw new XmpException("Invalid date string, after fractional second", XmpErrorCode.BadValue);
                    }
                    digits = input.Pos() - digits;
                    for (; digits > 9; --digits)
                    {
                        value = value / 10;
                    }
                    for (; digits < 9; ++digits)
                    {
                        value = value * 10;
                    }
                    binValue.Nanosecond = value;
                }
            }
            else if (input.Ch() != 'Z' && input.Ch() != '+' && input.Ch() != '-')
            {
                throw new XmpException("Invalid date string, after time", XmpErrorCode.BadValue);
            }

            var tzSign   = 0;
            var tzHour   = 0;
            var tzMinute = 0;

            if (!input.HasNext)
            {
                // no Timezone at all
                return(binValue);
            }
            if (input.Ch() == 'Z')
            {
                input.Skip();
            }
            else if (input.HasNext)
            {
                switch (input.Ch())
                {
                case '+':
                    tzSign = 1;
                    break;

                case '-':
                    tzSign = -1;
                    break;

                default:
                    throw new XmpException("Time zone must begin with 'Z', '+', or '-'", XmpErrorCode.BadValue);
                }
                input.Skip();
                // Extract the time zone hour.
                tzHour = input.GatherInt("Invalid time zone hour in date string", 23);
                if (input.HasNext)
                {
                    if (input.Ch() == ':')
                    {
                        input.Skip();
                        // Extract the time zone minute.
                        tzMinute = input.GatherInt("Invalid time zone minute in date string", 59);
                    }
                    else
                    {
                        throw new XmpException("Invalid date string, after time zone hour", XmpErrorCode.BadValue);
                    }
                }
            }

            // create a corresponding TZ and set it time zone
            var offset = TimeSpan.FromHours(tzHour) + TimeSpan.FromMinutes(tzMinute);

            if (tzSign < 0)
            {
                offset = -offset;
            }

            binValue.TimeZone = TimeZoneInfo.Local;
            binValue.Offset   = offset;

            if (input.HasNext)
            {
                throw new XmpException("Invalid date string, extra chars at end", XmpErrorCode.BadValue);
            }

            return(binValue);
        }
예제 #15
0
 /// <summary>
 /// Make sure a time is local. If the time zone is not the local zone, the time is adjusted and
 /// the time zone set to be local.
 /// </summary>
 /// <param name="dateTime"> the <code>XMPDateTime</code> variable containing the time to be modified. </param>
 /// <returns> Returns an updated <code>XMPDateTime</code>-object. </returns>
 public static IXmpDateTime ConvertToLocalTime(IXmpDateTime dateTime) {
     long timeInMillis = dateTime.Calendar.TimeInMillis;
     // has automatically local timezone
     XmpCalendar cal = new XmpCalendar();
     cal.TimeInMillis = timeInMillis;
     return new XmpDateTimeImpl(cal);
 }
예제 #16
0
 /// <summary>Make sure a time is local.</summary>
 /// <remarks>
 /// Make sure a time is local. If the time zone is not the local zone, the time is adjusted and
 /// the time zone set to be local.
 /// </remarks>
 /// <param name="dateTime">the <c>XMPDateTime</c> variable containing the time to be modified.</param>
 /// <returns>Returns an updated <c>XMPDateTime</c>-object.</returns>
 public static IXmpDateTime ConvertToLocalTime(IXmpDateTime dateTime)
 {
     var timeInMillis = dateTime.Calendar.GetTimeInMillis();
     // has automatically local timezone
     var cal = new GregorianCalendar();
     cal.SetTimeInMillis(timeInMillis);
     return new XmpDateTime(cal);
 }
예제 #17
0
 /// <summary>Convert from <c>XMPDateTime</c> to string.</summary>
 /// <param name="value">an <c>XMPDateTime</c></param>
 /// <returns>The string representation of the long.</returns>
 public static string ConvertFromDate(IXmpDateTime value)
 {
     return Iso8601Converter.Render(value);
 }
예제 #18
0
        /// <summary>Converts a <c>Calendar</c> into an ISO 8601 string.</summary>
        /// <remarks>
        /// Converts a <c>Calendar</c> into an ISO 8601 string.
        /// Format a date according to ISO 8601 and http://www.w3.org/TR/NOTE-datetime:
        /// <list type="bullet">
        /// <item>YYYY</item>
        /// <item>YYYY-MM</item>
        /// <item>YYYY-MM-DD</item>
        /// <item>YYYY-MM-DDThh:mmTZD</item>
        /// <item>YYYY-MM-DDThh:mm:ssTZD</item>
        /// <item>YYYY-MM-DDThh:mm:ss.sTZD</item>
        /// </list>
        /// Data fields:
        /// <list type="bullet">
        /// <item>YYYY = four-digit year</item>
        /// <item>MM     = two-digit month (01=January, etc.)</item>
        /// <item>DD     = two-digit day of month (01 through 31)</item>
        /// <item>hh     = two digits of hour (00 through 23)</item>
        /// <item>mm     = two digits of minute (00 through 59)</item>
        /// <item>ss     = two digits of second (00 through 59)</item>
        /// <item>s     = one or more digits representing a decimal fraction of a second</item>
        /// <item>TZD     = time zone designator (Z or +hh:mm or -hh:mm)</item>
        /// </list>
        /// <para />
        /// <em>Note:</em> ISO 8601 does not seem to allow years less than 1000 or greater than 9999.
        /// We allow any year, even negative ones. The year is formatted as "%.4d".
        /// <para />
        /// <em>Note:</em> Fix for bug 1269463 (silently fix out of range values) included in parsing.
        /// The quasi-bogus "time only" values from Photoshop CS are not supported.
        /// </remarks>
        /// <param name="dateTime">an XMPDateTime-object.</param>
        /// <returns>Returns an ISO 8601 string.</returns>
        public static string Render(IXmpDateTime dateTime)
        {
            var buffer = new StringBuilder();
            if (dateTime.HasDate)
            {
                // year is rendered in any case, even 0000
                buffer.Append(dateTime.Year.ToString("0000"));
                if (dateTime.Month == 0)
                    return buffer.ToString();

                // month
                buffer.Append('-');
                buffer.Append(dateTime.Month.ToString("00"));
                if (dateTime.Day == 0)
                    return buffer.ToString();

                // day
                buffer.Append('-');
                buffer.Append(dateTime.Day.ToString("00"));

                // time, rendered if any time field is not zero
                if (dateTime.HasTime)
                {
                    // hours and minutes
                    buffer.Append('T');
                    buffer.Append(dateTime.Hour.ToString("00"));
                    buffer.Append(':');
                    buffer.Append(dateTime.Minute.ToString("00"));
                    // seconds and nanoseconds
                    if (dateTime.Second != 0 || dateTime.Nanosecond != 0)
                    {
                        buffer.Append(':');
                        var seconds = dateTime.Second + dateTime.Nanosecond / 1e9d;
                        buffer.AppendFormat("{0:00.#########}", seconds);
                    }
                    // time zone
                    if (dateTime.HasTimeZone)
                    {
                        // used to calculate the time zone offset incl. Daylight Savings
                        var timeInMillis = dateTime.Calendar.GetTimeInMillis();
                        var offset = (int) dateTime.TimeZone.GetUtcOffset(XmpDateTime.UnixTimeToDateTimeOffset(timeInMillis).DateTime).TotalMilliseconds;
                        if (offset == 0)
                        {
                            // UTC
                            buffer.Append('Z');
                        }
                        else
                        {
                            var thours = offset / 3600000;
                            var tminutes = Math.Abs(offset % 3600000 / 60000);
                            buffer.Append(thours.ToString("+00;-00"));
                            buffer.Append(tminutes.ToString(":00"));
                        }
                    }
                }
            }
            return buffer.ToString();
        }
예제 #19
0
 /// <seealso cref= XMPMeta#SetPropertyDate(String, String, XMPDateTime) </seealso>
 public virtual void SetPropertyDate(string schemaNs, string propName, IXmpDateTime propValue) {
     SetProperty(schemaNs, propName, propValue, null);
 }
예제 #20
0
 /// <summary>
 /// Convert from <code>XMPDateTime</code> to string.
 /// </summary>
 /// <param name="value">
 ///            an <code>XMPDateTime</code> </param>
 /// <returns> The string representation of the long. </returns>
 public static string ConvertFromDate(IXmpDateTime value)
 {
     return(Iso8601Converter.Render(value));
 }