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的构造函数,会发现有非常多的构造方法,不过里面大部分参数我们都看的懂,比如yearmonthdayhour这些,因此这里就不讲解了,这里讲一下比较陌生的构造方法参数:

  • 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相关方法即可增加时间,比如AddDaysAddHours等等。要减少时间只需要改为负数即可。

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开头,比如TicksPerDayTicksPerSecond等等。可以使用Ticks除以对应的常量换算成对应的时间。

比如这里将Ticks换算成天数:

DateTime nowTime = DateTime.Now;
long ticks = nowTime.Ticks;
print(ticks / TimeSpan.TicksPerDay); // 739708