diff --git a/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs b/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs index 6a91d1a1..eb156ea2 100644 --- a/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs +++ b/Src/Newtonsoft.Json.Tests/Utilities/DateTimeUtilsTests.cs @@ -70,6 +70,32 @@ namespace Newtonsoft.Json.Tests.Utilities Assert.AreEqual(value, parsedDt); } + [Test] + public void Parse24HourDateTime() + { + DateTime dt; + Assert.IsTrue(DateTimeUtils.TryParseDateTimeIso(CreateStringReference("2000-12-15T24:00:00Z"), DateTimeZoneHandling.RoundtripKind, out dt)); + Assert.AreEqual(new DateTime(2000, 12, 16, 0, 0, 0, DateTimeKind.Utc), dt); + + Assert.IsFalse(DateTimeUtils.TryParseDateTimeIso(CreateStringReference("2000-12-15T24:01:00Z"), DateTimeZoneHandling.RoundtripKind, out dt)); + Assert.IsFalse(DateTimeUtils.TryParseDateTimeIso(CreateStringReference("2000-12-15T24:00:01Z"), DateTimeZoneHandling.RoundtripKind, out dt)); + Assert.IsFalse(DateTimeUtils.TryParseDateTimeIso(CreateStringReference("2000-12-15T24:00:00.0000001Z"), DateTimeZoneHandling.RoundtripKind, out dt)); + } + +#if !NET20 + [Test] + public void Parse24HourDateTimeOffset() + { + DateTimeOffset dt; + Assert.IsTrue(DateTimeUtils.TryParseDateTimeOffsetIso(CreateStringReference("2000-12-15T24:00:00Z"), out dt)); + Assert.AreEqual(new DateTimeOffset(2000, 12, 16, 0, 0, 0, TimeSpan.Zero), dt); + + Assert.IsFalse(DateTimeUtils.TryParseDateTimeOffsetIso(CreateStringReference("2000-12-15T24:01:00Z"), out dt)); + Assert.IsFalse(DateTimeUtils.TryParseDateTimeOffsetIso(CreateStringReference("2000-12-15T24:00:01Z"), out dt)); + Assert.IsFalse(DateTimeUtils.TryParseDateTimeOffsetIso(CreateStringReference("2000-12-15T24:00:00.0000001Z"), out dt)); + } +#endif + [Test] public void NewDateTimeParse() { diff --git a/Src/Newtonsoft.Json/JsonSerializerSettings.cs b/Src/Newtonsoft.Json/JsonSerializerSettings.cs index 7c0bb65c..cc18cb9e 100644 --- a/Src/Newtonsoft.Json/JsonSerializerSettings.cs +++ b/Src/Newtonsoft.Json/JsonSerializerSettings.cs @@ -138,7 +138,7 @@ namespace Newtonsoft.Json } /// - /// Gets or sets a collection that will be used during serialization. + /// Gets or sets a collection that will be used during serialization. /// /// The converters. public IList Converters { get; set; } diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs index 0a182694..9addb98e 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeParser.cs @@ -123,13 +123,14 @@ namespace Newtonsoft.Json.Utilities private bool ParseTime(ref int start) { if (!(Parse2Digit(start, out Hour) - && Hour < 24 + && Hour <= 24 && ParseChar(start + LzHH, ':') && Parse2Digit(start + LzHH_, out Minute) && Minute < 60 && ParseChar(start + LzHH_mm, ':') && Parse2Digit(start + LzHH_mm_, out Second) - && Second < 60)) + && Second < 60 + && (Hour != 24 || (Minute == 0 && Second == 0)))) // hour can be 24 if minute/second is zero) { return false; } @@ -162,6 +163,11 @@ namespace Newtonsoft.Json.Utilities Fraction *= Power10[MaxFractionDigits - numberOfDigits]; } + + if (Hour == 24 && Fraction != 0) + { + return false; + } } return true; } diff --git a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs index afe56b35..44e05350 100644 --- a/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/DateTimeUtils.cs @@ -206,8 +206,7 @@ namespace Newtonsoft.Json.Utilities return false; } - DateTime d = new DateTime(dateTimeParser.Year, dateTimeParser.Month, dateTimeParser.Day, dateTimeParser.Hour, dateTimeParser.Minute, dateTimeParser.Second); - d = d.AddTicks(dateTimeParser.Fraction); + DateTime d = CreateDateTime(dateTimeParser); long ticks; @@ -269,8 +268,7 @@ namespace Newtonsoft.Json.Utilities return false; } - DateTime d = new DateTime(dateTimeParser.Year, dateTimeParser.Month, dateTimeParser.Day, dateTimeParser.Hour, dateTimeParser.Minute, dateTimeParser.Second); - d = d.AddTicks(dateTimeParser.Fraction); + DateTime d = CreateDateTime(dateTimeParser); TimeSpan offset; @@ -302,6 +300,29 @@ namespace Newtonsoft.Json.Utilities } #endif + private static DateTime CreateDateTime(DateTimeParser dateTimeParser) + { + bool is24Hour; + if (dateTimeParser.Hour == 24) + { + is24Hour = true; + dateTimeParser.Hour = 0; + } + else + { + is24Hour = false; + } + + DateTime d = new DateTime(dateTimeParser.Year, dateTimeParser.Month, dateTimeParser.Day, dateTimeParser.Hour, dateTimeParser.Minute, dateTimeParser.Second); + d = d.AddTicks(dateTimeParser.Fraction); + + if (is24Hour) + { + d = d.AddDays(1); + } + return d; + } + internal static bool TryParseDateTime(StringReference s, DateTimeZoneHandling dateTimeZoneHandling, string dateFormatString, CultureInfo culture, out DateTime dt) { if (s.Length > 0)