diff --git a/src/Snap.Hutao/Snap.Hutao/Core/UnsafeDateTimeOffset.cs b/src/Snap.Hutao/Snap.Hutao/Core/UnsafeDateTimeOffset.cs index 92b408dc..f2fcb833 100644 --- a/src/Snap.Hutao/Snap.Hutao/Core/UnsafeDateTimeOffset.cs +++ b/src/Snap.Hutao/Snap.Hutao/Core/UnsafeDateTimeOffset.cs @@ -1,20 +1,20 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using System.Diagnostics.Contracts; +using System.Runtime.CompilerServices; + namespace Snap.Hutao.Core; -internal struct UnsafeDateTimeOffset +internal static class UnsafeDateTimeOffset { - private DateTime dateTime; - private short offsetMinutes; - - public DateTime DateTime { readonly get => dateTime; set => dateTime = value; } - + [Pure] [SuppressMessage("", "SH002")] public static unsafe DateTimeOffset AdjustOffsetOnly(DateTimeOffset dateTimeOffset, in TimeSpan offset) { - UnsafeDateTimeOffset* pUnsafe = (UnsafeDateTimeOffset*)&dateTimeOffset; - pUnsafe->offsetMinutes = (short)(offset.Ticks / TimeSpan.TicksPerMinute); - return dateTimeOffset; + return new(GetPrivateDateTime(ref dateTimeOffset), offset); } + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_dateTime")] + private static extern ref readonly DateTime GetPrivateDateTime(ref DateTimeOffset dateTimeOffset); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs b/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs index 0b005287..608eb0a4 100644 --- a/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs +++ b/src/Snap.Hutao/Snap.Hutao/Extension/WinRTExtension.cs @@ -12,17 +12,17 @@ internal static class WinRTExtension { IObjectReference objectReference = obj.NativeObject; - lock (GetDisposedLock(objectReference)) + lock (GetPrivateDisposedLock(objectReference)) { - return GetDisposed(objectReference); + return GetProtectedDisposed(objectReference); } } // protected bool disposed; [UnsafeAccessor(UnsafeAccessorKind.Field, Name ="disposed")] - private static extern ref bool GetDisposed(IObjectReference objRef); + private static extern ref bool GetProtectedDisposed(IObjectReference objRef); // private object _disposedLock [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_disposedLock")] - private static extern ref object GetDisposedLock(IObjectReference objRef); + private static extern ref object GetPrivateDisposedLock(IObjectReference objRef); } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs index 1733be16..1c8c26fc 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGF.cs @@ -104,6 +104,6 @@ internal sealed class UIGF : IJsonOnSerializing, IJsonOnDeserialized return new TimeSpan(offsetHours, 0, 0); } - return PlayerUid.GetRegionTimeZoneUtcOffset(Info.Uid); + return PlayerUid.GetRegionTimeZoneUtcOffsetForUid(Info.Uid); } } \ No newline at end of file diff --git a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs index 0fbbe77f..b5302513 100644 --- a/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs +++ b/src/Snap.Hutao/Snap.Hutao/Model/InterChange/GachaLog/UIGFInfo.cs @@ -75,7 +75,7 @@ internal sealed class UIGFInfo : IMappingFrom - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs index 72dd50e0..e4a6dc7f 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/Hk4e/Event/GachaInfo/GachaLogPage.cs @@ -1,13 +1,15 @@ // Copyright (c) DGP Studio. All rights reserved. // Licensed under the MIT license. +using Snap.Hutao.Core; + namespace Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo; /// /// 祈愿记录分页 /// [HighQuality] -internal sealed class GachaLogPage +internal sealed class GachaLogPage : IJsonOnDeserialized { /// /// 页码 @@ -40,4 +42,15 @@ internal sealed class GachaLogPage /// [JsonPropertyName("region")] public string Region { get; set; } = default!; + + public void OnDeserialized() + { + // Adjust items timezone + TimeSpan offset = PlayerUid.GetRegionTimeZoneUtcOffsetForRegion(Region); + + foreach (GachaLogItem item in List) + { + item.Time = UnsafeDateTimeOffset.AdjustOffsetOnly(item.Time, offset); + } + } } diff --git a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs index 9dbe74ee..7ac48128 100644 --- a/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs +++ b/src/Snap.Hutao/Snap.Hutao/Web/Hoyolab/PlayerUid.cs @@ -43,15 +43,8 @@ internal readonly partial struct PlayerUid return new(uid); } - /// - /// 判断是否为国际服 - /// - /// uid - /// 是否为国际服 public static bool IsOversea(string uid) { - // We make this a static method rather than property, - // to avoid unnecessary memory allocation (Region field). Must.Argument(UidRegex().IsMatch(uid), SH.WebHoyolabInvalidUid); return uid.AsSpan()[0] switch @@ -61,10 +54,8 @@ internal readonly partial struct PlayerUid }; } - public static TimeSpan GetRegionTimeZoneUtcOffset(string uid) + public static TimeSpan GetRegionTimeZoneUtcOffsetForUid(string uid) { - // We make this a static method rather than property, - // to avoid unnecessary memory allocation (Region field). Must.Argument(UidRegex().IsMatch(uid), SH.WebHoyolabInvalidUid); // 美服 UTC-05 @@ -78,6 +69,19 @@ internal readonly partial struct PlayerUid }; } + public static TimeSpan GetRegionTimeZoneUtcOffsetForRegion(string region) + { + // 美服 UTC-05 + // 欧服 UTC+01 + // 其他 UTC+08 + return region switch + { + "os_usa" => ServerRegionTimeZone.AmericaServerOffset, + "os_euro" => ServerRegionTimeZone.EuropeServerOffset, + _ => ServerRegionTimeZone.CommonOffset, + }; + } + /// public override string ToString() {