Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 20 additions & 22 deletions Core/Resgrid.Model/Helpers/TimeConverterHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,28 +12,26 @@ public static class TimeConverterHelper
{
public static DateTime TimeConverter(this DateTime timestamp, Department department)
{
DateTime newTime = timestamp;
TimeZoneInfo timeZoneInfo = null;

// If department is null we gotta just bail
if (department == null)
return timestamp;

try
{
string timeZone = "Pacific Standard Time"; // Default to Pacific as it's better then UTC

if (!String.IsNullOrEmpty(department.TimeZone))
timeZoneInfo =
TZConvert.GetTimeZoneInfo(
DateTimeHelpers.ConvertTimeZoneString(department
.TimeZone)); // TimeZoneInfo.FindSystemTimeZoneById(DateTimeHelpers.ConvertTimeZoneString(department.TimeZone));
else
timeZoneInfo = TZConvert.GetTimeZoneInfo("Pacific Standard Time");// TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"); // Default to Pacific as it's better then UTC
timeZone = department.TimeZone;

if (timeZoneInfo != null)
{
newTime = TimeZoneInfo.ConvertTimeFromUtc(timestamp, timeZoneInfo);
}
return newTime;
// Resolve via NodaTime's embedded IANA database instead of TimeZoneInfo /
// TZConvert.GetTimeZoneInfo. The hardened (DHI) container ships without ICU and
// runs in globalization-invariant mode, where TimeZoneInfo cannot map a Windows
// zone id and throws TimeZoneNotFoundException. NodaTime carries its own tzdb and
// needs neither ICU nor the OS /usr/share/zoneinfo files. Mirrors TimeConverterToString.
var ianaTz = TZConvert.WindowsToIana(DateTimeHelpers.ConvertTimeZoneString(timeZone));

var instant = Instant.FromDateTimeUtc(DateTime.SpecifyKind(timestamp, DateTimeKind.Utc));
return instant.InZone(DateTimeZoneProviders.Tzdb[ianaTz]).ToDateTimeUnspecified();
}
catch (Exception ex)
{
Expand Down Expand Up @@ -101,21 +99,21 @@ public static string FormatForDepartment(this DateTime timestamp, Department dep

public static TimeSpan GetOffsetForDepartment(Department department)
{
TimeZoneInfo timeZoneInfo = null;
TimeSpan timeSpan;

try
{
string timeZone = "Pacific Standard Time"; // Default to Pacific as it's better then UTC

if (!String.IsNullOrEmpty(department.TimeZone))
timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(DateTimeHelpers.ConvertTimeZoneString(department.TimeZone));
else
timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(DateTimeHelpers.WindowsToIana("Pacific Standard Time")); // Default to Pacific as it's better then UTC
timeZone = department.TimeZone;

timeSpan = timeZoneInfo.BaseUtcOffset;
var currentDateTime = DateTime.UtcNow.TimeConverter(department);
// NodaTime tzdb (no ICU / OS tzdata dependency, unlike TimeZoneInfo). GetUtcOffset
// already folds the active DST rule into the returned offset for the given instant.
var ianaTz = TZConvert.WindowsToIana(DateTimeHelpers.ConvertTimeZoneString(timeZone));
var instant = Instant.FromDateTimeUtc(DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc));

if (timeZoneInfo.GetAdjustmentRules() != null && timeZoneInfo.GetAdjustmentRules().Any())
timeSpan = timeZoneInfo.GetAdjustmentRules().Where(timeZoneAdjustment => timeZoneAdjustment.DateStart <= currentDateTime && timeZoneAdjustment.DateEnd >= currentDateTime).Aggregate(timeSpan, (current, timeZoneAdjustment) => current + timeZoneAdjustment.DaylightDelta);
timeSpan = DateTimeZoneProviders.Tzdb[ianaTz].GetUtcOffset(instant).ToTimeSpan();
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using NodaTime;
using Resgrid.Model;
using Resgrid.Model.Identity;
using Resgrid.Model.Providers;
using TimeZoneConverter;

namespace Resgrid.Services.CallEmailTemplates
{
Expand Down Expand Up @@ -51,8 +53,17 @@ public async Task<Call> GenerateCall(CallEmail email, string managingUser, List<
var priorityString = c.Name.Substring(0, c.Name.IndexOf(char.Parse("-"))).Trim();
priorityChar = Regex.Replace(priorityString, @"\d", "").Trim();

TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(department.TimeZone);
callTimeUtc = new DateTimeOffset(DateTime.Parse(data[0].Replace("Date:", "").Trim()), timeZone.BaseUtcOffset).UtcDateTime;
// NodaTime tzdb (no ICU / OS tzdata) — DHI runs in globalization-invariant mode where
// TimeZoneInfo.FindSystemTimeZoneById can't resolve a Windows zone id. InZoneLeniently is
// DST-aware (the prior BaseUtcOffset ignored DST, drifting an hour for ~8 months/year) and never throws.
// Default to Pacific (matches TimeConverterHelper) so WindowsToIana never receives a null/blank id
// and throws InvalidTimeZoneException, which would silently downgrade callTimeUtc to processing-time UTC.
var windowsTz = String.IsNullOrWhiteSpace(department.TimeZone)
? "Pacific Standard Time"
: department.TimeZone;
var ianaTz = TZConvert.WindowsToIana(windowsTz);
var localCallTime = LocalDateTime.FromDateTime(DateTime.Parse(data[0].Replace("Date:", "").Trim()));
callTimeUtc = localCallTime.InZoneLeniently(DateTimeZoneProviders.Tzdb[ianaTz]).ToDateTimeUtc();
Comment thread
coderabbitai[bot] marked this conversation as resolved.

is2ndPage = c.Notes.Contains("WCT2ndPage");

Expand Down
11 changes: 7 additions & 4 deletions Core/Resgrid.Services/WorkflowTemplateContextBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Resgrid.Framework;
using Resgrid.Model;
using Resgrid.Model.Events;
using Resgrid.Model.Providers;
Expand Down Expand Up @@ -357,10 +358,12 @@ private static void AddCommonTimestampVariables(ScriptObject obj, string timeZon
DateTime deptNow;
try
{
var tz = !string.IsNullOrWhiteSpace(timeZoneId)
? TimeZoneInfo.FindSystemTimeZoneById(timeZoneId)
: TimeZoneInfo.Utc;
deptNow = TimeZoneInfo.ConvertTimeFromUtc(utcNow, tz);
// NodaTime tzdb (no ICU / OS tzdata). DHI runs in globalization-invariant mode where
// TimeZoneInfo.FindSystemTimeZoneById can't map a Windows zone id (TimeZoneNotFoundException).
// DateTimeHelpers.GetLocalDateTime resolves UTC -> department-local via the embedded tzdb.
deptNow = string.IsNullOrWhiteSpace(timeZoneId)
? utcNow
: DateTimeHelpers.GetLocalDateTime(utcNow, timeZoneId);
}
catch
{
Expand Down
Loading