/// <summary>Converts a <code>Calendar</code> into an ISO 8601 string.</summary>
        /// <remarks>
        /// 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.
        /// </remarks>
        /// <param name="dateTime">an XMPDateTime-object.</param>
        /// <returns>Returns an ISO 8601 string.</returns>
        public static string Render(XMPDateTime dateTime)
        {
            StringBuilder buffer = new StringBuilder();

            if (dateTime.HasDate())
            {
                // year is rendered in any case, even 0000
                DecimalFormat df = new DecimalFormat("0000", new DecimalFormatSymbols(Sharpen.Extensions.GetEnglishCulture()));
                buffer.Append(df.Format(dateTime.GetYear()));
                if (dateTime.GetMonth() == 0)
                {
                    return(buffer.ToString());
                }
                // month
                df.ApplyPattern("'-'00");
                buffer.Append(df.Format(dateTime.GetMonth()));
                if (dateTime.GetDay() == 0)
                {
                    return(buffer.ToString());
                }
                // day
                buffer.Append(df.Format(dateTime.GetDay()));
                // time, rendered if any time field is not zero
                if (dateTime.HasTime())
                {
                    // hours and minutes
                    buffer.Append('T');
                    df.ApplyPattern("00");
                    buffer.Append(df.Format(dateTime.GetHour()));
                    buffer.Append(':');
                    buffer.Append(df.Format(dateTime.GetMinute()));
                    // seconds and nanoseconds
                    if (dateTime.GetSecond() != 0 || dateTime.GetNanoSecond() != 0)
                    {
                        double seconds = dateTime.GetSecond() + dateTime.GetNanoSecond() / 1e9d;
                        df.ApplyPattern(":00.#########");
                        buffer.Append(df.Format(seconds));
                    }
                    // time zone
                    if (dateTime.HasTimeZone())
                    {
                        // used to calculate the time zone offset incl. Daylight Savings
                        long timeInMillis = dateTime.GetCalendar().GetTimeInMillis();
                        int  offset       = dateTime.GetTimeZone().GetOffset(timeInMillis);
                        if (offset == 0)
                        {
                            // UTC
                            buffer.Append('Z');
                        }
                        else
                        {
                            int thours   = offset / 3600000;
                            int tminutes = Math.Abs(offset % 3600000 / 60000);
                            df.ApplyPattern("+00;-00");
                            buffer.Append(df.Format(thours));
                            df.ApplyPattern(":00");
                            buffer.Append(df.Format(tminutes));
                        }
                    }
                }
            }
            return(buffer.ToString());
        }