《C# DateTime与时间戳转换》
在C#开发中,处理日期时间(DateTime)和时间戳(Timestamp)的转换是常见需求。时间戳通常指Unix时间戳,表示从1970年1月1日00:00:00 UTC(协调世界时)到当前时间的秒数或毫秒数。本文将详细介绍如何在C#中实现DateTime与时间戳的双向转换,包括UTC时间处理、时区转换、性能优化等关键点。
一、时间戳基础概念
时间戳分为两种类型:
- 秒级时间戳:10位数字,精确到秒
- 毫秒级时间戳:13位数字,精确到毫秒
例如,2023年1月1日12:00:00 UTC的秒级时间戳为1672560000,毫秒级时间戳为1672560000000。
二、DateTime转时间戳
1. 秒级时间戳转换
核心逻辑:将DateTime转换为UTC时间后,减去Unix纪元(1970-01-01)的总秒数。
public static long DateTimeToUnixTimestamp(DateTime dateTime)
{
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long)(dateTime.ToUniversalTime() - unixEpoch).TotalSeconds;
}
使用示例:
DateTime now = DateTime.Now;
long timestamp = DateTimeToUnixTimestamp(now);
Console.WriteLine($"当前秒级时间戳: {timestamp}");
2. 毫秒级时间戳转换
只需将TotalSeconds改为TotalMilliseconds:
public static long DateTimeToUnixTimestampMilliseconds(DateTime dateTime)
{
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return (long)(dateTime.ToUniversalTime() - unixEpoch).TotalMilliseconds;
}
3. 时区处理注意事项
必须显式调用ToUniversalTime()将本地时间转为UTC,否则时区偏移会导致错误结果:
// 错误示例(未转换时区)
DateTime localTime = DateTime.Now;
long wrongTimestamp = (long)(localTime - new DateTime(1970, 1, 1)).TotalSeconds; // 结果错误
// 正确做法
long correctTimestamp = (long)(localTime.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalSeconds;
三、时间戳转DateTime
1. 秒级时间戳转DateTime
核心逻辑:从Unix纪元开始增加指定秒数,并指定为UTC时间。
public static DateTime UnixTimestampToDateTime(long timestamp)
{
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return unixEpoch.AddSeconds(timestamp).ToLocalTime(); // 转为本地时间
}
若需保留UTC时间,移除ToLocalTime()调用。
2. 毫秒级时间戳转DateTime
使用AddMilliseconds方法:
public static DateTime UnixTimestampMillisecondsToDateTime(long timestamp)
{
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return unixEpoch.AddMilliseconds(timestamp).ToLocalTime();
}
3. 边界值处理
处理超出DateTime范围的值(约±10000年):
public static DateTime SafeUnixTimestampToDateTime(long timestamp)
{
try
{
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return unixEpoch.AddSeconds(timestamp);
}
catch (ArgumentOutOfRangeException)
{
return DateTime.MinValue; // 或抛出自定义异常
}
}
四、性能优化技巧
1. 缓存Unix纪元对象
避免每次转换都创建新的DateTime对象:
public static class UnixTimeConverter
{
private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long ToTimestamp(DateTime dateTime)
{
return (long)(dateTime.ToUniversalTime() - UnixEpoch).TotalSeconds;
}
}
2. 使用Span处理字符串(.NET Core 3.0+)
高效解析时间戳字符串:
public static DateTime ParseTimestampString(ReadOnlySpan timestampSpan)
{
if (long.TryParse(timestampSpan, out long timestamp))
{
return UnixEpoch.AddSeconds(timestamp);
}
throw new FormatException("无效的时间戳格式");
}
五、跨平台时区处理
1. 使用TimeZoneInfo
精确处理不同时区的转换:
public static DateTime ConvertTimestampToLocalTime(long timestamp, string timeZoneId)
{
DateTime utcTime = UnixEpoch.AddSeconds(timestamp);
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, zone);
}
常用时区ID:
- "China Standard Time"(北京时间)
- "Eastern Standard Time"(美国东部时间)
2. IANA时区支持(.NET 6+)
使用System.TimeZoneInfo的扩展方法:
// 需安装Microsoft.Extensions.Options包
public static DateTime ConvertFromIanaTimeZone(long timestamp, string ianaTimeZone)
{
var utcTime = UnixEpoch.AddSeconds(timestamp);
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(utcTime, ianaTimeZone);
}
六、实际应用场景
1. API接口时间处理
接收时间戳参数的示例:
[HttpGet("events/{timestamp}")]
public IActionResult GetEventsByTimestamp(long timestamp)
{
DateTime queryTime = UnixEpoch.AddSeconds(timestamp);
var events = _context.Events
.Where(e => e.EventTime >= queryTime)
.ToList();
return Ok(events);
}
2. 日志系统时间同步
生成带时间戳的日志:
public class TimestampLogger
{
public void Log(string message)
{
long timestamp = (long)(DateTime.UtcNow - UnixEpoch).TotalSeconds;
Console.WriteLine($"[{timestamp}] {message}");
}
}
七、常见问题解决方案
1. 16位时间戳问题
某些系统使用16位年份表示的时间戳,需特殊处理:
public static DateTime Parse16BitTimestamp(ushort timestamp)
{
// 假设16位时间戳从1980年开始
int baseYear = 1980;
return new DateTime(baseYear + (timestamp >> 9),
(timestamp >> 5) & 0x0F,
timestamp & 0x1F);
}
2. JavaScript时间戳兼容
JavaScript使用毫秒级时间戳,C#需除以1000:
public static long JsTimestampToCSharp(double jsTimestamp)
{
return (long)(jsTimestamp / 1000); // 转为秒级
}
八、单元测试示例
使用xUnit进行转换测试:
public class UnixTimeTests
{
[Fact]
public void DateTimeToTimestamp_RoundTrip()
{
DateTime testTime = new DateTime(2023, 1, 1, 0, 0, 0, DateTimeKind.Utc);
long timestamp = (long)(testTime - UnixEpoch).TotalSeconds;
DateTime converted = UnixEpoch.AddSeconds(timestamp);
Assert.Equal(testTime, converted);
}
[Fact]
public void TimestampToDateTime_LocalConversion()
{
long timestamp = 1672560000; // 2023-01-01 00:00:00 UTC
DateTime localTime = UnixEpoch.AddSeconds(timestamp).ToLocalTime();
// 验证时区偏移是否正确
Assert.True(localTime.Hour >= 0 && localTime.Hour
九、扩展方法实现
为DateTime添加扩展方法:
public static class DateTimeExtensions
{
private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
public static long ToUnixTimestamp(this DateTime dateTime)
{
return (long)(dateTime.ToUniversalTime() - UnixEpoch).TotalSeconds;
}
public static DateTime FromUnixTimestamp(this long timestamp)
{
return UnixEpoch.AddSeconds(timestamp);
}
}
// 使用示例
DateTime now = DateTime.Now;
long ts = now.ToUnixTimestamp();
DateTime restored = ts.FromUnixTimestamp();
十、.NET 7+新特性
DateTime在.NET 7中新增的DateOnly/TimeOnly支持:
public static long DateOnlyToTimestamp(DateOnly date)
{
DateTime dt = date.ToDateTime(new TimeOnly(0, 0), DateTimeKind.Utc);
return (long)(dt - UnixEpoch).TotalSeconds;
}
关键词:C#、DateTime、时间戳转换、Unix时间戳、UTC时间、时区处理、性能优化、扩展方法、.NET时间处理
简介:本文全面介绍C#中DateTime与Unix时间戳的双向转换方法,涵盖秒级/毫秒级时间戳处理、时区转换、性能优化技巧及实际应用场景,提供完整的代码示例和单元测试方案。