除了"在操作系统中修改时区信息,然后重启.NET应用程序,使其生效"之外。如何在不修改操作系统时区的前提下,修改.NET中的默认时区呢?

这是一位 同学兼同事 于5月21日在技术群里问的问题,我当时简单地研究了一下,就写出来了。

现在写文章分享给大家,虽然我觉得这种需求非常小众,几乎不会有人用到。

正文

正常手段下,.NET是不允许开发者修改默认时区的,它没有公开这样的API。

在 .NET 中,管理时区的类型叫 TimeZoneInfo,它位于 System 命名空间下,由 System.Private.CoreLib.dll 提供。

使用 ILSpy 反编译 System.Private.CoreLib.dll,找到 TimeZoneInfo 类型,我们可以看到 TimeZoneInfo.Local 指向一个私有字段 s_cachedData 的成员属性 Local,该字段类型是一个属于 TimeZoneInfo 的私有嵌套类型 CachedData

当首次访问 CachedData.Local 时,它会先检查 _localTimeZone 私有字段是否有值。如果没有值,则调用 CreateLocal 方法从操作系统获取时区信息并且赋值。

看到了这里,我脑海里就浮现了两种方案:

  1. 使用 hook 技术挟持并修改 win32 api 返回的时区信息。
  2. 使用 reflection 技术反射并且修改时区信息。

方案1的优点是稳定,但可能会被杀毒软件报毒。

方案2的优点是不会报毒,但可能不稳定。

为什么说方案2不稳定呢?因为 s_cachedData 私有字段值有可能在某个时候被重置。

现在我们来看看方案2的实现:

public static bool TrySetLocalTimeZoneInfo(TimeZoneInfo timeZoneInfo)
{
Type timeZoneInfoType = typeof(TimeZoneInfo); // 获取TimeZoneInfo类型的私有静态字段成员信息s_cachedData
FieldInfo cachedDataFieldInfo = timeZoneInfoType.GetField("s_cachedData", BindingFlags.NonPublic | BindingFlags.Static);
if (cachedDataFieldInfo == null)
{
return false;
} // 获取TimeZoneInfo类型的私有嵌套类型CachedData
Type cachedDataType = timeZoneInfoType.GetNestedType("CachedData", BindingFlags.NonPublic);
if (cachedDataType == null)
{
return false;
} // 获取CachedData类型的私有字段成员信息_localTimeZone
FieldInfo localTimeZoneFieldInfo = cachedDataType.GetField("_localTimeZone", BindingFlags.NonPublic | BindingFlags.Instance);
if (localTimeZoneFieldInfo == null)
{
return false;
} // 获取TimeZoneInfo类型的私有静态字段s_cachedData值
object cachedData = cachedDataFieldInfo.GetValue(null);
if (cachedData == null)
{
return false;
} // 设置私有字段的值
localTimeZoneFieldInfo.SetValue(cachedData, timeZoneInfo);
return true;
}

PS: 该方法代码实际测试在 .NET Core 3.1, .NET 5.0, .NET 6.0, .NET 7.0, .NET 8.0 都可以正常工作。

用法:

void Main()
{
// 设置前
Console.WriteLine(TimeZoneInfo.Local); // 修改为 GMT 时区
TimeZoneInfo hkTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
bool setResult = TrySetLocalTimeZoneInfo(hkTimeZoneInfo); // 设置后
Console.WriteLine(TimeZoneInfo.Local);
}

注意:这种方案需要严谨测试,反复验证。


因为是篡改.NET内部私有变量,不知道是否会引起其它后果。

比如.NET内部其它API没有使用 TimeZoneInfo.Local,而是自己在其它地方又缓存了一套 TimeZoneInfo,那就GG了。

又比如,需要检查整个 .NET Runtime 和其它第三方组件,是否有调用 TimeZoneInfo.ClearCachedData 静态方法 或者 调用 CultureInfo.ClearCachedData 对象方法。

如何更改.NET中的默认时区?的更多相关文章

  1. MTK Android中设置默认时区

    设置默认时区 PRODUCT_PROPERTY_OVERRIDES += \ persist.sys.timezone=Asia/Shanghai\ 注:搜索“persist.sys.timezone ...

  2. 更改eclipse中jsp默认编码格式为UTF-8

        本文首发于cartoon的博客     转载请注明出处:https://cartoonyu.github.io/cartoon-blog     近段时间一直在学java三大框架,遇到了一个问 ...

  3. laravel中修改默认时区

    在config文件夹下app.php中找到timezone,有RTC改成PRC

  4. 怎么更改Rstudio中的默认目录

    方法一. 每次启动Rstudio之后,执行代码 setwd("F:/R/R_data") 默认目录就会修改为双引号内的位置路径. 方法二. 对Rstudio进行设置一次即可. ①点 ...

  5. 如何在Azure Websites中配置PHP从而改变系统默认时区

    Shirley_Wang  Tue, Mar 3 2015 7:29 AM Azure Website为我们提供了可高度扩展的网站部署平台.由于Website是PaaS(平台即服务)层的服务,当用户把 ...

  6. 【推荐】PHP中格式化时间函数date与gmdate的区别 | 修改PHP的默认时区

    PHP中的时间有2个格式化函数:date()和gmdate(),在官方的文档中的描述为: date -- 格式化一个本地时间/日期 gmdate -- 格式化一个 GMT/UTC 日期/时间,返回的是 ...

  7. 修改PHP的默认时区

    每个地区都有自己的本地时间,在网上及无线电通信中,时间的转换问题显得格外突出.整个地球分为24个时区,每个时区都有自己的本地时间.在国际无线电或网络通信场合,为了统一起见,使用一个统一的时间,成为通用 ...

  8. Android系统移植与调试之------->如何修改Android的默认语言、默认时区

    修改device/other/TBDG1073/ system.prop文件 1.设置默认语言 找到device/other/TBDG1073/ system.prop文件,修改属性ro.produc ...

  9. Date, TimeZone, MongoDB, java中date的时区问题

    打印new Date(),Fri Aug 12 13:37:51 CST 2016. 显示Asia/Shanghai的时区,但是date toString 的时区简写却是CST.更坑爹的是,Googl ...

  10. Oracle 11g中修改默认密码过期天数和锁定次数

    Oracle 11g中修改默认密码过期天数和锁定次数 密码过期的原因一般有两种可能: 一.由于Oracle中默认在default概要文件中设置了"PASSWORD_LIFE_TIME=180 ...

随机推荐

  1. MaxCompute跨境访问加速解决方案

    简介: MaxCompute联合全球加速服务,为有跨境访问需求的MaxCompute客户提供一套高效稳定的跨境访问加速方案. MaxCompute联合全球加速服务,为有跨境访问需求的MaxComput ...

  2. dotnet 如何将 Microsoft.Maui.Graphics 对接到 UNO 框架

    本文将和大家介绍如何将 Microsoft.Maui.Graphics 对接到 UNO 框架里面.一旦完成 Microsoft.Maui.Graphics 对接,即可让 UNO 框架复用现有的许多绘制 ...

  3. WPF 对接 Vortice 调用 D2D 使用 IWICBitmap 离屏渲染

    通过 Vortice 库可以使用非常底层的方式调用到 Direct2D1 进行渲染,本文将使用 D2D 离屏渲染到 IWICBitmap 上,再使用一点点反射黑科技,直接将此 IWICBitmap 对 ...

  4. 通过 KoP 将 Kafka 应用迁移到 Pulsar

    通过 KoP 将 Kafka 应用迁移到 Pulsar 版权声明:原文出自 https://github.com/streamnative/kop ,由 Redisant 进行整理和翻译 目录 通过 ...

  5. 深入浅出玩转fPGA-读书笔记

    笔记1 关于异步复位同步释放的理解 先看代码: 其中有两个always语句,把2个触发器叠加,当按下复位信号rst_n是,两个触发器都复位(清零).当rst_n释放时,重点就来了,rst_n释放的时刻 ...

  6. 深入理解Python协程:从基础到实战

    title: 深入理解Python协程:从基础到实战 date: 2024/4/27 16:48:43 updated: 2024/4/27 16:48:43 categories: 后端开发 tag ...

  7. 微分流形Loring Tu 习题21.2解答

    今天的作业,随手写到博客吧. \(Proof.\)对于任意的\(p \in M\),有p附近的坐标卡\((U,x^{1},\ldots,x^{n})\), 由引理\(21.4\),$$dx^{1}\w ...

  8. Mac Docker 挂载数据卷失败

    问题描述: docker: Error response from daemon: Mounts denied: The path /srv/docker/bind is not shared fro ...

  9. ansible(12)--ansible的cron模块

    1. cron模块 功能:管理被控端计划任务: 主要参数如下: 参数 说明 name 定时任务基本描述 job 定时任务要执行的命令 minute 分 hour 小时 day 日 month 月 we ...

  10. WEB服务与NGINX(17)- https协议及使用nginx实现https功能

    目录 1. https协议及使用nginx实现https功能 1.1 https协议概述 1.2 TLS/SSL协议原理 1.3 https的实现原理 1.4 使用openssl申请证书 1.5 ng ...