TimeSpan 是不必要的吗?
编辑 2009 年 11 月 4 日
好的,自从我第一次发布这个问题以来已经有一段时间了。在我看来,许多最初的回应者未能真正理解我所说的内容——常见的回应是“你所说的没有任何意义”——所以我做了一些方便的回答图表来真正说明我的观点。
当我们谈到数字时,我们通常指的是小学生所学的点,即数轴:
现在,当我们学习算术时,我们的大脑学会了对这个概念进行非常有趣的转换。例如,评估表达式 1 + 0.5
,如果我们只是应用“数轴思维”,则需要我们以某种方式理解这一点:
很难真正说明这一点,因为很难思考:“添加”两个点。这就是许多响应者对添加日期的想法感到困惑的地方(或者干脆认为这是荒谬的),因为他们将日期视为点。
然而,表达式 1 + 0.5
确实 对我们来说有意义,因为当我们想到它时,我们实际上是在想象:
也就是说,数字(或点< /strong>) 1,加上 向量 0.5,结果为点 1.5。
或者,我们可能会想象这样的:
即,向量 1,加上矢量 0.5,得到矢量 1.5。
换句话说,在处理数字时,我们可以互换地对待点和向量。但是日期呢?毕竟,日期基本上就是数字。如果您不相信我,请将此行与上面的数字行进行比较:
注意对应关系在时间线和数轴之间?这就是我的观点:如果我们用数字执行上面的转换,我们也应该能够对日期进行转换。因此,应用“时间线思维”,表达式 0001-Jan-02 00:00:00 + 0001-Jan-01 12:00:00
并没有多大意义,因为很多响应者指出:
但是,如果我们这样做每次加减数字时我们都会在头脑中进行相同的概念转换,我们可以轻松地“重新思考”上述内容,如下所示:
很明显,DateTime
和 TimeSpan
之间的区别是点和向量之间存在同样的差异。我认为导致很多人对我的建议做出负面反应的原因是,以这种方式将日期视为大小感觉很不自然。但我不相信没有明显的参考点可以用作零的论点。 有一个明显的参考点,我会提示您它在哪里:大约 2010 年前。
别误会我的意思:我并不是在质疑其有用性 em> 在 DateTime
和 TimeSpan
的概念之间划分概念。真的,我一直以来的问题应该是(正如 ChrisW 间接建议的那样),为什么我们在处理常规数字类型时要互换地对待数字和向量? (或者:为什么我们只有一种 int
类型,而不是 int
和 intspan
?)有很大的区别,但我们没有直到初中或高中的某个时候,当我们开始几何时,我们才会真正考虑过这个问题。然后它被视为一个新的数学概念,而实际上,自从我们学会用手指计数来添加数字以来,我们就一直在使用它。
最后,最好的答案来自 Strilanc,他指出 DateTime
和 TimeSpan
的使用实际上是 仿射空间,它具有不需要参考点作为原点的便利特性。谢谢,斯特兰克。然而,我对 ChrisW 给出了公认的答案,因为他是第一个提出向量和点概念的人,这确实触及了问题的关键。
原始问题(供后代)
我当然不是所有行业的编程高手,但我知道 PHP 和 .NET 除了 DateTime 之外还有一个
类(或 .NET 中的结构),我猜想在各种其他语言和框架中也是如此(尽管我主要参考 .NET 结构来编写本文)。这似乎是一个奇怪的问题,但是 TimeSpan
类TimeSpan
不是多余的吗?
如果您认为答案是显而易见的(“DateTime
是一个绝对时间点,而 TimeSpan
是一个时间范围 - 就这么简单!”),考虑一下:整数可以被概念化为绝对值(数轴上的点)或值之间的距离 - 并且我们不需要两种单独的数据类型来实现这些不同的概念化。我仍然可以写出 5 + 6,而我的意思没有任何歧义。
只要存在一致的零点引用,在我看来,就没有理由需要 TimeSpan 对象来对 DateTime 对象执行算术运算,或获取它们之间的距离。
我缺少什么?为什么不能将 TimeSpan
结构的独特方法和属性简单地折叠到 DateTime
中?
(免责声明:我并不是对这个或任何东西充满热情;我很喜欢使用 DateTime
和 TimeSpan
对象,因为它们一直都是预期的。我我只是问一个问题。)
编辑:好的,用一个过于简化的例子来说明我的观点:
考虑等式 10 - 5 = 5。人们可以将其读作“从 10(值)开始,向左移动 5(跨度),最终得到 5(值)。”
假设,为了让事情变得简单,我们将 1900 年 1 月 1 日设为零点,并仅以天为单位定义 TimeSpan
对象。
那么 10 - 5 = 5 在 DateTime
术语中可以被理解为 1900 年 1 月 11 日 - 1900 年 1 月 6 日 = 1900 年 1 月 6 日。这很好,因为 1 月 11 日只是“10”我们的定义和 1 月 6 日是“5”。事实上,我们将 10 视为一个值,将前 5 个视为跨度,最后 5 个再次视为值,这仅仅是为了我们自己的概念利益。我的观点是:唯一的区别在于你如何看待这个数字,而不是它实际上是什么。这就是为什么我们没有单独的结构,例如整数值和整数范围——一个普通的旧整数涵盖了我们所有的基础。
我说得有道理吗?
EDIT 2009-Nov-04
OK, so it's been a little while since I first posted this question. It seems to me that many of the initial responders failed to really get what I was saying--a common response was some variation on "What you're saying doesn't make any sense"--and so I've made some handy diagrams to really illustrate my point.
When we speak of numbers, we are generally referring to points on what grade school children learn is called the Number Line:
Now, when we learn arithmetic, our minds learn to perform a very interesting transformation of this concept. Evalutating the expression 1 + 0.5
, for example, if we simply applied our "number line thinking", would require us to somehow make sense of this:
It's difficult to really illustrate that, because it's difficult to think about that: "adding" two points. This is where a lot of responders struggled with the idea of adding dates (or simply dismissed it as absurd), because they were thinking of dates as points.
However, the expression 1 + 0.5
does make sense to us, because when we think of it, we're really imagining this:
That is, the number (or point) 1, plus the vector 0.5, resulting in point 1.5.
Alternately, we may be imagining this:
That is, the vector 1, plus the vector 0.5, resulting in the vector 1.5.
In other words, when dealing with numbers, we treat points and vectors interchangeably. But what about dates? Dates are, after all, basically numbers. If you don't believe me, compare this line to the number line above:
Notice the correspondence between the timeline and the number line? This was my point: if we perform the transformation above with numbers, we ought to be able to do it with dates as well. So, applying "timeline thinking", the expression 0001-Jan-02 00:00:00 + 0001-Jan-01 12:00:00
doesn't make a lot of sense, as plenty of responders pointed out:
But, if we do the same conceptual transformation in our head that we perform every time we add or subtract numbers, we can easily "rethink" the above as this:
So clearly, the difference between a DateTime
and a TimeSpan
is the same difference that exists between a point and a vector. What I think caused a lot of people to respond negatively to my suggestion is that it just feels so unnatural to think of dates as magnitudes in this way. But I don't buy the argument that there's no obvious reference point to use as zero. There is an obvious reference point, and I'll give you a hint where it is: about 2010 years ago.
Don't get me wrong: I'm not questioning the usefulness of drawing a conceptual divide between the notion of a DateTime
and a TimeSpan
. Really, my question all along should have been (as ChrisW indirectly suggested), why do we treat numbers and vectors interchangeably when dealing with regular numeric types? (Or: why do we have just one int
type, instead of int
and intspan
?) There's a big difference, and yet we don't ever really think about it until sometime in junior high or high school, when we begin geometry. And then it's treated as this new mathematical concept, when in reality it's something we've been utilizing ever since we learned to add numbers by counting with our fingers.
In the end, the best answer came from Strilanc, who pointed out that the use of DateTime
and TimeSpan
is really an implementation of an affine space, which has the convenient property of not needing a reference point to treat as the origin. So thanks, Strilanc. I'm giving the accepted answer to ChrisW, however, for being the first one to bring up the concept of vectors and points, which really got to the crux of the matter.
ORIGINAL QUESTION (for posterity)
I am certainly no programming jack of all trades, but I know both PHP and .NET have a TimeSpan
class in addition to a DateTime
class (or structure in .NET), and I am guessing this is the case in a variety of other languages and frameworks as well (though I am writing this primarily with reference to the .NET structures). This might seem a strange question, but isn't TimeSpan
redundant?
In case you think the answer is obvious ("A DateTime
is an absolute point in time, while a TimeSpan
is a range of time -- simple as that!"), consider this: an integer can be conceptualized as either an absolute value (the point on the number line) or a distance between values--and we don't need two separate data types for these different conceptualizations. I can still write 5 + 6 without any ambiguity as to what I mean.
As long as there is a consistent zero-point reference, it seems to me there should be no reason why one would need a TimeSpan
object to perform arithmetic operations on DateTime
objects, or to get the distance between them.
What am I missing? Why can't the unique methods and properties of the TimeSpan
structure simply be folded into DateTime
?
(Disclaimer: It isn't like I'm passionate about this or anything; I'm fine using DateTime
and TimeSpan
objects as they're intended all the time. I'm just asking a question.)
EDIT: Okay, over-simplified example to illustrate my point:
Consider the equation 10 - 5 = 5. One could read this as "Start at 10 (value), move 5 to the left (span), and you end up at 5 (value)."
Suppose, just to make things easy, we let January 1 1900 be point zero and we define TimeSpan
objects in terms of days only.
Then 10 - 5 = 5 could be understood, in DateTime
terms, as January 11 1900 - January 6 1900 = January 6 1900. This is fine, because January 11 is just "10" by our definition and January 6 is "5". The fact that we are viewing the 10 as a value, the first 5 as a span, and the last 5 as a value again is merely for our own conceptual benefit. My point is just this: that the only difference is in how you think of the number, not in what it actually is. This is why we don't have separate structures for, say, integer values and integer spans -- a plain old integer covers all our bases.
Am I making any sense?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
一个原因是,拆分类型可以防止出现一类错误,在这些错误中,您认为自己有相对时间,但实际上有绝对时间,反之亦然。例如,如果两种类型不同,则两个绝对时间的相加可能会被标记为编译器错误。
此外,当成员数量较少时,IntelliSense(以及新手的发现)效果更好 - 通过在两种类型之间拆分方法,使每种类型的工作变得更容易。
One reason is that splitting the types prevents a class of bugs where you think you have a relative time but really have an absolute time, and vice versa. For example, addition of two absolute times can be flagged as a compiler error if the two types are separate.
Also, IntelliSense (and discovery for newbies) works better when the number of members is smaller-- by splitting methods between the two types, working with each gets easier.
反过来问:在这方面削弱类型系统有什么好处?
这都是成本与收益的问题,而
DateTime
具有通过禁止此类操作来减少由于不合逻辑的日期/时间计算而导致的错误的巨大好处。DateTime
存在的原因与严格类型检查系统存在的原因非常相似:使代码中的语义错误产生编译时消息。通知程序员代码中的错误。相反,拥有
DateTime
的成本是:zilch。现在考虑删除
DateTime
。我们会得到什么?直接回答你的问题:“TimeSpan 不是多余的吗?”绝对不是,它减少了错误。对我来说,确实如此。
Asked the other way round: what would the benefit of weakening the type system in that regard be?
It’s all a question of cost vs. benefit and
DateTime
has the great benefit of reducing bugs due to illogical date/time calculations by forbidding such actions.DateTime
exists for very much the same reasons that a strict type-checking system exists in the first place: to make semantic errors in the code produce compile-time messages. that notify the programmers of errors in their code.Conversely, there’s the cost of having
DateTime
: zilch.Now consider dropping
DateTime
. What would we gain?To answer your question directly: “isn't
TimeSpan
redundant?” Absolutely not, it reduces bugs. It definitely has, for me.从概念上考虑一下。如果我告诉你我将在 7 天后举办聚会,那么这句话中的“7 天”就是日期。我可以说我的聚会是 7 天吗?当然不是,因为7天不是一个日期。面向对象编程的关键思想之一是将系统中的此类概念表示为类型。确实,我们可以将所有内容表示为整数(事实上,很多人都已经这样做了),但在面向对象编程中,我们有项目类型及其行为和属性的概念,从这个意义上说,它使得感觉有一个表达这一点的对象。
Think about it conceptually. If I tell you that I'm having a party 7 days from now, is "7 days" in that sentence a date. Could I just say my party is on 7 days? Of course not, because 7 days isn't a date. One of the key ideas of object oriented programming is to represent concepts like this in the system as types. It's true that we could represent everything as an integer (and in fact, many people have and do), but in object oriented programming, we have the notion of types of items, and their behaviors and properties, and in that sense, it makes sense to have an object that expresses this.
我认为你可以提出相反的论点,即
DateTime
是多余的,我们应该只有TimeSpan
:)说真的,所有日期实际上都只是时间跨度。它们都与某个起点相关。从技术上讲,基督教历法中没有“零年”(因为你不能真正拥有“我们主的零年”),但如果我们将公元前 0001 年 1 月 1 日凌晨 12:00 指定为“零点” ,那么之后(或之前)的每个日期都可以被认为是相对于该日期的。因此,2009 年 9 月 19 日凌晨 12:00 的时间跨度为 734033 天。
因此,从数学角度来说,DateTime 和 TimeSpan 是多余的。但当我们编写代码时,我们试图交流的不仅仅是抽象的数学结构。任何给定的 DateTime 实例实际上可能只是相对于某个任意零点的时间跨度,但对于大多数阅读代码的人来说,它将暗示日历上的特定点。类似地,
TimeSpan
表示日历上两点之间的间隔。在这种情况下,微软选择了明确而不是吝啬。我不能说我不同意这个决定。
I think you could make the opposite argument that
DateTime
is redundant, and we should only haveTimeSpan
:)Seriously, all dates really are just time spans. They are all relative to some starting point. Technically, there is no "year zero" in the Christian calendar (since you can't really have a "zeroth year of our lord"), but if we assign 12:00 A.M. January 1, 0001 B.C. as the "zero point", then every date that comes after (or before) can be thought of as relative to that date. So, 12:00 A.M. on September 19, 2009 would have a TimeSpan of 734033 days.
So, mathematically,
DateTime
andTimeSpan
are redundant. But when we write code, we are attempting to communicate much more than just abstract mathematical constructs. Any givenDateTime
instance may in fact just be a time span relative to some arbitrary zero point, but to most people reading your code, it will imply a particular point on the calendar. Similarly, aTimeSpan
implies the gap between two points on the calendar.In this case, Microsoft has chosen to be clear rather than parsimonious. I can't say I disagree with the decision.
日期有很多复杂性,例如:
将日期和时间跨度视为不同的事物意味着这些在实践中,这类问题不太可能让你感到困惑。
There are a lot of complications in dates, for example:
Treating Dates and TimeSpans as different things means that these kinds of issues are much less likely to confuse you in practise.
它的糖不多也不少......
its sugar not more or less....
根据您的逻辑,TimeSpan 不是不必要的:而是 DateTime 是不必要的,可以用 TimeSpan 替换(从零开始的持续时间)。
另外,整数有一个明显的零,而日期则没有明显的零;但是,如果您想用“距零/原点的距离/跨度”替换“数轴上的位置”,那么有一个明显的零是必要的。
编辑:
点(平面上的位置)与矢量不同。
它们看起来很相似...
...但是,如果原点表示给定点所需的向量值将会改变变化。
将两个(相对)向量相加总是有意义的;但是,除了将这些点转换为向量然后将向量相加之外,将两个点相加是没有意义的。
两个向量的总和不受原点变化的影响,但如果通过将它们转换为向量并添加向量来求和,则两个点的总和将受到原点变化的影响(因为更改原点会影响原点变化)这些向量的值)。
[在上面的参数中,将“点”替换为 DateTime,将“向量”替换为 TimeSpan。]
我认为绝对值和相对值之间存在真正的差异。我不知道为什么这种差异在算术中不那么明显,即为什么“数字”似乎可以互换地用来表示绝对值和相对值。
By your logic, it isn't TimeSpan that's unecessary: rather it's DateTime that's unnecessary, and could be replaced by TimeSpan (duration since zero).
Plus there's the fact that integers have an obvious zero, whereas Dates however don't have an obvious zero; but having an obvious zero is necessary, if you want to replace "place on the number line" with "distance/span from the zero/origin".
Edit:
A point (location on a plane) isn't the same as a vector.
They seem similar ...
... however the value of the vector that's required to represent a given point will change if the origin changes.
It always makes sense to add two (relative) vectors; but, it makes no sense to add two points, except by converting those points to vectors and then adding the vectors.
The sum of two vectors is unaffected by a change in the origin, but the sum of two points would be affected by a change in the origin if you summed them by converting them to vectors and adding the vectors (because changing the origin would affect the values of those vectors).
[Replace 'point' with DateTime and 'vector' with TimeSpan in the argument above.]
I think there is a genuine difference between absolute and relative values. I'm don't know why that difference isn't more apparent in arithmetic, i.e. why 'numbers' are used seemingly interchangeably to represent both absolute and relative values.
(以数学家的身份发言)这是因为“日期”上的算术运算不是封闭的或明确定义的,因此需要额外的结构。
例如,2000 年 1 月 1 日 - 1999 年 12 月 1 日 = ... ?我们知道它们之间有 31 天,但如果将其解释为日期,则答案是纪元(即零)+ 31 天。这不再是有效的“日期”。
类似地,整数上的所有算术运算都没有明确定义(1 / 2 在整数中没有答案。整数数学在这里返回零,但 0 * 2 = 0,而不是您期望的 1)。这就需要一个我们称之为分数的额外结构。
(Speaking as a mathematician) It's because arithmetic operations on a "date" aren't closed or well defined, necessitating the need for an additional structure.
For example, January 1, 2000 - December 1, 1999 = ... ? We know there's 31 days between them, but if this were interpreted as a date, then the answer is Epoch (i.e., zero) + 31 days. This is not a valid "date" anymore.
Similarly, all the arithmetic operations on integers aren't well defined (1 / 2 has no answer in the integers .. integer math returns zero here, but 0 * 2 = 0, not 1 as you would expect). This necessitates the need for an additional structure that we call fractions.
仅仅因为您可以定义操作并不意味着您应该。例如,未定义除以零的原因之一是因为定义它需要牺牲算术的一些非常有用的属性(例如结合性等)。
时间跨度和日期之间的区别归结为加法。添加两个时间跨度是有意义的,但添加两个日期是没有意义的,除非您有任意的参考日期。通过不允许添加日期,您可以抽象出任意参考日期。我不知道 .Net 中的日期“0”是什么,而且我从来不需要知道。这不是很好吗?
添加两个日期几乎总是一个错误(说真的,试着想想这在数字命理学之外的意义)。通过引入时间跨度(创建仿射空间),您可以消除一整类错误。
Just because you can define an operation doesn't mean you should. For example, one of the reasons division by zero is undefined is because defining it would require sacrificing some very useful properties of arithmetic (eg. associativity, etc).
The distinction between a timespan and a date comes down to addition. It makes sense to add two timespans, but it doesn't make sense to add two dates unless you have an arbitrary reference date. By not allowing addition of dates, you abstract away that arbitrary reference date. I don't know what date '0' is in .Net, and I've never needed to know. Isn't that nice?
Adding two dates is almost always a bug (seriously, try to think of where this makes sense outside of numerology). By introducing timespans (creating an Affine Space) you eliminate a whole class of bugs.