diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs index 21ca3f6925a..620993b9d25 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/DateType.cs @@ -10,6 +10,7 @@ namespace HotChocolate.Types; public class DateType : ScalarType { private const string DateFormat = "yyyy-MM-dd"; + private readonly bool _enforceSpecFormat; /// /// Initializes a new instance of the class. @@ -17,10 +18,24 @@ public class DateType : ScalarType public DateType( string name, string? description = null, - BindingBehavior bind = BindingBehavior.Explicit) + BindingBehavior bind = BindingBehavior.Explicit, + bool disableFormatCheck = false) : base(name, bind) { Description = description; + _enforceSpecFormat = !disableFormatCheck; + } + + /// + /// Initializes a new instance of the class. + /// + public DateType(bool disableFormatCheck) + : this( + ScalarNames.Date, + TypeResources.DateType_Description, + BindingBehavior.Implicit, + disableFormatCheck: disableFormatCheck) + { } /// @@ -110,14 +125,27 @@ public override bool TryDeserialize(object? resultValue, out object? runtimeValu private static string Serialize(IFormattable value) => value.ToString(DateFormat, CultureInfo.InvariantCulture); - private static bool TryDeserializeFromString( + private bool TryDeserializeFromString( string? serialized, [NotNullWhen(true)] out DateOnly? value) { - if (DateOnly.TryParseExact( - serialized, - DateFormat, - out var date)) + if (_enforceSpecFormat) + { + if (DateOnly.TryParseExact( + serialized, + DateFormat, + CultureInfo.InvariantCulture, + DateTimeStyles.None, + out var date)) + { + value = date; + return true; + } + } + else if (DateOnly.TryParse( + serialized, + CultureInfo.InvariantCulture, + out var date)) { value = date; return true; diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs index 742adf22679..42725ec92f2 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalDateType.cs @@ -15,6 +15,7 @@ namespace HotChocolate.Types; public class LocalDateType : ScalarType { private const string LocalFormat = "yyyy-MM-dd"; + private readonly bool _enforceSpecFormat; /// /// Initializes a new instance of the class. @@ -22,10 +23,24 @@ public class LocalDateType : ScalarType public LocalDateType( string name, string? description = null, - BindingBehavior bind = BindingBehavior.Explicit) + BindingBehavior bind = BindingBehavior.Explicit, + bool disableFormatCheck = false) : base(name, bind) { Description = description; + _enforceSpecFormat = !disableFormatCheck; + } + + /// + /// Initializes a new instance of the class. + /// + public LocalDateType(bool disableFormatCheck) + : this( + ScalarNames.LocalDate, + TypeResources.LocalDateType_Description, + BindingBehavior.Implicit, + disableFormatCheck: disableFormatCheck) + { } /// @@ -122,17 +137,27 @@ private static string Serialize(IFormattable value) return value.ToString(LocalFormat, CultureInfo.InvariantCulture); } - private static bool TryDeserializeFromString( + private bool TryDeserializeFromString( string? serialized, [NotNullWhen(true)] out DateOnly? value) { - if (serialized is not null - && DateOnly.TryParseExact( + if (_enforceSpecFormat) + { + if (DateOnly.TryParseExact( serialized, LocalFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var date)) + { + value = date; + return true; + } + } + else if (DateOnly.TryParse( + serialized, + CultureInfo.InvariantCulture, + out var date)) { value = date; return true; diff --git a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs index 977440a9bc2..1bda74143b7 100644 --- a/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs +++ b/src/HotChocolate/Core/src/Types/Types/Scalars/LocalTimeType.cs @@ -14,6 +14,7 @@ namespace HotChocolate.Types; public class LocalTimeType : ScalarType { private const string LocalFormat = "HH:mm:ss"; + private readonly bool _enforceSpecFormat; /// /// Initializes a new instance of the class. @@ -21,10 +22,24 @@ public class LocalTimeType : ScalarType public LocalTimeType( string name, string? description = null, - BindingBehavior bind = BindingBehavior.Explicit) + BindingBehavior bind = BindingBehavior.Explicit, + bool disableFormatCheck = false) : base(name, bind) { Description = description; + _enforceSpecFormat = !disableFormatCheck; + } + + /// + /// Initializes a new instance of the class. + /// + public LocalTimeType(bool disableFormatCheck) + : this( + ScalarNames.LocalTime, + TypeResources.LocalTimeType_Description, + BindingBehavior.Implicit, + disableFormatCheck: disableFormatCheck) + { } /// @@ -121,17 +136,27 @@ private static string Serialize(IFormattable value) return value.ToString(LocalFormat, CultureInfo.InvariantCulture); } - private static bool TryDeserializeFromString( + private bool TryDeserializeFromString( string? serialized, [NotNullWhen(true)] out TimeOnly? value) { - if (serialized is not null - && TimeOnly.TryParseExact( + if (_enforceSpecFormat) + { + if (TimeOnly.TryParseExact( serialized, LocalFormat, CultureInfo.InvariantCulture, DateTimeStyles.None, out var time)) + { + value = time; + return true; + } + } + else if (TimeOnly.TryParse( + serialized, + CultureInfo.InvariantCulture, + out var time)) { value = time; return true; diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs index 2c706b70b5f..dd12e328538 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/DateTypeTests.cs @@ -474,6 +474,20 @@ public async Task DateOnly_As_ReturnValue() .MatchSnapshotAsync(); } + [Fact] + public void DateType_Relaxed_Format_Check() + { + // arrange + const string s = "2011-08-30T08:46:14.116"; + + // act + var dateType = new DateType(disableFormatCheck: true); + var result = dateType.Deserialize(s); + + // assert + Assert.IsType(result); + } + public class Query { [GraphQLType(typeof(DateType))] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs index 0b87ec3ed2a..cbbce141d73 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalDateTypeTests.cs @@ -507,6 +507,20 @@ public async Task DateOnly_As_ReturnValue() .MatchSnapshotAsync(); } + [Fact] + public void LocalDate_Relaxed_Format_Check() + { + // arrange + const string s = "2011-08-30T08:46:14.116"; + + // act + var localDateType = new LocalDateType(disableFormatCheck: true); + var result = localDateType.Deserialize(s); + + // assert + Assert.IsType(result); + } + public class Query { [GraphQLType(typeof(LocalDateType))] diff --git a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs index 544d0d3ddde..3304c03b801 100644 --- a/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs +++ b/src/HotChocolate/Core/test/Types.Tests/Types/Scalars/LocalTimeTypeTests.cs @@ -472,6 +472,20 @@ public async Task TimeOnly_As_ReturnValue() .MatchSnapshotAsync(); } + [Fact] + public void LocalTime_Relaxed_Format_Check() + { + // arrange + const string s = "8:46 am"; + + // act + var localTimeType = new LocalTimeType(disableFormatCheck: true); + var result = localTimeType.Deserialize(s); + + // assert + Assert.IsType(result); + } + public class Query { [GraphQLType(typeof(LocalTimeType))]