fullcalendar / fullcalendar

Full-sized drag & drop event calendar in JavaScript
https://fullcalendar.io
MIT License
18.65k stars 3.62k forks source link

Major bug: If Date has Start End range, End-Date is wrong. Also in v. 3.4.0 #3679

Closed sgdp closed 5 years ago

sgdp commented 7 years ago

Hi, I am not sure how to fix it. At the moment, i just add +1 day as workaround server side script. But I want to have it fixed. Maybe you guys can fix it, so we could release a new awesome version called 3.4.1 ;)?

image

reymarth commented 7 years ago

As stated in docs: https://fullcalendar.io/docs/event_data/Event_Object/

It is the moment immediately after the event has ended. For example, if the last full day of an event is Thursday, the exclusive end of the event will be 00:00:00 on Friday!

We really need to add 1 day to include the real end date. But it's better if this get fixed :)

espen commented 7 years ago

No this is not a major bug. This is by design and following the iCalendar specification:

The "DTEND" property for a "VEVENT" calendar component specifies the non-inclusive end of the event.

The value MUST be later in time than the value of the "DTSTART" property.

If you have all day events you can simplify this process by setting allDay:true. Alternative if all your events in the source is all day events then you can set allDayDefault:true on the event source.

jhwinters commented 7 years ago

To expand on what others have said...

This is definitely not a bug - it's how it is designed and documented to work, and what's more, it's how it must work. If you are storing your events in a database or anywhere then you need to follow exactly the same convention or you will surprise yourself.

Take the case of two events - one an all-day event running from Mon 1st to Wed 3rd, and the other a timed event on Wed 3rd from 10:00 to 11:00.

If you store the former in your database with the start and end fields containing "Mon 1st" and "Wed 3rd", then a comparison against the second event will indicate that that they do not overlap. The first ends at 00:00 on Wed 3rd, and the second doesn't start until 10:00 on the same day. This would be a bug in your code.

To achieve consistent processing, you must store the first event as running from:

2017-XX-01 00:00 to 2017-xx-04 00:00

which is what it in reality does. The confusion arises because of the way we refer to the duration of all-day events in normal speech. We talk about them running from the 1st to the 3rd, and it's implicit that we mean to the end of the 3rd. Computers aren't good on odd implicit conventions, so it needs to be tidied up.

Provided you use the right convention in your storage (exclusive end date/times) then your back end and FC will communicate just fine. Drag and drop re-positioning and re-sizing will also work just fine. The only exception comes if you want to present any kind of dialogue box to your users, presenting the times of an all-day event as text. Then, as you present, you need to subtract 1 day from the end date/time, and as you receive input from the user you need to add 1 day. Note that you only need to do this for all-day events - humans use a perfectly consistent convention when referring to timed events.

Code snippet of what I use:

  def ends_at_text
    if all_day
      ends_at ? (ends_at.to_date - 1.day).strftime("%d/%m/%Y") : ""
    else
      ends_at ? ends_at.strftime("%d/%m/%Y %H:%M") : ""
    end
  end

  def ends_at_text=(value)
    self.ends_at = value
    if all_day
      #
      #  People expect to give the day on which the event ends, but we
      #  want to store the time at which it ends, which is 00:00:00 on
      #  the following day.
      #
      self.ends_at = self.ends_at.to_date + 1.day
    end
  end
sgdp commented 7 years ago

Okay I understand your points. But for example, if i give Date Range without time it should be whole day, like:

Hey how long is weekend going, dad? Son from Saturday to Sunday. And From Monday to Friday regulary work.

As you see dad gives no special time. So if the son looks in the calendar, he will see weekend only at Saturday and workweek from Monday do Thurthday, because dad tipped in the day, but at your point it would be wrong, dad has to fill in time.

I understand it on programmer logic way, but it is a misslogic way, because something got forgotten. ~ hope i said it right.

And now something funny, to better understand.

At the moment, let say us, we have every first day in Month diaper money. It would say:

title: 'Diaper Money', start: '2017-06-01'

title: 'Diaper Money', start: '2017-07-01'

etc.etc.

And if we look at the calender, we see whole day entry.

And now something funny comes. Let us say mum and dad has splittet. So dad got the Child for 2 day. Let us say every month one time, from 2nd to 3rd.

title: 'Dad cares of child, i am free ~ Mum', start: '2017-06-02', ebd: '2017-06-03'

title: 'Dad cares of child, i am free ~ Mum', start: '2017-07-02', ebd: '2017-07-03'

If we look now at calendar, what do we see? Right just 2017-06-2 marked and 2017-07-02 marked. So with this kind of logic, we should not be able to see Diaper Money even marked one day in calender. And this is because it breaks, all point of logics and is a major bug.

I would adive as a better point of logic, to say as default. If in array is not set a specific time with date. It should be marked in the Calender as full date.

So at least, doesn't matter what is documented as mentioned. Sometimes, we have to rethink things. I hope my english is good enough to understand my explaination.

~I am sry, for later answering this question, to much to do.

jhwinters commented 7 years ago

For a fuller explanation of why your suggested way of doing it just doesn't work, see: https://github.com/fullcalendar/fullcalendar/issues/3190 and in particular my final comment.

Sometimes, we have to rethink things.

Indeed yes - you need to rethink the way you are storing your data or you will cause endless problems for yourself, regardless of whether or not you are using FullCalendar.

Note again - because you seem to have missed this point - that you should not call upon your users to adjust the way they enter the information. Your dialogues should recognise the slightly odd way in which people refer to date ranges (implicitly they mean from the start of the first date which they give to the end of the second date) and correct it at the point of entry and before saving to your data store. If you don't do that, lots of things will fail even if you aren't using FullCalendar.

espen commented 7 years ago

You list many real life examples but this should be handled by your app, not your users @sgdp. As mentioned this is the standardised (RFC) way of handling calendar events. This is what every calendar application uses (any CalDAV based calendar). For FullCalendar to work differently would indeed by a major bug.

This should be solvable by doing what I recommended earlier:

If you have all day events you can simplify this process by setting allDay:true. Alternative if all your events in the source is all day events then you can set allDayDefault:true on the event source.

sgdp commented 7 years ago

ok, first what i see is a big emotinal answers and discussion. Pls, stay cool and rational.

It is not a problem for me to have a workaround at my aplication etc. I am talking here, because i see a logical-bug if we take a look from outside on fullcalendar.

Maybe, because I am from thrid party, I can see it, but others dont. It is like if you work in a company for years, someone new sees how to do things better or mistakes. I know that feeling, and but very often this new person has a good reason to see it. Because always if someone new comes, he ask same old rules again. Until we change it. So pls, take minute before answering and coming relaxed.

If we look from outside to fullcalender we have 2 situations.

Events with 1 day Events with range

If we have one day fullcalendar says

title: '1 Day', start: '2017-06-02'

In fullcallender logic: "Oh one day, i have to place Start at 2017-06-02 00:00:00 and also an end 2017-06-23:59:59 .

title: '1 Day', start: '2017-06-02 00:00:00' end: '2017-06-02 23:59:59'

If it so, for one day it should be the same for 2 days.

And why?

because the secound day would end as this logic at 23:59:59 not at 00:00:00

As you said, default full day is off. Maybe it should be on by default?

jhwinters commented 7 years ago

ok, first what i see is a big emotinal answers and discussion. Pls, stay cool and rational.

You do?! I don't see any emotional stuff at all, except a little bit from you in calling it a "major bug". All I see is several people trying to explain to you carefully and patiently why you're wrong.

Did you read that bit I referred you to? It explains quite clearly why, even if you don't store times with your event dates, you need to store the end date as an exclusive one. This has nothing to do with FullCalendar - just getting your basic logic to work needs that.

In fullcallender logic: "Oh one day, i have to place Start at 2017-06-02 00:00:00 and also an end 2017-06-23:59:59 .

No, you very specifically don't do that. For a one day event, if you include times to make the meaning clearer then the start and end are:

start = 2017-06-02 00:00:00 end = 2017-06-03 00:00:00

and then to use mathematical notation, your event is as follows:

start <= event < end

Note the pure "<" symbol in the second position. This is what is meant by talking about an exclusive end date.

Even if you don't store times with your events - if you store them as:

start = 2017-06-02 end = 2017-06-03

you still need to store them in the same way, because otherwise none of your calculations about overlaps or durations will work.

You use a rather interesting image of people working in a company for years and not seeing something which is obvious to a newcomer. A better simile (if you insist on introducing this sort of thing) is of the newcomer who arrives and, without bothering to understand the existing process, keeps shouting that it's wrong because he hasn't taken the time to understand it and it isn't the way he first thought of. Try to understand - a lot of people with a lot more experience than you have studied this particular problem for years.

As espen and I have both explained to you - this is not a feature of FullCalendar. It's the way any calendaring solution works behind the scenes - although not necessarily the way it's presented to the customer.

You talk of "programmer logic" as if there's something wrong with it. In reality you absolutely must learn to think in programmer logic if you ever want to become any good at programming. Currently you're muddling up the user interface with the behind-the-scenes processing. The two need to be kept quite separate in your mind.

Programmer logic lets us identify the exact single place where an adjustment between the two is required - at the point of data entry - and if you get that right then all your later processing will be simple and straightforward. If you persist in getting it wrong and keep trying to change all the other components to cope with your initial mistake, you'll drive yourself crazy.

So - in a genuine spirit of trying to help you - please go and read that article I referred you to before.

sgdp commented 7 years ago

Wow fantastic.

I read your links. But did you check ISO 8601 it is the Norm we all have to follow. You can buy the newest version for 100 boxes. And it says

"As every day both starts and ends with midnight, the two notations 00:00 and 24:00 are available to distinguish the two midnights that can be associated with one date. This means that the following two notations refer to exactly the same point in time"

So in this case, a date range and also the given example of 2 date range is given. And it says the secound date ends by default without given time just the day YYYY/MM/DD every day starts and ends at midnight. It also gives an example that says the last day ends at midnight.

So.. now we talk about the ISO Standard.. and if we look back. The new one has right, because the old one, dont buy the newest and accepted version of ISO/IEC 8601

jhwinters commented 7 years ago

But did you check ISO 8001 it is the Norm we all have to follow.

Ah, I get it now - you're a troll. Well done, I fell for it.

To save anyone else time, ISO 8001 is a standard relating to cinematography, and in particular under-exposed motion-picture films.

sgdp commented 7 years ago

No I am not a troll. What no. Oh not 8001 sry, miss tipped 8601.

http://www.din.de/de/mitwirken/normenausschuesse/nia/entwuerfe/wdc-beuth:din21:266843381

https://de.wikipedia.org/wiki/ISO_8601#Trenner_bei_Angaben_von_Zeitspannen

jhwinters commented 7 years ago

Ah, not a troll - good.

Yes, ISO8601 is indeed about times and durations, but nothing in it disagrees with the points which have been put to you. Indeed, it even codifies the common practice of referring to a date range by talking about the first and last dates which the range includes.

For clarification.

If your user wants to enter a one day event (and he doesn't just want to do it graphically by clicking) then he absolutely should be able to enter just 2016-06-01 and have the system understand that he means the whole of that day. (2016-06-01 00:00:00 to 2016-06-02 00:00:00)

If your user wants to enter a three day event (and again, prefers not to do it graphically but by picking or typing in dates) then he absolutely should be able to enter 2016-06-01 and 2016-06-03 and have the system understand that he means 2016-06-01 00:00:00 to 2016-06-04 00:00:00 (or if you prefer, 2016-06-03 24:00:00).

However, if you then simply store what he entered you will create chaos for yourself in all your later processing. Duration calculations won't work. Overlap calculations won't work. You'll need frigs all over the place.

You can if you wish store the end time as 2016-06-03 24:00:00 but you'll almost certainly find that whatever time/date handling library you're using immediately changes it into 2016-06-04 00:00:00.

Get the data correctly stored at the point of entry and you'll find that everything else then gets much easier.

Separate the user experience - where you should cater to the user's expectations - from the data store - which needs to be precise and unambiguous.

sgdp commented 7 years ago

Yes, ISO8601 is indeed about times and durations, but nothing in it disagrees with the points which have been put to you. Indeed, it even codifies the common practice of referring to a date range by talking about the first and last dates which the range includes.

As i Mentioned in ISO 8601 the newest version it says. If we want to have date Range 2017-06-01 - 2017-06-02 and no specific time is given. The Range is 2017-06-01 00:00:00 - 2017-06-02 24:00:00 not 2017-06-02 00:00:00 at morning. It is midnight for each date and we have to keep it in touch for our calculation. I have bought a newer version of it right now... you can see it if you have one. I dont want to share it here because of copyrights.

So on this case fullcallender has to set show fulll days or not? So if we have 2 dates, the last one has to end at midgnight.

You told me you work with this norm, but at least you ignore it.

So in this case, what we will do? Ignoring 8601? And says we have to make a workaround in our aplication, so that fullcalender works after 8601?

espen commented 7 years ago

@sgdp Fullcalender supports ISO8601. It defines how to represent dates, and yes also durations which in ISO8601 are inclusive. However this issue is about calendar event data. That is defined by RFC2445. It's ok if you don't think it should work like that but please consider the way you respond based on this being the standard that every calendar application uses. Again; for Fullcalendar to work differently than any other calendar application would be a major bug. Also Fullcalendar offers an easy way to parse inclusive end dates.

jhwinters commented 7 years ago

You told me you work with this norm

Where? You're starting to make things up.

You seem to be misinterpreting the purpose of ISO 8601. To quote from ISO's own web site:

https://www.iso.org/iso-8601-date-and-time-format.html

ISO 8601 can be used by anyone who wants to use a standardized way of presenting dates and times. It helps cut out the uncertainty and confusion when communicating internationally.

The full standard covers ways to write:

Note those two crucial words - "presenting" and "write". It's a standard telling you how to write down dates and how to understand written dates. As such, it backs up what I've been saying all along about how you should interpret your users' written input.

However it doesn't in any way address or relate to how dates are stored and manipulated within a computer program. It does however make it perfectly clear that if a user enters:

` 2016-06-01 to 2016-06-03

then you should interpret that as meaning 2016-06-01 00:00:00 to 2016-06-04 00:00:00.

Now you seem to be arguing that this interpretation should be left till as late as possible, even pushing it back into libraries which you're using. All I'm saying is that you will find life much easier if you do it as early as possible. Convert it as soon as the user enters it and all will be hunky.

Try to do it by a whole series of frigs later on in your code and you really will drive yourself crazy.

So in this case, what we will do? Ignoring 8601?

Nobody is advocating ignoring it. All the advice which you've been given advocates following it. However it has nothing to do with your program internals.

jhwinters commented 7 years ago

As a final way to try to help you with what you're doing wrong...

You refer to ISO8601 and how it tells you that you should interpret:

"2016-06-01 - 2016-06-03"

as a range stretching from the start of 2016-06-01 (that is, 2016-06-01 00:00:00) to the end of 2016-06-03 (i.e. 2016-06-04 00:00:00), and yet you're not doing that. Instead you're storing the end date as 2016-06-03, and then complaining that other components (e.g. FC) fail to correct your error.

Do as the nice ISO standard tells you to do and all will be well.

billynapo commented 6 years ago

It is a bit strange to see in month view, example Apr-01-2018 9:00 am to Apr-02-2018 7:00 am you would expect to see both Apr 1st and Apr 2nd in month view since the event extends past midnight, but only the first day is shown. You can only show both days in month view if the end time is late enough (it happens to be >= 9:00 am). In agendaWeek the behavior is as expected: any end time after midnight will show as both days.

UpwardProcess commented 6 years ago

@billynapo, check this: https://fullcalendar.io/docs/nextDayThreshold

mlewis-everley commented 6 years ago

This seems to be a slightly heated topic so hopefully I wont step on anyone's toes! I have just been caught out by this and legitimately got confused (until I found this thread).

Having read this thread, I will update my app to increase the end date by X hours, but it did take me a little while to track down this issue and I can see from issues #4204 and #4096 (not to mention this issue) that I am not the only one getting confused...

From my perspective, it would be really helpful if the Event docs made this a little clearer (possibly adding a NOTE under the allDay description, maybe even a link to @jhwinters really helpful explanation).

I can see that you have added Throughout the API this will become a real Moment object. It is the moment immediately after the event has ended. For example, if the last full day of an event is Thursday, the exclusive end of the event will be 00:00:00 on Friday! under the Event.end explanation, but at the time of initial reading, the meaning not really clear (to me at least).

Many thanks for the great module!

TomS- commented 6 years ago

This has caught me out too. You would expect the event to end on the end date, however it ends before. Really doesn't make sense because even if you set allDay to true it still ends the day before. I get that 2018-04-23 for example defaults to midnight there for ends at the end of 2018-04-22. But without the time provided it doesn't feel like what the user intends.

mlewis-everley commented 6 years ago

One issue with the solution provided by @jhwinters (at least for me) is that now the summary popup incorrectly represents the date. So the all day field is accurate, but the summary popup shows the event being a day longer :-s

jhwinters commented 6 years ago

Ah - I think you may have implemented only half of my suggested approach. If you look back at the top of this thread (fourth comment - my first contribution) you'll see that there are two bits of special processing needed.

Problem: When people say an event runs from the 1st to the 3rd they mean from the start of the 1st to the end of the 3rd

Observation: We should not and cannot ask people to change this behaviour.

Solution: When accepting input of this type, interpret it correctly and when re-displaying the date range as text convert it back into the form which they expect.

This isn't just an issue with FullCalendar. Any program attempting to accept and process dates of events needs to implement this behaviour for the reasons explained above.

If you do it in the way which I have advised then you require just two bits of special processing in your code - one at the point of date entry, and the other when you wish to display the dates again to the user in textual form (as opposed to graphically).

If you don't do it in this way - if for instance you store the date just as entered by the user - then you will need frig after frig after frig in your code to correct this initial error. Just getting FC modified to accommodate your erroneous data won't really help. You're trying to hide the problem rather than fixing it.

There are various other threads linked from this one where you can find fuller explanations of why it's not a good idea to store the dates un-corrected.

mlewis-everley commented 6 years ago

Hmm, OK, I think I can see what I have missed, I will try and amend my code and see if that helps.

Like I said in my previous post @jhwinters I personally don't feel FullCalendar needs to change anything, but the documentation could really be improved to highlight this potential issue/point of confusion.

jhwinters commented 6 years ago

Agreed on the documentation front. This is potentially a very confusing issue to the newcomer (witness how many people have been caught out by it) and it needs flagging in big flashing letters. Date processing in general is far trickier than one would expect.

Just wait until you try to keep track of time zones and daylight saving time as well. You might think that as you're only handling dates these don't affect you, but they do. Some days are 23 or 25 hours long! A 3 day all-day event can be 71, 72 or 73 hours long.

JorgeGante commented 6 years ago

Perhaps a solution for all of this would be that Fullcalendar could represent events depending not only in their dates and times but their date position in the calendar. Allowing a reasonable margin (day before/next) and adding a calendar date field in every event could be more flexible and coherent with visual representation when an user clicks and selects cells.

magicmb commented 5 years ago

+1 on the confusional aspect for newcomers

Spent ages fiddling with dates for alldDay events and it took me lots of reading up on threads like these, plus lots of trial and error based on numerous suggestion before I got it to work in a "human" interpretable way.

After reading this thread it seems there's an overwhelming case for the way it is working i.e. "as it should be" and I guess we are dealing with code. So not being an out an out coder, it may seem odd to the likes of moi, but hey c'est la vie!

+mlewis-everley & jhwinters about the documentation. I would also add that newbies like me would appreciate a few more code snippets alongside the docs, especially when dealing with all the tricky stuff.

arshaw commented 5 years ago

this ticket deals with making the docs better in this regard: https://github.com/fullcalendar/fullcalendar/issues/3205