Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

epoch should be UTC? #2651

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ internal static partial class Library
/// </summary>
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<T>(this IServiceProvider services, T defaultService)
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Microsoft.PowerFx.Repl/Repl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,8 @@ public virtual async Task<ReplResult> HandleCommandAsync(string expression, Canc
ServiceProvider = new BasicServiceProvider(this.InnerServices)
};

runtimeConfig.SetTimeZone(TimeZoneInfo.Local);

if (this.UserInfo != null)
{
if (!_userEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
Loading