/// <summary> /// Returns the string representation of this {@code FileTime}. The string /// is returned in the <a /// href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> format: /// <pre> /// YYYY-MM-DDThh:mm:ss[.s+]Z /// </pre> /// where "{@code [.s+]}" represents a dot followed by one of more digits /// for the decimal fraction of a second. It is only present when the decimal /// fraction of a second is not zero. For example, {@code /// FileTime.fromMillis(1234567890000L).toString()} yields {@code /// "2009-02-13T23:31:30Z"}, and {@code FileTime.fromMillis(1234567890123L).toString()} /// yields {@code "2009-02-13T23:31:30.123Z"}. /// /// <para> A {@code FileTime} is primarily intended to represent the value of a /// file's time stamp. Where used to represent <i>extreme values</i>, where /// the year is less than "{@code 0001}" or greater than "{@code 9999}" then /// this method deviates from ISO 8601 in the same manner as the /// <a href="http://www.w3.org/TR/xmlschema-2/#deviantformats">XML Schema /// language</a>. That is, the year may be expanded to more than four digits /// and may be negative-signed. If more than four digits then leading zeros /// are not present. The year before "{@code 0001}" is "{@code -0001}". /// /// </para> /// </summary> /// <returns> the string representation of this file time </returns> public override String ToString() { if (ValueAsString == null) { long secs = 0L; int nanos = 0; if (Instant == null && Unit.CompareTo(TimeUnit.SECONDS) >= 0) { secs = Unit.ToSeconds(Value); } else { secs = ToInstant().EpochSecond; nanos = ToInstant().Nano; } LocalDateTime ldt; int year = 0; if (secs >= -SECONDS_0000_TO_1970) { // current era long zeroSecs = secs - SECONDS_PER_10000_YEARS + SECONDS_0000_TO_1970; long hi = Math.FloorDiv(zeroSecs, SECONDS_PER_10000_YEARS) + 1; long lo = Math.FloorMod(zeroSecs, SECONDS_PER_10000_YEARS); ldt = LocalDateTime.OfEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC); year = ldt.Year + (int)hi * 10000; } else { // before current era long zeroSecs = secs + SECONDS_0000_TO_1970; long hi = zeroSecs / SECONDS_PER_10000_YEARS; long lo = zeroSecs % SECONDS_PER_10000_YEARS; ldt = LocalDateTime.OfEpochSecond(lo - SECONDS_0000_TO_1970, nanos, ZoneOffset.UTC); year = ldt.Year + (int)hi * 10000; } if (year <= 0) { year = year - 1; } int fraction = ldt.Nano; StringBuilder sb = new StringBuilder(64); sb.Append(year < 0 ? "-" : ""); year = System.Math.Abs(year); if (year < 10000) { Append(sb, 1000, System.Math.Abs(year)); } else { sb.Append(Convert.ToString(year)); } sb.Append('-'); Append(sb, 10, ldt.MonthValue); sb.Append('-'); Append(sb, 10, ldt.DayOfMonth); sb.Append('T'); Append(sb, 10, ldt.Hour); sb.Append(':'); Append(sb, 10, ldt.Minute); sb.Append(':'); Append(sb, 10, ldt.Second); if (fraction != 0) { sb.Append('.'); // adding leading zeros and stripping any trailing zeros int w = 100000000; while (fraction % 10 == 0) { fraction /= 10; w /= 10; } Append(sb, w, fraction); } sb.Append('Z'); ValueAsString = sb.ToString(); } return(ValueAsString); }