.Net中如何实现SystemTime与FileTime之间的相互转换?
嘿,我来帮你搞定.NET里SystemTime和FileTime的转换问题!
首先得说,你对FileTime的理解完全没错——它就是个64位值,记录从1601年1月1日UTC零点开始的100纳秒间隔数。至于为啥在Stack Overflow搜不到太多相关结果?其实是因为.NET里已经把这些Windows API的功能封装成了更易用的方法,大家很少直接用SystemTimeToFileTime这种原生API名称来提问,所以才会搜不到。
下面给你两种最常用的实现方式,按需选就行:
1. 用.NET内置的DateTime方法(最简单,推荐)
如果你不需要直接操作原生的SYSTEMTIME或FILETIME结构体,只是要在“类似SystemTime的日期时间”和FileTime数值之间转换,用DateTime的内置方法就够了,完全不用碰Windows API:
把日期时间(对应SystemTime)转成FileTime
直接调用ToFileTime()或者ToFileTimeUtc()方法,就能得到对应的64位FileTime值:
// 假设你有一个要转换的DateTime(比如当前UTC时间) DateTime targetTime = DateTime.UtcNow; // 转成UTC的FileTime long fileTime = targetTime.ToFileTimeUtc();
把FileTime转成日期时间(对应SystemTime)
用FromFileTime()或FromFileTimeUtc()方法把64位数值转成DateTime,之后你可以直接获取年、月、日、时这些SystemTime包含的字段:
long fileTime = 133245678901234567; // 转成UTC的DateTime DateTime targetTime = DateTime.FromFileTimeUtc(fileTime); // 现在可以获取各个字段,比如targetTime.Year、targetTime.Hour等等
2. 直接和原生SYSTEMTIME/FILETIME结构体交互
如果因为业务需求(比如和原生Windows API交互)必须直接操作这两个结构体,也有两种方式:
方式A:通过DateTime中转(不用P/Invoke)
先把结构体转成DateTime,再转成目标结构体,代码更简洁:
using System.Runtime.InteropServices.ComTypes; // SYSTEMTIME转FILETIME SYSTEMTIME systemTime = new SYSTEMTIME { Year = 2024, Month = 5, Day = 20, Hour = 10, Minute = 30 }; // 先转成DateTime DateTime dateTime = new DateTime( systemTime.Year, systemTime.Month, systemTime.Day, systemTime.Hour, systemTime.Minute, systemTime.Second, systemTime.Millisecond, DateTimeKind.Utc); // 再转成FileTime数值,然后填充FILETIME结构体 long fileTimeValue = dateTime.ToFileTimeUtc(); FILETIME fileTimeStruct = new FILETIME { dwLowDateTime = (int)(fileTimeValue & 0xFFFFFFFF), dwHighDateTime = (int)(fileTimeValue >> 32) }; // FILETIME转SYSTEMTIME FILETIME inputFt = new FILETIME(); // 假设已经给inputFt赋值了dwLowDateTime和dwHighDateTime long inputFtValue = ((long)inputFt.dwHighDateTime << 32) | (uint)inputFt.dwLowDateTime; DateTime inputDt = DateTime.FromFileTimeUtc(inputFtValue); SYSTEMTIME outputSt = new SYSTEMTIME { Year = (ushort)inputDt.Year, Month = (ushort)inputDt.Month, Day = (ushort)inputDt.Day, Hour = (ushort)inputDt.Hour, Minute = (ushort)inputDt.Minute, Second = (ushort)inputDt.Second, Millisecond = (ushort)inputDt.Millisecond, DayOfWeek = (ushort)inputDt.DayOfWeek };
方式B:直接调用Windows API(P/Invoke)
如果你一定要用原生的SystemTimeToFileTime和FileTimeToSystemTime函数,也可以用P/Invoke来实现:
using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; [DllImport("kernel32.dll", SetLastError = true)] private static extern bool SystemTimeToFileTime([In] ref SYSTEMTIME lpSystemTime, out FILETIME lpFileTime); [DllImport("kernel32.dll", SetLastError = true)] private static extern bool FileTimeToSystemTime([In] ref FILETIME lpFileTime, out SYSTEMTIME lpSystemTime); // 使用示例 SYSTEMTIME inputSt = new SYSTEMTIME { Year = 2024, Month = 5, Day = 20 }; FILETIME outputFt; if (SystemTimeToFileTime(ref inputSt, out outputFt)) { // 转换成功,outputFt就是结果 } SYSTEMTIME outputSt; if (FileTimeToSystemTime(ref outputFt, out outputSt)) { // 转换成功,outputSt就是结果 }
总结一下:日常开发优先用第一种DateTime内置方法,简单省心;如果要和原生API交互,再选第二种方式。
内容的提问来源于stack exchange,提问作者user1889116

