我想从文件日期>今天截止日期的所有文件的列表中获取文件,因此,我有以下代码集
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
枚举值之一。它是Local
、Utc
或Unspecified
。
在DateTime.Now
的情况下,Kind
将是DateTimeKind.Local
。File.GetLastWriteTime
也返回其具有局部种类的值。因此,如果你总是以问题中所示的方式从DateTime.Now
导出dtCutOff
,那么它几乎总是正确的比较函数。
"几乎"源于DateTimeKind.Local
实际上可以在封面下代表两种不同的类型。换句话说,实际上有四种,但其中两种是一种暴露出来的。这在Jon Skeet的博客文章《用DateTime更有趣》中被描述为"DateTime的黑暗秘密",在.NET Framework参考源的评论中也提到了这一点。在实践中,你应该只在夏时制倒计时转换期间的模糊时间遇到这种情况(比如上周日发生在美国的2015-11-01)。
现在,更可能的情况是,dtCutOff
实际上不是从DateTime.Now
派生的,而是从用户输入或数据库查找或其他机制派生的,那么它可能实际上代表了其他时区的本地时间,而不是本地计算机上的时区。换句话说,如果dtCutOff
具有DateTimeKind.Utc
的Kind
,则该值以UTC为单位。如果它的Kind
为DateTimeKind.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();