请考虑以下两种情况:情景1).今天是2012年5月1日,情景2).今天是2012年9月1日。
现在,考虑一下我们在网页上写了以下关于某人留下的评论:“此评论是在3个月零12天前写的”。即使语句完全相同,这两种情况下的天数也总是不同的。在情况1中,“3个月零12天”等于102 days
。但是,在情况2中,“3个月零12天”将等于104 days
!
现在,为了更好地理解我的观点,让我们使用一个不同的示例,假设有人在2013年1月30日在我们的网站上发表了评论,今天是2013年3月10日。我们的真实的TimeSpan对象需要知道这个相对日期,并可以计算出以下内容:
- 三月有十天,
- 一月有一天(从30号算到31号)。
- 二月是一个月,不管它有多少天(即使它是28天)。
因此,这意味着总共10天+1天+1个月,转换为This comment was posted 1 Month and 11 Days ago
。
现在,如果您使用MS样式TimeSpan对象(或任何语言中的任何TimeSpan对象),它将为您提供从1月30日到3月10日的天数(39天),并且因为TimeSpan对象不存储相对日期(我们减去基准/初始日期得到TimeSpan),如果你问它已经过了多少个月和多少天,它会假设一个月有30天,最坏的情况是,平均值大于30天,然后以天为单位返回其余的值,因此要返回39天,它会告诉您已经过了1个月零9天,您将收到This comment was posted 1 Month and 9 Days ago
消息。请记住,这两种情况都具有相同的开始日期和相同的当前/结束日期,是的,Microsoft TimeSpan对象,不允许我们告诉它应该考虑2013年2月,给了我们一个完全不同的时间跨度,整整偏离了2天。实际上,它欺骗了我们。
问题是,人们会相信这一点,谁知道他们可能会有什么感知,他们对过去的感知可能会如何变化,以及当他们试图在自己的头脑中重建过去的事件时可能会做出的决定和生活选择,而从来没有注意到或理解的缺点和固有的失败表示时间是如此普遍的今天。他们将不会理解编程语言不'我没有意识到(或不在乎)上个月有31天,而不是30天、29天或28天--反之亦然,而且当你增加TimeSpan时,这些天就会加起来。
这是这篇文章的核心问题,我明白大多数人不会在意这个差异(但要确保我们中的一些人这样做,不能有这个在我们的背上),如果这不打扰你,没关系。我希望它没有打扰我,我会节省自己一些时间,压力和失望。如果这不是一个麻烦,您可以使用该函数来高效地文本显示相对时间(可定制为1到6个节点,从秒到年),而不是使用它来提供通常可以忽略不计的精确度。
令我失望的是,我注意到没有真实的的时间跨度对象,如果你得到一个时间跨度,然后执行.years
或.months
,你将一无所获,你只会得到.days
和更小的值,因为timeSpan对象没有任何东西来告诉它timeSpan是在哪一年或哪一月创建的,因此它永远不会知道它到底有多少个月。It“自从一年中每个月的天数不同,甚至在闰年中更是如此。
为了回应这个问题,我将发布一个我开发的函数,以获得准确的读数,并能够在我的ASP.NET网页上返回如下内容...
4年3个月14天15小时18分24秒前发表
我以为会有...timeSpan.GetActualNumberOf[Months/Days/Hours/etc]
(当然必须提供基准日期)
...此数据类型上的类型方法,但没有。
您真正需要做的就是在timeSpan对象上创建另一个属性,为它提供一个计算差值的基准日期,然后上面可爱的字符串将非常容易计算,并且.year
& .month
将存在!
更新:我已经显着扩大和更新了我的官方答案和代码使用细节在我的答案如下,100%的工作答案和代码(完整),准确和确切的相对时间/日期,没有近似-谢谢。
8条答案
按热度按时间hgqdbh6s1#
下面是如何用C#添加一些使用均值的扩展方法:
drnojrws2#
您要查找的内容确实不是
TimeSpan
所表示的内容。TimeSpan
将间隔表示为刻度计数,而不考虑基数DateTime
或Calendar
。新的
DateDifference
类型在这里可能更有意义,它的构造函数或工厂方法接受一个基DateTime
、一个目标DateTime
和可选的Calendar
(默认为CultureInfo.CurrentCulture),使用它们来计算各种差异分量(年、月等)。**编辑:**在我看来,Noda Time可能拥有您所需的工具-
Period
类“[r]代表一段时间,以人类的时间顺序表示:小时、天、周、月等等”,特别是Period.Between(then, now, PeriodUnits.AllUnits)
似乎是你所要求的精确计算--但它必然是一个比TimeSpan
复杂得多的类。野田时间维基上的Key Concepts page解释了“人类如何把时间弄得一团糟”:撇开天文学和相对论的微妙之处不谈,人类仍然让时间变得难以谈判。如果我们都用Unix时代的滴答声来谈论时间,就不需要像野田时间这样的图书馆了。
但是不,我们喜欢用年、月、天、周来说话--出于某种原因,我们喜欢把下午12点(令人困惑的是,这是下午1点之前的时间)大致定为太阳最高的时间......所以我们有“时区”。
不仅如此,我们对月份的划分也不尽相同。不同的文明有不同的划分方法,也有不同的年份数字。这些就是“日历系统”。
ep6jt1vc3#
好吧,我想最好迟一点;)
C# function giving everything
这是我修改过的版本:
uidvcgyl4#
Here is the main answer with code, please note that you can get any number of dates/times accuracy, seconds & minutes, or seconds, minutes and days, anywhere up to years (which would contain 6 parts/segments). If you specify top two and it's over a year old, it will return "1 year and 3 months ago" and won't return the rest because you've requested two segments. if it's only a few hours old, then it will only return "2 hours and 1 minute ago". Of course, same rules apply if you specify 1, 2, 3, 4, 5 or 6 segmets (maxes out at 6 because seconds, minutes, hours, days, months, years only make 6 types). It will also correct grammer issues like "minutes" vs "minute" depending on if it's 1 minute or more, same for all types, and the "string" generated will always be grammatically correct.
Here are some examples for use: bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)...
"3 years, 2 months and 13 days"
(won't include hours, minutes and seconds as the top 3 time categories are returned), if however, the date was a newer date, such as something a few days ago, specifying the same segments (3) will return"4 days, 1 hour and 13 minutes ago"
instead, so it takes everything into account!if bAllowSegments is 2 it would return
"3 years and 2 months"
and if 6 (maximum value) would return"3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
, but, be reminded that it willNEVER RETURN
something like this"0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago"
as it understands there is no date data in the top 3 segments and ignores them, even if you specify 6 segments, so don't worry :). Of course, if there is a segment with 0 in it, it will take that into account when forming the string, and will display as"3 days and 4 seconds ago"
and ignoring the "0 hours" part! Enjoy and please comment if you like.Of course, you will need a "ReplaceLast" function, which takes a source string, and an argument specifying what needs to be replaced, and another arg specifying what you want to replace it with, and it only replaces the last occurance of that string... i've included my one if you don't have one or dont want to implement it, so here it is, it will work "as is" with no modification needed. I know the reverseit function is no longer needed (exists in .net) but the ReplaceLast and the ReverseIt func are carried over from the pre-.net days, so please excuse how dated it may look (still works 100% tho, been using em for over ten years, can guarante they are bug free)... :). Also, if you are using VB6, you can use StrReverse (wrapping it around the string extended with the .ReverseIt extension method), instead of using the ReverseIt() function (provided as an extension method). So, instead of doing sReplacable.ReverseIt, you'd do StrReverse(sReplacable) as StrReverse() is a built in VB6 function (and does the exact same thing, reverses a given string, and does nothing more). If you use StrReverse() instead of my generic ReverseIt function, feel free to delete the ReverseIt function/extension. StrReverse() function should be available in .NET as long as you are importing the legacy ms-visualbasic-dll library. Makes no difference either way, I had written ReverseIt() before I even know a StrReverse() function had existed, and had been using it ever since out of habit (no real reason to use mine as opposed to the in-built generic function StrReverse) - in fact, I'm sure StrReverse (or a similar, newer .NET specific version of a string reversing function) would be written to be more efficient :). cheers.
qcuzuvrc5#
使用.Net 4.5和
CultureInfo
类,可以向给定日期添加月份和年份。因为这需要大量的输入,所以我更喜欢创建扩展方法:
klh5stk16#
我认为当前TimeSpan是一个真实的时间跨度对象,即2008年1月1日1:31 a.m.到2008年2月3日6:45 a.m.之间的时间量与2008年2月5日1:45 p.m.到2008年3月9日6:59 p.m.之间的时间量相同。实际上,您要查找的是两个日期时间之间的差值。
至于.MakeMagicHappen.gimmeSomethingPretty.surelyMShasThoughtAboutThisDilema来满足你的系统的特定需求,这就是为什么人们雇佣你作为程序员。如果你使用的框架做了所有的事情,你的公司只需要按下一个按钮,他们的系统就会完全成形,你就会和我们其他程序员沿着站在失业线上。
ukxgm1gy7#
我相信下面的方法是非常可信和直接的,因为它基于框架的日期计算,并返回可读的运行时间字符串,就像Facebook的字符串一样。抱歉使用了一些葡萄牙语单词和复数处理,在我的情况下,这是必要的。
sy5wg1nm8#
我接受了被接受的答案,并将其从VB .NET转换为C#,同时也做了一些修改/改进。我去掉了字符串反转(用于替换字符串的最后一个示例),并使用了一个扩展方法,可以更直接地查找和替换字符串的最后一个示例。
如何调用方法的示例:
主要方法:
ReplaceLast扩展方法: