使用DateTime类使用夏令时

Working with daylight saving time with the DateTime class

本文关键字:夏令时 DateTime 使用      更新时间:2023-10-16

我正在将C++程序移植到C#。该程序需要能够读取文件的"修改"时间戳,并将其存储在List中。这就是我目前所拥有的:

C#代码:

ret = new List<Byte>(); //list to store the timestamp
var file = new FileInfo(filename);
//Get revision date/time
DateTime revTime_lastWriteTime_LT = file.LastWriteTime;
//Copy date/time into the List (binary buffer)
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Month));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Day));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Year % 100)); // 2-digit year
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Hour));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Minute));
ret.Add(Convert.ToByte(revTime_lastWriteTime_LT.Second));

读取Hours值时出现问题。如果该文件是在夏令时(如夏季月份)期间修改的,则C++程序中的小时值将减去1。我似乎无法在我的程序中复制这一点。在MSDN为DateTime撰写的文章中,它在"DateTime值"下说:"当地时间可能会受到夏令时的影响,夏令时会从一天的长度中增加或减去一个小时"。在我的C#代码中,我确保使用ToLocalTime()DateTime对象更改为本地时间,但显然我还没有设置本文所讨论的选项在读取夏令时期间修改的文件时,如何确保本地时间的DateTime对象减去一个值

C++代码以防万一:

static WIN32_FILE_ATTRIBUTE_DATA get_file_data(const std::string & filename)
{
  WIN32_FILE_ATTRIBUTE_DATA ret;
  if (!GetFileAttributesEx(filename.c_str(), GetFileExInfoStandard, &ret))
    RaiseLastWin32Error();
  return ret;
}
//---------------------------------------------------------------------------
static SYSTEMTIME get_file_time(const std::string & filename)
{
  const WIN32_FILE_ATTRIBUTE_DATA data(get_file_data(filename));
  FILETIME local;
  if (!FileTimeToLocalFileTime(&data.ftLastWriteTime, &local))
    RaiseLastWin32Error();
  SYSTEMTIME ret;
  if (!FileTimeToSystemTime(&local, &ret))
    RaiseLastWin32Error();
  return ret;
}
void parse_asm()
{
    // Get revision date/time and size
    const SYSTEMTIME rev = get_file_time(filename);
    // Copy date/time into the binary buffer
    ret.push_back(rev.wMonth);
    ret.push_back(rev.wDay);
    ret.push_back(rev.wYear % 100); // 2-digit year
    ret.push_back(rev.wHour);
    ret.push_back(rev.wMinute);
    ret.push_back(rev.wSecond);
}

清晰更新:

在Windows时间设置中,我在(UTC-05:00)东部时间(美国和加拿大)。该文件最后一次修改是在2013年9月3日(星期二)下午12:13:52。C++应用程序使用上面的代码将小时值显示为11,C#应用程序显示小时值为12。我需要C#应用程序显示与C++应用程序相同的小时值。

这个错误实际上不在.NET中,而是在C++代码中。您使用的是FileTimeToLocalFileTime,它有一个众所周知的错误,如KB932955:中所述

注意FileTimeToLocalFileTime()函数和LocalFileTimeToFileTime()函数执行UTC之间的转换仅使用当前时区信息的时间和本地时间以及DST信息。无论正在转换的时间戳。

因此,在你给出的例子中,2013年9月3日下午12:13:52,美国东部时区确实应该在夏令时。但因为现在是(2015年2月)而不是夏令时,所以您目前在C++程序中每小时获得11分。如果你在下个月的转换(2015年3月8日)后运行完全相同的C++代码,那么你将获得12个小时。

C++代码的修复程序在MSDN中FileTimeToLocalFileTime函数的注释部分进行了描述:

要在将文件时间转换为本地时间时考虑夏令时,请使用以下函数序列代替FileTimeToLocalFileTime:

  1. FileTimeToSystemTime
  2. SystemTimeToTzSpecificLocalTime
  3. SystemTimeToFileTime

既然你已经了解了这个bug——如果你真的想在C#中保持这种行为(我建议而不是),那么你应该做以下事情:

TimeSpan currentOffset = TimeZoneInfo.Local.GetUtcOffset(DateTime.UtcNow);
DateTime revTime_LastWriteTime_Lt = file.LastWriteTimeUtc.Add(currentOffset);

更好的做法是保持当前代码的原样(使用file.LastWriteTime),并修复错误。

对不起,您需要使用Add而不是AddHoursAdd接受TimeSpan。所以你正在寻找:

 file.LastWriteTimeUtc.Add(TimeZoneInfo.Local.BaseUtcOffset);