-
Notifications
You must be signed in to change notification settings - Fork 7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
duration().days() returns inconsistent value. #961
Comments
When you specify days only, then moment guesses that months have 30 days and that's how the 2 years and 3 months are formed. Of course that's not 100% correct and it also gives ~5 days per year difference (12 * 30 = 360 vs 365), so that's normal. The implementation can probably try and be smarter (by using 365 for years), but that's not the case, and even if that were true it would still be off (leap years, months with 31 days etc). |
I would argue that you shouldn't be able to arbitrarily convert a duration to every possible unit. Other frameworks/languages specifically disallow conversions from variable-length types such as Month and Year. Moment seems to take a different approach, defining a month as 30 days and a year as 365 days (from the documentation). But this seems rather arbitrary. I'd rather not see methods that have hidden connotations. For reference, I checked Think of this related question in human terms, "How many days are there in 3 months?" Clearly, that depends on when you start counting from. Without a starting moment, the only correct answer is "it depends". Moment.js is saying "exactly 90", but IMHO, it should either say "approximately 90", or it should prevent you from asking the question. |
In most cases this is used for non critical operations, and in that case an approximation works just fine. If you really care about precision you'd implement it yourself, as has always been the case. |
Yeah, I'm thinking that unless you're working with specific periods in time, then approximations like 365 or 360 days = 1 year, and 30 days = 1 month are okay. As soon as you start involving dates, like asking stuff like "what will the date be 800 days from today?" then sure, leap years and specific month lengths and stuff matter. But working with just durations, I think approximations are okay as long as they're well documented. Anyway, so if I understand correctly, 365 is used when moment goes from years-to-days, and 360 is used for days-to-years? So like this, http://jsfiddle.net/v7N8K/. Even if the 360 arises by way of the 12 * 30 days/month approximation, I fee like it should stick to one number or the other. I'm not sure if it matters which, but I think it should be consistent. |
I agree about 360 vs 365. I'd be happy to merge a pull request :) |
I hope I can keep this discussion going. Moment.js today is by far the most popular (if not the only) date library. Approximations to date calculations/manipulations are definitely useful, but maybe it is not a bad idea to have an underlying "solid" library? The approximations could be done on top of this. Or even as a plugin (don't shoot me). Only having experience with PHP's Date and Time implementation, I can say a lot of effort went into that to make it both ISO compliant and un-opinionated. A little background behind my comment: currently I'm trying to create a clone of PHP's |
@smhg You've summarized my exact feelings. The key question is - is Moment primarily about making it easier to manipulate values for display? Or is it primarily about being precise so you can't screw things up? The banner on the home page says
Much of what I've loved about moment is in the parsing and formatting areas, and in that regard - I see no problems with approximations. Functions like But in the validation and manipulation areas, my personal opinion is that we should be more rigid. Making approximations when you are calculating seems like a recipe for shooting the proverbial foot off. But I guess it comes down to intent of the design. Perhaps @timrwood can weigh in on his thoughts. There have been other libraries for date/time in javascript before, such as DateJS which got caught up in this problem. People expected it to be accurate, when it wasn't. Then there's libraries like Sugar that does some minor amount of manipulation, but focuses primarily on parsing humanized strings. I'm not sure which Moment is more like. Well, perhaps the comparison is unfair. There is plenty of room for healthy competition in this space. With that in mind, I'm wondering if perhaps there's room for a separate project that focused less on parsing and formatting, and more on precision and safety. Something like Noda Time or Joda Time for JavaScript. It would have a completely different design approach, so this isn't something that could be a moment plugin, but it could certainly interact with moment or sugar to do parsing and formatting. The key design differences would be:
If there is interest in this, I'd be glad to spike a prototype and start a separate project going. I really love Moment though, and would want to do this in friendly cooperation - not in any sort of aggressive or overtaking manner. The final product would "play nice" with moment, and sugar, and others. Please let me know what you think. The alternative would be to work out exactly what is and isn't precise in Moment and clearly document those things. The approximations talked about earlier in this thread would probably just be the tip of the iceberg. |
The reason for using approximations in moment is because there aren't really any correct answers for some of the problems. The question at hand relates to converting between days, months, and years. How many months in a year?
How many days in a year?
How many days in a month?
There isn't really a foolproof solution for converting days to months or days to years or back. As there are different definitions for years and months, it is impossible to find a context free solution. There are libraries like Twix.js that solve this by using a start and end date rather than a unattached duration. It's not that moment is against being precise and correct. It's that sometimes there are questions that are ambiguous enough to be interpreted many ways, and there is no way to account for all the ambiguities. We try to find the solution that is most likely answering the intended question. |
The other libraries I mentioned (Noda Time, Joda Time) take the approach of preventing you from asking those questions in the first place. You can't ask "how many days in year" - you have to ask "how many days in 2013 in the Gregorian calendar". The same goes for any other question you might ask that has ambiguities. You either have to be precise in your question, or you can't ask it. Hence why I think that there may be room for another library. It doesn't feel right to force moment down that path, but often that is exactly the path you should be on. If you're forced to think of these things up front, then they can't come back to bite you down the road. |
While looking up some background to this, I have to correct myself: an issue I bumped into earlier seems to work as expected in 2.1. But the last part of this discussion is not about choosing between approximations and limitations (no conversions when approximation would be the only answer). Both are needed. I'll get back to this when I have more time. |
I don't like that. The goal is to be as useful as possible, and often imprecise but simple-to-get answers are really useful. The developer has to know whether this is a question that's even possible to answer with precision. That it's a sharp tool that can cut you is...the nature of things. That precise library sounds useful, and I think the right way to do it would be to make it easy to interop with moment, like |
Because the year/day thing now works, I'm closing this out, though this is a great discussion to reference. > moment.duration({years: 1}).asDays()
365 |
(for the sake of simplicity this response is within the context of the Gregorian calendar) How can anyone expect moment.duration({years: 1}).asDays(); to return something meaningful?
Of course anyone is free to define a year always lasts 365 days. Who am I to judge this. But because moment is so popular, creating a new calendar system is a though decision. The fact that it is not called a "date calculation" library basically covers this, but the many issue-reports related to this show many don't realize (including myself). Many more probably just didn't bump into it (yet). Personally, I would really love moment to do date calculation 100% accurate. Since it has all these useful methods like moment.duration(1, 'year').someConvertPluginMethod('day');
/*
someConvertPluginMethod probably needs to allow the definition of conversion rules
(with a default set to 365 days for instance)
*/ Writing this, I really wonder in which (correct) circumstances this is used? Anyhow, this last paragraph sounds like a perfect direction for 3.0.0 to me. |
You're assuming that the answers have to be 100% accurate to useful. Perhaps for you, it's not. If the context-free "how long is a year in days?" isn't a meaningful question to your application, it seems silly you'd ask exactly that question of an API. You seem to agree... But declaring the question verboten for people who do find it useful is a different story. Ask someone on the street how long a year is in days, you'll get "about 365". That's a really useful approximation, and hoards of people use it every day without thinking of themselves as creating a new calendaring system. The basic clash here, I think, is whether having an approximation that isn't perfectly accurate is more or less useful than not having it at all. That's a reasonable question about which there can be plenty of debate, and I look forward to that debate as moment continues forward. But casting your side of it as The Way Time Works doesn't add much to the discussion. |
I agree with parts of both sides of this argument, and I'm very happy that we can have these sort of debates without some of the kneejerk reactions or derogatory arguments that commonly occur in other parts of the interwebs. However, I wish we had a discussion forum so it didn't linger in issue comments, but anyway... Yes, it is common for people to say there are "365 days in a year" and that's often good enough. The best places for that sort of thing are when displaying text meant to be ready by a human being. In that regard, moment is mostly doing the right thing, and where it's not we can address those issues individually. But there are many situations where an application's business logic requires algorithmic manipulation of date/time values. In those situations, it's much more necessary to be precise. If the function that returns number of days in a year requires the year to be passed as a parameter, then it can be precise in it's response. If moment was only ever used in the browser, I'd say that there's no direct need for anything else. There are some pretty decent server-side date/time libraries for various languages already. But moment is also used on the server with node.js, and there aren't a whole lot of other options out there. Putting it another way, if someone told me today that they wanted to write an employee scheduling system, or an astrology program, or any other app with date/time complexities, I wouldn't recommend they write it in pure JavaScript because it's just not reliable. Besides the calculation issues, you have the ES5 issue (#831), and the general problems that come with the I think Moment has done a great job of adding missing features to But I certainly think there is room for a date/time library that doesn't depend on the Regarding the "that's how time works" argument, I'd say it's more appropriate to say that there is a disconnect between how the technical details of the ISO-8601/Gregorian calendar system actually works, and the way that the average human being typically describes their perception of that calendar. I think this is best illustrated by a certain movie involving a time traveling DeLorean, with this instrument console: Knowing the technical details, you would think a time machine would need to set the time in UTC. Even if it was smart enough to use its GPS coordinates to resolve the machine's local time zone, it would have to have some way to resolve DST ambiguities in its input. Had this panel shown October 27 1985 (the next day), it could have been one of two possible moments in time. But try explaining that to a movie audience without boring them to tears! |
See this fiddle: http://jsfiddle.net/KbNxf/
Basically, if I create two equivalent duration objects, one with years/months/days and the other with just days, the second's days() method returns a value different than the first.
Am I correct in thinking these two durations should be equivalent, and days() should return the same thing?
The text was updated successfully, but these errors were encountered: