除了"在操作系统中修改时区信息,然后重启.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. WPF 引用 UWP 控件 不打包为 MSIX 分发的方法

    按照微软的官方文档,大部分的文档都会说如果用了 XAML Islands 等技术的时候,需要新建一个打包项目,将 WPF 应用打包为 msix 等才可以进行分发和使用.但是实际上不打包也可以,此时可以 ...

  2. 2018-8-10-WPF-省市县3级联动

    title author date CreateTime categories WPF 省市县3级联动 lindexi 2018-08-10 19:16:53 +0800 2018-2-13 17:2 ...

  3. Java Collection接口下的“ List 集合” 与 “ Set 集合 ”

    Java Collection接口下的" List 集合" 与 " Set 集合 " 每博一文案 一个人最好的底牌,就这两个字: 靠谱,是最高级的聪明. 师父说 ...

  4. PostgreSQL世界上最先进的开源关系型数据库

    PostgreSQL 的 Slogan 是 "世界上最先进的开源关系型数据库". PostgreSQL是一个功能非常强大.源代码开放的对象关系数据库系统(ORDBMS),在灵活的B ...

  5. flex布局方案

    参考:https://blog.csdn.net/weixin_39717076/article/details/82586915

  6. RustDesk 自建服务器部署和使用教程

    RustDesk 是一个强大的开源远程桌面软件,是中国开发者的作品,它使用 Rust 编程语言构建,提供安全.高效.跨平台的远程访问体验.可以说是目前全球最火的开源远程桌面软件了,GitHub 星星数 ...

  7. win系统执行脚本报错策略更改无法加载文件 C:\Users\xx\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本

    Start-Process powershell -Verb runAs Get-ExecutionPolicy Get-ExecutionPolicy -List set-ExecutionPoli ...

  8. Vue3 项目

    创建 Vue3 项目的步骤如下: 安装 Node.js Vue3 需要依赖 Node.js 环境,因此需要先安装 Node.js.可以从官网下载 Node.js 的安装包并安装,也可以使用包管理器安装 ...

  9. Gradle常用功能拾掇

    介绍 Gradle 是一个基于groovy动态语言的java项目管理工具,灵活性和速度好于java,他的build脚本完全可以以写groovy代码的方式来实现,所以灵活性很高,当然也就比maven的x ...

  10. C 语言编程 — 编程实践

    目录 文章目录 目录 前文列表 程序示例 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> < ...