chronos icon indicating copy to clipboard operation
chronos copied to clipboard

diffForHumans() gives misleading results for future dates

Open Bilge opened this issue 3 years ago • 13 comments

Consider the following example of a future date two weeks ahead of today's date:

echo Chronos::parse(new DateTime('2 weeks'))->diffForHumans();

1 week from now

It seems to me the expected out put should be two weeks from now.

Also consider that as the current time ticks forward, the diff should probably not flip from two weeks to one week, since this is not very granular output. That is, once the difference becomes less than two weeks, it should probably change scale to days, e.g. 11 days, 10 days, etc. If it jumps straight from two weeks to one week, when should this occur? One second prior to the full two weeks? Half way between one week and two weeks? Up to one second after one full week? This presents a boundary condition problem that is difficult to reason about if we do not switch to a more granular time output, e.g. from weeks to days.

As an aside, the behaviour is not the same for past dates:

echo Chronos::parse(new DateTime('-2 weeks'))->diffForHumans();

2 weeks ago

Bilge avatar Jan 06 '22 10:01 Bilge

echo Chronos::parse(new DateTime('-2 weeks'))->diffForHumans();

2 weeks ago

This is a different interval since now will still be at least 2 weeks away.

othercorey avatar Jan 06 '22 13:01 othercorey

I'm not sure what you're saying. -2 weeks is two weeks ago as +2 weeks is two weeks ahead. This is demonstrably the case even just by using this software, given that:

echo Chronos::parse(new DateTime('2 weeks 1 sec'))->diffForHumans();

2 weeks from now

Ergo this is a boundary condition problem on the surface, but as I explained in my opening post, I believe the scale is also inappropriate.

Bilge avatar Jan 06 '22 13:01 Bilge

That is, once the difference becomes less than two weeks, it should probably change scale to days, e.g. 11 days, 10 days, etc. If it jumps straight from two weeks to one week, when should this occur? One second prior to the full two weeks? Half way between one week and two weeks? Up to one second after one full week? This presents a boundary condition problem that is difficult to reason about if we do not switch to a more granular time output, e.g. from weeks to days.

When do you think we should switch from days to weeks? I agree that after 1 week is probably too soon. Should we go to 30 days?

markstory avatar Jan 06 '22 14:01 markstory

I haven't given it too much thought, but I cannot see any issue with your proposal.

Bilge avatar Jan 06 '22 16:01 Bilge

A month seems reasonable.

othercorey avatar Jan 06 '22 23:01 othercorey

It would be useful if the documentation for this method made it plain exactly where the boundaries are for each unit switch, as that seems to be where the art for this method really comes in. In order to please everyone, it may be necessary to create a method that accepts a custom boundary descriptor that allows the caller to specify exactly where the boundary changes occur. However, I also believe in the fundamental goal of this method which is to define a default set of boundary conditions that will satisfy most use cases, I just think we should do a better job of documenting the ones we have chosen in order to demystify this method a bit.

Bilge avatar Jan 07 '22 00:01 Bilge

It's just supposed to be a friendly description, but we can try to make it more useful sequences that reflect how most people view time periods.

othercorey avatar Jan 07 '22 00:01 othercorey

In order to please everyone, it may be necessary to create a method that accepts a custom boundary descriptor that allows the caller to specify exactly where the boundary changes occur.

This sounds like a something users that need custom boundaries can build themselves. We can document the boundaries better and tweak the threshold for using weeks but there won't be an implementation that pleases everyone. :smile:

markstory avatar Jan 07 '22 15:01 markstory

Any progress on this?

Bilge avatar Jan 23 '22 11:01 Bilge

If you have a proposal, a PR is welcome.

othercorey avatar Jan 23 '22 15:01 othercorey

To the math-mobile! Here's our current distribution, "precision" being (max - min) / max as a way of quantifying "how accurate is our unit before it switches over to the next":

Unit Range Precision
Year 365+ inf
Month 30-365 92
Week 7-30 77
Day 1-7 86
Hour 1-24 96
Minute 1-60 98
Second 1-60 98

(Those units are a bit of a shorthand, but it's easier to read then a common unit like seconds:)

Unit Range Precision
Year 315_360_00+ inf
Month 2_678_400..31_536_000 92
Week 604_800..2_678_400 77
Day 86_400..604_800 86
Hour 3600..86_400 96
Minute 60..3600 98
Second 1..60 98

If we want to aim of a precision similar to our time units (95) then our equation goes something like this (where x is our max):

100 * (x - 1) / x = 95
x - 1 = 0.95x
0.05x = 1
x = 20

20 days! Let's say 21 to make the weeks fit nicely:

Unit Range Precision
Year 365+ inf
Month 30-365 92
Week 3-4 25
Day 1-21 95
Hour 1-24 96
Minute 1-60 98
Second 1-60 98

Notice this squishes our week unit a lot, but if we apply the same goal of 95 precision then we get 60 weeks which then smushes months... basically, I think this shows that "weeks" is not a very helpful unit.

So here's my proposal: Increase days to be 1..21, give weeks a slight bump (like 3..6 or 3..8) and leave the rest alone.

MGatner avatar Sep 05 '22 14:09 MGatner

That seems like a better scale than what we have now.

markstory avatar Sep 05 '22 15:09 markstory

I'll work on a PR soon.

MGatner avatar Sep 05 '22 16:09 MGatner