日期时间子系统(CategoryTime)
SDL 提供实时时钟和日期/时间相关的函数,用于处理日历时间(区别于 Timer 模块的短时长计时)。
本模块核心使用两种数据类型:
SDL_Time:表示从某个特定时间点("纪元/epoch")开始的纳秒数(时间戳);SDL_DateTime:将时间拆解为人类可读的组件(年、月、日、时、分、秒等)。
模块的大部分功能围绕这两种类型的相互转换,以及获取时间相关的辅助信息展开。
函数
- SDL_DateTimeToTime:将 SDL_DateTime 结构体转换为 SDL_Time 时间戳(纳秒级)
- SDL_GetCurrentTime:获取当前系统时间的 SDL_Time 时间戳(基于 UTC 时间,纳秒级)
- SDL_GetDateTimeLocalePreferences:获取当前系统的日期/时间格式偏好(如日期格式、时间格式)
- SDL_GetDayOfWeek:根据 SDL_DateTime 计算该日期是一周中的第几天(0=周日,1=周一,…,6=周六)
- SDL_GetDayOfYear:根据 SDL_DateTime 计算该日期是一年中的第几天(1-366)
- SDL_GetDaysInMonth:获取指定年份和月份的天数(自动处理闰年)
- SDL_TimeFromWindows:将 Windows 系统的 FILETIME 时间转换为 SDL_Time 时间戳
- SDL_TimeToDateTime:将 SDL_Time 时间戳转换为 SDL_DateTime 结构体(拆解为年月日时分秒)
- SDL_TimeToWindows:将 SDL_Time 时间戳转换为 Windows 系统的 FILETIME 时间格式
数据类型
- (无)
结构体
- SDL_DateTime:日期时间结构体(包含年、月、日、时、分、秒、毫秒、微秒、纳秒、时区偏移等字段)
枚举
- SDL_DateFormat:日期格式枚举(如 MM/DD/YYYY、DD/MM/YYYY、YYYY/MM/DD 等)
- SDL_TimeFormat:时间格式枚举(如 12小时制、24小时制)
FreeBASIC 示例代码
' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库)
#Include "SDL.bi"
' 补充 SDL_Time 类型定义(纳秒级时间戳,无符号64位整型)
Type SDL_Time As ULLong
' 补充 SDL_DateTime 结构体定义
Type SDL_DateTime
year As Integer ' 年份(如 2026)
month As Integer ' 月份(1-12)
day As Integer ' 日期(1-31)
hour As Integer ' 小时(0-23)
minute As Integer ' 分钟(0-59)
second As Integer ' 秒(0-59)
millisecond As Integer ' 毫秒(0-999)
microsecond As Integer ' 微秒(0-999)
nanosecond As Integer ' 纳秒(0-999)
tz_offset_minutes As Integer ' 时区偏移(分钟,UTC+8 为 480)
End Type
' 补充日期/时间格式枚举定义
Enum SDL_DateFormat
SDL_DATE_FORMAT_MMDDYYYY = 0 ' 月/日/年(美式)
SDL_DATE_FORMAT_DDMMYYYY = 1 ' 日/月/年(欧式)
SDL_DATE_FORMAT_YYYYMMDD = 2 ' 年/月/日(ISO)
End Enum
Enum SDL_TimeFormat
SDL_TIME_FORMAT_24HR = 0 ' 24小时制
SDL_TIME_FORMAT_12HR = 1 ' 12小时制
End Enum
' 补充函数声明(FreeBASIC 绑定可能缺失)
Declare Function SDL_GetCurrentTime CDecl () As SDL_Time
Declare Function SDL_TimeToDateTime CDecl (ByVal time As SDL_Time, ByVal dt As SDL_DateTime Ptr) As Integer
Declare Function SDL_DateTimeToTime CDecl (ByVal dt As SDL_DateTime Ptr, ByVal time As SDL_Time Ptr) As Integer
Declare Function SDL_GetDayOfWeek CDecl (ByVal dt As SDL_DateTime Ptr) As Integer
Declare Function SDL_GetDayOfYear CDecl (ByVal dt As SDL_DateTime Ptr) As Integer
Declare Function SDL_GetDaysInMonth CDecl (ByVal year As Integer, ByVal month As Integer) As Integer
Declare Sub SDL_GetDateTimeLocalePreferences CDecl (ByVal date_format As SDL_DateFormat Ptr, ByVal time_format As SDL_TimeFormat Ptr)
' 打印 SDL_DateTime 结构体内容
Sub PrintDateTime(ByVal dt As SDL_DateTime Ptr, ByVal title As ZString Ptr)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== %s ===", title)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 日期:%04d年%02d月%02d日", dt->year, dt->month, dt->day)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 时间:%02d:%02d:%02d.%03d%03d%03d", dt->hour, dt->minute, dt->second, _
dt->millisecond, dt->microsecond, dt->nanosecond)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 时区:UTC%+d (偏移 %d 分钟)", dt->tz_offset_minutes / 60, dt->tz_offset_minutes)
' 计算星期几
Dim As Integer weekday = SDL_GetDayOfWeek(dt)
Dim As ZString * 10 weekdayStr
Select Case weekday
Case 0: weekdayStr = "周日"
Case 1: weekdayStr = "周一"
Case 2: weekdayStr = "周二"
Case 3: weekdayStr = "周三"
Case 4: weekdayStr = "周四"
Case 5: weekdayStr = "周五"
Case 6: weekdayStr = "周六"
End Select
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 星期:%s (一周的第%d天)", weekdayStr, weekday)
' 计算一年中的第几天
Dim As Integer dayOfYear = SDL_GetDayOfYear(dt)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 年内天数:第%d天", dayOfYear)
' 计算当月天数
Dim As Integer daysInMonth = SDL_GetDaysInMonth(dt->year, dt->month)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 当月天数:%d天", daysInMonth)
End Sub
' 主程序
Sub Main()
' 初始化 SDL(Time 模块无需显式初始化子系统)
If (SDL_Init(0) < 0) Then
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
Exit Sub
End If
' ========== 1. 获取当前系统时间 ==========
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "【1. 获取当前系统时间】")
Dim As SDL_Time currentTime = SDL_GetCurrentTime()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "当前时间戳(纳秒):%llu", currentTime)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "当前时间戳(秒):%.3f", currentTime / 1000000000.0)
' ========== 2. 时间戳转换为日期时间 ==========
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【2. 时间戳转日期时间】")
Dim As SDL_DateTime dt
If (SDL_TimeToDateTime(currentTime, @dt) = 0) Then
PrintDateTime(@dt, "当前系统日期时间")
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "时间戳转日期时间失败:%s", SDL_GetError())
End If
' ========== 3. 日期时间转换为时间戳 ==========
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【3. 日期时间转时间戳】")
' 手动构造一个日期时间(2026年3月8日 12:34:56.123456789,UTC+8)
Dim As SDL_DateTime customDt
customDt.year = 2026
customDt.month = 3
customDt.day = 8
customDt.hour = 12
customDt.minute = 34
customDt.second = 56
customDt.millisecond = 123
customDt.microsecond = 456
customDt.nanosecond = 789
customDt.tz_offset_minutes = 8 * 60 ' UTC+8
PrintDateTime(@customDt, "自定义日期时间")
' 转换为时间戳
Dim As SDL_Time customTime
If (SDL_DateTimeToTime(@customDt, @customTime) = 0) Then
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "自定义日期时间对应的时间戳:")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 纳秒:%llu", customTime)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, " 秒:%.9f", customTime / 1000000000.0)
Else
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "日期时间转时间戳失败:%s", SDL_GetError())
End If
' ========== 4. 获取系统日期时间格式偏好 ==========
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【4. 获取系统日期时间格式偏好】")
Dim As SDL_DateFormat dateFmt
Dim As SDL_TimeFormat timeFmt
SDL_GetDateTimeLocalePreferences(@dateFmt, @timeFmt)
Dim As ZString * 20 dateFmtStr
Select Case dateFmt
Case SDL_DATE_FORMAT_MMDDYYYY: dateFmtStr = "MM/DD/YYYY(月/日/年)"
Case SDL_DATE_FORMAT_DDMMYYYY: dateFmtStr = "DD/MM/YYYY(日/月/年)"
Case SDL_DATE_FORMAT_YYYYMMDD: dateFmtStr = "YYYY/MM/DD(年/月/日)"
End Select
Dim As ZString * 20 timeFmtStr
Select Case timeFmt
Case SDL_TIME_FORMAT_24HR: timeFmtStr = "24小时制"
Case SDL_TIME_FORMAT_12HR: timeFmtStr = "12小时制"
End Select
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "系统日期格式:%s", dateFmtStr)
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "系统时间格式:%s", timeFmtStr)
' ========== 5. 闰年测试 ==========
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "【5. 闰年/月份天数测试】")
Dim As Integer years(0 To 3) = {2024, 2025, 2026, 2000}
Dim As Integer months(0 To 1) = {2, 4} ' 2月、4月
For i As Integer = 0 To 3
For j As Integer = 0 To 1
Dim As Integer days = SDL_GetDaysInMonth(years(i), months(j))
Dim As ZString * 10 leapStr = IIf(months(j)=2 And days=29, "(闰年)", "")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "%d年%d月的天数:%d天 %s", years(i), months(j), days, leapStr)
Next
Next
' 清理 SDL
SDL_Quit()
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "程序正常退出")
End Sub
' 运行主程序
Main()
核心知识点补充
-
SDL_Time 核心特性:
- 本质是无符号64位整型(ULLong),表示从 "Unix 纪元"(1970-01-01 00:00:00 UTC)开始的纳秒数;
- 范围覆盖约 584 年(0 ~ 18446744073709551615 纳秒),足够满足常规日期时间需求;
- 与系统时钟同步,可精准表示当前系统时间。
-
SDL_DateTime 字段规则:
- 月份范围:1(1月)~ 12(12月),而非0开始;
- 日期范围:1 ~ 当月最大天数(由
SDL_GetDaysInMonth计算); - 时间字段:小时(0-23)、分钟(0-59)、秒(0-59),毫秒/微秒/纳秒均为 0-999;
- 时区偏移:以分钟为单位,UTC+8 对应 480 分钟,UTC-5 对应 -300 分钟。
-
闰年判断逻辑:
SDL_GetDaysInMonth会自动处理闰年:- 能被400整除的年份是闰年;
- 能被4整除但不能被100整除的年份是闰年;
- 其他年份为平年;
- 闰年2月有29天,平年2月有28天。
-
本地化格式偏好:
SDL_GetDateTimeLocalePreferences获取系统默认的日期/时间显示格式;- 常见日期格式:
- MM/DD/YYYY:美式(如 03/08/2026);
- DD/MM/YYYY:欧式(如 08/03/2026);
- YYYY/MM/DD:ISO标准(如 2026/03/08);
- 时间格式:12小时制(带AM/PM)、24小时制。
总结
-
核心优势:
- 提供跨平台的日历时间处理接口,屏蔽不同系统的时间API差异;
- 支持纳秒级高精度时间戳,兼顾精度与易用性;
- 内置日期时间拆解/组装、星期/年内天数计算、闰年判断等实用功能;
- 支持本地化格式偏好获取,适配不同地区的显示习惯。
-
使用建议:
SDL_GetCurrentTime是获取当前时间的首选方式(UTC 时间,无时区偏差);- 转换时间戳/日期时间时,需检查函数返回值(0=成功,非0=失败);
- 处理时区时,注意
tz_offset_minutes字段的单位是分钟,需转换为小时展示; - 计算星期/年内天数前,确保 SDL_DateTime 结构体的年月日字段有效。
-
关键接口:
- 时间获取:
SDL_GetCurrentTime(); - 类型转换:
SDL_TimeToDateTime()/SDL_DateTimeToTime(); - 日期计算:
SDL_GetDayOfWeek()/SDL_GetDayOfYear()/SDL_GetDaysInMonth(); - 本地化:
SDL_GetDateTimeLocalePreferences()。
- 时间获取:
评论一下?