From ac28974140dd5d01026b0975b4a17aa4933fa610 Mon Sep 17 00:00:00 2001 From: jas-valgotar Date: Wed, 25 Sep 2024 20:57:10 -0400 Subject: [PATCH] wip --- .../Public/Values/DateTimeValue.cs | 38 +++++++++---------- .../Functions/Library.cs | 7 +++- src/libraries/Microsoft.PowerFx.Repl/Repl.cs | 2 + .../ConfigTests.cs | 15 ++++++++ 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Values/DateTimeValue.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Values/DateTimeValue.cs index cc6889d287..21507f5e89 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Values/DateTimeValue.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Values/DateTimeValue.cs @@ -39,37 +39,33 @@ public DateTime GetConvertedValue(TimeZoneInfo timeZoneInfo) internal static DateTime GetConvertedDateTimeValue(DateTime value, TimeZoneInfo timeZoneInfo) { - // If timeZoneInfo is null and stored value is in UTC, we don't want to convert. - if (timeZoneInfo == null && value.Kind == DateTimeKind.Utc) - { - timeZoneInfo = TimeZoneInfo.Utc; - } - else if (timeZoneInfo == null) + // Ensure timeZoneInfo is not null; default to local time zone if it is. + if (timeZoneInfo == null) { timeZoneInfo = TimeZoneInfo.Local; } - - // Since we can't convert LocalKind time to UTC, if the time was of kind local just change kind. - if (value.Kind == DateTimeKind.Local && timeZoneInfo.Equals(TimeZoneInfo.Utc)) - { - return DateTime.SpecifyKind(value, DateTimeKind.Utc); - } - else if (value.Kind == DateTimeKind.Local && !timeZoneInfo.Equals(TimeZoneInfo.Utc)) + + DateTime result; + + if (value.Kind == DateTimeKind.Local) { - // This code should be modified as we don't return a UTC time here - // https://github.com/microsoft/Power-Fx/issues/1931 - return DateTime.SpecifyKind(value, DateTimeKind.Unspecified); + // Convert from local time to the specified time zone. + result = TimeZoneInfo.ConvertTime(value, TimeZoneInfo.Local, timeZoneInfo); } - else if (value.Kind == DateTimeKind.Unspecified && timeZoneInfo.Equals(TimeZoneInfo.Utc)) + else if (value.Kind == DateTimeKind.Utc) { - return TimeZoneInfo.ConvertTimeToUtc(value, timeZoneInfo); + // Convert from UTC to the specified time zone. + result = TimeZoneInfo.ConvertTimeFromUtc(value, timeZoneInfo); } - else if (value.Kind == DateTimeKind.Utc && !timeZoneInfo.Equals(TimeZoneInfo.Utc)) + else { - return TimeZoneInfo.ConvertTime(value, timeZoneInfo); + // DateTimeKind.Unspecified + // Assume the unspecified DateTime is in the specified time zone. + // If you need to convert it to another time zone, specify the source time zone. + result = DateTime.SpecifyKind(value, DateTimeKind.Unspecified); } - return value; + return result; } internal DateTimeValue(IRContext irContext, DateTime value) diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/Library.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/Library.cs index 367e632f10..d4054d7519 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/Library.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/Library.cs @@ -28,7 +28,12 @@ internal static partial class Library /// public static readonly TexlFunction DistinctInterpreterFunction = new DistinctFunction(); - internal static readonly DateTime _epoch = new DateTime(1899, 12, 30, 0, 0, 0, 0); + internal static readonly DateTime _epoch = new DateTime(1899, 12, 30, 0, 0, 0, 0, DateTimeKind.Utc); + + internal static DateTime Epoch(TimeZoneInfo tzi) + { + return TimeZoneInfo.ConvertTimeFromUtc(_epoch, tzi); + } // Helper to get a service or fallback to a default if the service is missing. private static T GetService(this IServiceProvider services, T defaultService) diff --git a/src/libraries/Microsoft.PowerFx.Repl/Repl.cs b/src/libraries/Microsoft.PowerFx.Repl/Repl.cs index 1d0657ff1b..44d75750bf 100644 --- a/src/libraries/Microsoft.PowerFx.Repl/Repl.cs +++ b/src/libraries/Microsoft.PowerFx.Repl/Repl.cs @@ -254,6 +254,8 @@ public virtual async Task HandleCommandAsync(string expression, Canc ServiceProvider = new BasicServiceProvider(this.InnerServices) }; + runtimeConfig.SetTimeZone(TimeZoneInfo.Local); + if (this.UserInfo != null) { if (!_userEnabled) diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/ConfigTests.cs b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/ConfigTests.cs index b189dc4194..907567b4c8 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/ConfigTests.cs +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/ConfigTests.cs @@ -35,6 +35,21 @@ public async Task BasicEvaluation() Assert.Equal(5.0, result.ToObject()); } + [Fact] + public async Task TestDecimalToDateTimeCoercion() + { + // Per expression. + var engine = new RecalcEngine(); + var rc = new RuntimeConfig(); + rc.SetTimeZone(TimeZoneInfo.Utc); + + var res = await engine.EvalAsync("If(false, DateTime(1899, 12, 30, 0, 0, 0, 0), 0)", CancellationToken.None, runtimeConfig: rc); + + var dt = res.ToObject(); + + Assert.Equal(DateTimeKind.Utc, ((DateTime)dt).Kind); + } + [Fact] public async Task BasicDirectEvalFunc() {