17.CSharp其它知识补充-日期和时间
17.1 知识点
目前学习过和时间相关的内容
- 目前我们只在Unity当中学习过Time类
- 我们可以通过Time获取当前游戏相关的时间,比如帧间隔时间,游戏运行的时间和帧数等等内容
- 但是我们并没有学习过和真实世界时间相关的内容,比如如何得知当前时间的 年、月、日、时、分、秒
- 这节课我们将要学习的就是真实时间相关的内容
时间对于我们的作用
- 在游戏开发当中我们经常会有和时间打交道的内容
- 比如每日签到、活动倒计时、建造时间、激活时间等等的功能
- 如果想要完成这些功能,仅仅用Unity提供给我们的Time类是远远不够用的
- 所以我们需要学习专门的日期和时间相关的知识
- 而C#便提供了对应的结构方便我们处理时间相关逻辑
- DateTime 日期结构体
- TimeSpan 时间跨度结构体
一些关于时间的名词说明
单位换算
- 1s秒 = 1000ms毫秒
- 1ms毫秒 = 1000μs微秒
- 1μs微妙 = 1000ns纳秒
格里高利历
- 格里高利历一般指公元
- 公元,即公历纪年法
- 目前我们所说公历,就是格里高利历
- 比如2022年就是从公元元年开始算起的两千二十二年
格林尼治时间(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/3153 6000=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
初始化
- 主要参数:
- 年、月、日、时、分、秒、毫秒
- ticks:以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字
- 次要参数:
- DateTimeKind:日期时间种类
- Local:本地时间
- Utc:UTC时间
- Unspecified:不指定
- Calendar:日历 使用哪个国家的日历,一般在Unity开发中不使用
DateTime dateTime = new DateTime(2022, 12, 1, 13, 30, 45, 500);
//年、月、日、时、分、秒、毫秒
print(dateTime.Year + "-" + dateTime.Month + "-" + dateTime.Day + "-" + dateTime.Hour + "-" + dateTime.Minute + "-" + dateTime.Second + "-" + dateTime.Millisecond);
//以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字
print(dateTime.Ticks);
//一年的第多少天
print(dateTime.DayOfYear);
//星期几
print(dateTime.DayOfWeek);
获取时间
- 获取当前日期和时间
- 返回今日日期
- 返回当前UTC日期和时间,在中国就是北京时间
- 区别:
- DateTime.Now 返回当前日期和时间,包括年、月、日、时、分、秒、毫秒等详细信息,根据当前系统的时区进行调整,返回的是本地时间
- DateTime.Today 返回今日的日期,即年、月、日,时、分、秒和毫秒部分都是零,不受系统时区的影响
// 获取当前日期和时间
DateTime nowTime = DateTime.Now;
print(nowTime.Minute); // 打印当前分钟数
// 返回今日日期
DateTime nowTime2 = DateTime.Today;
print(nowTime2.Year + "-" + nowTime2.Month + "-" + nowTime2.Day); // 打印当前年月日
// 返回当前UTC日期和时间,在中国就是北京时间
DateTime nowTimeUTC = DateTime.UtcNow;
//DateTime.Now 和 DateTime.Today 是 DateTime 类的两个属性,用于获取日期和时间的不同方面信息。
//DateTime.Now 返回当前日期和时间,包括年、月、日、时、分、秒、毫秒等详细信息。它会根据当前系统的时区进行调整,所以返回的是本地时间。
//DateTime.Today 返回今日的日期,即年、月、日,时、分、秒和毫秒部分都是零。该值表示当天的午夜时间。它不受系统时区的影响,始终返回当地时间的日期。
//因此,主要区别在于:
//DateTime.Now 包含了日期和时间的所有信息,而 DateTime.Today 只包含了日期信息。
//DateTime.Now 返回的是本地时间,考虑了系统时区的影响。而 DateTime.Today 始终返回当地时间的日期,不受系统时区的影响。
//总的来说,如果需要获取当前的完整日期和时间信息,使用 DateTime.Now;如果只需要获取当前日期(不包括时间部分),使用 DateTime.Today。
计算时间
- 各种加时间
DateTime nowTime3 = nowTime.AddDays(-1);
print(nowTime3.Day);
字符串输出
print(nowTime.ToString()); // 输出当前时间的默认格式,例如 “2023/07/16 15:20:13”
print(nowTime.ToShortTimeString()); // 输出当前时间的短时间格式,例如 “15:20”
print(nowTime.ToShortDateString()); // 输出当前时间的短日期格式,例如 “2023/07/16”
print(nowTime.ToLongTimeString()); // 输出当前时间的长时间格式,例如 “15:20:13”
print(nowTime.ToLongDateString()); // 输出当前时间的长日期格式,例如 “2023年7月16日”
print(nowTime.ToString("D")); // 输出当前时间的长日期格式,与 ToLongDateString() 相同
print(nowTime.ToString("yyyy - MM - dd - ddd / HH - mm - ss")); // 输出当前时间的自定义格式,例如 “2023-07-16-日/15-20-13”
字符串转DateTime
- 字符串想要转回 DateTime 成功的话
- 格式要求:年/月/日 时:分:秒
// 字符串想要转回 DateTime 成功的话
// 那么这个字符串的格式是有要求的,一定是最基本的 ToString 的转换出来的字符串才能转回去
// 年/月/日 时:分:秒
string str = nowTime.ToString(); // 将当前时间转换为字符串并赋值给变量 str
str = "1988/5/4 18:00:08"; // 将字符串变量 str 的值修改为指定的字符串
print(str); // 输出修改后的字符串
DateTime dateTime2; // 创建一个新的 DateTime 变量 dateTime2
if (DateTime.TryParse(str, out dateTime2)) // 尝试将字符串转换为 DateTime 类型并赋值给 dateTime2,并检查转换是否成功
{
print(dateTime2); // 如果转换成功,则输出转换后的 DateTime 值
}
else
{
print("转换失败"); // 如果转换失败,则输出提示信息
}
存储时间
存储时间 方式很多
- 以直接存字符串 不建议
- 可以直接存Ticks 不建议
- 可以直接存时间戳信息 建议存储时间戳的形式 更加节约
得到当前时间戳
DateTime currentTime = DateTime.Now;
long timeStamp = ((DateTimeOffset)currentTime).ToUnixTimeSeconds();
Console.WriteLine("当前时间戳:" + timeStamp);
TimeSpan
概述
- 命名空间:System
- TimeSpan 是 C# 提供给我们的时间跨度结构体
- 用两个DateTime对象相减 可以得到该对象
TimeSpan timeSpan = DateTime.Now - new DateTime(1970, 1, 1);
// 创建一个 TimeSpan 对象 timeSpan,表示当前时间与 1970 年 1 月 1 日之间的时间间隔
print("总分钟数: " + timeSpan.TotalMinutes);
// 输出时间间隔的总分钟数
print("总秒数: " + timeSpan.TotalSeconds);
// 输出时间间隔的总秒数
print("总天数: " + timeSpan.TotalDays);
// 输出时间间隔的总天数
print("总小时数: " + timeSpan.TotalHours);
// 输出时间间隔的总小时数
print("总刻度数: " + timeSpan.Ticks);
// 输出时间间隔的总刻度数
print("时间间隔: " + timeSpan.Days + "-" + timeSpan.Hours + "-" + timeSpan.Minutes + "-" + timeSpan.Seconds + "-" + timeSpan.Milliseconds);
// 使用连接符将时间间隔的天数、小时数、分钟数、秒数和毫秒数以字符串形式进行拼接,并输出
初始化TimeSpan来代表时间间隔
TimeSpan timeSpan2 = new TimeSpan(1, 0, 0, 0);
// 创建一个 TimeSpan 对象 timeSpan2,表示一个时间间隔为 1 天(1 天 = 24 小时 = 1440 分钟 = 86400 秒)
DateTime timeNow = DateTime.Now + timeSpan2;
// 创建一个 DateTime 对象 timeNow,表示当前时间加上 timeSpan2 所表示的时间间隔后的时间
用TimeSpan相互计算
TimeSpan timeSpan3 = new TimeSpan(0, 1, 1, 1);
// 创建一个 TimeSpan 对象 timeSpan3,表示一个时间间隔为 1 小时、1 分钟和 1 秒的时间
TimeSpan timeSpan4 = timeSpan2 + timeSpan3;
// 将 timeSpan2 和 timeSpan3 所表示的时间间隔相加,将结果赋值给 timeSpan4
print(timeSpan4.Days + "-" + timeSpan4.Hours);
// 输出 timeSpan4 的天数和小时数
自带常量方便用于和ticks进行计算
TicksPerSecond
是TimeSpan
结构中的一个静态字段,它表示一秒钟所包含的时间刻度数。在C#中,时间被表示为一系列的时间刻度(ticks),其中1秒包含的刻度数是固定的,即10,000,000个刻度。因此,TicksPerSecond
的值就是10,000,000,表示每秒钟包含了10,000,000个时间刻度。
print(timeSpan4.Ticks / TimeSpan.TicksPerSecond);
// 输出 timeSpan4 表示的时间间隔的总秒数
17.2 知识点代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson17_CSharp其它知识补充_日期和时间 : MonoBehaviour
{
void Start()
{
#region 知识点一 目前学习过和时间相关的内容
//目前我们只在Unity当中学习过Time类
//我们可以通过Time获取当前游戏相关的时间
//比如帧间隔时间,游戏运行的时间和帧数等等内容
//但是我们并没有学习过和真实世界时间相关的内容
//比如如何得知当前时间的 年、月、日、时、分、秒
//这节课我们将要学习的就是真实时间相关的内容
#endregion
#region 知识点二 时间对于我们的作用
//在游戏开发当中我们经常会有和时间打交道的内容
//比如每日签到、活动倒计时、建造时间、激活时间等等的功能
//如果想要完成这些功能,仅仅用Unity提供给我们的Time类是远远不够用的
//所以我们需要学习专门的日期和时间相关的知识
//才能制作某些功能需求
//而C#便提供了对应的结构方便我们处理时间相关逻辑
//1.DateTime 日期结构体
//2.TimeSpan 时间跨度结构体
#endregion
#region 知识点三 一些关于时间的名词说明
//单位换算
//1s秒 = 1000ms毫秒
//1ms毫秒 = 1000μs微秒
//1μs微妙 = 1000ns纳秒
//格里高利历:
//格里高利历一般指公元
//公元,即公历纪年法
//目前我们所说公历,就是格里高利历
//比如2022年就是从公元元年开始算起的两千二十二年
//格林尼治时间(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/3153 6000=68.1年
//也就是说因为早期用32位来表示时间,最大的时间间隔是68年
//而最早出现的UNIX操作系统考虑到计算机产生的年代和应用的
//时限综合取了1970年1月1日作为UNIX TIME的纪元时间(开始时间)
#endregion
#region 知识点四 DateTime
#region 概述
//命名空间:System
//DateTime 是 C# 提供给我们处理日期和时间的结构体
//DateTime 对象的默认值和最小值是0001年1月1日00:00:00(午夜)
// 最大值可以是9999年12月31日晚上11:59:59
#endregion
#region 初始化
//主要参数:
//年、月、日、时、分、秒、毫秒
//ticks:以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字
//次要参数:
//DateTimeKind:日期时间种类
//Local:本地时间
//Utc:UTC时间
//Unspecified:不指定
//Calendar:日历 使用哪个国家的日历,一般在Unity开发中不使用
DateTime dateTime = new DateTime(2022, 12, 1, 13, 30, 45, 500);
//年、月、日、时、分、秒、毫秒
print(dateTime.Year + "-" + dateTime.Month + "-" + dateTime.Day + "-" + dateTime.Hour + "-" + dateTime.Minute + "-" + dateTime.Second + "-" + dateTime.Millisecond);
//以格里高利历00:00:00.000年1月1日以来的100纳秒间隔数表示,一般是一个很大的数字
print(dateTime.Ticks);
//一年的第多少天
print(dateTime.DayOfYear);
//星期几
print(dateTime.DayOfWeek);
#endregion
#region 获取时间
// 获取当前日期和时间
DateTime nowTime = DateTime.Now;
print(nowTime.Minute); // 打印当前分钟数
// 返回今日日期
DateTime nowTime2 = DateTime.Today;
print(nowTime2.Year + "-" + nowTime2.Month + "-" + nowTime2.Day); // 打印当前年月日
// 返回当前UTC日期和时间,在中国就是北京时间
DateTime nowTimeUTC = DateTime.UtcNow;
//DateTime.Now 和 DateTime.Today 是 DateTime 类的两个属性,用于获取日期和时间的不同方面信息。
//DateTime.Now 返回当前日期和时间,包括年、月、日、时、分、秒、毫秒等详细信息。它会根据当前系统的时区进行调整,所以返回的是本地时间。
//DateTime.Today 返回今日的日期,即年、月、日,时、分、秒和毫秒部分都是零。该值表示当天的午夜时间。它不受系统时区的影响,始终返回当地时间的日期。
//因此,主要区别在于:
//DateTime.Now 包含了日期和时间的所有信息,而 DateTime.Today 只包含了日期信息。
//DateTime.Now 返回的是本地时间,考虑了系统时区的影响。而 DateTime.Today 始终返回当地时间的日期,不受系统时区的影响。
//总的来说,如果需要获取当前的完整日期和时间信息,使用 DateTime.Now;如果只需要获取当前日期(不包括时间部分),使用 DateTime.Today。
#endregion
#region 计算时间
//各种加时间
DateTime nowTime3 = nowTime.AddDays(-1);
print(nowTime3.Day);
#endregion
#region 字符串输出
print(nowTime.ToString()); // 输出当前时间的默认格式,例如 “2023/07/16 15:20:13”
print(nowTime.ToShortTimeString()); // 输出当前时间的短时间格式,例如 “15:20”
print(nowTime.ToShortDateString()); // 输出当前时间的短日期格式,例如 “2023/07/16”
print(nowTime.ToLongTimeString()); // 输出当前时间的长时间格式,例如 “15:20:13”
print(nowTime.ToLongDateString()); // 输出当前时间的长日期格式,例如 “2023年7月16日”
print(nowTime.ToString("D")); // 输出当前时间的长日期格式,与 ToLongDateString() 相同
print(nowTime.ToString("yyyy - MM - dd - ddd / HH - mm - ss")); // 输出当前时间的自定义格式,例如 “2023-07-16-日/15-20-13”
#endregion
#region 字符串转DateTime
// 字符串想要转回 DateTime 成功的话
// 那么这个字符串的格式是有要求的,一定是最基本的 ToString 的转换出来的字符串才能转回去
// 年/月/日 时:分:秒
string str = nowTime.ToString(); // 将当前时间转换为字符串并赋值给变量 str
str = "1988/5/4 18:00:08"; // 将字符串变量 str 的值修改为指定的字符串
print(str); // 输出修改后的字符串
DateTime dateTime2; // 创建一个新的 DateTime 变量 dateTime2
if (DateTime.TryParse(str, out dateTime2)) // 尝试将字符串转换为 DateTime 类型并赋值给 dateTime2,并检查转换是否成功
{
print(dateTime2); // 如果转换成功,则输出转换后的 DateTime 值
}
else
{
print("转换失败"); // 如果转换失败,则输出提示信息
}
#endregion
#region 存储时间
//存储时间 方式很多
//1.以直接存字符串 不建议
//2.可以直接存Ticks 不建议
//3.可以直接存时间戳信息 建议
//存储时间戳的形式 更加节约
#endregion
#endregion
#region 知识点五 TimeSpan
#region 概述
//命名空间:System
//TimeSpan 是 C# 提供给我们的时间跨度结构体
//用两个DateTime对象相减 可以得到该对象
TimeSpan timeSpan = DateTime.Now - new DateTime(1970, 1, 1);
// 创建一个 TimeSpan 对象 timeSpan,表示当前时间与 1970 年 1 月 1 日之间的时间间隔
print("总分钟数: " + timeSpan.TotalMinutes);
// 输出时间间隔的总分钟数
print("总秒数: " + timeSpan.TotalSeconds);
// 输出时间间隔的总秒数
print("总天数: " + timeSpan.TotalDays);
// 输出时间间隔的总天数
print("总小时数: " + timeSpan.TotalHours);
// 输出时间间隔的总小时数
print("总刻度数: " + timeSpan.Ticks);
// 输出时间间隔的总刻度数
print("时间间隔: " + timeSpan.Days + "-" + timeSpan.Hours + "-" + timeSpan.Minutes + "-" + timeSpan.Seconds + "-" + timeSpan.Milliseconds);
// 使用连接符将时间间隔的天数、小时数、分钟数、秒数和毫秒数以字符串形式进行拼接,并输出
#endregion
#region 初始化TimeSpan来代表时间间隔
TimeSpan timeSpan2 = new TimeSpan(1, 0, 0, 0);
// 创建一个 TimeSpan 对象 timeSpan2,表示一个时间间隔为 1 天(1 天 = 24 小时 = 1440 分钟 = 86400 秒)
DateTime timeNow = DateTime.Now + timeSpan2;
// 创建一个 DateTime 对象 timeNow,表示当前时间加上 timeSpan2 所表示的时间间隔后的时间
#endregion
#region 用TimeSpan相互计算
TimeSpan timeSpan3 = new TimeSpan(0, 1, 1, 1);
// 创建一个 TimeSpan 对象 timeSpan3,表示一个时间间隔为 1 小时、1 分钟和 1 秒的时间
TimeSpan timeSpan4 = timeSpan2 + timeSpan3;
// 将 timeSpan2 和 timeSpan3 所表示的时间间隔相加,将结果赋值给 timeSpan4
print(timeSpan4.Days + "-" + timeSpan4.Hours);
// 输出 timeSpan4 的天数和小时数
#endregion
#region 自带常量方便用于和ticks进行计算
print(timeSpan4.Ticks / TimeSpan.TicksPerSecond);
// 输出 timeSpan4 表示的时间间隔的总秒数
#endregion
#endregion
}
}
17.3 练习题
如果想要记录一个以当前系统时间起,间隔2天后的时间戳信息。如何通过代码获取该时间戳?如果又要将该时间戳转换为对应DateTime应该如何转换?如果想要进行倒计时,计算当前时间离目标时间还有多久应该如何计算?
//获取时间戳
//用当前时间加上2天 再 减去 1970年1月1日的时间 得到时间差
TimeSpan time = DateTime.Now.AddDays(2) - new DateTime(1970, 1, 1);
//再将该时间差转换为秒 便得到最终的时间戳 我们只需要存储该int变量即可
int timeStamp = (int)(time.Ticks / TimeSpan.TicksPerSecond);
//将该时间戳转换为对应DateTime应该如何转换
//由于时间戳的单位为秒,所以我们将其乘以转换常量 转为为ticks的单位
TimeSpan time2 = new TimeSpan(timeStamp * TimeSpan.TicksPerSecond);
//再用1970年1月1日+上该时间跨度即可
DateTime date = new DateTime(1970, 1, 1) + time2;
//计算当前时间离目标时间还有多久
//每次打开面板时计算目标时间和当前时间的秒数差
//在面板中对显示内容进行更新
//注意:不要在更新函数中不停用DateTime.Now来计算,浪费性能。我们只需要在面板打开时计算一次时间差
//之后 用该时间差进行计算即可
int seconds = (int)(date - DateTime.Now).TotalSeconds;
17.4 练习题代码
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson17_练习题 : MonoBehaviour
{
void Start()
{
#region 练习题一
//如果想要记录一个以当前系统时间起,间隔2天后的时间戳信息。
//如何通过代码获取该时间戳?
//如果又要将该时间戳转换为对应DateTime应该如何转换?
//如果想要进行倒计时,计算当前时间离目标时间还有多久应该如何计算?
//获取时间戳
//用当前时间加上2天 再 减去 1970年1月1日的时间 得到时间差
TimeSpan time = DateTime.Now.AddDays(2) - new DateTime(1970, 1, 1);
//再将该时间差转换为秒 便得到最终的时间戳 我们只需要存储该int变量即可
int timeStamp = (int)(time.Ticks / TimeSpan.TicksPerSecond);
//将该时间戳转换为对应DateTime应该如何转换
//由于时间戳的单位为秒,所以我们将其乘以转换常量 转为为ticks的单位
TimeSpan time2 = new TimeSpan(timeStamp * TimeSpan.TicksPerSecond);
//再用1970年1月1日+上该时间跨度即可
DateTime date = new DateTime(1970, 1, 1) + time2;
//计算当前时间离目标时间还有多久
//每次打开面板时计算目标时间和当前时间的秒数差
//在面板中对显示内容进行更新
//注意:不要在更新函数中不停用DateTime.Now来计算,浪费性能。我们只需要在面板打开时计算一次时间差
//之后 用该时间差进行计算即可
int seconds = (int)(date - DateTime.Now).TotalSeconds;
#endregion
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com