From 111d2bf2647683a5a7711f08bc8b73e42e249592 Mon Sep 17 00:00:00 2001 From: TekH Date: Wed, 8 Jul 2026 10:36:13 +0200 Subject: [PATCH] fix(domain): use DateTime.Now instead of DateTime.UtcNow for legacy compatibility CRITICAL FIX: Replace all DateTime.UtcNow with DateTime.Now throughout the application. Reason: Legacy VB.NET system uses local server time, and database stores all timestamps as local time. Using UTC breaks compatibility and causes incorrect time comparisons. Changes: - EmailProcessedEvent: ProcessedDate now uses DateTime.Now - EmailHistory.MarkAsProcessed(): ProcessedDate now uses DateTime.Now - EmailHistory.MarkAsFailed(): ProcessedDate now uses DateTime.Now - EmailProfile.UpdateLastPollTime(): LastPollTime now uses DateTime.Now - EmailProfile.ShouldPoll(): Poll interval comparison now uses DateTime.Now Documentation: - Added critical note to agents.md about DateTime usage - Includes examples and detailed explanation for future developers This ensures all date/time operations remain compatible with legacy database. --- agents.md | 24 ++++++++++++++++++- .../Entities/EmailHistory.cs | 4 ++-- .../Entities/EmailProfile.cs | 4 ++-- .../Events/EmailProcessedEvent.cs | 21 +++++----------- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/agents.md b/agents.md index bd8cbb7..4464866 100644 --- a/agents.md +++ b/agents.md @@ -33,7 +33,29 @@ The `MessageIdGenerator` in `Domain.Services` must use **exactly the same algori **Algorithm**: SHA256 hash of `{originalMessageId}|{sender}|{date:yyyyMMddHHmmss}|{subject}` -### 3. No Commits Without Permission +### 3. DateTime Usage - ALWAYS Use Local Time +**CRITICAL**: Always use `DateTime.Now` instead of `DateTime.UtcNow` throughout the entire application. + +**Reason**: The legacy system uses local server time, and the database stores all timestamps as local time. Using UTC would break compatibility and cause incorrect time comparisons. + +**Examples**: +```csharp +// ✅ CORRECT +profile.CreatedDate = DateTime.Now; +var lastPoll = DateTime.Now.AddMinutes(-profile.PollIntervalMinutes); + +// ❌ WRONG - DO NOT USE +profile.CreatedDate = DateTime.UtcNow; // NEVER USE UTC +var lastPoll = DateTime.UtcNow.AddMinutes(-profile.PollIntervalMinutes); // NEVER USE UTC +``` + +**Important**: This applies to: +- All entity audit fields (CreatedDate, ModifiedDate, LastPollDate, etc.) +- All date comparisons in business logic +- All timestamps in logs and error messages +- All date parameters in queries + +### 4. No Commits Without Permission **NEVER** commit changes to git automatically. Always wait for explicit user instruction to commit. --- diff --git a/src/DigitalData.EmailProfiler.Domain/Entities/EmailHistory.cs b/src/DigitalData.EmailProfiler.Domain/Entities/EmailHistory.cs index a262d64..35724a9 100644 --- a/src/DigitalData.EmailProfiler.Domain/Entities/EmailHistory.cs +++ b/src/DigitalData.EmailProfiler.Domain/Entities/EmailHistory.cs @@ -99,7 +99,7 @@ public class EmailHistory : BaseEntity public void MarkAsProcessed() { Status = EmailStatus.Processed.ToString(); - ProcessedDate = DateTime.UtcNow; + ProcessedDate = DateTime.Now; } public void MarkAsFailed(ErrorCode errorCode, string message) @@ -107,6 +107,6 @@ public class EmailHistory : BaseEntity Status = EmailStatus.Failed.ToString(); ErrorCodeValue = (int)errorCode; ErrorMessage = message; - ProcessedDate = DateTime.UtcNow; + ProcessedDate = DateTime.Now; } } diff --git a/src/DigitalData.EmailProfiler.Domain/Entities/EmailProfile.cs b/src/DigitalData.EmailProfiler.Domain/Entities/EmailProfile.cs index b6b965e..15b261f 100644 --- a/src/DigitalData.EmailProfiler.Domain/Entities/EmailProfile.cs +++ b/src/DigitalData.EmailProfiler.Domain/Entities/EmailProfile.cs @@ -77,12 +77,12 @@ public class EmailProfile : BaseEntity, IAggregateRoot public virtual ICollection EmailHistories { get; set; } = new List(); // Domain methods - public void UpdateLastPollTime() => LastPollTime = DateTime.UtcNow; + public void UpdateLastPollTime() => LastPollTime = DateTime.Now; public bool ShouldPoll() { if (!IsActive) return false; if (!LastPollTime.HasValue) return true; - return DateTime.UtcNow >= LastPollTime.Value.AddMinutes(PollIntervalMinutes); + return DateTime.Now >= LastPollTime.Value.AddMinutes(PollIntervalMinutes); } } diff --git a/src/DigitalData.EmailProfiler.Domain/Events/EmailProcessedEvent.cs b/src/DigitalData.EmailProfiler.Domain/Events/EmailProcessedEvent.cs index 19e5562..1f1be62 100644 --- a/src/DigitalData.EmailProfiler.Domain/Events/EmailProcessedEvent.cs +++ b/src/DigitalData.EmailProfiler.Domain/Events/EmailProcessedEvent.cs @@ -3,20 +3,11 @@ using DigitalData.EmailProfiler.Domain.Enums; namespace DigitalData.EmailProfiler.Domain.Events; -public class EmailProcessedEvent : INotification +public class EmailProcessedEvent(int emailHistoryId, int profileId, string messageId, EmailStatus status) : INotification { - public int EmailHistoryId { get; } - public int ProfileId { get; } - public string MessageId { get; } - public EmailStatus Status { get; } - public DateTime ProcessedDate { get; } - - public EmailProcessedEvent(int emailHistoryId, int profileId, string messageId, EmailStatus status) - { - EmailHistoryId = emailHistoryId; - ProfileId = profileId; - MessageId = messageId; - Status = status; - ProcessedDate = DateTime.UtcNow; - } + public int EmailHistoryId { get; } = emailHistoryId; + public int ProfileId { get; } = profileId; + public string MessageId { get; } = messageId; + public EmailStatus Status { get; } = status; + public DateTime ProcessedDate { get; } = DateTime.Now; }