聊聊.netcore采坑那一些事之系统时间and文件路径

Hi,小伙伴大家好,最近工作比较忙,很久没有和大家分享点东西了。这个周末都加了两天班。公司的新项目都是采用.netcore来开发,在开发过程中,也踩到了一些坑,在此先总结两个坑,这两个坑都是关于Linux(CentOS)和windows下的兼容性问题。我们最开始的开发环境接口调用一直是部署在windows环境运行一切正常,但是部署到Linux(CentOS)环境下,就出现了这两个问题,其实问题也简单:获取系统时间,实际时间少了8个小时;文件路径​被识别为了文件名。下面就简单分享一下解决方式,其实只要你一看,发现很简单的,之所以分享出来,当你才开始用户.netcore时,可以有一个提示作用,嘿嘿!

一、DateTime.Now获取系统时间少了8个小时

.net core项目,部署到Linux(CentOS)上的时候,发现DateTime.Now获取的时间与Windows不一致,获取到系统时间比系统的时间实际少了8个小时,发现这一个问题,大家第一时间想到的是时区差异。网上搜了一下,发现还有不少的小伙伴遇到了同样的问题,有给出了对应的解决方式,具体如下:

具体原因就是:Linux和Windows两者所采用的时区不同,两者的时区分别为:Linux:IANA,Windows:Windows time zone IDs。这就是最终元凶啦!

找到原因后,那么该如何解决呢?方式很简单,就是两者采用同一个时区不就完事了嘛,最终统一采用IANA,在实现上可以借助第三方库:NodaTime。具体实现代码如下:

 /// <summary>

        /// 获取系统当前时间

        /// </summary>

        /// <returns>系统当前时间</returns>

        public static DateTime GetSysDateTimeNow()

        {

            Instant now = SystemClock.Instance.GetCurrentInstant();

            var shanghaiZone = DateTimeZoneProviders.Tzdb["Asia/Shanghai"];

            return now.InZone(shanghaiZone).ToDateTimeUnspecified();

      }

  

是不是so easy?

其实我们使用时间的时候,会有很多种方式,也会对时间做很多格式转换,比如:yyyy-MM-dd HH:mm:ss格式化时间,时间和时间戳的相互转换等等。为了统一规范操作,在实际项目中,我们对时间的操作根据实际需要做了一个统一封装,当然了在很多人看来是没有多大技术含量的,也是哦,其目的是为了实现统一控制,方便管理,提高代码的复用性。现在我也把代码贴出,如果有需要的,你可以参考一下,同时我也生成了一个包,放到Nuget上,包名为(XYH.Tools.DateTimeTools),如果有需要的,可以挡下来使用。

我已经将源码上传到GitHub上,有兴趣的可以档下来

源码地址:https://github.com/xuyuanhong0902/XYH.Tools.git

源码:

/* ==============================================================================
* 功能描述:所有时间的相关操作集合
* 创 建 者:程序修炼之旅 交流微信号:15908150902
* 创建日期: 2020-03-08
* CLR Version :1.0
* ==============================================================================*/ using NodaTime;
using System; /// <summary>
/// 公用帮助类
/// </summary>
namespace XYH.Tools.DateTimeTools
{
/// <summary>
/// 时间相关的操作类
/// </summary>
public static class DateTimeTools
{
#region 获取系统当前时间的几个方法(返回时间+格式化后的时间字符串) /// <summary>
/// 获取系统当前时间
/// </summary>
/// <returns>系统当前时间</returns>
public static DateTime GetSysDateTimeNow()
{
Instant now = SystemClock.Instance.GetCurrentInstant();
var shanghaiZone = DateTimeZoneProviders.Tzdb["Asia/Shanghai"];
return now.InZone(shanghaiZone).ToDateTimeUnspecified();
} /// <summary>
/// 获取系统当前时间格式化字符串 24小时制 被格式化为 (yyyy-MM-dd HH:mm:ss.fff)
/// </summary>
/// <returns>系统当前格式化的时间字符串(yyyy-MM-dd HH:mm:ss.fff)</returns>
public static string GetSysDateTimeNowStringYMD24HMSF()
{
return GetSysDateTimeNow().ToStringYMD24HMSF();
} /// <summary>
/// 获取系统当前时间格式化字符串 12小时制 被格式化为 (yyyy-MM-dd hh:mm:ss.fff)
/// </summary>
/// <returns>系统当前格式化的时间字符串(yyyy-MM-dd hh:mm:ss.fff)</returns>
public static string GetSysDateTimeNowStringYMD12HMSF(this DateTime time)
{
return GetSysDateTimeNow().ToStringYMD12HMSF();
} /// <summary>
/// 获取系统当前时间格式化字符串 24小时制 被格式化为 (yyyy-MM-dd HH:mm:ss)
/// </summary>
/// <returns>系统当前格式化的时间字符串(yyyy-MM-dd HH:mm:ss)</returns>
public static string GetSysDateTimeNowStringYMD24HMS(this DateTime time)
{
return GetSysDateTimeNow().ToStringYMD24HMS();
} /// <summary>
/// 获取系统当前时间格式化字符串 12小时制 被格式化为 (yyyy-MM-dd hh:mm:ss)
/// </summary>
/// <returns>系统当前格式化的时间字符串(yyyy-MM-dd hh:mm:ss)</returns>
public static string GetSysDateTimeNowStringYMD12HMS(this DateTime time)
{
return GetSysDateTimeNow().ToStringYMD12HMS();
} /// <summary>
/// 获取系统当前时间格式化字符串 被格式化为 (yyyy-MM-dd)
/// </summary>
/// <returns>系统当前格式化的时间字符串(yyyy-MM-dd)</returns>
public static string GetSysDateTimeNowStringYMD(this DateTime time)
{
return GetSysDateTimeNow().ToStringYMD();
} #endregion #region DateTime 扩展几个 格式方法 /// <summary>
/// 时间 格式化 24小时制 被格式化为 (yyyy-MM-dd HH:mm:ss.fff)
/// </summary>
/// <param name="time">被格式的时间</param>
/// <returns>格式化后的时间字符串(yyyy-MM-dd HH:mm:ss.fff)</returns>
public static string ToStringYMD24HMSF(this DateTime time)
{
return time.ToString("yyyy-MM-dd HH:mm:ss.fff");
} /// <summary>
/// 时间 格式化 12小时制 被格式化为 (yyyy-MM-dd hh:mm:ss.fff)
/// </summary>
/// <param name="time">被格式化时间</param>
/// <returns>格式化后的时间字符串(yyyy-MM-dd hh:mm:ss.fff)</returns>
public static string ToStringYMD12HMSF(this DateTime time)
{
return time.ToString("yyyy-MM-dd hh:mm:ss.fff");
} /// <summary>
/// 时间 格式化 24小时制 被格式化为 (yyyy-MM-dd HH:mm:ss)
/// </summary>
/// <param name="time">被格式化时间</param>
/// <returns>格式化后的时间字符串(yyyy-MM-dd HH:mm:ss)</returns>
public static string ToStringYMD24HMS(this DateTime time)
{
return time.ToString("yyyy-MM-dd HH:mm:ss");
} /// <summary>
/// 时间 格式化 12小时制 被格式化为 (yyyy-MM-dd hh:mm:ss)
/// </summary>
/// <param name="time">被格式化时间</param>
/// <returns>格式化后的时间字符串(yyyy-MM-dd hh:mm:ss)</returns>
public static string ToStringYMD12HMS(this DateTime time)
{
return time.ToString("yyyy-MM-dd hh:mm:ss");
} /// <summary>
/// 时间 格式化 被格式化为 (yyyy-MM-dd)
/// </summary>
/// <param name="time">被格式化时间</param>
/// <returns>格式化后的时间字符串(yyyy-MM-dd)</returns>
public static string ToStringYMD(this DateTime time)
{
return time.ToString("yyyy-MM-dd");
} #endregion #region 获取时间戳 /// <summary>
/// 获取时间戳(秒)
/// </summary>
/// <returns>秒时间戳</returns>
public static long GetSecondTimestamp()
{
// 以1970-1-1 为时间开始 同系统当前时间的秒差值即为秒时间戳
TimeSpan ts = GetSysDateTimeNow() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds);
} /// <summary>
/// 获取时间戳(毫秒)
/// </summary>
/// <returns>毫秒时间戳</returns>
public static long GetMilliSecondTimestamp()
{
// 以1970-1-1 为时间开始 同系统当前时间的毫秒差值即为毫秒时间戳
TimeSpan ts = GetSysDateTimeNow() - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalMilliseconds);
} #endregion #region 将一个时间戳转换为一个时间 /// <summary>
/// 将一个秒时间戳转换为时间格式(秒)
/// </summary>
/// <param name="secondTimestamp">秒时间戳</param>
/// <returns>转换后的时间</returns>
public static DateTime? SecondStampToDateTime(long secondTimestamp)
{
// 做一个简单的判断
if (secondTimestamp <= 0)
{
return null;
} // 以1970-1-1 为时间开始,通过计算与之的时间差,来计算其对应的时间
DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
dateTime = dateTime.AddSeconds(secondTimestamp).ToLocalTime();
return dateTime;
} /// <summary>
/// 将一个字符串秒时间戳转换为时间格式(秒)
/// </summary>
/// <param name="secondTimestampStr">字符串秒时间戳</param>
/// <returns>转换后的时间</returns>
public static DateTime? SecondStampToDateTime(string secondTimestampStr)
{
// 如果为空,那么直接返回null
if (string.IsNullOrEmpty(secondTimestampStr))
{
return null;
} // 首先将字符串时间戳转换为数字
long secondTimestamp = 0;
long.TryParse(secondTimestampStr, out secondTimestamp); // 调用
return SecondStampToDateTime(secondTimestamp);
} /// <summary>
/// 将一个字符串毫秒时间戳转换为时间格式(毫秒)
/// </summary>
/// <param name="secondTimestampStr">字符串毫秒时间戳</param>
/// <returns>转换后的时间</returns>
public static DateTime? MilliSecondStampToDateTime(long secondTimestamp)
{
// 做一个简单的判断
if (secondTimestamp <= 0)
{
return null;
} // 以1970-1-1 为时间开始,通过计算与之的时间差,来计算其对应的时间
DateTime dateTime = new System.DateTime(1970, 1, 1, 0, 0, 0, 0);
dateTime = dateTime.AddMilliseconds(secondTimestamp).ToLocalTime(); return dateTime;
} /// <summary>
/// 将一个毫秒时间戳转换为时间格式(毫秒)
/// </summary>
/// <param name="milliSecondStampStr">毫秒时间戳</param>
/// <returns>转换后的时间</returns>
public static DateTime? MilliSecondStampToDateTime(string milliSecondStampStr)
{
// 如果为空,那么直接返回null
if (string.IsNullOrEmpty(milliSecondStampStr))
{
return null;
} // 首先将字符串时间戳转换为数字
long milliSecondStamp = 0;
long.TryParse(milliSecondStampStr, out milliSecondStamp); // 调用
return MilliSecondStampToDateTime(milliSecondStamp);
} #endregion
}
}

  

二、文件路径被识别为了文件名

哈哈,最近还遇到一个有趣的事情,就是在Windows上,文件路径的创建,都是正确的,但是部署到CentOS,所创建的文件,所有路径都变成了文件名称,所有文件都在根目录下了。

网上找了一下原因,就是文件路径左斜杠和右斜杠的问题。在Windows上无论是左斜杠还是右斜杠都没有问题,但是在linux中只支持右斜杠,将代码中所用到的路径操作,都统一修改为右斜杠,问题就解决了。文件路径1/文件路径2/文件名

三、总结

  回头来看这两个问题,都是系统的兼容性问题,在仔细想一下,也是一个习惯性问题,尤其是文件路径这问题,我们要习惯的用右斜杠。

我们以后在写.net程序的时候,无论是否会采用.netcore实现linux系统部署,我们都也该想到不同系统的兼容性问题,在实现上都采用一个通用的方式来实现,那么以后在做项目升级,系统迁移的时候,就会少一些麻烦。嘿嘿,今天就先到这,后续我在分享一下其它.netcore实战所踩的坑。谢谢您的阅读。

Hi,小伙伴大家好,最近工作比较忙,很久没有和大家分享点东西了。这个周末都加了两天班。公司的新项目都是采用.netcore来开发,在开发过程中,也踩到了一些坑,在此先总结两个坑,这两个坑都是关于Linux(CentOS)和windows下的兼容性问题。我们最开始的开发环境接口调用一直是部署在windows环境运行一切正常,但是部署到Linux(CentOS)环境下,就出现了这两个问题,其实问题也简单:获取系统时间,实际时间少了8个小时;文件路径​被识别为了文件名。下面就简单分享一下解决方式,其实只要你一看,发现很简单的,之所以分享出来,当你才开始用户.netcore时,可以有一个提示作用,嘿嘿!

END
为了更高的交流,欢迎大家关注我的公众号,扫描下面二维码即可关注,谢谢:

聊聊.netcore采坑那一些事之系统时间and文件路径的更多相关文章

  1. Cloudera Manager 5.9 和 CDH 5.9 离线安装指南及个人采坑填坑记

    公司的CDH早就装好了,一直想自己装一个玩玩,最近组了台电脑,笔记本就淘汰下来了,加上之前的,一共3台,就在X宝上买了CPU和内存升级了下笔记本,就自己组了个集群. 话说,好想去捡垃圾,捡台8核16线 ...

  2. angular采坑记录

    在angular中会遇到一些莫名的问题,导致不能完成想要的功能,可能是某项用法使用错误,或许是angular相对应不支持,或者是我们功力根本就没有达到.为了在每次采坑之后能有所收获,再遇到时能理解其根 ...

  3. 分布式改造剧集之Redis缓存采坑记

    Redis缓存采坑记 ​ 前言 ​ 这个其实应该属于分布式改造剧集中的一集(第一集见前面博客:http://www.cnblogs.com/Kidezyq/p/8748961.html),本来按照顺序 ...

  4. 采坑:python base64

    需求:  读取文本内容,对字符串进行base64加密 >>> str = 'aaaaaaaaaaaaaaaaaaa\nbbbbbbbbbbbbbbbbbbbbbbbbbbb\nccc ...

  5. Hadoop环境搭建--Docker完全分布式部署Hadoop环境(菜鸟采坑吐血整理)

    系统:Centos 7,内核版本3.10 本文介绍如何从0利用Docker搭建Hadoop环境,制作的镜像文件已经分享,也可以直接使用制作好的镜像文件. 一.宿主机准备工作 0.宿主机(Centos7 ...

  6. Spring Cloud Config采坑记

    1. Spring Cloud Config采坑记 1.1. 问题 在本地运行没问题,本地客户端服务能连上本地服务端服务,可一旦上线,发现本地连不上线上的服务 服务端添加security登录加密,客户 ...

  7. rabbitmq在ios中实战采坑

    1. rabbitmq在ios中实战采坑 1.1. 问题 ios使用rabbitmq连接,没过多久就断开,并报错.且用android做相同的步骤并不会报错,错误如下 Received connecti ...

  8. 从源码看Spring Security之采坑笔记(Spring Boot篇)

    一:唠嗑 鼓捣了两天的Spring Security,踩了不少坑.如果你在学Spring Security,恰好又是使用的Spring Boot,那么给我点个赞吧!这篇博客将会让你了解Spring S ...

  9. Charles 抓包工具安装和采坑记录

    Charles 抓包工具安装和采坑记录 网络抓包是解决网络问题的第一步,也是网络分析的基础.网络出现问题,第一步肯定是通过抓包工具进行路径分析,看哪一步出现异常.做网络爬虫,第一步就是通过抓包工具对目 ...

随机推荐

  1. 关于Java集合框架总结

    Java集合专门用来存放多个对象,方便程序处理数据.Java提供了多种集合类,以便满足不同的应用需求,这些集合类分为两大系列:Collection和Map List List的通用方法 boolean ...

  2. JavaScript 的DOM操作及实例

    一.Windows对象操作 (1).用代码打开窗口:window.open("第一部分","第二部分","第三部分","第四部分& ...

  3. jmeter常用定时器以及事物控制器

    定时器(并发):Synchronizing Timer 事物控制器: 勾选Generate parent sample当单看主要数据和页面数据性能测试结果还是有比较大的差异的,因而在进行页面性能测试的 ...

  4. sm3算法的简单介绍

    转自:https://blog.csdn.net/hugewaves/article/details/53765063 SM3算法也是一种哈希算法,中国国家密码管理局在2010年发布,其名称是SM3密 ...

  5. [洛谷P4549] [模板] 裴蜀定理

    18.10.03模拟赛T1. 出题人xcj(Mr.Handsome)十分良心,给了一道送分题...... 互测题好久没有出现送分题了.xcj真棒. 题目传送门 幸亏之前看过,否则真的是送分题都拿不到. ...

  6. Java Servlet XML文件配置

  7. 大家都在关注AI,但这些事你可能并不知道!

    我们正处在第四次工业革命,其特点是机器人和自驾车技术的进步,智能家电的泛滥等等.所有这些最前沿的是人工智能(AI),也是自动化计算机系统的发展,可以匹配甚至超过人类的智力. 你的自动驾驶可能会编程杀死 ...

  8. 奇异值分解原理及Python实例

    奇异值分解 SVD(Singular Value Decomposition)是一种重要的矩阵分解方法,可以看做是特征分解在任意矩阵上的推广,SVD是在机器学习领域广泛应用的算法. 特征值和特征向量 ...

  9. Android编程权威指南(第2版)--第16章 使用intent拍照 挑战练习

    16.7挑战练习:优化照片显示 新建dialog_photo.xml 1234567891011121314 <?xml version="1.0" encoding=&qu ...

  10. JavaScript是如何工作的(一)

    简评:JavaScript 是越来越受欢迎了,很多团队都在采用这些语言工作.前端.后端.嵌入式设备等等,都可以看见它的身影.虽然我们知其然,但又知其所以然吗? 大家应该都知道 JavaScript 是 ...