如何更改.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 ...
随机推荐
- 打通JAVA与内核系列之一ReentrantLock锁的实现原理
简介:写JAVA代码的同学都知道,JAVA里的锁有两大类,一类是synchronized锁,一类是concurrent包里的锁(JUC锁).其中synchronized锁是JAVA语言层面提供的能力 ...
- 前沿分享|阿里云数据库资深技术专家 姚奕玮:AnalyticDB MySQL离在线一体化技术揭秘
简介: 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中,阿里云数据库资深技术专家 姚奕玮关于"AnalyticDB MySQL离在线一体化技术揭秘&q ...
- Java对象转换方案分析与mapstruct实践
简介: 随着系统模块分层不断细化,在Java日常开发中不可避免地涉及到各种对象的转换,如:DO.DTO.VO等等,编写映射转换代码是一个繁琐重复且还易错的工作,一个好的工具辅助,减轻了工作量.提升开发 ...
- WPF开源轻便、快速的桌面启动器
前言 今天大姚给大家分享一款WPF开源.简单.轻便.快速的桌面启动器(支持多主题.多语言:简体中文.繁体中文.英文等):CurvaLauncher. WPF介绍 WPF 是一个强大的桌面应用程序框架, ...
- [Nova] KeyValue Field 设置默认 key 的方式
1. 使用 withMeta: KeyValue::make('options') ->withMeta([ 'value' => $this->options ?? [ 'A' = ...
- Redisant Toolbox——面向开发者的多合一工具箱
Redisant Toolbox--面向开发者的多合一工具箱 Redisant Toolbox 拥有超过30种常用的开发工具:精心设计,快速.高效:离线使用,尊重您的隐私.官网地址:http://ww ...
- C++ 构造函数和析构函数(Constructors & Destructors)
一.定义: 当object产生,有一个特殊的称为constructor的函数会自动执行.当object死亡,有一个特殊的称为destructor的函数会自动执行.Constructor 可以不只一个, ...
- ansible(18)--ansible的selinux模块
1. selinux模块 功能:管理远端主机的 SELINUX 防火墙: 主要参数如下: 参数 说明 state Selinux模式:enforcing.permissive.disabled pol ...
- MSP 通过 Splashtop SOS 远程支持非托管设备
RMM 是 MSP 的绝佳工具.它们使 MSP 可以通过集中控制台来管理其所有客户计算机,通常使他们能够远程访问任何计算机以提供远程支持. 但是,这样做的一个很大限制是--并非所有客户设备都在 MSP ...
- C++:面向对象
文章目录 继承与多态 继承 继承的构造与析构 虚继承 多态 ❀虚/纯虚函数❀ 虚析构/纯虚析构 对象的生命周期 实例化对象 构造函数与析构函数 拷贝构造函数 防止拷贝 总结 深拷贝与浅拷贝 初始化列表 ...