summaryrefslogtreecommitdiffstats
path: root/comm/calendar/base/src/CalWeekInfoService.jsm
blob: a94145f44e48999e22a6814c6d43dba15dbdc3d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var EXPORTED_SYMBOLS = ["CalWeekInfoService"];

var { XPCOMUtils } = ChromeUtils.importESModule("resource://gre/modules/XPCOMUtils.sys.mjs");

const SUNDAY = 0;
const THURSDAY = 4;

const lazy = {};

XPCOMUtils.defineLazyPreferenceGetter(lazy, "startWeekday", "calendar.week.start", SUNDAY);

function CalWeekInfoService() {
  this.wrappedJSObject = this;
}
CalWeekInfoService.prototype = {
  QueryInterface: ChromeUtils.generateQI(["calIWeekInfoService"]),
  classID: Components.ID("{6877bbdd-f336-46f5-98ce-fe86d0285cc1}"),

  // calIWeekInfoService:
  getWeekTitle(aDateTime) {
    /**
     * This implementation is based on the ISO 8601 standard.
     * ISO 8601 defines week one as the first week with at least 4
     * days, and defines Monday as the first day of the week.
     * Equivalently, the week one is the week with the first Thursday.
     *
     * This implementation uses the second definition, because it
     * enables the user to set a different start-day of the week
     * (Sunday instead of Monday is a common setting).  If the first
     * definition was used, all week-numbers could be off by one
     * depending on the week start day.  (For example, if weeks start
     * on Sunday, a year that starts on Thursday has only 3 days
     * [Thu-Sat] in that week, so it would be part of the last week of
     * the previous year, but if weeks start on Monday, the year would
     * have four days [Thu-Sun] in that week, so it would be counted
     * as week 1.)
     */

    // The week number is the number of days since the start of week 1,
    // divided by 7 and rounded up. Week 1 is the week containing the first
    // Thursday of the year.
    // Thus, the week number of any day is the same as the number of days
    // between the Thursday of that week and the Thursday of week 1, divided
    // by 7 and rounded up. (This takes care of days at end/start of a year
    // which may be part of first/last week in the other year.)
    // The Thursday of a week is the Thursday that follows the first day
    // of the week.
    // The week number of a day is the same as the week number of the first
    // day of the week. (This takes care of days near the start of the year,
    // which may be part of the week counted in the previous year.) So we
    // need the startWeekday.

    // The number of days since the start of the week.
    // Notice that the result of the subtraction might be negative.
    // We correct for that by adding 7, and then using the remainder operator.
    let sinceStartOfWeek = (aDateTime.weekday - lazy.startWeekday + 7) % 7;

    // The number of days to Thursday is the difference between Thursday
    // and the start-day of the week (again corrected for negative values).
    let startToThursday = (THURSDAY - lazy.startWeekday + 7) % 7;

    // The yearday number of the Thursday this week.
    let thisWeeksThursday = aDateTime.yearday - sinceStartOfWeek + startToThursday;

    if (thisWeeksThursday < 1) {
      // For the first few days of the year, we still are in week 52 or 53.
      let lastYearDate = aDateTime.clone();
      lastYearDate.year -= 1;
      thisWeeksThursday += lastYearDate.endOfYear.yearday;
    } else if (thisWeeksThursday > aDateTime.endOfYear.yearday) {
      // For the last few days of the year, we already are in week 1.
      thisWeeksThursday -= aDateTime.endOfYear.yearday;
    }

    let weekNumber = Math.ceil(thisWeeksThursday / 7);
    return weekNumber;
  },

  /**
   * gets the first day of a week of a passed day under consideration
   * of the preference setting "calendar.week.start"
   *
   * @param aDate     a date time object
   * @returns a dateTime-object denoting the first day of the week
   */
  getStartOfWeek(aDate) {
    let date = aDate.clone();
    date.isDate = true;
    let offset = lazy.startWeekday - aDate.weekday;
    date.day += offset;
    if (offset > 0) {
      date.day -= 7;
    }
    return date;
  },

  /**
   * gets the last day of a week of a passed day under consideration
   * of the preference setting "calendar.week.start"
   *
   * @param aDate     a date time object
   * @returns a dateTime-object denoting the last day of the week
   */
  getEndOfWeek(aDate) {
    let date = this.getStartOfWeek(aDate);
    date.day += 6;
    return date;
  },
};