除了"在操作系统中修改时区信息,然后重启.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. 阿里千万实例可观测采集器-iLogtail正式开源

    ​简介:11月23日,阿里正式开源可观测数据采集器iLogtail.作为阿里内部可观测数据采集的基础设施,iLogtail承载了阿里巴巴集团.蚂蚁的日志.监控.Trace.事件等多种可观测数据的采集工 ...

  2. 移动端、微信小程序兼容性问题汇总(持续更新……

    1. safari浏览器字体不能自动随网页缩放调整大小 -webkit-text-size-adjust:100% 2. 点击<button><input>有灰色透明背景 -w ...

  3. Spirng 当中 Bean的作用域

    Spirng 当中 Bean的作用域 @ 目录 Spirng 当中 Bean的作用域 每博一文案 1. Spring6 当中的 Bean的作用域 1.2 singleton 默认 1.3 protot ...

  4. Golang ETCD包的安装使用 golang安装etcd第三方库clientv3 报错 解决

    目录 ETCD 官网 视频地址 课件资料 ETCD 日志收集项目 为什么要自己写不用ELK? 项目的架构 上节课项目进度 etcd介绍 安装etcd windows安装 Ubuntu(linux系统) ...

  5. DP-Modeler三维修模软件简介

    图像快速建模系统DP-Modeler是天际航自主研发的一款集精细化单体建模及Mesh网格模型修饰于一体的新型软件.通过特有的摄影测量算法,支持航测摄影.无人机影像.地面影像.车载影像.激光点云等多数据 ...

  6. IPv6 — 综合组网技术

    目录 文章目录 目录 前文列表 IPv4v6 综合组网技术(转换机制) 双栈策略 隧道策略 前文列表 <IPv6 - 网际协议第 6 版> <IPv6 - 地址格式与寻址模式> ...

  7. 谈谈 JVM 垃圾回收机制

    前言 垃圾回收需要思考三件事情,哪些内存需要回收?什么时候回收?如何回收? 一.哪些内存需要回收 JVM 的内存区域中,程序计数器.虚拟机栈和本地方法栈的生命周期是随线程而生,随线程而灭的.这几个区域 ...

  8. PageOffice——动态填充Word模板并在线编辑

    说明:使用pageoffice动态给word模板填充数据,插入图片.excel.word格式的文件和创建表格 一.准备工作: 本地创建一个doc或者docx格式的文件,在文件中需要插入数据的地方设置以 ...

  9. java学习之旅(day.22)

    CSS 前端三要素:HTML.CSS.javaScript ​ 结构 表现 交互 相当于骨头,表皮 ,血肉吧 如何学习CSS CSS是什么 CSS怎么用(快速入门) CSS选择器(重点+难点) 美化网 ...

  10. vue多页面应用

    多页面应用本身和单页面应用没什么差别,无非是多了几个入口点. 入口点多的话,还可以写个函数扫描路径取添加入口点. 比较让人好奇的是路径的问题.我们要开发的时候要体现目录层级接口,所以入口文件是一层套一 ...