From 073b10929a0cb3a270ab07ef4f037d4197779fd0 Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Thu, 24 Aug 2023 18:37:33 +0200 Subject: [PATCH 1/2] Fix for Schedular Allows incorrect Time format #3184 Modified code to accept correct time types. --- Oqtane.Client/Modules/Admin/Jobs/Edit.razor | 42 ++++++++++----------- Oqtane.Shared/Shared/Utilities.cs | 27 ++++++++----- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor index 34780aa0..ec6532b2 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor @@ -56,7 +56,7 @@
- +
@@ -69,7 +69,7 @@
- +
@@ -82,7 +82,7 @@
- +
@@ -97,22 +97,22 @@ @code { - private ElementReference form; - private bool validated = false; - private int _jobId; - private string _name = string.Empty; - private string _jobType = string.Empty; - private string _isEnabled = "True"; - private string _interval = string.Empty; - private string _frequency = string.Empty; - private DateTime? _startDate = null; - private string _startTime = string.Empty; - private DateTime? _endDate = null; - private string _endTime = string.Empty; - private string _retentionHistory = string.Empty; - private DateTime? _nextDate = null; - private string _nextTime = string.Empty; - private string createdby; + private ElementReference form; + private bool validated = false; + private int _jobId; + private string _name = string.Empty; + private string _jobType = string.Empty; + private string _isEnabled = "True"; + private string _interval = string.Empty; + private string _frequency = string.Empty; + private DateTime? _startDate = null; + private DateTime? _startTime = null; + private DateTime? _endDate = null; + private DateTime? _endTime = null; + private string _retentionHistory = string.Empty; + private DateTime? _nextDate = null; + private DateTime? _nextTime = null; + private string createdby; private DateTime createdon; private string modifiedby; private DateTime modifiedon; @@ -133,9 +133,9 @@ _interval = job.Interval.ToString(); _frequency = job.Frequency; (_startDate, _startTime) = Utilities.UtcAsLocalDateAndTime(job.StartDate); - (_endDate, _endTime) = Utilities.UtcAsLocalDateAndTime(job.EndDate); + (_endDate, _endTime) = Utilities.UtcAsLocalDateAndTime(job.EndDate); _retentionHistory = job.RetentionHistory.ToString(); - (_nextDate, _nextTime) = Utilities.UtcAsLocalDateAndTime(job.NextExecution); + (_nextDate, _nextTime) = Utilities.UtcAsLocalDateAndTime(job.NextExecution); createdby = job.CreatedBy; createdon = job.CreatedOn; modifiedby = job.ModifiedBy; diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index cdf0e05e..26eec073 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -490,35 +490,39 @@ namespace Oqtane.Shared return $"[{@class.GetType()}] {message}"; } - public static DateTime? LocalDateAndTimeAsUtc(DateTime? date, string time, TimeZoneInfo localTimeZone = null) + public static DateTime? LocalDateAndTimeAsUtc(DateTime? date, DateTime? time, TimeZoneInfo localTimeZone = null) { localTimeZone ??= TimeZoneInfo.Local; + if (date != null) { - if (!string.IsNullOrEmpty(time)) + if (time != null) { - return TimeZoneInfo.ConvertTime(DateTime.Parse(date.Value.Date.ToShortDateString() + " " + time), localTimeZone, TimeZoneInfo.Utc); + DateTime localDateTime = date.Value.Date.Add(time.Value.TimeOfDay); + return TimeZoneInfo.ConvertTimeToUtc(localDateTime, localTimeZone); } - return TimeZoneInfo.ConvertTime(date.Value.Date, localTimeZone, TimeZoneInfo.Utc); + + return TimeZoneInfo.ConvertTimeToUtc(date.Value.Date, localTimeZone); } + return null; } - public static (DateTime? date, string time) UtcAsLocalDateAndTime(DateTime? dateTime, TimeZoneInfo timeZone = null) + public static (DateTime? date, DateTime? time) UtcAsLocalDateAndTime(DateTime? dateTime, TimeZoneInfo timeZone = null) { timeZone ??= TimeZoneInfo.Local; DateTime? localDateTime = null; - string localTime = string.Empty; + DateTime? localTime = null; if (dateTime.HasValue && dateTime?.Kind != DateTimeKind.Local) { if (dateTime?.Kind == DateTimeKind.Unspecified) { // Treat Unspecified as Utc not Local. This is due to EF Core, on some databases, after retrieval will have DateTimeKind as Unspecified. - // All values in database should be UTC. + // All values in the database should be UTC. // Normal .net conversion treats Unspecified as local. // https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo.converttime?view=net-6.0 - localDateTime = TimeZoneInfo.ConvertTime(new DateTime(dateTime.Value.Ticks, DateTimeKind.Utc), timeZone); + localDateTime = TimeZoneInfo.ConvertTime(new DateTimeOffset(dateTime.Value.Ticks, TimeSpan.Zero), timeZone).DateTime; } else { @@ -526,14 +530,17 @@ namespace Oqtane.Shared } } - if (localDateTime != null && localDateTime.Value.TimeOfDay.TotalSeconds != 0) + if (localDateTime != null) { - localTime = localDateTime.Value.ToString("HH:mm"); + localTime = localDateTime.Value.TimeOfDay.TotalSeconds != 0 ? localDateTime.Value.Date.Add(localDateTime.Value.TimeOfDay) : (DateTime?)null; } return (localDateTime?.Date, localTime); } + + + [Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)] public static string ContentUrl(Alias alias, int fileId) { From 96480b43821c6245266724056d8283bcdc513a8a Mon Sep 17 00:00:00 2001 From: Leigh Pointer Date: Fri, 25 Aug 2023 12:09:16 +0200 Subject: [PATCH 2/2] Override and 2 new functions --- Oqtane.Client/Modules/Admin/Jobs/Edit.razor | 13 ++++-- Oqtane.Shared/Shared/Utilities.cs | 52 ++++++++++++++++++--- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor index ec6532b2..249ea3b7 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Edit.razor @@ -132,11 +132,14 @@ _isEnabled = job.IsEnabled.ToString(); _interval = job.Interval.ToString(); _frequency = job.Frequency; - (_startDate, _startTime) = Utilities.UtcAsLocalDateAndTime(job.StartDate); - (_endDate, _endTime) = Utilities.UtcAsLocalDateAndTime(job.EndDate); - _retentionHistory = job.RetentionHistory.ToString(); - (_nextDate, _nextTime) = Utilities.UtcAsLocalDateAndTime(job.NextExecution); - createdby = job.CreatedBy; + _startDate = Utilities.UtcAsLocalDateAndTimeToDate(job.StartDate); + _startTime = Utilities.UtcAsLocalDateAndTimeToTime(job.StartDate); + _endDate = Utilities.UtcAsLocalDateAndTimeToDate(job.EndDate); + _endTime = Utilities.UtcAsLocalDateAndTimeToTime(job.EndDate); + _retentionHistory = job.RetentionHistory.ToString(); + _nextDate = Utilities.UtcAsLocalDateAndTimeToDate(job.NextExecution); + _nextTime = Utilities.UtcAsLocalDateAndTimeToTime(job.NextExecution); + createdby = job.CreatedBy; createdon = job.CreatedOn; modifiedby = job.ModifiedBy; modifiedon = job.ModifiedOn; diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 26eec073..febff300 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -508,21 +508,21 @@ namespace Oqtane.Shared return null; } - public static (DateTime? date, DateTime? time) UtcAsLocalDateAndTime(DateTime? dateTime, TimeZoneInfo timeZone = null) + public static (DateTime? date, string time) UtcAsLocalDateAndTime(DateTime? dateTime, TimeZoneInfo timeZone = null) { timeZone ??= TimeZoneInfo.Local; DateTime? localDateTime = null; - DateTime? localTime = null; + string localTime = string.Empty; if (dateTime.HasValue && dateTime?.Kind != DateTimeKind.Local) { if (dateTime?.Kind == DateTimeKind.Unspecified) { // Treat Unspecified as Utc not Local. This is due to EF Core, on some databases, after retrieval will have DateTimeKind as Unspecified. - // All values in the database should be UTC. + // All values in database should be UTC. // Normal .net conversion treats Unspecified as local. // https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo.converttime?view=net-6.0 - localDateTime = TimeZoneInfo.ConvertTime(new DateTimeOffset(dateTime.Value.Ticks, TimeSpan.Zero), timeZone).DateTime; + localDateTime = TimeZoneInfo.ConvertTime(new DateTime(dateTime.Value.Ticks, DateTimeKind.Utc), timeZone); } else { @@ -530,16 +530,56 @@ namespace Oqtane.Shared } } - if (localDateTime != null) + if (localDateTime != null && localDateTime.Value.TimeOfDay.TotalSeconds != 0) { - localTime = localDateTime.Value.TimeOfDay.TotalSeconds != 0 ? localDateTime.Value.Date.Add(localDateTime.Value.TimeOfDay) : (DateTime?)null; + localTime = localDateTime.Value.ToString("HH:mm"); } return (localDateTime?.Date, localTime); } + public static DateTime? LocalDateAndTimeAsUtc(DateTime? date, string time, TimeZoneInfo localTimeZone = null) + { + localTimeZone ??= TimeZoneInfo.Local; + if (date != null) + { + if (!string.IsNullOrEmpty(time)) + { + return TimeZoneInfo.ConvertTime(DateTime.Parse(date.Value.Date.ToShortDateString() + " " + time), localTimeZone, TimeZoneInfo.Utc); + } + return TimeZoneInfo.ConvertTime(date.Value.Date, localTimeZone, TimeZoneInfo.Utc); + } + return null; + } + public static DateTime? UtcAsLocalDateAndTimeToDate(DateTime? dateTime, TimeZoneInfo timeZone = null) + { + var result = UtcAsLocalDateAndTime(dateTime, timeZone); + return result.date; + } + public static DateTime? UtcAsLocalDateAndTimeToTime(DateTime? dateTime, TimeZoneInfo timeZone = null) + { + var result = UtcAsLocalDateAndTime(dateTime, timeZone); + if (string.IsNullOrEmpty(result.time)) + { + return result.date; + } + else + { + var timeParts = result.time.Split(':'); + if (timeParts.Length == 2 && int.TryParse(timeParts[0], out int hours) && int.TryParse(timeParts[1], out int minutes)) + { + TimeSpan timeOfDay = new TimeSpan(hours, minutes, 0); + return result.date?.Date + timeOfDay; + } + else + { + // Handle parsing error + return null; + } + } + } [Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)] public static string ContentUrl(Alias alias, int fileId)