使用 DateTime class 使用夏令时

Working with daylight saving time with the DateTime class

我正在将 C++ 程序移植到 C#。该程序需要能够读取文件的 "modified" 时间戳并将其存储在 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++ 程序中的小时值将减一。我似乎无法在我的程序中复制它。在 DateTimeMSDN article 中,它在 "DateTime values" 下显示:"local time is optionally affected by daylight saving time, which adds or subtracts an hour from the length of a day"。在我的 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++ 应用程序相同的小时值。

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

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

该错误实际上与 .NET 无关,而与您的 C++ 代码有关。您正在使用 FileTimeToLocalFileTime,它有一个众所周知的错误,如 KB932955:

中所述

Note The FileTimeToLocalFileTime() function and the LocalFileTimeToFileTime() function perform the conversion between UTC time and local time by using only the current time zone information and the DST information. This conversion occurs regardless of the timestamp that is being converted.

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

FileTimeToLocalFileTime 函数的 MSDN entry 的备注部分描述了 C++ 代码的修复:

To account for daylight saving time when converting a file time to a local time, use the following sequence of functions in place of using FileTimeToLocalFileTime:

  1. FileTimeToSystemTime
  2. SystemTimeToTzSpecificLocalTime
  3. SystemTimeToFileTime

既然您了解了错误 - 如果您真的想在 C# 中保留该行为(我推荐),那么您将执行以下操作:

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

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