.NET WebFrom跨时区项目时间问题处理方法
前段时间因为公司的一个 WebFrom 项目设计到跨时区的问题,处理了一段时间,终于解决了,写个博客记录一下,方便以后回顾以及给他人提供一个参考的方法。
本次的项目因为跨越了多个时区,在一些时间上会受到时区的影响,比如在美国分部使用系统插入了一条数据,在美国分部显示的时间是“2019-09-25 00:00:00“,那么在北京分部看到的时间就应该自动转换成”2019-09-25 12:00:00“(美国比北京少十二个小时),因此系统要能实现自动获取客户端的时区并转换成 UTC 时间,保存到数据库,在取出来的时候再根据客户端时区转换为当地时间。
一开始是受部门运维的引导,知道了 oracle 自带一种数据类型叫做 timestamp with local time zone ,即按照数据库缓存的时区(Database Session Timezone),当用户存取时间时按照用户 Session 的时区对时间字段转换为当地时间。这个在我 CSDN 的博客中有提到这样的东西,链接为:https://blog.csdn.net/Wujiakai123/article/details/95391436 。然而当我开始尝试在项目中改进的时候才发现,发布到 IIS 的项目,不管有多少个客户连接进来,始终是以我的服务器为客户端去连接 oracle 的,这就导致了 oracle 中 Session 的时区一直是我的服务器的时区。因此推翻了使用 oracle 自带数据类型对时间字段进行自动转换的方法。
此路不通,所以就只能尝试在项目里面做改进了。经过与部门其他同事讨论之后,决定在登录时通过 JS 方法获取到客户端电脑的时区,保存到用户的登录信息中,这样,在用户进行操作时,涉及到时间的都按照该时区进行转换。因为本人刚毕业不久,代码技术水平不高,因此只想出了这样的笨方法,下面将具体实现方法列出来,如果有大佬有更好的解决办法欢迎评论,我可以多学习学习。
Login.aspx:
<div class="newBox">
<asp:HiddenField ID="hidTimezone" runat="server" ClientIDMode="Static" /> //
<asp:Button ID="btnLogin" CssClass="LoginBtn" runat="server" OnClientClick="Login()"
Text="Sign In" OnClick="btnLogin_Click" />
</div>
hidTimezone 控件用于保存当前用户浏览器时区的值,btnLogin 按钮点击调用 Login() 方法
Login()方法:
<script type="text/javascript"> function Login() { //得到本地时间
var d = new Date();
//得到1970年一月一日到现在的秒数
var local = d.getTime();
//本地时间与GMT时间的时间偏移差
var offset = d.getTimezoneOffset() * ;
//获取本地时区,判断如果是负的则相加得到格林尼治时间,正的则相减
var timezone = new Date().getTimezoneOffset() / * (-);
document.getElementById("hidTimezone").value = timezone.toString(); return true;
}
</script>
通过 JS 方法将获取到的时区的值赋给 hidTimezone 中,登录的时候将该控件的值跟着用户的登录信息一起放在 Session 中,大概就是这样:
UserModel model = new UserModel();
model.Timezone = Convert.ToDouble(hidTimezone.value);
Session["UserModelInfo"] = model;
这样子就能将用户的浏览器时区写入到 Session 中,方便后续做时间转换的时候可使用。
因为系统中所有页面都是继承了模板页 BasePage ,因此只要在模板页获取时区信息就可以了。
private UserLoginInfo _UserLoginInfo;
protected override void OnLoad(EventArgs e)
{
_UserLoginInfo = (UserLoginInfo)Session["UserLoginInfo"];
base.OnLoad(e);
} public class UserLoginInfo
{
/// <summary>
/// 用户所在时区
/// </summary>
public double Timezone { get; set; }
}
这样一来,只要页面继承了 BasePage,就可以用 base.UserLoginInfo.Timezone 获取到时区信息。
在Helper 类中新增时区转换方法:
/// <summary>
/// 根据时区获取本地时间
/// </summary>
/// <param name="timezone">时区</param>
/// <returns></returns>
public static DateTime GetLocalTime(double timezone)
{
try
{
double min = timezone * ;
var localtime = DateTime.UtcNow.AddMinutes(min);
return localtime;
}
catch (Exception ex)
{
LogHelper.Write(ex.Message);
throw new Exception(ex.Message);
} } /// <summary>
/// 根据时区将UTC时间转换成本地时间
/// </summary>
/// <param name="UTCTime">数据库中保存的UTC时间</param>
/// <param name="timezone">用户本地计算机时区</param>
/// <returns></returns>
public static DateTime UTCToLocal(DateTime UTCTime, double timezone)
{
try
{
double min = timezone * ;
var localtime = UTCTime.AddMinutes(min);
return localtime;
}
catch (Exception ex)
{
LogHelper.Write(ex.Message);
throw new Exception(ex.Message);
}
} /// <summary>
/// 根据时区将本地时间转换成UTC时间
/// </summary>
/// <param name="UTCTime">数据库中保存的UTC时间</param>
/// <param name="timezone">用户本地计算机时区</param>
/// <returns></returns>
public static DateTime LocalToUTC(DateTime localtime, double timezone)
{
try
{
double min = timezone * * (-);
var UTCTime = localtime.AddMinutes(min);
return UTCTime;
}
catch (Exception ex)
{
LogHelper.Write(ex.Message);
throw new Exception(ex.Message);
}
}
/// <summary>
/// 将时区信息转换为分钟偏移量
/// 例:GMT+09:00 转换结果为:540
/// </summary>
/// <param name="timezone">时区信息</param>
/// <returns></returns>
public static double GetTimezoneMinOffset(string timezone)
{
try
{
string strSub = timezone.Substring(timezone.Length - , ); string[] timestr = strSub.Split(':');
double min;
if (Convert.ToDouble(timestr[]) < )
{
min = Convert.ToDouble(timestr[]) * - Convert.ToDouble(timestr[]);
}
else
{
min = Convert.ToDouble(timestr[]) * + Convert.ToDouble(timestr[]);
}
return min;
}
catch (Exception ex)
{
LogHelper.Write(ex.Message);
throw new Exception(ex.Message);
} }
这样子就成功了一半了,接下来要做的,就是将原本系统中,执行 Insert 语句插入数据库之前获取数据中时间的 DateTime.Now 统一改成 DateTime.UtcNow,就能保证数据保存到数据库中是以当前 UTC 时间进行保存的,若涉及到时间,可用以上方法进行转换之后再保存到数据库中。同理,当用户查看数据时,涉及到时间的也根据以上方法,将数据库中的 UTC 时间转换成当地时间显示。这样一来就可以实现不同时区的人无论存数据或者查看数据都按照当地的时区。
那以上就是我对于 .NET WebFrom 项目跨时区的一个比较愚钝的解决办法,我相信肯定会有更方便更容易的方法,只是在当时项目赶着交付的情况下,我直接选取了这种比较笨的方法,优点就是用户是无感知的,在登录的时候就已经自动获取到了用户的时区信息,获取数据时也自动转换出来,对于用户来说不用特地去维护自己的时区信息。当然缺点就是这样一来,这套项目往后所有有关时间的信息都要按照这样的转换,若是有遗漏了,就会出现时间上不统一的问题,对应项目的再次开发以及以后交付给他人都是一个负担。
如果各位大佬有其他更好的方法欢迎评论区留言,让我这个菜鸟能多学习学习。这次也是第一次在博客园写博客,怎么说呢,自己本身基础并不扎实,还在学习中,若有不对之处请尽请指出!多谢各位!
.NET WebFrom跨时区项目时间问题处理方法的更多相关文章
- 利用SimpleDateFormat进行时间的跨时区转换 - Java
* 次方法主要用来将特定时区的时间转换成指定时区的时间,比如将北京时间“2018-04-08 15:40:49.031”,转换对应的美国东部时间是“2018-04-08 03:40:49.031” ...
- Isilon的WebUI上指定跨时区时间的小问题
Isilon的WebUI的界面长这样: 假设我们在中国,也就是GMT+8的时区,我们想修改一个远在美国的Isilon cluster的时间. 你会发现,界面上用于指定时间的地方应该填写的不是下面选择的 ...
- .Net DateTime跨时区相关问题
项目:.Net CS结构,WCF通信,MySql存储. 场景:客户端(UTC+07:00)获取本地时间(DateTime对象)2017-01-17 15:20:12,通过WCF(http)传输至服务端 ...
- 如何使不同时区的时间与京8区一致?(JS实现)
如何使不同时区的时间与京8区一致?(JS实现) Update:2019/1/28 更简单的是使用这个函数(toDate): // 自定义日期格式如下(年月日都必须提供): // "2011- ...
- 用JS将指定时间转化成用户当地时区的时间
公司的项目是面向海外用户的,但是最初的设计没考虑到时差问题,存入数据库的时间都是东八区的时间,导致现在补救有点坑爹...... 有一个需求是,产品详细页需要注明此款产品的开售时间,当海外的用户来访问这 ...
- PMP备考_第六章_项目时间管理
项目时间管理 前言 项目时间管理是项目管理中最难的一个环节,与个人时间管理类似,团体的效率如果管理不当,是低于个人效率的,为了管理好时间,从预估,执行到反馈均需要严格的分析和处理.如果制定的计划是无法 ...
- 查看修改Linux时区和时间
查看/修改Linux时区和时间 一.时区 1. 查看当前时区 date -R 2. 修改设置时区 方法(1) tzselect 方法(2) 仅限于RedHat Linux 和 CentOS timec ...
- TFS - 使用微软测试管理器实现跨团队项目的测试用例管理
在团队项目之间实现测试用例和测试计划的共享,是很多客户关注的问题.尤其在开发产品+服务的团队中,对测试用例的共享要求比较高.下面就如何在Team Foundation Server中如何实现团队项目之 ...
- NSDate获取当前时区的时间
[NSDate date]获取的是GMT时间,要想获得某个时区的时间,以下代码可以解决这个问题 NSDate *date = [NSDate date]; NSTimeZone *zone = [NS ...
随机推荐
- Python3---爬虫---抓取百度贴吧
前言 该文章主要描述如何抓取百度贴吧内容.当然是简单爬虫实现功能,没有实现输入参数过滤等辅助功能,仅供小白学习. 修改时间:20191219 天象独行 import os,urllib.request ...
- python凯撒加密
在密码学中,恺撒密码是一种最简单且最广为人知的加密技术.它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文.例,当偏移量是3的时候,所有的字母A将 ...
- 剑指offer 17:合并两个有序链表
题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 解题思路 链表基础操作考察,难点在于对于输入数据的把握,一定要考虑输入数据的全面性 1.出现 ...
- MySQL 部署 MHA 高可用架构 (二)
实现 MHA VIP 功能 配置 master_ip_failover 脚本(db3) 把 master_ip_failover 上传到 /iba/software 上 master_ip_failo ...
- MYSQL第一课
rm-rf /* 不能用 完全删除 数据库不能直接存储数据 table 表 DB 数据库 DBMS 数据库操作系统 SQL 结构化查询语言 语句不区分大小写,但字符串常量区区分大小写.建议命令大写. ...
- 一些有价值bug产生的思考
1.异步处理时防止重复点击的逻辑校验 场景 打款请求时,进入异步处理的队列,生成一个任务号,存在如数据库,且状态为未完成.此时,如果并发操作,如重复点击或者重复调用接口,则发出的两条请求可能被分配到不 ...
- 自定义MVC三
完成t_mvc_book表的增删改查1.通用分页的jar.自定义mvc框架.自定义标签 导入jar.导入之前写好的pageTag.自定义mvc.xml pageTag private static f ...
- ARM的堆栈方式
当堆栈指针指向最后压入堆栈的数据时,称为满堆栈(Full Stack): 当堆栈指针指向下一个将要放入数据的空位置时,称为空堆栈(Empty Stack): 根据对战的生成方式分为:递增堆栈(Asce ...
- java.net 基本测试
java.net 基本测试 包 java.net java.net.ssl 类 java.net.URL 测试类 package com.mozq.boot.kuayu01.demo; import ...
- luoguP3233 [HNOI2014]世界树
题意 看见数据范围就知道是虚树,于是先建出虚树. 考虑先求出虚树上的点的管理点,显然两边dfs,一遍从下往上,一遍从上往下. 之后考虑不在虚树上的点,对于虚树上的每一条边\((u,v)\),我们考虑上 ...