Browse Source

Fix more compatiable timezone problem.

pull/22236/head
maliming 1 year ago
parent
commit
c7bc2baa08
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 7
      framework/Volo.Abp.sln
  2. 10
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs
  3. 20
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs
  4. 40
      framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs
  5. 43
      framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Clock.cs
  6. 13
      framework/src/Volo.Abp.Timing/Volo/Abp/Timing/IClock.cs
  7. 16
      framework/test/Volo.Abp.Timing.Tests/Volo.Abp.Timing.Tests.csproj
  8. 14
      framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/AbpTimingTestModule.cs
  9. 110
      framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/Clock_Default_Tests.cs
  10. 132
      framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/Clock_Utc_Tests.cs
  11. 9
      npm/packs/core/src/abp.js
  12. 52
      npm/packs/luxon/src/abp.luxon.js

7
framework/Volo.Abp.sln

@ -485,6 +485,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Bunny"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.BlobStoring.Bunny.Tests", "test\Volo.Abp.BlobStoring.Bunny.Tests\Volo.Abp.BlobStoring.Bunny.Tests.csproj", "{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Timing.Tests", "test\Volo.Abp.Timing.Tests\Volo.Abp.Timing.Tests.csproj", "{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1447,6 +1449,10 @@ Global
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915}.Release|Any CPU.Build.0 = Release|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1691,6 +1697,7 @@ Global
{C753DDD6-5699-45F8-8669-08CE0BB816DE} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{1BBCBA72-CDB6-4882-96EE-D4CD149433A2} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6}
{BC4BB2D6-DFD8-4190-AAC3-32C0A7A8E915} = {447C8A77-E5F0-4538-8687-7383196D04EA}
{58FCF22D-E8DB-4EB8-B586-9BB6E9899D64} = {447C8A77-E5F0-4538-8687-7383196D04EA}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}

10
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs

@ -54,7 +54,7 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
{
if(x is string s && DateTime.TryParse(s, out var dt))
{
return Clock.Convert(dt).ToString("O");
return Clock.ConvertTo(dt).ToString("O");
}
return string.Empty;
@ -65,7 +65,7 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
{
if(x is DateTime dt && dt != default)
{
return Clock.Convert(dt).ToString("O");
return Clock.ConvertTo(dt).ToString("O");
}
return string.Empty;
@ -76,7 +76,7 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
{
if(x is DateTime dt && dt != default)
{
return Clock.Convert(dt).ToString("O");
return Clock.ConvertTo(dt).ToString("O");
}
return string.Empty;
}
@ -86,7 +86,7 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
{
if(x is DateTimeOffset dto && dto != default)
{
return Clock.Convert(dto).ToString("O");
return Clock.ConvertTo(dto).DateTime.ToString("O");
}
return string.Empty;
@ -97,7 +97,7 @@ public abstract class AbpDatePickerBaseTagHelperService<TTagHelper> : AbpTagHelp
{
if(x is DateTimeOffset dto && dto != default)
{
return Clock.Convert(dto).ToString("O");
return Clock.ConvertTo(dto).DateTime.ToString("O");
}
return string.Empty;

20
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs

@ -53,13 +53,23 @@ public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService<A
For = TagHelper.AspFor
};
var attributes = new TagHelperAttributeList { { "data-date", "true" }, { "type", "hidden" } };
var attributes = new TagHelperAttributeList { { "data-hidden-datepicker", "true" }, { "data-date", "true" }, { "type", "hidden" } };
if (Clock.SupportsMultipleTimezone && TagHelper.AspFor.Model is DateTime dateTime)
if (Clock.SupportsMultipleTimezone)
{
DateTagHelper.Format = "{0:O}";
DateTagHelper.Value = Clock.Convert(dateTime).ToString("O");
attributes.Add("value", DateTagHelper.Value);
if (TagHelper.AspFor.Model is DateTime dateTime)
{
DateTagHelper.Format = "{0:O}";
DateTagHelper.Value = Clock.ConvertTo(dateTime).ToString("O");
attributes.Add("value", DateTagHelper.Value);
}
if (TagHelper.AspFor.Model is DateTimeOffset dateTimeOffset)
{
DateTagHelper.Format = "{0:O}";
DateTagHelper.Value = Clock.ConvertTo(dateTimeOffset).UtcDateTime.ToString("O");
attributes.Add("value", DateTagHelper.Value);
}
}
DateTagHelperOutput = await DateTagHelper.ProcessAndGetOutputAsync(attributes, context, "input");

40
framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs

@ -38,7 +38,7 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ
{
if (TagHelper.AspForStart != null)
{
var startDateAttributes = new TagHelperAttributeList { { "data-start-date", "true" }, { "type", "hidden" } };
var startDateAttributes = new TagHelperAttributeList { { "data-hidden-datepicker", "true" }, { "data-start-date", "true" }, { "type", "hidden" } };
StartDateTagHelper = new InputTagHelper(Generator)
{
ViewContext = TagHelper.ViewContext,
@ -46,11 +46,21 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ
InputTypeName = "hidden"
};
if (Clock.SupportsMultipleTimezone && TagHelper.AspForStart.Model is DateTime dateTime)
if (Clock.SupportsMultipleTimezone)
{
StartDateTagHelper.Format = "{0:O}";
StartDateTagHelper.Value = Clock.Convert(dateTime).ToString("O");
startDateAttributes.Add("value", StartDateTagHelper.Value);
if (TagHelper.AspForStart.Model is DateTime dateTime)
{
StartDateTagHelper.Format = "{0:O}";
StartDateTagHelper.Value = Clock.ConvertTo(dateTime).ToString("O");
startDateAttributes.Add("value", StartDateTagHelper.Value);
}
if (TagHelper.AspForStart.Model is DateTimeOffset dateTimeOffset)
{
StartDateTagHelper.Format = "{0:O}";
StartDateTagHelper.Value = Clock.ConvertTo(dateTimeOffset).UtcDateTime.ToString("O");
startDateAttributes.Add("value", StartDateTagHelper.Value);
}
}
StartDateTagHelperOutput = await StartDateTagHelper.ProcessAndGetOutputAsync(startDateAttributes, context, "input");
@ -58,7 +68,7 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ
if (TagHelper.AspForEnd != null)
{
var endDateAttributes = new TagHelperAttributeList { { "data-end-date", "true" }, { "type", "hidden" } };
var endDateAttributes = new TagHelperAttributeList { { "data-hidden-datepicker", "true" }, { "data-end-date", "true" }, { "type", "hidden" } };
EndDateTagHelper = new InputTagHelper(Generator)
{
ViewContext = TagHelper.ViewContext,
@ -66,11 +76,21 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ
InputTypeName = "hidden"
};
if (Clock.SupportsMultipleTimezone && TagHelper.AspForEnd.Model is DateTime dateTime)
if (Clock.SupportsMultipleTimezone)
{
EndDateTagHelper.Format = "{0:O}";
EndDateTagHelper.Value = Clock.Convert(dateTime).ToString("O");
endDateAttributes.Add("value", EndDateTagHelper.Value);
if (TagHelper.AspForEnd.Model is DateTime dateTime)
{
EndDateTagHelper.Format = "{0:O}";
EndDateTagHelper.Value = Clock.ConvertTo(dateTime).ToString("O");
endDateAttributes.Add("value", EndDateTagHelper.Value);
}
if (TagHelper.AspForEnd.Model is DateTimeOffset dateTimeOffset)
{
EndDateTagHelper.Format = "{0:O}";
EndDateTagHelper.Value = Clock.ConvertTo(dateTimeOffset).UtcDateTime.ToString("O");
endDateAttributes.Add("value", EndDateTagHelper.Value);
}
}
EndDateTagHelperOutput = await EndDateTagHelper.ProcessAndGetOutputAsync(endDateAttributes, context, "input");

43
framework/src/Volo.Abp.Timing/Volo/Abp/Timing/Clock.cs

@ -26,6 +26,11 @@ public class Clock : IClock, ITransientDependency
public virtual bool SupportsMultipleTimezone => Options.Kind == DateTimeKind.Utc;
/// <summary>
/// Normalizes given <see cref="DateTime"/>.
/// </summary>
/// <param name="dateTime">DateTime to be normalized.</param>
/// <returns>Normalized DateTime</returns>
public virtual DateTime Normalize(DateTime dateTime)
{
if (Kind == DateTimeKind.Unspecified || Kind == dateTime.Kind)
@ -46,7 +51,12 @@ public class Clock : IClock, ITransientDependency
return DateTime.SpecifyKind(dateTime, Kind);
}
public virtual DateTime Convert(DateTime dateTime)
/// <summary>
/// Converts given UTC <see cref="DateTime"/> to user's time zone.
/// </summary>
/// <param name="dateTime">DateTime to be normalized.</param>
/// <returns>Converted DateTime</returns>
public virtual DateTime ConvertTo(DateTime dateTime)
{
if (!SupportsMultipleTimezone ||
dateTime.Kind != DateTimeKind.Utc ||
@ -59,7 +69,12 @@ public class Clock : IClock, ITransientDependency
return TimeZoneInfo.ConvertTime(dateTime, timezoneInfo);
}
public virtual DateTimeOffset Convert(DateTimeOffset dateTimeOffset)
/// <summary>
/// Converts given <see cref="DateTimeOffset"/> to user's time zone.
/// </summary>
/// <param name="dateTimeOffset">DateTimeOffset to be normalized.</param>
/// <returns>Converted DateTimeOffset</returns>
public virtual DateTimeOffset ConvertTo(DateTimeOffset dateTimeOffset)
{
if (!SupportsMultipleTimezone ||
CurrentTimezoneProvider.TimeZone.IsNullOrWhiteSpace())
@ -70,4 +85,28 @@ public class Clock : IClock, ITransientDependency
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone);
return TimeZoneInfo.ConvertTime(dateTimeOffset, timezoneInfo);
}
/// <summary>
/// Converts given user's <see cref="DateTime"/> to UTC or not.
/// </summary>
/// <param name="dateTime">DateTime to be normalized.</param>
/// <returns>Converted DateTime</returns>
public DateTime ConvertFrom(DateTime dateTime)
{
if (!SupportsMultipleTimezone ||
CurrentTimezoneProvider.TimeZone.IsNullOrWhiteSpace())
{
return dateTime;
}
var timezoneInfo = TimezoneProvider.GetTimeZoneInfo(CurrentTimezoneProvider.TimeZone);
var targetDateTime = dateTime;
if (dateTime.Kind == DateTimeKind.Utc)
{
return dateTime;
}
targetDateTime = DateTime.SpecifyKind(targetDateTime, DateTimeKind.Unspecified);
return TimeZoneInfo.ConvertTimeToUtc(targetDateTime, timezoneInfo);
}
}

13
framework/src/Volo.Abp.Timing/Volo/Abp/Timing/IClock.cs

@ -27,16 +27,23 @@ public interface IClock
DateTime Normalize(DateTime dateTime);
/// <summary>
/// Converts given <see cref="DateTime"/> to user's time zone.
/// Converts given UTC <see cref="DateTime"/> to user's time zone.
/// </summary>
/// <param name="dateTime">DateTime to be normalized.</param>
/// <returns>Converted DateTime</returns>
DateTime Convert(DateTime dateTime);
DateTime ConvertTo(DateTime dateTime);
/// <summary>
/// Converts given <see cref="DateTimeOffset"/> to user's time zone.
/// </summary>
/// <param name="dateTimeOffset">DateTimeOffset to be normalized.</param>
/// <returns>Converted DateTimeOffset</returns>
DateTimeOffset Convert(DateTimeOffset dateTimeOffset);
DateTimeOffset ConvertTo(DateTimeOffset dateTimeOffset);
/// <summary>
/// Converts given user's <see cref="DateTime"/> to UTC or not.
/// </summary>
/// <param name="dateTime">DateTime to be normalized.</param>
/// <returns>Converted DateTime</returns>
DateTime ConvertFrom(DateTime dateTime);
}

16
framework/test/Volo.Abp.Timing.Tests/Volo.Abp.Timing.Tests.csproj

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.test.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Timing\Volo.Abp.Timing.csproj" />
<ProjectReference Include="..\AbpTestBase\AbpTestBase.csproj" />
<PackageReference Include="Microsoft.NET.Test.Sdk" />
</ItemGroup>
</Project>

14
framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/AbpTimingTestModule.cs

@ -0,0 +1,14 @@
using Volo.Abp.Modularity;
namespace Volo.Abp.Timing;
[DependsOn(
typeof(AbpTimingModule),
typeof(AbpTestBaseModule)
)]
public class AbpTimingTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
}
}

110
framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/Clock_Default_Tests.cs

@ -0,0 +1,110 @@
using System;
using Shouldly;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Timing;
public class Clock_Default_Tests : AbpIntegratedTest<AbpTimingTestModule>
{
private readonly IClock _clock;
private readonly ICurrentTimezoneProvider _currentTimezoneProvider;
public Clock_Default_Tests()
{
_clock = GetRequiredService<IClock>();
_currentTimezoneProvider = GetRequiredService<ICurrentTimezoneProvider>();
}
[Fact]
public void ConvertTo_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Utc);
convertedDateTime.ToString("O").ShouldBe("2025-03-01T05:30:00.0000000Z");
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Local);
convertedDateTime.ToString("O").ShouldBe(dateTime.ToString("O"));
}
using(_currentTimezoneProvider.Change(null))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Local);
convertedDateTime.ToString("O").ShouldBe(dateTime.ToString("O"));
}
}
[Fact]
public void ConvertTo_DateTimeOffset_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc), TimeSpan.Zero);
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.Zero);
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.Zero);
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.Zero);
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(3));
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(3));
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(8));
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(8));
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
}
[Fact]
public void ConvertFrom_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Unspecified);
convertedDateTime.ShouldBe(dateTime);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Local);
convertedDateTime.ShouldBe(dateTime);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Utc);
convertedDateTime.ShouldBe(dateTime);
}
}
}

132
framework/test/Volo.Abp.Timing.Tests/Volo/Abp/Timing/Clock_Utc_Tests.cs

@ -0,0 +1,132 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Testing;
using Xunit;
namespace Volo.Abp.Timing;
public class Clock_Utc_Tests : AbpIntegratedTest<AbpTimingTestModule>
{
private readonly IClock _clock;
private readonly ICurrentTimezoneProvider _currentTimezoneProvider;
public Clock_Utc_Tests()
{
_clock = GetRequiredService<IClock>();
_currentTimezoneProvider = GetRequiredService<ICurrentTimezoneProvider>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.Configure<AbpClockOptions>(options =>
{
options.Kind = DateTimeKind.Utc;
});
base.AfterAddApplication(services);
}
[Fact]
public void ConvertTo_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Unspecified);
convertedDateTime.ToString("O").ShouldBe("2025-03-01T08:30:00.0000000"); //Without Z
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
// ConvertTo will not convert the DateTimeKind.Local
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Local);
convertedDateTime.ToString("O").ShouldBe(dateTime.ToString("O"));
}
using(_currentTimezoneProvider.Change(null))
{
// ConvertTo will not convert if the timezone is not set
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertTo(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Local);
convertedDateTime.ToString("O").ShouldBe(dateTime.ToString("O"));
}
}
[Fact]
public void ConvertTo_DateTimeOffset_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc), TimeSpan.Zero);
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(3));
convertedDateTimeOffset.ToString("O").ShouldBe("2025-03-01T08:30:00.0000000+03:00");
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.Zero);
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(3));
convertedDateTimeOffset.ToString("O").ShouldBe("2025-03-01T08:30:00.0000000+03:00");
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(3));
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(3));
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(8));
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(3));
convertedDateTimeOffset.DateTime.ShouldBe(new DateTime(2025, 3, 1, 0, 30, 0, DateTimeKind.Unspecified));
}
using(_currentTimezoneProvider.Change(null))
{
// ConvertTo will not convert if the timezone is not set
var dateTimeOffset = new DateTimeOffset(new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified), TimeSpan.FromHours(8));
var convertedDateTimeOffset = _clock.ConvertTo(dateTimeOffset);
convertedDateTimeOffset.Offset.ShouldBe(TimeSpan.FromHours(8));
convertedDateTimeOffset.ShouldBe(dateTimeOffset);
}
}
[Fact]
public void ConvertFrom_Test()
{
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Unspecified);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Utc);
convertedDateTime.ToString("O").ShouldBe("2025-03-01T02:30:00.0000000Z");
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Local);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Utc);
convertedDateTime.ToString("O").ShouldBe("2025-03-01T02:30:00.0000000Z");
}
using(_currentTimezoneProvider.Change("Europe/Istanbul"))
{
var dateTime = new DateTime(2025, 3, 1, 5, 30, 0, DateTimeKind.Utc);
var convertedDateTime = _clock.ConvertFrom(dateTime);
convertedDateTime.Kind.ShouldBe(DateTimeKind.Utc);
convertedDateTime.ToString("O").ShouldBe("2025-03-01T05:30:00.0000000Z");
}
}
}

9
npm/packs/core/src/abp.js

@ -775,7 +775,7 @@ var abp = abp || {};
if (abp.clock.supportsMultipleTimezone()) {
var timeZone = abp.clock.timeZone();
var now = new Date();
var formattedDate = now.toLocaleString('en-US', { timeZone: timeZone, timeZoneName: 'short' });
var formattedDate = now.toLocaleString('en-US', { timeZone: timeZone, timeZoneName: 'longOffset' });
var match = formattedDate.match(/GMT([+-]\d+)/);
var targetOffsetHours = match ? parseInt(match[1], 10) : 0;
var dateObj = new Date(dateObj.getTime() - (targetOffsetHours * 60 * 60 * 1000));
@ -805,14 +805,15 @@ var abp = abp || {};
return dateString;
}
var culture = abp.localization.currentCulture.cultureName;
options = Object.assign({}, abp.clock.toLocaleStringOptions, options || {});
if (abp.clock.supportsMultipleTimezone()) {
var timezone = abp.clock.timeZone();
if (timezone) {
options = options || {};
return date.toLocaleString(abp.localization.currentCulture.cultureName, Object.assign({}, abp.clock.toLocaleStringOptions, options, { timeZone: timezone }));
return date.toLocaleString(culture, Object.assign({}, options, { timeZone: timezone }));
}
}
return date.toLocaleString();
return date.toLocaleString(culture, options);
}
/* FEATURES *************************************************/

52
npm/packs/luxon/src/abp.luxon.js

@ -43,4 +43,56 @@ var abp = abp || {};
return form;
}
// Normalize Date object or date string to standard string format that will be sent to server
abp.clock.normalizeToString = function (date) {
if (!date) {
return date;
}
var dateObj = date instanceof Date ? date : new Date(date);
if (isNaN(dateObj)) {
return date;
}
var timeZone = abp.clock.timeZone();
if (abp.clock.supportsMultipleTimezone() && timeZone) {
return DateTime.fromObject({
year: dateObj.getFullYear(),
month: dateObj.getMonth() + 1,
day: dateObj.getDate(),
hour: dateObj.getHours(),
minute: dateObj.getMinutes(),
second: dateObj.getSeconds()
}, { zone: timeZone }).setZone("utc").toISO();
} else {
return luxon.DateTime.fromJSDate(dateObj).toFormat("yyyy-MM-dd'T'HH:mm:ss");
}
};
// Normalize date string to locale date string that will be displayed to user
abp.clock.normalizeToLocaleString = function (dateString, options) {
if (!dateString) {
return dateString;
}
var date = new Date(dateString);
if (isNaN(date)) {
return dateString;
}
options = options || luxon.DateTime.DATETIME_FULL;
if (abp.clock.supportsMultipleTimezone()) {
var timezone = abp.clock.timeZone();
if (timezone) {
return luxon.DateTime.fromJSDate(date)
.setZone(timezone)
.setLocale(abp.localization.currentCulture.cultureName)
.toLocaleString(Object.assign({}, abp.clock.toLocaleStringOptions, options));
}
}
return luxon.DateTime.fromJSDate(date)
.setLocale(abp.localization.currentCulture.cultureName)
.toLocaleString(Object.assign({}, abp.clock.toLocaleStringOptions, options));
}
})(jQuery);

Loading…
Cancel
Save