@@ -77,7 +77,7 @@ Module.register("calendar", {
77
77
78
78
// Define required scripts.
79
79
getScripts ( ) {
80
- return [ "calendarutils.js" , "moment.js" ] ;
80
+ return [ "calendarutils.js" , "moment.js" , "moment-timezone.js" ] ;
81
81
} ,
82
82
83
83
// Define required translations.
@@ -215,18 +215,9 @@ Module.register("calendar", {
215
215
this . updateDom ( this . config . animationSpeed ) ;
216
216
} ,
217
217
218
- eventEndingWithinNextFullTimeUnit ( event , ONE_DAY ) {
219
- const now = new Date ( ) ;
220
- return event . endDate - now <= ONE_DAY ;
221
- } ,
222
-
223
218
// Override dom generator.
224
219
getDom ( ) {
225
220
const ONE_SECOND = 1000 ; // 1,000 milliseconds
226
- const ONE_MINUTE = ONE_SECOND * 60 ;
227
- const ONE_HOUR = ONE_MINUTE * 60 ;
228
- const ONE_DAY = ONE_HOUR * 24 ;
229
-
230
221
const events = this . createEventList ( true ) ;
231
222
const wrapper = document . createElement ( "table" ) ;
232
223
wrapper . className = this . config . tableClass ;
@@ -258,7 +249,9 @@ Module.register("calendar", {
258
249
let lastSeenDate = "" ;
259
250
260
251
events . forEach ( ( event , index ) => {
261
- const dateAsString = moment ( event . startDate , "x" ) . format ( this . config . dateFormat ) ;
252
+ const eventStartDateMoment = this . timestampToMoment ( event . startDate ) ;
253
+ const eventEndDateMoment = this . timestampToMoment ( event . endDate ) ;
254
+ const dateAsString = eventStartDateMoment . format ( this . config . dateFormat ) ;
262
255
if ( this . config . timeFormat === "dateheaders" ) {
263
256
if ( lastSeenDate !== dateAsString ) {
264
257
const dateRow = document . createElement ( "tr" ) ;
@@ -340,7 +333,7 @@ Module.register("calendar", {
340
333
repeatingCountTitle = this . countTitleForUrl ( event . url ) ;
341
334
342
335
if ( repeatingCountTitle !== "" ) {
343
- const thisYear = new Date ( parseInt ( event . startDate ) ) . getFullYear ( ) ,
336
+ const thisYear = eventStartDateMoment . year ( ) ,
344
337
yearDiff = thisYear - event . firstYear ;
345
338
346
339
repeatingCountTitle = `, ${ yearDiff } ${ repeatingCountTitle } ` ;
@@ -395,14 +388,14 @@ Module.register("calendar", {
395
388
timeWrapper . className = `time light ${ this . config . flipDateHeaderTitle ? "align-right " : "align-left " } ${ this . timeClassForUrl ( event . url ) } ` ;
396
389
timeWrapper . style . paddingLeft = "2px" ;
397
390
timeWrapper . style . textAlign = this . config . flipDateHeaderTitle ? "right" : "left" ;
398
- timeWrapper . innerHTML = moment ( event . startDate , "x" ) . format ( "LT" ) ;
391
+ timeWrapper . innerHTML = eventStartDateMoment . format ( "LT" ) ;
399
392
400
393
// Add endDate to dataheaders if showEnd is enabled
401
394
if ( this . config . showEnd ) {
402
395
if ( this . config . showEndsOnlyWithDuration && event . startDate === event . endDate ) {
403
396
// no duration here, don't display end
404
397
} else {
405
- timeWrapper . innerHTML += ` - ${ CalendarUtils . capFirst ( moment ( event . endDate , "x" ) . format ( "LT" ) ) } ` ;
398
+ timeWrapper . innerHTML += ` - ${ CalendarUtils . capFirst ( eventEndDateMoment . format ( "LT" ) ) } ` ;
406
399
}
407
400
}
408
401
@@ -415,70 +408,69 @@ Module.register("calendar", {
415
408
const timeWrapper = document . createElement ( "td" ) ;
416
409
417
410
eventWrapper . appendChild ( titleWrapper ) ;
418
- const now = new Date ( ) ;
411
+ const now = moment ( ) ;
419
412
420
413
if ( this . config . timeFormat === "absolute" ) {
421
414
// Use dateFormat
422
- timeWrapper . innerHTML = CalendarUtils . capFirst ( moment ( event . startDate , "x" ) . format ( this . config . dateFormat ) ) ;
415
+ timeWrapper . innerHTML = CalendarUtils . capFirst ( eventStartDateMoment . format ( this . config . dateFormat ) ) ;
423
416
// Add end time if showEnd
424
417
if ( this . config . showEnd ) {
425
418
// and has a duation
426
419
if ( event . startDate !== event . endDate ) {
427
420
timeWrapper . innerHTML += "-" ;
428
- timeWrapper . innerHTML += CalendarUtils . capFirst ( moment ( event . endDate , "x" ) . format ( this . config . dateEndFormat ) ) ;
421
+ timeWrapper . innerHTML += CalendarUtils . capFirst ( eventEndDateMoment . format ( this . config . dateEndFormat ) ) ;
429
422
}
430
423
}
431
424
432
425
// For full day events we use the fullDayEventDateFormat
433
426
if ( event . fullDayEvent ) {
434
427
//subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day
435
- event . endDate -= ONE_SECOND ;
436
- timeWrapper . innerHTML = CalendarUtils . capFirst ( moment ( event . startDate , "x" ) . format ( this . config . fullDayEventDateFormat ) ) ;
428
+ eventEndDateMoment . subtract ( 1 , "second" ) ;
429
+ timeWrapper . innerHTML = CalendarUtils . capFirst ( eventStartDateMoment . format ( this . config . fullDayEventDateFormat ) ) ;
437
430
// only show end if requested and allowed and the dates are different
438
- if ( this . config . showEnd && ! this . config . showEndsOnlyWithDuration && moment ( event . startDate , "x" ) . format ( "YYYYMMDD" ) !== moment ( event . endDate , "x" ) . format ( "YYYYMMDD ") ) {
431
+ if ( this . config . showEnd && ! this . config . showEndsOnlyWithDuration && ! eventStartDateMoment . isSame ( eventEndDateMoment , "d " ) ) {
439
432
timeWrapper . innerHTML += "-" ;
440
- timeWrapper . innerHTML += CalendarUtils . capFirst ( moment ( event . endDate , "x" ) . format ( this . config . fullDayEventDateFormat ) ) ;
441
- } else
442
- if ( ( moment ( event . startDate , "x" ) . format ( "YYYYMMDD" ) !== moment ( event . endDate , "x" ) . format ( "YYYYMMDD" ) ) && ( moment ( event . startDate , "x" ) < moment ( now , "x" ) ) ) {
443
- timeWrapper . innerHTML = CalendarUtils . capFirst ( moment ( now , "x" ) . format ( this . config . fullDayEventDateFormat ) ) ;
444
- }
445
- } else if ( this . config . getRelative > 0 && event . startDate < now ) {
433
+ timeWrapper . innerHTML += CalendarUtils . capFirst ( eventEndDateMoment . format ( this . config . fullDayEventDateFormat ) ) ;
434
+ } else if ( ! eventStartDateMoment . isSame ( eventEndDateMoment , "d" ) && eventStartDateMoment . isBefore ( now ) ) {
435
+ timeWrapper . innerHTML = CalendarUtils . capFirst ( now . format ( this . config . fullDayEventDateFormat ) ) ;
436
+ }
437
+ } else if ( this . config . getRelative > 0 && eventStartDateMoment . isBefore ( now ) ) {
446
438
// Ongoing and getRelative is set
447
439
timeWrapper . innerHTML = CalendarUtils . capFirst (
448
440
this . translate ( "RUNNING" , {
449
441
fallback : `${ this . translate ( "RUNNING" ) } {timeUntilEnd}` ,
450
- timeUntilEnd : moment ( event . endDate , "x" ) . fromNow ( true )
442
+ timeUntilEnd : eventEndDateMoment . fromNow ( true )
451
443
} )
452
444
) ;
453
- } else if ( this . config . urgency > 0 && event . startDate - now < this . config . urgency * ONE_DAY ) {
445
+ } else if ( this . config . urgency > 0 && eventStartDateMoment . diff ( now , "d" ) < this . config . urgency ) {
454
446
// Within urgency days
455
- timeWrapper . innerHTML = CalendarUtils . capFirst ( moment ( event . startDate , "x" ) . fromNow ( ) ) ;
447
+ timeWrapper . innerHTML = CalendarUtils . capFirst ( eventStartDateMoment . fromNow ( ) ) ;
456
448
}
457
449
if ( event . fullDayEvent && this . config . nextDaysRelative ) {
458
450
// Full days events within the next two days
459
451
if ( event . today ) {
460
452
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "TODAY" ) ) ;
461
453
} else if ( event . yesterday ) {
462
454
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "YESTERDAY" ) ) ;
463
- } else if ( event . startDate - now < ONE_DAY && event . startDate - now > 0 ) {
455
+ } else if ( event . tomorrow ) {
464
456
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "TOMORROW" ) ) ;
465
- } else if ( event . startDate - now < 2 * ONE_DAY && event . startDate - now > 0 ) {
457
+ } else if ( event . dayAfterTomorrow ) {
466
458
if ( this . translate ( "DAYAFTERTOMORROW" ) !== "DAYAFTERTOMORROW" ) {
467
459
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "DAYAFTERTOMORROW" ) ) ;
468
460
}
469
461
}
470
462
}
471
463
} else {
472
464
// Show relative times
473
- if ( event . startDate >= now || ( event . fullDayEvent && this . eventEndingWithinNextFullTimeUnit ( event , ONE_DAY ) ) ) {
465
+ if ( eventStartDateMoment . isSameOrAfter ( now ) || ( event . fullDayEvent && eventEndDateMoment . diff ( now , "days" ) === 0 ) ) {
474
466
// Use relative time
475
467
if ( ! this . config . hideTime && ! event . fullDayEvent ) {
476
468
Log . debug ( "event not hidden and not fullday" ) ;
477
- timeWrapper . innerHTML = `${ CalendarUtils . capFirst ( moment ( event . startDate , "x" ) . calendar ( null , { sameElse : this . config . dateFormat } ) ) } ` ;
469
+ timeWrapper . innerHTML = `${ CalendarUtils . capFirst ( eventStartDateMoment . calendar ( null , { sameElse : this . config . dateFormat } ) ) } ` ;
478
470
} else {
479
471
Log . debug ( "event full day or hidden" ) ;
480
472
timeWrapper . innerHTML = `${ CalendarUtils . capFirst (
481
- moment ( event . startDate , "x" ) . calendar ( null , {
473
+ eventStartDateMoment . calendar ( null , {
482
474
sameDay : this . config . showTimeToday ? "LT" : `[${ this . translate ( "TODAY" ) } ]` ,
483
475
nextDay : `[${ this . translate ( "TOMORROW" ) } ]` ,
484
476
nextWeek : "dddd" ,
@@ -488,33 +480,33 @@ Module.register("calendar", {
488
480
}
489
481
if ( event . fullDayEvent ) {
490
482
// Full days events within the next two days
491
- if ( event . today || ( event . fullDayEvent && this . eventEndingWithinNextFullTimeUnit ( event , ONE_DAY ) ) ) {
483
+ if ( event . today || ( event . fullDayEvent && eventEndDateMoment . diff ( now , "days" ) === 0 ) ) {
492
484
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "TODAY" ) ) ;
493
485
} else if ( event . dayBeforeYesterday ) {
494
486
if ( this . translate ( "DAYBEFOREYESTERDAY" ) !== "DAYBEFOREYESTERDAY" ) {
495
487
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "DAYBEFOREYESTERDAY" ) ) ;
496
488
}
497
489
} else if ( event . yesterday ) {
498
490
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "YESTERDAY" ) ) ;
499
- } else if ( event . startDate - now < ONE_DAY && event . startDate - now > 0 ) {
491
+ } else if ( event . tomorrow ) {
500
492
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "TOMORROW" ) ) ;
501
- } else if ( event . startDate - now < 2 * ONE_DAY && event . startDate - now > 0 ) {
493
+ } else if ( event . dayAfterTomorrow ) {
502
494
if ( this . translate ( "DAYAFTERTOMORROW" ) !== "DAYAFTERTOMORROW" ) {
503
495
timeWrapper . innerHTML = CalendarUtils . capFirst ( this . translate ( "DAYAFTERTOMORROW" ) ) ;
504
496
}
505
497
}
506
498
Log . info ( "event fullday" ) ;
507
- } else if ( event . startDate - now < this . config . getRelative * ONE_HOUR ) {
499
+ } else if ( eventStartDateMoment . diff ( now , "h" ) < this . config . getRelative ) {
508
500
Log . info ( "not full day but within getrelative size" ) ;
509
501
// If event is within getRelative hours, display 'in xxx' time format or moment.fromNow()
510
- timeWrapper . innerHTML = `${ CalendarUtils . capFirst ( moment ( event . startDate , "x" ) . fromNow ( ) ) } ` ;
502
+ timeWrapper . innerHTML = `${ CalendarUtils . capFirst ( eventStartDateMoment . fromNow ( ) ) } ` ;
511
503
}
512
504
} else {
513
505
// Ongoing event
514
506
timeWrapper . innerHTML = CalendarUtils . capFirst (
515
507
this . translate ( "RUNNING" , {
516
508
fallback : `${ this . translate ( "RUNNING" ) } {timeUntilEnd}` ,
517
- timeUntilEnd : moment ( event . endDate , "x" ) . fromNow ( true )
509
+ timeUntilEnd : eventEndDateMoment . fromNow ( true )
518
510
} )
519
511
) ;
520
512
}
@@ -593,46 +585,46 @@ Module.register("calendar", {
593
585
return false ;
594
586
} ,
595
587
588
+ /**
589
+ * converts the given timestamp to a moment with a timezone
590
+ * @param {number } timestamp timestamp from an event
591
+ * @returns {moment.Moment } moment with a timezone
592
+ */
593
+ timestampToMoment ( timestamp ) {
594
+ return moment ( timestamp , "x" ) . tz ( moment . tz . guess ( ) ) ;
595
+ } ,
596
+
596
597
/**
597
598
* Creates the sorted list of all events.
598
599
* @param {boolean } limitNumberOfEntries Whether to filter returned events for display.
599
600
* @returns {object[] } Array with events.
600
601
*/
601
602
createEventList ( limitNumberOfEntries ) {
602
- const ONE_SECOND = 1000 ; // 1,000 milliseconds
603
- const ONE_MINUTE = ONE_SECOND * 60 ;
604
- const ONE_HOUR = ONE_MINUTE * 60 ;
605
- const ONE_DAY = ONE_HOUR * 24 ;
606
-
607
- let now , today , future ;
608
- if ( this . config . forceUseCurrentTime || this . defaults . forceUseCurrentTime ) {
609
- now = new Date ( ) ;
610
- today = moment ( ) . startOf ( "day" ) ;
611
- future = moment ( ) . startOf ( "day" ) . add ( this . config . maximumNumberOfDays , "days" ) . toDate ( ) ;
612
- } else {
613
- now = new Date ( Date . now ( ) ) ; // Can use overridden time
614
- today = moment ( now ) . startOf ( "day" ) ;
615
- future = moment ( now ) . startOf ( "day" ) . add ( this . config . maximumNumberOfDays , "days" ) . toDate ( ) ;
616
- }
603
+ let now = moment ( ) ;
604
+ let today = now . clone ( ) . startOf ( "day" ) ;
605
+ let future = now . clone ( ) . startOf ( "day" ) . add ( this . config . maximumNumberOfDays , "days" ) ;
606
+
617
607
let events = [ ] ;
618
608
619
609
for ( const calendarUrl in this . calendarData ) {
620
610
const calendar = this . calendarData [ calendarUrl ] ;
621
611
let remainingEntries = this . maximumEntriesForUrl ( calendarUrl ) ;
622
- let maxPastDaysCompare = now - this . maximumPastDaysForUrl ( calendarUrl ) * ONE_DAY ;
612
+ let maxPastDaysCompare = now . clone ( ) . subtract ( this . maximumPastDaysForUrl ( calendarUrl ) , "days" ) ;
623
613
let by_url_calevents = [ ] ;
624
614
for ( const e in calendar ) {
625
615
const event = JSON . parse ( JSON . stringify ( calendar [ e ] ) ) ; // clone object
616
+ const eventStartDateMoment = this . timestampToMoment ( event . startDate ) ;
617
+ const eventEndDateMoment = this . timestampToMoment ( event . endDate ) ;
626
618
627
619
if ( this . config . hidePrivate && event . class === "PRIVATE" ) {
628
620
// do not add the current event, skip it
629
621
continue ;
630
622
}
631
623
if ( limitNumberOfEntries ) {
632
- if ( event . endDate < maxPastDaysCompare ) {
624
+ if ( eventEndDateMoment . isBefore ( maxPastDaysCompare ) ) {
633
625
continue ;
634
626
}
635
- if ( this . config . hideOngoing && event . startDate < now ) {
627
+ if ( this . config . hideOngoing && eventStartDateMoment . isBefore ( now ) ) {
636
628
continue ;
637
629
}
638
630
if ( this . config . hideDuplicates && this . listContainsEvent ( events , event ) ) {
@@ -641,47 +633,46 @@ Module.register("calendar", {
641
633
}
642
634
643
635
event . url = calendarUrl ;
644
- event . today = event . startDate >= today && event . startDate < today + ONE_DAY ;
645
- event . dayBeforeYesterday = event . startDate >= today - ONE_DAY * 2 && event . startDate < today - ONE_DAY ;
646
- event . yesterday = event . startDate >= today - ONE_DAY && event . startDate < today ;
647
- event . tomorrow = ! event . today && event . startDate >= today + ONE_DAY && event . startDate < today + 2 * ONE_DAY ;
648
- event . dayAfterTomorrow = ! event . tomorrow && event . startDate >= today + ONE_DAY * 2 && event . startDate < today + 3 * ONE_DAY ;
636
+ event . today = eventStartDateMoment . isSame ( now , "d" ) ;
637
+ event . dayBeforeYesterday = eventStartDateMoment . isSame ( now . clone ( ) . subtract ( 2 , "days" ) , "d" ) ;
638
+ event . yesterday = eventStartDateMoment . isSame ( now . clone ( ) . subtract ( 1 , "days" ) , "d" ) ;
639
+ event . tomorrow = eventStartDateMoment . isSame ( now . clone ( ) . add ( 1 , "days" ) , "d" ) ;
640
+ event . dayAfterTomorrow = eventStartDateMoment . isSame ( now . clone ( ) . add ( 2 , "days" ) , "d" ) ;
649
641
650
642
/*
651
643
* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
652
644
* otherwise, esp. in dateheaders mode it is not clear how long these events are.
653
645
*/
654
- const maxCount = Math . round ( ( event . endDate - 1 - moment ( event . startDate , "x" ) . endOf ( "day" ) . format ( "x" ) ) / ONE_DAY ) + 1 ;
646
+ const maxCount = eventEndDateMoment . diff ( eventStartDateMoment , "days" ) ;
655
647
if ( this . config . sliceMultiDayEvents && maxCount > 1 ) {
656
648
const splitEvents = [ ] ;
657
649
let midnight
658
- = moment ( event . startDate , "x" )
650
+ = eventStartDateMoment
659
651
. clone ( )
660
652
. startOf ( "day" )
661
653
. add ( 1 , "day" )
662
- . endOf ( "day" )
663
- . format ( "x" ) ;
654
+ . endOf ( "day" ) ;
664
655
let count = 1 ;
665
- while ( event . endDate > midnight ) {
656
+ while ( eventEndDateMoment . isAfter ( midnight ) ) {
666
657
const thisEvent = JSON . parse ( JSON . stringify ( event ) ) ; // clone object
667
- thisEvent . today = thisEvent . startDate >= today && thisEvent . startDate < today + ONE_DAY ;
668
- thisEvent . tomorrow = ! thisEvent . today && thisEvent . startDate >= today + ONE_DAY && thisEvent . startDate < today + 2 * ONE_DAY ;
669
- thisEvent . endDate = moment ( midnight , "x" ) . clone ( ) . subtract ( 1 , "day" ) . format ( "x" ) ;
658
+ thisEvent . today = this . timestampToMoment ( thisEvent . startDate ) . isSame ( now , "d" ) ;
659
+ thisEvent . tomorrow = this . timestampToMoment ( thisEvent . startDate ) . isSame ( now . clone ( ) . add ( 1 , "days" ) , "d" ) ;
660
+ thisEvent . endDate = midnight . clone ( ) . subtract ( 1 , "day" ) . format ( "x" ) ;
670
661
thisEvent . title += ` (${ count } /${ maxCount } )` ;
671
662
splitEvents . push ( thisEvent ) ;
672
663
673
- event . startDate = midnight ;
664
+ event . startDate = midnight . format ( "x" ) ;
674
665
count += 1 ;
675
- midnight = moment ( midnight , "x" ) . add ( 1 , "day" ) . endOf ( "day" ) . format ( "x ") ; // next day
666
+ midnight = midnight . clone ( ) . add ( 1 , "day" ) . endOf ( "day" ) ; // next day
676
667
}
677
668
// Last day
678
669
event . title += ` (${ count } /${ maxCount } )` ;
679
- event . today += event . startDate >= today && event . startDate < today + ONE_DAY ;
680
- event . tomorrow = ! event . today && event . startDate >= today + ONE_DAY && event . startDate < today + 2 * ONE_DAY ;
670
+ event . today += this . timestampToMoment ( event . startDate ) . isSame ( now , "d" ) ;
671
+ event . tomorrow = this . timestampToMoment ( event . startDate ) . isSame ( now . clone ( ) . add ( 1 , "days" ) , "d" ) ;
681
672
splitEvents . push ( event ) ;
682
673
683
674
for ( let splitEvent of splitEvents ) {
684
- if ( splitEvent . endDate > now && splitEvent . endDate <= future ) {
675
+ if ( this . timestampToMoment ( splitEvent . endDate ) . isAfter ( now ) && this . timestampToMoment ( splitEvent . endDate ) . isSameOrBefore ( future ) ) {
685
676
by_url_calevents . push ( splitEvent ) ;
686
677
}
687
678
}
@@ -716,16 +707,16 @@ Module.register("calendar", {
716
707
*/
717
708
if ( this . config . limitDays > 0 ) {
718
709
let newEvents = [ ] ;
719
- let lastDate = today . clone ( ) . subtract ( 1 , "days" ) . format ( "YYYYMMDD" ) ;
710
+ let lastDate = today . clone ( ) . subtract ( 1 , "days" ) ;
720
711
let days = 0 ;
721
712
for ( const ev of events ) {
722
- let eventDate = moment ( ev . startDate , "x" ) . format ( "YYYYMMDD" ) ;
713
+ let eventDate = this . timestampToMoment ( ev . startDate ) ;
723
714
724
715
/*
725
716
* if date of event is later than lastdate
726
717
* check if we already are showing max unique days
727
718
*/
728
- if ( eventDate > lastDate ) {
719
+ if ( eventDate . isAfter ( lastDate ) ) {
729
720
// if the only entry in the first day is a full day event that day is not counted as unique
730
721
if ( ! this . config . limitDaysNeverSkip && newEvents . length === 1 && days === 1 && newEvents [ 0 ] . fullDayEvent ) {
731
722
days -- ;
0 commit comments