System.DateTime比较(">")或"<")没有给出我期望的



我想从文件日期>今天截止日期的所有文件的列表中获取文件,因此,我有以下代码集

string[] MyFiles = Directory.GetFiles(MyConfig.pathTransmittedFiles, "*.adf")
        .Where(file => new FileInfo(file).LastWriteTime > dtCutOff).ToArray();

我有一个文件,其LastWriteTime为"{11/3/2015下午1:33:26}",我的收藏使用dtCutOff=="{2015年11月3日下午1:33:20}"提取该文件!所以">"似乎不起作用。

首先,我会尝试在不使用Where子句的情况下运行它,只是为了确保您期望的所有文件都是从Directory.GetFiles返回的初始数组的一部分。日期/时间的比较完全有可能不是差异的来源。它可能更多地与伊万在问题评论中链接的问题有关,也可能与权限有关,或者其他一些事情。

接下来,请注意,DateTime违反了SRP,因为它具有Kind属性,这是三个DateTimeKind枚举值之一。它是LocalUtcUnspecified

DateTime.Now的情况下,Kind将是DateTimeKind.LocalFile.GetLastWriteTime也返回其具有局部种类的值。因此,如果你总是以问题中所示的方式从DateTime.Now导出dtCutOff,那么它几乎总是正确的比较函数。

"几乎"源于DateTimeKind.Local实际上可以在封面下代表两种不同的类型。换句话说,实际上有四种,但其中两种是一种暴露出来的。这在Jon Skeet的博客文章《用DateTime更有趣》中被描述为"DateTime的黑暗秘密",在.NET Framework参考源的评论中也提到了这一点。在实践中,你应该只在夏时制倒计时转换期间的模糊时间遇到这种情况(比如上周日发生在美国的2015-11-01)。

现在,更可能的情况是,dtCutOff实际上不是从DateTime.Now派生的,而是从用户输入或数据库查找或其他机制派生的,那么它可能实际上代表了其他时区的本地时间,而不是本地计算机上的时区。换句话说,如果dtCutOff具有DateTimeKind.UtcKind,则该值以UTC为单位。如果它的KindDateTimeKind.Unspecified,则值可能是UTC、本地时区或其他时区。

关键是:两个DateTime值的比较评估Ticks属性的基础值。它不考虑Kind

由于文件时间是通用时间的绝对点(无论如何在NTFS上),因此您确实应该使用File.GetLastWriteTimeUtc方法,而不是在本地时间工作的方法。

有两种方法可以使用:

  • modified属性加载为UTC,使用:

    myResult.modified = File.GetLastWriteTimeUtc(myFile);
    
  • 适当填充dtOffset

    • 如果从当前时间加载,请使用DateTime.UtcNow
    • 如果从其他输入加载,请确保将值转换为UTC以匹配输入场景。例如,如果值在本地时区中,请使用.ToUniversalTime();如果值在另一个时区中,则使用TimeZoneInfo类中的转换函数

  • modified属性更改为DateTimeOffset,而不是DateTime
  • 使用加载

    myResult.modified = new DateTimeOffset(File.GetLastWriteTimeUtc(myFile));
    
  • dtCutOff定义为DateTimeOffset,并适当填充。

    • 如果从当前时间加载,请使用DateTimeOffset.UtcNow
    • 如果从其他输入加载,请确保偏移量设置为与输入场景匹配。如果需要从其他时区转换,请使用TimeZoneInfo函数

DateTime相比,DateTimeOffset具有许多优点,例如不违反SRP。它总是代表一个绝对的时刻。在这种情况下,知道DateTimeOffset上的比较运算符总是反映那个绝对时刻会有所帮助。(换句话说,在进行比较之前,它会在内部调整为UTC。)

此代码有效:

var cutffDate = new DateTime(2015,1,1); // or whatever
var allFiles = Directory.GetFiles(MyConfig.pathTransmittedFiles, "*.adf");
var datedFiles = allFiles.Where(f => (new FileInfo(f)).LastWriteTime > cutffDate);

更新:由于您的问题似乎与精度有关,您可以将比较更改为:

const long precision = 10; // vary this as needed
allFiles.Where(f =>
  (new FileInfo(f)).LastWriteTime.ToFileTime()/precision > cutffDate.ToFileTime()/precision);

或者,您可以使用...LastAccessTime.Ticks/TimeSpan.TicksPerMillisecond除此之外,您可能需要将所有DateTime值转换为UTC(LastAccessTimeUtc和DateTime.UtcNow),以确保这不是一些奇怪的时区问题

由于文件每天被输入队列一次,因此不需要精确到一毫秒左右。因此,一秒的TimeSpan差异是可以接受的,可以完成这个技巧并使我的案例发挥作用。

string[] MyFiles = Directory.GetFiles(MyConfig.pathTransmittedFiles, "*.adf")
  .Where(file => new FileInfo(file).LastWriteTime - TimeSpan.FromSeconds(1) > dtCutOff)
  .ToArray();

现在,当我的截止日期为"{11/3/2015 1:33:26 PM}"时,我的修改日期为"{11/3/2015 11:33:26 PM}"的文件没有进入我的收藏,而我的另一个修改日期为{11/3/2015 1:33:27 PM}的文件已按预期成功进入我的藏品!!所以,它是有效的,这就是在所有这些建议之后它应该如何工作!谢谢大家。

看起来您的Where子句lambda可能不正确。试试这个。

string[] MyFiles = Directory.GetFiles(MyConfig.pathTransmittedFiles, "*.adf").Where(file => file.modified > dtCutOff).ToArray();

相关内容

最新更新