Skip to content

Commit

Permalink
Add DateTimeOffset, DateOnly/TimeOnly (.NET6+) types conversion support.
Browse files Browse the repository at this point in the history
  • Loading branch information
i2van committed May 5, 2022
1 parent e80ee4b commit 214e72d
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 30 deletions.
77 changes: 76 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ Authors.First()

### Extension Methods ###

Driver provides extension methods for converting string to `T?`. `CultureInfo.InvariantCulture` is used by default.
Driver provides extension methods for converting `string` (and `ReadOnlySpan<char>` for .NET Core/.NET) to `T?`. `CultureInfo.InvariantCulture` is used by default.

```csharp
// Bool.
Expand Down Expand Up @@ -393,11 +393,38 @@ DateTime? ToDateTime(
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// .NET Core/.NET only.
DateTime? ToDateTime(
ReadOnlySpan<char> format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

DateTime? ToDateTime(
string[] formats,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// DateTimeOffset.
DateTimeOffset? ToDateTimeOffset(
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

DateTimeOffset? ToDateTimeOffset(
string format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// .NET Core/.NET only.
DateTimeOffset? ToDateTimeOffset(
ReadOnlySpan<char> format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

DateTimeOffset? ToDateTimeOffset(
string[] formats,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// TimeSpan.
TimeSpan? ToTimeSpan(CultureInfo? cultureInfo = null);

Expand All @@ -406,10 +433,58 @@ TimeSpan? ToTimeSpan(
TimeSpanStyles timeSpanStyles = TimeSpanStyles.None,
CultureInfo? cultureInfo = null);

// .NET Core/.NET only.
TimeSpan? ToTimeSpan(
ReadOnlySpan<char> format,
TimeSpanStyles timeSpanStyles = TimeSpanStyles.None,
CultureInfo? cultureInfo = null);

TimeSpan? ToTimeSpan(
string[] formats,
TimeSpanStyles timeSpanStyles = TimeSpanStyles.None,
CultureInfo? cultureInfo = null);

// .NET 6+: DateOnly.
DateOnly? ToDateOnly(
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

DateOnly? ToDateOnly(
string format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// .NET Core/.NET only.
DateOnly? ToDateOnly(
ReadOnlySpan<char> format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

DateOnly? ToDateOnly(
string[] formats,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// .NET 6+: TimeOnly.
TimeOnly? ToTimeOnly(
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

TimeOnly? ToTimeOnly(
string format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

// .NET Core/.NET only.
TimeOnly? ToTimeOnly(
ReadOnlySpan<char> format,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);

TimeOnly? ToTimeOnly(
string[] formats,
DateTimeStyles dateTimeStyles = DateTimeStyles.None,
CultureInfo? cultureInfo = null);
```

## Known Issues ##
Expand Down
2 changes: 1 addition & 1 deletion Src/CsvLINQPadDriver/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<Version>7.3.4</Version>
<PackageReleaseNotes>Update Humanizer.Core.</PackageReleaseNotes>
<PackageReleaseNotes>Added DateTimeOffset, DateOnly/TimeOnly (.NET6+) types conversion support.</PackageReleaseNotes>
</PropertyGroup>

<PropertyGroup>
Expand Down
154 changes: 154 additions & 0 deletions Src/CsvLINQPadDriver/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,48 +15,191 @@ public static class StringExtensions
public static int? ToInt(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(int.TryParse(str, NumberStyles.Integer, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static int? ToInt(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(int.TryParse(str, NumberStyles.Integer, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static long? ToLong(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(long.TryParse(str, NumberStyles.Integer, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static long? ToLong(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(long.TryParse(str, NumberStyles.Integer, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static float? ToFloat(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(float.TryParse(str, NumberStyles.Float | NumberStyles.AllowThousands, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static float? ToFloat(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(float.TryParse(str, NumberStyles.Float | NumberStyles.AllowThousands, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static double? ToDouble(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(double.TryParse(str, NumberStyles.Float | NumberStyles.AllowThousands, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static double? ToDouble(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(double.TryParse(str, NumberStyles.Float | NumberStyles.AllowThousands, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static decimal? ToDecimal(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(decimal.TryParse(str, NumberStyles.Number, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static decimal? ToDecimal(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(decimal.TryParse(str, NumberStyles.Number, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static DateTime? ToDateTime(this string? str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTime? ToDateTime(this ReadOnlySpan<char> str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static DateTime? ToDateTime(this string? str, string format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTime? ToDateTime(this ReadOnlySpan<char> str, ReadOnlySpan<char> format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static DateTime? ToDateTime(this string? str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTime? ToDateTime(this ReadOnlySpan<char> str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTime.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static DateTimeOffset? ToDateTimeOffset(this string? str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTimeOffset? ToDateTimeOffset(this ReadOnlySpan<char> str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static DateTimeOffset? ToDateTimeOffset(this string? str, string format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTimeOffset? ToDateTimeOffset(this ReadOnlySpan<char> str, ReadOnlySpan<char> format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static DateTimeOffset? ToDateTimeOffset(this string? str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static DateTimeOffset? ToDateTimeOffset(this ReadOnlySpan<char> str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateTimeOffset.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static TimeSpan? ToTimeSpan(this string? str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParse(str, SelectCulture(cultureInfo), out var parsedValue), parsedValue);

#if NETCOREAPP
public static TimeSpan? ToTimeSpan(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParse(str, SelectCulture(cultureInfo), out var parsedValue), parsedValue);
#endif

public static TimeSpan? ToTimeSpan(this string? str, string format, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParseExact(str, format, SelectCulture(cultureInfo), timeSpanStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static TimeSpan? ToTimeSpan(this ReadOnlySpan<char> str, ReadOnlySpan<char> format, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParseExact(str, format, SelectCulture(cultureInfo), timeSpanStyles, out var parsedValue), parsedValue);
#endif

public static TimeSpan? ToTimeSpan(this string? str, string[] formats, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParseExact(str, formats, SelectCulture(cultureInfo), timeSpanStyles, out var parsedValue), parsedValue);

#if NETCOREAPP
public static TimeSpan? ToTimeSpan(this ReadOnlySpan<char> str, string[] formats, TimeSpanStyles timeSpanStyles = TimeSpanStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeSpan.TryParseExact(str, formats, SelectCulture(cultureInfo), timeSpanStyles, out var parsedValue), parsedValue);
#endif

#if NET6_0_OR_GREATER
public static DateOnly? ToDateOnly(this string? str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static DateOnly? ToDateOnly(this ReadOnlySpan<char> str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static DateOnly? ToDateOnly(this string? str, string format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static DateOnly? ToDateOnly(this ReadOnlySpan<char> str, ReadOnlySpan<char> format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static DateOnly? ToDateOnly(this string? str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static DateOnly? ToDateOnly(this ReadOnlySpan<char> str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(DateOnly.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this string? str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this ReadOnlySpan<char> str, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParse(str, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this string? str, string format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this ReadOnlySpan<char> str, ReadOnlySpan<char> format, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParseExact(str, format, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this string? str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);

public static TimeOnly? ToTimeOnly(this ReadOnlySpan<char> str, string[] formats, DateTimeStyles dateTimeStyles = DateTimeStyles.None, CultureInfo? cultureInfo = null) =>
GetValueOrNull(TimeOnly.TryParseExact(str, formats, SelectCulture(cultureInfo), dateTimeStyles, out var parsedValue), parsedValue);
#endif

public static Guid? ToGuid(this string? str) =>
GetValueOrNull(Guid.TryParse(str, out var parsedValue), parsedValue);

#if NETCOREAPP
public static Guid? ToGuid(this ReadOnlySpan<char> str) =>
GetValueOrNull(Guid.TryParse(str, out var parsedValue), parsedValue);
#endif

public static Guid? ToGuid(this string? str, string format) =>
GetValueOrNull(Guid.TryParseExact(str, format, out var parsedValue), parsedValue);

#if NETCOREAPP
public static Guid? ToGuid(this ReadOnlySpan<char> str, ReadOnlySpan<char> format) =>
GetValueOrNull(Guid.TryParseExact(str, format, out var parsedValue), parsedValue);
#endif

// ReSharper disable once ParameterTypeCanBeEnumerable.Global
public static Guid? ToGuid(this string? str, string[] formats) =>
formats
.Select(format => GetValueOrNull(Guid.TryParseExact(str, format, out var parsedValue), parsedValue))
.FirstOrDefault(static guid => guid is not null);

#if NETCOREAPP
public static Guid? ToGuid(this ReadOnlySpan<char> str, string[] formats)
{
foreach (var format in formats)
{
var guid = GetValueOrNull(Guid.TryParseExact(str, format, out var parsedValue), parsedValue);
if (guid is not null)
{
return guid;
}
}

return null;
}
#endif

public static bool? ToBool(this string? str, CultureInfo? cultureInfo = null)
{
var longValue = str.ToLong(cultureInfo);
Expand All @@ -66,6 +209,17 @@ public static class StringExtensions
: GetValueOrNull(bool.TryParse(str, out var parsedValue), parsedValue);
}

#if NETCOREAPP
public static bool? ToBool(this ReadOnlySpan<char> str, CultureInfo? cultureInfo = null)
{
var longValue = str.ToLong(cultureInfo);

return longValue.HasValue
? longValue.Value != 0
: GetValueOrNull(bool.TryParse(str, out var parsedValue), parsedValue);
}
#endif

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static CultureInfo SelectCulture(CultureInfo? cultureInfo) =>
cultureInfo ?? DefaultCultureInfo;
Expand Down
Loading

0 comments on commit 214e72d

Please sign in to comment.