CS5L12——日期和时间

本章代码关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
DateTime                //C#提供给我们处理日期和时间的结构体
new DateTime() //以年、月、日、时、分、秒、毫秒初始化(一般可以不需要全部填入,有多个重载)
dateTime.Year //年
dateTime.Month //月
dateTime.Day //日
dateTime.Hour //小时
dateTime.Minute //分钟
dateTime.Second //秒
dateTime.Millisecond //毫秒
dateTime.Ticks //以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字
dateTime.DayOfYear //一年的第几天
dateTime.DayOfWeek //星期几
DateTime.Now //获取当前日期和时间
DateTime.Today //获取今日日期
DateTime.UtcNow //获取当前UTC日期和时间
dateTime.Add() //计算时间
dateTime.ToString() //输出字符串,可通过传入参数来决定输出格式
DateTime.TryParse() //字符串转时间,一定要dateTime.ToString()不带任何参数转出来的形式才能转回时间
TimeSpan //C#提供给我们的时间跨度结构体

目前学习过和时间相关的内容

目前我们只在Unity当中学习过 Time​ 类,我们可以通过 Time​ 获取当前游戏相关的时间,比如帧间隔时间,游戏运行的时间和帧数等等内容

但是我们并没有学习过和真实世界时间相关的内容,比如如何得知当前时间的 年、月、日、时、分、秒
本章就是学习的就是真实时间相关的内容

时间对于我们的作用

在游戏开发当中我们经常会有和时间打交道的内容,比如每日签到、活动倒计时、建造时间、激活时间等等的功能
如果想要完成这些功能,仅仅用Unity提供给我们的Time类是远远不够用的
所以我们需要学习专门的日期和时间相关的知识,才能制作某些功能需求
而 C# 便提供了对应的结构方便我们处理时间相关逻辑

  1. DateTime​ 日期结构体
  2. TimeSpan​ 时间跨度结构体

一些关于时间的名词说明

  • 时间单位

    1s 秒 = 1000ms 毫秒
    1ms 毫秒 = 1000μs 微妙
    1μs 微妙 = 1000ns 纳秒

  • 格里高利历

    格里高利历一般指公元, 公元,即公历纪年法
    目前我们所说公历,就是格里高利历,比如2023年就是从公元元年开始算起的两千二十三年

  • 格林尼治时间(GMT)

    格林尼治标准时间,是指位于英国伦敦郊区的皇家格林尼治天文台的标准时间,因为本初子午线被定义在通过那里的经线
    地球每天的自转是有些不规则的,而且正在缓慢减速,所以,格林尼治时间已经不再被作为标准时间使用
    现在的标准时间就是协调世界时(UTC)

  • 协调世界时(UTC)

    又称世界统一时间、世界标准时间、国际协调时间
    UTC协调世界时格林尼治平太阳时间,是指格林尼治所在地的标准时间,也是表示地球自转速率的一种形式
    UTC基于国际原子时间,通过不规则的加入闰秒来抵消地球自转变慢的影响,是世界上调节时钟和时间的主要时间标准

  • 时间戳

    从1970年1月1日(UNIX时间戳的起点时间)到现在的时间(单位为秒)
    计算机时间和众多的编程语言的时间都是从1970年1月1日开始算起,
    因为很多编程语言起源于UNIX系统,而UNIX系统认为1970年1月1日0点是时间纪元
    所以我们常说的UNIX时间戳是以1970年1月1日0点为计时起点时间的

    原因:
    最初计算机操作系统是32位,而时间也是用32位表示,我们知道32位能代表的最大十进制数是2147483647
    1年是365天,总秒数是3153 6000,那么 2147483647/31536000 = 68.1年
    也就是说因为早期用32位来表示时间,最大的时间间隔是68年,而最早出现的UNIX操作系统考虑到计算机产生的年代和应用的
    时限综合取了1970年1月1日作为 UNIX TIME​ 的纪元时间(开始时间)

DateTime

命名空间:System
DateTime​ 是 C# 提供给我们处理日期和时间的结构体
DateTime​ 对象的默认值和最小值是 ** 0001年1月1日00:00:00(午夜),** 最大值可以是 9999年12月31日晚上11:59:59

初始化与时间表示

1
DateTime dt = new DateTime(2023, 11, 1, 21, 38, 00, 500);    //以年、月、日、时、分、秒、毫秒初始化(一般可以不需要全部填入,有多个重载)

主要参数:
年、月、日、时、分、秒、毫秒
**或者:**​ticks​:以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字(该重载几乎不使用)

次要参数:
DateTimeKind​:日期时间种类:

  • Local​:本地时间(默认参数,以系统上设置的时间为准)
  • Utc​:UTC时间
  • Unspecified​:不指定

Calendar​:日历,使用哪个国家的日历,一般在Unity开发中不使用

年、月、日、时、分、秒、毫秒

1
2
print(dt.Year + "-" + dt.Month +  "-" + dt.Day + ": " + dt.Hour + ":" + dt.Minute + ":" + dt.Second + ":" + dt.Millisecond);
//输出:2023-11-1: 21:38:0:500

tick表示

以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字

1
print(dt.Ticks);    //输出:638344714805000000

一年的第几天

1
print(dt.DayOfYear);    //输出:305

星期几

1
print(dt.DayOfWeek);    //输出:Wednesday

获取时间

  • 当前日期和时间

    注意:不要在帧更新函数中不停地用 DateTime.Now​ 来计算,浪费性能。我们只需要在面板打开时计算一次时间差!之后再用该时间差来计算即可

    1
    2
    DateTime nowTime = DateTime.Now;
    print(nowTime.Year + "-" + nowTime.Month + "-" + nowTime.Day + ": " + nowTime.Hour + ":" + nowTime.Minute + ":" + nowTime.Second);
  • 返回今日日期

    1
    2
    DateTime nowTime2 = DateTime.Today;
    print(nowTime2.Year + "-" + nowTime2.Month + "-" + nowTime2.Day);
  • 返回当前UTC日期和时间

    1
    2
    DateTime nowTimeUTC = DateTime.UtcNow;
    print(nowTimeUTC.Hour + ":" + nowTimeUTC.Minute);

计算时间

就是很简单的各种加时间

1
2
3
DateTime nowTime3 = nowTime.AddDays(1);    //加一天
DateTime nowTime3 = nowTime.AddDays(-2); //减两天
print(nowTime3.Day);

DateTime的字符串输出

1
2
3
4
5
6
7
8
9
10
11
12
//格式:月/日/年 时:分:秒
print(nowTime);
//格式:年/月/日 时:分:秒
print(nowTime.ToString());
//短时间信息,格式:时:分
print(nowTime.ToShortTimeString());
//短日期信息,格式:年/月/日
print(nowTime.ToShortDateString());
//长时间信息,格式:时:分:秒
print(nowTime.ToLongTimeString());
//长日期信息,格式:xxxx年xx月xx日
print(nowTime.ToLongDateString());

​​image​​

通过传入参数来决定输出格式

1
2
3
//传入参数,以使用特定的格式来输出字符串
print(nowTime.ToString("D"));
print(nowTime.ToString("yyyy-MM-dd-ddd/HH-mm-ss"));

image

image

字符串转DateTime

字符串想要转回 DateTime​ 成功的话,那么这个字符串的格式是有要求的,
一定是
最基本的 toString()的转换出来的字符串才能转回去(即一定要 dateTime.ToString()转出来的形式,不能带任何参数)
要求格式:年/月/日 时:分:秒

1
2
3
4
5
6
7
8
9
10
string str = nowTime.ToString();
DateTime dt3;
if (DateTime.TryParse(str, out dt3))
{
print(dt3);
}
else
{
print("转换失败");
}

存储时间

存储时间 方式很多

  1. 以直接存字符串
  2. 可以直接存Ticks
  3. 可以直接存时间戳信息

建议直接用存储时间戳的形式 更加节约,但存储时间戳需要用 TimeSpan​ 的类

TimeSpan

命名空间:System
TimeSpan​ 是 C# 提供给我们的时间跨度结构体,用两个 DateTime​ 对象相减 可以得到该对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//时间戳
TimeSpan ts = DateTime.Now - new DateTime(1970, 1, 1);
//间隔时间,单位:天
print(ts.TotalDays);
//间隔时间,单位:小时
print(ts.TotalHours);
//间隔时间,单位:分钟
print(ts.TotalMinutes);
//间隔时间,单位:秒
print(ts.TotalSeconds);
//间隔时间,单位:刻
print(ts.Ticks);
//
print(ts.Days + "-" + ts.Hours + "-" + ts.Minutes + "-" + ts.Seconds);

image

初始化它来代表时间间隔

1
2
TimeSpan ts2 = new TimeSpan(1, 2, 1, 0);    //天数,小时,分钟,秒
DateTime timeNow = DateTime.Now + ts2; //直接与DateTime类型变量相加

TimeSpan相互计算

1
2
3
TimeSpan ts3 = new TimeSpan(0, 1, 1, 1);
TimeSpan ts4 = ts2 + ts3;
print(ts4.Days + "-" + ts4.Hours);

TimeSpan常量方便用于和ticks进行计算

1
2
print(ts4.Ticks / TimeSpan.TicksPerSecond);    //将tick数转换为秒数
print(ts4.TotalSeconds) //效果和上面的一样

DateTime和Timespan的应用

假设要记录 以当前系统时间起,间隔2天后的 时间戳信息

获取并存储时间戳

1
2
3
4
//用当前时间加上两天,再减去UNIX TIME纪元时间,得到时间差
TimeSpan time = DateTime.Now.AddDays(2) - new DateTime(1970, 1, 1);
//再将时间差转换为秒,便得到最终的时间戳,我们只需要存储该int变量即可
int timeStamp = (int)(time.Ticks / TimeSpan.TicksPerSecond);

将时间戳转换为DateTime

1
2
3
4
//由于时间戳以秒为单位存储,我们需要先将时间戳转换为以ticks为单位的TimeSpan,得到较UNIX TIME纪元时间的时间差
TimeSpan time2 = new TimeSpan(timeStamp * TimeSpan.TicksPerSecond);
//再将UNIX TIME纪元时间加上时间差,即可得到数据
DateTime date = new DateTime(1970, 1, 1) + time2;

计算倒计时

每次打开面板时计算目标时间与当前时间的秒数差,在面板中对显示内容进行更新

注意:不要在帧更新函数中不停用 DateTime.Now​ 来计算,浪费性能。我们只需要在面板打开时计算一次时间差!之后再用该时间差来计算即可

1
int remainingSeconds = (int)(date - DateTime.Now).TotalSeconds;