Support DateTimeFormat.UTC in Text (#1246)

Fix issue: https://github.com/microsoft/Power-Fx/issues/1240
This commit is contained in:
Hoa Nguyen 2023-03-27 14:38:50 -07:00 коммит произвёл GitHub
Родитель 3cddde71f3
Коммит ffd33c7eb2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 74 добавлений и 16 удалений

Просмотреть файл

@ -47,7 +47,7 @@ namespace Microsoft.PowerFx.Functions
private static readonly Regex _minutesDetokenizeRegex = new Regex("[\u000A][\u000A]+", RegExFlags);
private static readonly Regex _secondsDetokenizeRegex = new Regex("[\u0008][\u0008]+", RegExFlags);
private static readonly Regex _milisecondsDetokenizeRegex = new Regex("[\u000e]+", RegExFlags);
// Char is used for PA string escaping
public static FormulaValue Char(IRContext irContext, NumberValue[] args)
{
@ -264,7 +264,7 @@ namespace Microsoft.PowerFx.Functions
// It's a number, formatted as date/time. Let's convert it to a date/time value first
var newDateTime = Library.NumberToDateTime(formatInfo, IRContext.NotInSource(FormulaType.DateTime), num);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "g", newDateTime.GetConvertedValue(timeZoneInfo), culture, formatInfo.CancellationToken, out result);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "g", newDateTime.GetConvertedValue(timeZoneInfo), timeZoneInfo, culture, formatInfo.CancellationToken, out result);
}
else
{
@ -281,7 +281,7 @@ namespace Microsoft.PowerFx.Functions
}
else
{
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "g", dateTimeValue.GetConvertedValue(timeZoneInfo), culture, formatInfo.CancellationToken, out result);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "g", dateTimeValue.GetConvertedValue(timeZoneInfo), timeZoneInfo, culture, formatInfo.CancellationToken, out result);
}
break;
@ -293,7 +293,7 @@ namespace Microsoft.PowerFx.Functions
}
else
{
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "d", dateValue.GetConvertedValue(timeZoneInfo), culture, formatInfo.CancellationToken, out result);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "d", dateValue.GetConvertedValue(timeZoneInfo), timeZoneInfo, culture, formatInfo.CancellationToken, out result);
}
break;
@ -306,7 +306,7 @@ namespace Microsoft.PowerFx.Functions
else
{
var dtValue = Library.TimeToDateTime(formatInfo, IRContext.NotInSource(FormulaType.DateTime), timeValue);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "t", dtValue.GetConvertedValue(timeZoneInfo), culture, formatInfo.CancellationToken, out result);
return TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, formatString, "t", dtValue.GetConvertedValue(timeZoneInfo), timeZoneInfo, culture, formatInfo.CancellationToken, out result);
}
break;
@ -321,14 +321,7 @@ namespace Microsoft.PowerFx.Functions
return result != null;
}
internal static FormulaValue ExpandDateTimeExcelFormatSpecifiers(IRContext irContext, string format, string defaultFormat, DateTime dateTime, CultureInfo culture, CancellationToken cancellationToken)
{
bool isStringValue = TryExpandDateTimeExcelFormatSpecifiersToStringValue(irContext, format, defaultFormat, dateTime, culture, cancellationToken, out StringValue result);
return isStringValue ? result : CommonErrors.GenericInvalidArgument(irContext, StringResources.Get(TexlStrings.ErrTextInvalidFormat, culture.Name));
}
internal static bool TryExpandDateTimeExcelFormatSpecifiersToStringValue(IRContext irContext, string format, string defaultFormat, DateTime dateTime, CultureInfo culture, CancellationToken cancellationToken, out StringValue result)
internal static bool TryExpandDateTimeExcelFormatSpecifiersToStringValue(IRContext irContext, string format, string defaultFormat, DateTime dateTime, TimeZoneInfo timeZoneInfo, CultureInfo culture, CancellationToken cancellationToken, out StringValue result)
{
result = null;
if (format == null)
@ -353,6 +346,11 @@ namespace Microsoft.PowerFx.Functions
var formatStr = ExpandDateTimeFormatSpecifiers(format, culture);
result = new StringValue(irContext, dateTime.ToString(formatStr, culture));
break;
case "'utc'":
case "utc":
var formatUtcStr = ExpandDateTimeFormatSpecifiers(format, culture);
result = new StringValue(irContext, ConvertToUTC(dateTime, timeZoneInfo).ToString(formatUtcStr, culture));
break;
default:
try
{
@ -399,7 +397,8 @@ namespace Microsoft.PowerFx.Functions
case "'longdate'":
return info.LongDatePattern;
case "'utc'":
return info.UniversalSortableDateTimePattern;
case "utc":
return "yyyy-MM-ddTHH:mm:ss.fffZ";
default:
return format;
}
@ -857,7 +856,7 @@ namespace Microsoft.PowerFx.Functions
{
break;
}
if (--instanceNum == 0)
{
strBuilder.Replace(match.Value, replacement.Value, idx, match.Value.Length);
@ -868,7 +867,7 @@ namespace Microsoft.PowerFx.Functions
return new StringValue(irContext, strBuilder.ToString());
}
public static FormulaValue StartsWith(IRContext irContext, StringValue[] args)
{
var text = args[0];
@ -927,5 +926,11 @@ namespace Microsoft.PowerFx.Functions
var logicalName = optionSet.Option;
return new StringValue(irContext, logicalName);
}
private static DateTime ConvertToUTC(DateTime dateTime, TimeZoneInfo fromTimeZone)
{
var resultDateTime = new DateTimeOffset(DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified), fromTimeZone.GetUtcOffset(dateTime));
return resultDateTime.UtcDateTime;
}
}
}

Просмотреть файл

@ -44,3 +44,6 @@ DateTime(2022,9,29,13,0,0,0)
>> DateTimeValue("2022-09-29T20:00:00-08:00")
DateTime(2022,9,29,21,0,0,0)
>> Text(DateTime(2023, 3, 24, 19, 12, 34, 567), DateTimeFormat.UTC)
"2023-03-25T02:12:34.567Z"

Просмотреть файл

@ -99,3 +99,6 @@ DateTime(2011,1,30,8,0,0,0)
>> DateTimeValue("2011-01-30T08:00:00.1234567")
DateTime(2011,1,30,8,0,0,123)
>> With({d:DateTimeValue("March 10, 2023 5:30 PM")}, DateTimeValue(Text(d, DateTimeFormat.UTC)) = d)
true

Просмотреть файл

@ -9,3 +9,6 @@ Date(2022,9,29)
>> DateValue("2022-09-29T20:00:00-08:00")
Date(2022,9,30)
>> Text(DateTime(2023, 3, 24, 19, 12, 34, 567), DateTimeFormat.UTC)
"2023-03-24T18:12:34.567Z"

Просмотреть файл

@ -380,3 +380,9 @@ Error({Kind:ErrorKind.BadLanguageCode})
//Excel doesn't support three arguments
>> Text(Date(2016,1,31), "dddd mmmm d", "es-ES")
"domingo enero 31"
>> Text(DateTimeValue("2023-02-03 04:05:06Z"), DateTimeFormat.UTC)
"2023-02-03T04:05:06.000Z"
>> Text(DateTimeValue("2023-12-21T12:34:56.789Z"), DateTimeFormat.UTC)
"2023-12-21T12:34:56.789Z"

Просмотреть файл

@ -0,0 +1,38 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Microsoft.PowerFx.Core.Tests;
using Microsoft.PowerFx.Functions;
using Microsoft.PowerFx.Syntax;
using Microsoft.PowerFx.Types;
using Xunit;
namespace Microsoft.PowerFx.Interpreter.Tests
{
public class TextDateTimeToUTCTests : PowerFxTest
{
[Theory]
[InlineData("Text(DateTimeValue(\"March 10, 2023 5:30 PM\"), DateTimeFormat.UTC)", "Pacific Standard Time", "2023-03-11T01:30:00.000Z")]
[InlineData("Text(DateTimeValue(\"March 10, 2023 5:30 PM\"), DateTimeFormat.UTC)", "Tokyo Standard Time", "2023-03-10T08:30:00.000Z")]
[InlineData("Text(DateTimeValue(\"March 10, 2023 5:30 PM\"), DateTimeFormat.UTC)", "SE Asia Standard Time", "2023-03-10T10:30:00.000Z")]
public async void TextDateTimeToUTC(string inputExp, string timeZoneId, string expectedDateTimeUTC)
{
var engine = new RecalcEngine();
var rc = new RuntimeConfig();
rc.SetTimeZone(TimeZoneInfo.FindSystemTimeZoneById(timeZoneId));
var check = engine.Check(inputExp);
Assert.True(check.IsSuccess);
var utcResult = await check.GetEvaluator().EvalAsync(CancellationToken.None, rc);
Assert.Equal(expectedDateTimeUTC, utcResult.ToObject());
}
}
}