[英]Add a duration to a repeating event's start time so that it's end is always the same time (i.e 2pm to 4 pm)
I have a bunch of rrules (implemented in rrule.js ) that gives me an array of event start times (see the demo ). 我有一堆rrule(在rrule.js中实现),为我提供了一系列事件开始时间(请参见演示 )。 rrule.js
doesn't actually provide the concept of an event duration or endtime
... So it can tell me the precise date when the millionth occurrence of a repeating event will start but not when it will end. rrule.js
实际上并没有提供事件持续时间或endtime
时间的概念 ...因此它可以告诉我确切的日期,即重复事件的百万分之一开始发生的时间,而不是结束时间。 Turns out I actually want to know when an event ends so I'll have to get creative. 原来,我实际上是想知道活动何时结束,所以我必须发挥创造力。 As far as I see it I've got two options 据我所知,我有两种选择
DB SIDE: Store an rrule string + an event duration
. DB SIDE:存储规则字符串+事件duration
。
CLIENT SIDE: Reconstitute events start date array from rrule string. 客户端:从事件字符串重构事件开始日期数组。 Only start times
would be known and end times
would be calculated by adding the duration as an offset to each start time in the array. 通过将持续时间添加为数组中每个开始时间的偏移量,将仅知道start times
,并且将计算end times
。
DB SIDE: Store a modified rrule string which encodes an endtime
. DB SIDE:存储修改后的rrule字符串,该字符串对endtime
进行编码。
CLIENT SIDE: A special wrapper function reads the modified rrule string and reconstitutes it as two date arrays; 客户端:一个特殊的包装函数读取修改后的rrule字符串,并将其重构为两个日期数组。 one representing event start times and the other end times. 一个代表事件的开始时间,另一个代表事件的结束时间。
Option 1 seems easier but I suspect it will run into problems with daylight savings. 选项1似乎更容易,但我怀疑它会遇到夏令时的问题。 For example, say I've an event that is every Tuesday from 6pm to 2 am Wednesday. 例如,假设我有一个活动,该活动在每个星期二的晚上6点至星期三的凌晨2点。 In that case I'd store a duration of 8 hours in my database alongside that stringified rrule. 在这种情况下,我将在数据库中存储8个小时的时间以及该字符串规则。 Now let's fast forward to any 6pm Tuesday in the future. 现在,让我们快进到星期二下午6点。 Does my event always end on Wednesday at 2am (or does that 8 hour duration sometimes make my event end at 1am or 3am)? 我的活动是否总是在星期三凌晨2点结束(或者持续8个小时有时使我的活动在凌晨1点或凌晨3点结束)? How do I get it to always end at 2am? 如何使它始终在凌晨2点结束?
... If you know the answer then just stop reading here. ...如果您知道答案,请在这里停止阅读。
According to Kip in How to add 30 minutes to a JavaScript Date object? 根据Kip中的方法, 如何向JavaScript Date对象添加30分钟? the smart way to offset a date time is to use a fancy library like moment.js. 偏移日期时间的明智方法是使用精美的库,例如moment.js。
He emphasizes that point by showing how easily things go wrong using non fancy date time libraries (showing how a naive minute offset function fails due to daylight savings) 他通过使用非理想的日期时间库显示问题出处的难易程度来强调这一点(显示天真的分钟偏移量功能由于夏令时而失败)
function addMinutes(date, minutes) {
return new Date(date.getTime() + minutes*60000);
}
addMinutes(new Date('2014-11-02'), 60*24) //In USA, prints 11pm on Nov 2, not 12am Nov 3!
But something weird happens for me. 但是对我来说有些奇怪的事情发生了。 The function above was supposed to output 11pm on Nov 2
- which is the wrong answer ie it was supposed to fail because of daylight savings. 上面的函数应该11pm on Nov 2
输出-这是错误的答案,即由于夏令时而失败。 When I run it, it actually outputs the right time 12am on Nov 3
(note: I'm in Chicago/Central time). 当我运行它时,它实际上12am on Nov 3
输出正确的时间(注意:我在芝加哥/中部时间)。
When I compare the output of his naive function to the output of moment.js and luxon.js, I get the same answer as you can see in this observable notebook . 当我将其朴素函数的输出与moment.js和luxon.js的输出进行比较时,得到的答案与您在此可观察笔记本中看到的相同。
What's more, if using luxon or moment, when you add a days worth of minutes to 2014-11-02
you get 2014-11-03T00:00:00.000Z
but if you just directly add a day to 2014-11-02
you get 2014-11-03T01:00:00.000Z
- it's an hour off. 更重要的是,如果使用luxon或moment,当您在2014-11-02
增加一分钟的时间时,您将获得2014-11-03T00:00:00.000Z
但如果您直接在2014-11-02
增加一天,则得到2014-11-03T01:00:00.000Z
这是一个小时的2014-11-03T01:00:00.000Z
。
So am I better off pursuing option 2? 所以我最好选择选项2吗?
Now let's fast forward to any 6pm Tuesday in the future. 现在,让我们快进到星期二下午6点。 Does my event always end on Wednesday at 2am (or does that 8 hour duration sometimes make my event end at 1am or 3am)? 我的活动是否总是在星期三凌晨2点结束(或者持续8个小时有时使我的活动在凌晨1点或凌晨3点结束)? How do I get it to always end at 2am? 如何使它始终在凌晨2点结束?
The standard Javascript Date object automatically handles the daylight savings shift for you. 标准的Javascript Date对象自动为您处理夏令时。 Even if you add 8 hours to a date at 6pm the day before daylight savings, the new date will still end at 2am the next day. 即使您在夏令时的前一天下午6点增加8小时的日期,新日期仍将在第二天凌晨2点结束。
Incidently, I implemented duration support in rSchedule and since it supports both the standard javascript Date
as well as moment
/ luxon
dates, you can test a recurring event with a duration using either library and see that they both produce the same result. 顺便说一句,我在rSchedule中实现了持续时间支持,并且由于它支持标准的javascript Date
以及moment
/ luxon
日期,因此您可以使用任一库来测试持续时间的重复事件,并查看它们是否产生相同的结果。
This example can be seen on stackblitz . 这个例子可以在stackblitz上看到 。
import { Schedule } from '@rschedule/rschedule';
import { StandardDateAdapter } from '@rschedule/standard-date-adapter';
// This example will also work with `moment`, `moment-timezone`, and `luxon`
// (assuming you import the proper date adapter -- see rSchedule docs)
const schedule = new Schedule({
rrules: [
{
start: new Date(2019,9,10,18),
frequency: "DAILY",
duration: 1000 * 60 * 60 * 8,
count: 30
}
],
dateAdapter: StandardDateAdapter,
});
schedule.occurrences().toArray().forEach(adapter => {
console.log(
{
start: adapter.date.toLocaleString(),
end: adapter.end.toLocaleString(),
}
)
})
Turns out I actually want to know when an event ends 原来我真的想知道事件何时结束
To find out when this event ends, you could do: 要了解此事件何时结束,您可以执行以下操作:
const iterator = schedule.occurrences({ reverse: true })
const { end } = iterator.next().value
This trick would only work with an event that actually has an end date (so not an event with infinite occurrences). 此技巧仅适用于实际具有结束日期的事件(因此不适用于无限次发生的事件)。
I wrote the original answer you are referring to about a decade ago. 我写的原始答案大约是十年前。 Seven years later, I made an edit, changing new Date(2014, 10, 2)
to new Date('2014-11-02')
. 七年后,我进行了修改,将new Date(2014, 10, 2)
更改为new Date('2014-11-02')
。 I thought this would be easier to read (because you don't have to explain that the months in that version of the constructor start at 0 instead of 1). 我认为这将更易于阅读(因为您不必解释该版本的构造函数中的月份从0而不是1开始)。 But as @RobG pointed out , formatting in this way causes it to be parsed as UTC. 但是正如@RobG指出的那样 ,以这种方式进行格式化会导致将其解析为UTC。 I've gone back and fixed this now (thanks for pointing it out). 我已经回过头来,现在解决了这个问题(感谢您指出)。
To get to your "scratching my head" part of your question: 为了解决您的问题“抓我的头”部分:
What's more, if using luxon or moment, when you add a days worth of minutes to
2014-11-02
you get2014-11-03T00:00:00.000Z
更重要的是,如果使用luxon或moment,当您在2014-11-02
添加一整天的分钟数时,您将获得2014-11-03T00:00:00.000Z
The Z
at the end of that timestamp means it is in UTC, and UTC does not observe daylight savings time. 该时间戳记末尾的Z
表示它位于UTC中,并且UTC不遵守夏令时。 So if you start with 2014-11-02T00:00:00.000Z
, and add 24 hours, you get 2014-11-03T00:00:00.000Z
. 因此,如果您从2014-11-02T00:00:00.000Z
,并加上24小时,您将获得2014-11-03T00:00:00.000Z
。 When you add hours/minutes/seconds, there's no need to worry about daylight saving time. 当您增加小时/分钟/秒时,则无需担心夏令时。
but if you just directly add a day to
2014-11-02
you get2014-11-03T01:00:00.000Z
- it's an hour off. 但是,如果您直接在2014-11-02
添加一天,则会获得2014-11-03T01:00:00.000Z
这是一个小时的休假。
In this case what is happening is you are starting with 2014-11-02T00:00:00.000Z
, but when you tell the library to add one day, and you don't specify a time zone, the library is assuming you are in your local time zone, so it adds one local day. 在这种情况下,发生的事情是您从2014-11-02T00:00:00.000Z
,但是当您告诉图书馆增加一天,而您未指定时区时,图书馆就会假设您位于您当地的时区,因此会增加一个本地日期。 Because you cross a DST boundary, that day is 25 hours long, and when you print it as an ISO timestamp in UTC, you end up with 2014-11-03T01:00:00.000Z
(25 hours later). 因为您越过DST边界,所以这一天长达25小时,而当您将其打印为UTC中的ISO时间戳时,您将得到2014-11-03T01:00:00.000Z
(25小时后)。
Time zone stuff is hard, even if you are using a library. 即使使用库,时区内容也很难。 Most people can get by for a long time not knowing or caring that for many users one day a year is 25 hours long. 大多数人可以在很长一段时间内不了解或关心许多用户一年一天的时间长达25小时。 But if these edge cases will matter to you, the best approach is to play around with them like you're doing, and make sure you really understand what is happening and why. 但是,如果这些极端情况对您来说很重要,那么最好的方法就是像您所做的那样与它们一起玩耍,并确保您真正了解正在发生的事情以及原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.