From 33fd92d015e1c23ba13c4661b2df5b9538b416af Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 1 Oct 2024 02:39:01 +0700 Subject: [PATCH] Fix DateTimeOffset.DateTime UTC bug (#7349) Co-authored-by: Aaron Stannard --- .../verify/CoreAPISpec.ApproveCore.DotNet.verified.txt | 4 ++++ .../verify/CoreAPISpec.ApproveCore.Net.verified.txt | 4 ++++ .../CoreAPISpec.ApproveTestKit.DotNet.verified.txt | 1 + .../verify/CoreAPISpec.ApproveTestKit.Net.verified.txt | 1 + src/core/Akka.Persistence/Eventsourced.cs | 2 +- src/core/Akka.TestKit/TestScheduler.cs | 4 ++++ src/core/Akka.Tests/Actor/ActorSystemSpec.cs | 1 + .../Akka.Tests/Actor/Scheduler/SchedulerShutdownSpec.cs | 1 + src/core/Akka/Actor/Scheduler/DateTimeNowTimeProvider.cs | 2 ++ .../Akka/Actor/Scheduler/HashedWheelTimerScheduler.cs | 5 +++++ src/core/Akka/Actor/Scheduler/ITimeProvider.cs | 6 +++++- src/core/Akka/Actor/Scheduler/SchedulerBase.cs | 9 ++++++++- 12 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt index 60fa2406c64..07d24aa497a 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt @@ -592,6 +592,7 @@ namespace Akka.Actor [System.ObsoleteAttribute("This class will be removed in Akka.NET v1.6.0 - use the IScheduler instead.")] public class DateTimeOffsetNowTimeProvider : Akka.Actor.IDateTimeOffsetNowTimeProvider, Akka.Actor.ITimeProvider { + public System.DateTime DateTimeNow { get; } public System.TimeSpan HighResMonotonicClock { get; } public static Akka.Actor.DateTimeOffsetNowTimeProvider Instance { get; } public System.TimeSpan MonotonicClock { get; } @@ -932,6 +933,7 @@ namespace Akka.Actor public sealed class HashedWheelTimerScheduler : Akka.Actor.SchedulerBase, Akka.Actor.IDateTimeOffsetNowTimeProvider, Akka.Actor.ITimeProvider, System.IDisposable { public HashedWheelTimerScheduler(Akka.Configuration.Config scheduler, Akka.Event.ILoggingAdapter log) { } + protected override System.DateTime DateTimeNow { get; } public override System.TimeSpan HighResMonotonicClock { get; } public override System.TimeSpan MonotonicClock { get; } protected override System.DateTimeOffset TimeNow { get; } @@ -1172,6 +1174,7 @@ namespace Akka.Actor } public interface ITimeProvider { + System.DateTime DateTimeNow { get; } System.TimeSpan HighResMonotonicClock { get; } System.TimeSpan MonotonicClock { get; } System.DateTimeOffset Now { get; } @@ -1622,6 +1625,7 @@ namespace Akka.Actor protected readonly Akka.Event.ILoggingAdapter Log; protected readonly Akka.Configuration.Config SchedulerConfig; protected SchedulerBase(Akka.Configuration.Config scheduler, Akka.Event.ILoggingAdapter log) { } + protected abstract System.DateTime DateTimeNow { get; } public abstract System.TimeSpan HighResMonotonicClock { get; } public abstract System.TimeSpan MonotonicClock { get; } protected abstract System.DateTimeOffset TimeNow { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt index eccf3f67d9b..c9b83f24a7d 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt @@ -592,6 +592,7 @@ namespace Akka.Actor [System.ObsoleteAttribute("This class will be removed in Akka.NET v1.6.0 - use the IScheduler instead.")] public class DateTimeOffsetNowTimeProvider : Akka.Actor.IDateTimeOffsetNowTimeProvider, Akka.Actor.ITimeProvider { + public System.DateTime DateTimeNow { get; } public System.TimeSpan HighResMonotonicClock { get; } public static Akka.Actor.DateTimeOffsetNowTimeProvider Instance { get; } public System.TimeSpan MonotonicClock { get; } @@ -930,6 +931,7 @@ namespace Akka.Actor public sealed class HashedWheelTimerScheduler : Akka.Actor.SchedulerBase, Akka.Actor.IDateTimeOffsetNowTimeProvider, Akka.Actor.ITimeProvider, System.IDisposable { public HashedWheelTimerScheduler(Akka.Configuration.Config scheduler, Akka.Event.ILoggingAdapter log) { } + protected override System.DateTime DateTimeNow { get; } public override System.TimeSpan HighResMonotonicClock { get; } public override System.TimeSpan MonotonicClock { get; } protected override System.DateTimeOffset TimeNow { get; } @@ -1170,6 +1172,7 @@ namespace Akka.Actor } public interface ITimeProvider { + System.DateTime DateTimeNow { get; } System.TimeSpan HighResMonotonicClock { get; } System.TimeSpan MonotonicClock { get; } System.DateTimeOffset Now { get; } @@ -1620,6 +1623,7 @@ namespace Akka.Actor protected readonly Akka.Event.ILoggingAdapter Log; protected readonly Akka.Configuration.Config SchedulerConfig; protected SchedulerBase(Akka.Configuration.Config scheduler, Akka.Event.ILoggingAdapter log) { } + protected abstract System.DateTime DateTimeNow { get; } public abstract System.TimeSpan HighResMonotonicClock { get; } public abstract System.TimeSpan MonotonicClock { get; } protected abstract System.DateTimeOffset TimeNow { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.DotNet.verified.txt index 55cff536c32..31de4931eff 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.DotNet.verified.txt @@ -577,6 +577,7 @@ namespace Akka.TestKit { public TestScheduler(Akka.Configuration.Config schedulerConfig, Akka.Event.ILoggingAdapter log) { } public Akka.Actor.IAdvancedScheduler Advanced { get; } + public System.DateTime DateTimeNow { get; } public System.TimeSpan HighResMonotonicClock { get; } public System.TimeSpan MonotonicClock { get; } public System.DateTimeOffset Now { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.Net.verified.txt index 681fff75319..43d0479d33c 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveTestKit.Net.verified.txt @@ -577,6 +577,7 @@ namespace Akka.TestKit { public TestScheduler(Akka.Configuration.Config schedulerConfig, Akka.Event.ILoggingAdapter log) { } public Akka.Actor.IAdvancedScheduler Advanced { get; } + public System.DateTime DateTimeNow { get; } public System.TimeSpan HighResMonotonicClock { get; } public System.TimeSpan MonotonicClock { get; } public System.DateTimeOffset Now { get; } diff --git a/src/core/Akka.Persistence/Eventsourced.cs b/src/core/Akka.Persistence/Eventsourced.cs index 4d34a40745e..04683204439 100644 --- a/src/core/Akka.Persistence/Eventsourced.cs +++ b/src/core/Akka.Persistence/Eventsourced.cs @@ -218,7 +218,7 @@ public void LoadSnapshot(string persistenceId, SnapshotSelectionCriteria criteri /// TBD public void SaveSnapshot(object snapshot) { - SnapshotStore.Tell(new SaveSnapshot(new SnapshotMetadata(SnapshotterId, SnapshotSequenceNr, Context.System.Scheduler.Now.Date), snapshot)); + SnapshotStore.Tell(new SaveSnapshot(new SnapshotMetadata(SnapshotterId, SnapshotSequenceNr, Context.System.Scheduler.DateTimeNow), snapshot)); } /// diff --git a/src/core/Akka.TestKit/TestScheduler.cs b/src/core/Akka.TestKit/TestScheduler.cs index 43e39765176..73d64b5e51c 100644 --- a/src/core/Akka.TestKit/TestScheduler.cs +++ b/src/core/Akka.TestKit/TestScheduler.cs @@ -212,6 +212,10 @@ public void ScheduleRepeatedly(TimeSpan initialDelay, TimeSpan interval, Action /// /// TBD /// + public DateTime DateTimeNow { get { return DateTime.SpecifyKind(_now.DateTime, DateTimeKind.Utc); } } + /// + /// TBD + /// public TimeSpan MonotonicClock { get { return Util.MonotonicClock.Elapsed; } } /// /// TBD diff --git a/src/core/Akka.Tests/Actor/ActorSystemSpec.cs b/src/core/Akka.Tests/Actor/ActorSystemSpec.cs index d6b02a7d71f..658c913c3b1 100644 --- a/src/core/Akka.Tests/Actor/ActorSystemSpec.cs +++ b/src/core/Akka.Tests/Actor/ActorSystemSpec.cs @@ -452,6 +452,7 @@ public void ScheduleTellRepeatedly(TimeSpan initialDelay, TimeSpan interval, ICa } public DateTimeOffset Now { get; private set; } + public DateTime DateTimeNow { get; private set; } public TimeSpan MonotonicClock { get; private set; } public TimeSpan HighResMonotonicClock { get; private set; } public IAdvancedScheduler Advanced { get; private set; } diff --git a/src/core/Akka.Tests/Actor/Scheduler/SchedulerShutdownSpec.cs b/src/core/Akka.Tests/Actor/Scheduler/SchedulerShutdownSpec.cs index bf613c85095..929fcb5c939 100644 --- a/src/core/Akka.Tests/Actor/Scheduler/SchedulerShutdownSpec.cs +++ b/src/core/Akka.Tests/Actor/Scheduler/SchedulerShutdownSpec.cs @@ -36,6 +36,7 @@ private class ShutdownScheduler : SchedulerBase, IDisposable protected override DateTimeOffset TimeNow { get; } + protected override DateTime DateTimeNow { get; } public override TimeSpan MonotonicClock { get; } public override TimeSpan HighResMonotonicClock { get; } diff --git a/src/core/Akka/Actor/Scheduler/DateTimeNowTimeProvider.cs b/src/core/Akka/Actor/Scheduler/DateTimeNowTimeProvider.cs index d8784095c64..2ed4ef2f36d 100644 --- a/src/core/Akka/Actor/Scheduler/DateTimeNowTimeProvider.cs +++ b/src/core/Akka/Actor/Scheduler/DateTimeNowTimeProvider.cs @@ -19,6 +19,8 @@ private DateTimeOffsetNowTimeProvider() { } public DateTimeOffset Now { get { return DateTimeOffset.UtcNow; } } + public DateTime DateTimeNow => DateTime.UtcNow; + public TimeSpan MonotonicClock {get { return Util.MonotonicClock.Elapsed; }} public TimeSpan HighResMonotonicClock{get { return Util.MonotonicClock.ElapsedHighRes; }} diff --git a/src/core/Akka/Actor/Scheduler/HashedWheelTimerScheduler.cs b/src/core/Akka/Actor/Scheduler/HashedWheelTimerScheduler.cs index 78429b41754..ce346ff52c4 100644 --- a/src/core/Akka/Actor/Scheduler/HashedWheelTimerScheduler.cs +++ b/src/core/Akka/Actor/Scheduler/HashedWheelTimerScheduler.cs @@ -396,6 +396,11 @@ private void PlaceInBucket(SchedulerRegistration reg) /// protected override DateTimeOffset TimeNow => DateTimeOffset.UtcNow; + /// + /// TBD + /// + protected override DateTime DateTimeNow => DateTime.UtcNow; + /// /// TBD /// diff --git a/src/core/Akka/Actor/Scheduler/ITimeProvider.cs b/src/core/Akka/Actor/Scheduler/ITimeProvider.cs index 6f8f30a5adf..a889ddab8e0 100644 --- a/src/core/Akka/Actor/Scheduler/ITimeProvider.cs +++ b/src/core/Akka/Actor/Scheduler/ITimeProvider.cs @@ -20,10 +20,14 @@ namespace Akka.Actor public interface ITimeProvider { /// - /// Gets the scheduler's notion of current time. + /// Gets the scheduler's notion of current time in . /// DateTimeOffset Now { get; } /// + /// Gets the scheduler's notion of current time in . + /// + DateTime DateTimeNow { get; } + /// /// TBD /// TimeSpan MonotonicClock { get; } diff --git a/src/core/Akka/Actor/Scheduler/SchedulerBase.cs b/src/core/Akka/Actor/Scheduler/SchedulerBase.cs index c5416e16535..7e11197ec01 100644 --- a/src/core/Akka/Actor/Scheduler/SchedulerBase.cs +++ b/src/core/Akka/Actor/Scheduler/SchedulerBase.cs @@ -97,11 +97,18 @@ void IActionScheduler.ScheduleRepeatedly(TimeSpan initialDelay, TimeSpan interva IAdvancedScheduler IScheduler.Advanced { get { return this; } } DateTimeOffset ITimeProvider.Now { get { return TimeNow; } } + DateTime ITimeProvider.DateTimeNow => DateTime.SpecifyKind(TimeNow.DateTime, DateTimeKind.Utc); + /// - /// The current time in UTC. + /// The current time in UTC. /// protected abstract DateTimeOffset TimeNow { get; } + /// + /// The current time in UTC. + /// + protected abstract DateTime DateTimeNow { get; } + /// /// The current time since startup, as determined by the monotonic clock implementation. ///