C#学习笔记——日期与时间
在使用C#的过程中,我们可能会经常使用到时间相关的内容,而C#提供了对应的结构体方便我们处理时间相关的逻辑,它们便是:
- DateTime 日期结构结构体
- TimeSpan 时间跨度结构体
一、时间相关知识点
1、时间单位
1秒 = 1000毫秒(1s = 1000ms)
1毫秒 = 1000微妙(1ms = 1000us)
1微妙 = 1000纳秒(1us = 1000ns)
2、格里高利历
格里高利历一般指公元
公元,即公历纪年法,目前我们所说公历,就是格里高利历
比如 2026 年就是从公元元年开始算起的两千零二十六年
3、格林尼治时间 (GMT)
格林尼治标准时间,是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线
地球每天的自转是有些不规则的,而且正在缓慢减速,所以,格林尼治时间已经不再被作为标准时间使用,现在的标准时间 — 协调世界时(UTC)
4、协调世界时 (UTC)
又称世界统一时间、世界标准时间、国际协调时间
UTC 协调世界时即格林尼治平太阳时间,是指格林尼治所在地的标准时间,也是表示地球自转速率的一种形式。
UTC 基于国际原子时间,通过不规则的加入闰秒来抵消地球自转变慢的影响,是世界上调节时钟和时间的主要时间标准
5、时间戳
从 1970 年 1 月 1 日(UNIX 时间戳的起点时间)到现在的时间。
计算机时间和众多的编程语言的时间都是从1970 年 1 月 1 日开始算起,是因为很多编程语言起源于 UNIX 系统,而 UNIX 系统认为1970 年 1 月 1 日 0 点是时间纪元。所以我们常说的时间戳是以1970 年 1 月 1 日 0 点为计时起点的。
最初计算机操作系统是 32 位,而时间也是用 32 位表示,而 32 位能代表的最大十进制数是 2147483647。1 年 365 天的总秒数是 31536000,那么2147483647 / 31536000 = 68.1 年,也就是说32 位的时间戳最大可以到2038年,而现代系统已普遍使用 64 位时间戳解决该问题。
二、DateTime
1、概念
DateTime是C#提供的处理日期和时间的结构体,对象默认值和最小值是0001年1月1日00 :00:00,最大值是9999年12月31日晚上11:59:59
2、初始化
使用构造函数进行初始化:
DateTime dt = new DateTime();
我们查看DateTime的构造函数,会发现有非常多的构造方法,不过里面大部分参数我们都看的懂,比如year、month、day、hour这些,因此这里就不讲解了,这里讲一下比较陌生的构造方法参数:
- ticks
以格里高利历00:00:00.000年1月1日来的100纳秒借个数表示,一般是一个很大的数字
- DateTimeKind
一个日期时间种类的枚举类,有如下三种:
Local:本地时间
Utc:UTC时间
Unspecified:不指定,单纯当成数字时间,不带任何时区信息(默认)
- Calender
日历类,下面有很多实现类,可以指定使用哪个国家的日历。这个使用的比较少,这里就不展开了
3、常用成员属性
// 年月日时分秒
print($"{dt.Year}-{dt.Month}-{dt.Day} {dt.Hour}:{dt.Minute}:{dt.Second}");
// 获取Ticks
print(dt.Ticks);
// 一年内的第几天
print(dt.DayOfYear);
// 星期几
print(dt.DayOfWeek);
4、获取时间
- 当前系统时间
DateTime nowTime = DateTime.Now;
- 当前日期(只获取日期,时分秒都是
0)
DateTime today = DateTime.Today;
- 当前UTC时间
DateTime utcTime = DateTime.UtcNow;
5、计算时间
使用Add相关方法即可增加时间,比如AddDays、AddHours等等。要减少时间只需要改为负数即可。
DateTime dt = new DateTime();
print($"{dt.Hour}:{dt.Minute}:{dt.Second}"); // 0:0:0
DateTime dt2 = dt.AddHours(5);
print($"{dt2.Hour}:{dt2.Minute}:{dt2.Second}"); // 5:0:0
6、字符串输出
直接打印对象即可获取时间的字符串,或者ToString()也是可以的
DateTime nowTime = DateTime.Now;
print(nowTime); 04/03/2026 20:00:09
当然还可以以短形式或者长形式来打印时间信息:
DateTime nowTime = DateTime.Now;
print(nowTime.ToShortTimeString()); // 短时间:20:02
print(nowTime.ToShortDateString()); // 短日期:2026/4/3
print(nowTime.ToLongTimeString()); // 长时间:20:02:55
print(nowTime.ToLongDateString()); // 长日期:2026年4月3日
当然还可以格式化打印,在ToString()中填入指定格式即可,编译器一般会有提示:
DateTime nowTime = DateTime.Now;
print(nowTime.ToString("F")); // 2026年4月3日 20:08:10
常见的标准格式
d:短日期格式(MM/dd/yyyy)D:长日期格式(dddd, MMMM dd, yyyy)t:短时间格式(hh:mm tt)T:长时间格式(hh:mm:ss tt)f:完整日期时间(dddd, MMMM dd, yyyy hh:mm tt)F:完整日期时间(dddd, MMMM dd, yyyy hh:mm:ss tt)g:常规日期时间(MM/dd/yyyy hh:mm tt)G:常规日期时间(MM/dd/yyyy hh:mm:ss tt)M:月份和日期(MMMM dd)Y:年份和月份(MMMM yyyy)
7、字符串转DateTime
使用Parse相关方法即可,推荐使用TryParse,更安全。
这里的字符串需要是日期类对象ToString()出来的才行(不带格式化参数)
DateTime nowTime = DateTime.Now;
string dateStr = nowTime.ToString();
if (DateTime.TryParse(dateStr, out DateTime result))
{
Debug.Log("日期转换成功: " + result); // 日期转换成功: 2026/4/3 20:11:12
}
8、存储时间
有时候我们有存储时间的需求,比如游戏中带有CD冷却的副本,我们需要计算下次进入副本的时间,然后记录这个时间,如果当前时间超过了记录的时间,才可以进入副本。
DateTime存储时间的方式有很多,比如:
- 直接存储字符串
- 转成Ticks存储
- 存储时间戳信息
存储时间戳的形式会更好一些,相比字符串更简洁,而且又不像Ticks那样数字特别大。具体转换方式如下:(可以先看后面的TimeSpan知识点)
- 先计算 目标时间 与 1970年1月1日 的时间跨度TimeSpan
- 获取TimeSpan的ticks,并将ticks转换为以秒为单位,减小数字大小
比如存储当前时间两天后的时间,可以这样获取时间戳,然后存储这个timeStamp即可:
TimeSpan time = DateTime.Now.AddDays(2) - new DateTime(1970, 1, 1); // 2天后的时间与时间戳的起点时间的跨度
int timeStamp = (int)(time.Ticks / TimeSpan.TicksPerSecond); // 时间戳,转换成秒
想要timeStamp转换回具体日期,可以这样:
TimeSpan time = new TimeSpan(timeStamp * TimeSpan.TicksPerSecond); // 计算时间跨度
DateTime date = new DateTime(1970, 1, 1) + time; // 转换为日期
三、TimeSpan
1、概念
TimeSpan是C#提供的时间跨度结构体,通过两个DateTime对象相减,可以得到该对象。
主要用于处理时间计算
2、初始化
使用两个日期相减获取TimeSpan对象:
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1);
使用构造函数初始化,比如传入ticks,或者具体的日时分秒:
TimeSpan ts = new TimeSpan(5, 23, 59, 59); // 5天23小时59分钟59秒
3、常用成员属性
- 总时间跨度
可以通过Total相关的方法获取总的时间跨度,Ticks可以获取具体的ticks
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1);
print(ts.TotalMinutes); // 总分钟数:29587467.332083
print(ts.TotalSeconds); // 总秒数:1775248039.92498
print(ts.TotalDays); // 总天数:20546.8523139466
print(ts.TotalHours); // 总小时数:493124.455534717
print(ts.Ticks); // ticks:17752480399249826
- 具体时间
通过下面这些属性来获取具体的时间
print(ts.Days); // 具体天数:20546
print(ts.Hours); // 具体小时数:20
print(ts.Minutes); // 具体分钟数:31
print(ts.Seconds); // 具体秒数:3
print(ts.Milliseconds); // 具体毫秒数:928
4、计算
- TimeSpan的计算
可以和DateTime搭配进行计算,DateTime重载了+和-:
DateTime nowTime = DateTime.Now;
print(nowTime); // 04/03/2026 20:36:20
TimeSpan ts = new TimeSpan(1, 0, 0, 0); // 1天
DateTime dt = nowTime + ts; // 加上1天
print(dt); // 04/04/2026 20:36:20
TimeSpan之间也是可以相互计算的,这里就不举例了。
- Ticks的计算
TimeSpan提供了Ticks相关的常量,以TicksPer开头,比如TicksPerDay、TicksPerSecond等等。可以使用Ticks除以对应的常量换算成对应的时间。
比如这里将Ticks换算成天数:
DateTime nowTime = DateTime.Now;
long ticks = nowTime.Ticks;
print(ticks / TimeSpan.TicksPerDay); // 739708