如何更改.NET中的默认时区?
除了"在操作系统中修改时区信息,然后重启.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 方法从操作系统获取时区信息并且赋值。
看到了这里,我脑海里就浮现了两种方案:
- 使用
hook技术挟持并修改win32 api返回的时区信息。 - 使用
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中的默认时区?的更多相关文章
- MTK Android中设置默认时区
设置默认时区 PRODUCT_PROPERTY_OVERRIDES += \ persist.sys.timezone=Asia/Shanghai\ 注:搜索“persist.sys.timezone ...
- 更改eclipse中jsp默认编码格式为UTF-8
本文首发于cartoon的博客 转载请注明出处:https://cartoonyu.github.io/cartoon-blog 近段时间一直在学java三大框架,遇到了一个问 ...
- laravel中修改默认时区
在config文件夹下app.php中找到timezone,有RTC改成PRC
- 怎么更改Rstudio中的默认目录
方法一. 每次启动Rstudio之后,执行代码 setwd("F:/R/R_data") 默认目录就会修改为双引号内的位置路径. 方法二. 对Rstudio进行设置一次即可. ①点 ...
- 如何在Azure Websites中配置PHP从而改变系统默认时区
Shirley_Wang Tue, Mar 3 2015 7:29 AM Azure Website为我们提供了可高度扩展的网站部署平台.由于Website是PaaS(平台即服务)层的服务,当用户把 ...
- 【推荐】PHP中格式化时间函数date与gmdate的区别 | 修改PHP的默认时区
PHP中的时间有2个格式化函数:date()和gmdate(),在官方的文档中的描述为: date -- 格式化一个本地时间/日期 gmdate -- 格式化一个 GMT/UTC 日期/时间,返回的是 ...
- 修改PHP的默认时区
每个地区都有自己的本地时间,在网上及无线电通信中,时间的转换问题显得格外突出.整个地球分为24个时区,每个时区都有自己的本地时间.在国际无线电或网络通信场合,为了统一起见,使用一个统一的时间,成为通用 ...
- Android系统移植与调试之------->如何修改Android的默认语言、默认时区
修改device/other/TBDG1073/ system.prop文件 1.设置默认语言 找到device/other/TBDG1073/ system.prop文件,修改属性ro.produc ...
- Date, TimeZone, MongoDB, java中date的时区问题
打印new Date(),Fri Aug 12 13:37:51 CST 2016. 显示Asia/Shanghai的时区,但是date toString 的时区简写却是CST.更坑爹的是,Googl ...
- Oracle 11g中修改默认密码过期天数和锁定次数
Oracle 11g中修改默认密码过期天数和锁定次数 密码过期的原因一般有两种可能: 一.由于Oracle中默认在default概要文件中设置了"PASSWORD_LIFE_TIME=180 ...
随机推荐
- WPF 引用 UWP 控件 不打包为 MSIX 分发的方法
按照微软的官方文档,大部分的文档都会说如果用了 XAML Islands 等技术的时候,需要新建一个打包项目,将 WPF 应用打包为 msix 等才可以进行分发和使用.但是实际上不打包也可以,此时可以 ...
- 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 ...
- Java Collection接口下的“ List 集合” 与 “ Set 集合 ”
Java Collection接口下的" List 集合" 与 " Set 集合 " 每博一文案 一个人最好的底牌,就这两个字: 靠谱,是最高级的聪明. 师父说 ...
- PostgreSQL世界上最先进的开源关系型数据库
PostgreSQL 的 Slogan 是 "世界上最先进的开源关系型数据库". PostgreSQL是一个功能非常强大.源代码开放的对象关系数据库系统(ORDBMS),在灵活的B ...
- flex布局方案
参考:https://blog.csdn.net/weixin_39717076/article/details/82586915
- RustDesk 自建服务器部署和使用教程
RustDesk 是一个强大的开源远程桌面软件,是中国开发者的作品,它使用 Rust 编程语言构建,提供安全.高效.跨平台的远程访问体验.可以说是目前全球最火的开源远程桌面软件了,GitHub 星星数 ...
- win系统执行脚本报错策略更改无法加载文件 C:\Users\xx\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本
Start-Process powershell -Verb runAs Get-ExecutionPolicy Get-ExecutionPolicy -List set-ExecutionPoli ...
- Vue3 项目
创建 Vue3 项目的步骤如下: 安装 Node.js Vue3 需要依赖 Node.js 环境,因此需要先安装 Node.js.可以从官网下载 Node.js 的安装包并安装,也可以使用包管理器安装 ...
- Gradle常用功能拾掇
介绍 Gradle 是一个基于groovy动态语言的java项目管理工具,灵活性和速度好于java,他的build脚本完全可以以写groovy代码的方式来实现,所以灵活性很高,当然也就比maven的x ...
- C 语言编程 — 编程实践
目录 文章目录 目录 前文列表 程序示例 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> < ...