1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5var EXPORTED_SYMBOLS = ["CalWeekInfoService"];
6
7var { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
8
9const SUNDAY = 0;
10const THURSDAY = 4;
11
12XPCOMUtils.defineLazyPreferenceGetter(this, "startWeekday", "calendar.week.start", SUNDAY);
13
14function CalWeekInfoService() {
15  this.wrappedJSObject = this;
16}
17CalWeekInfoService.prototype = {
18  QueryInterface: ChromeUtils.generateQI(["calIWeekInfoService"]),
19  classID: Components.ID("{6877bbdd-f336-46f5-98ce-fe86d0285cc1}"),
20
21  // calIWeekInfoService:
22  getWeekTitle(aDateTime) {
23    /**
24     * This implementation is based on the ISO 8601 standard.
25     * ISO 8601 defines week one as the first week with at least 4
26     * days, and defines Monday as the first day of the week.
27     * Equivalently, the week one is the week with the first Thursday.
28     *
29     * This implementation uses the second definition, because it
30     * enables the user to set a different start-day of the week
31     * (Sunday instead of Monday is a common setting).  If the first
32     * definition was used, all week-numbers could be off by one
33     * depending on the week start day.  (For example, if weeks start
34     * on Sunday, a year that starts on Thursday has only 3 days
35     * [Thu-Sat] in that week, so it would be part of the last week of
36     * the previous year, but if weeks start on Monday, the year would
37     * have four days [Thu-Sun] in that week, so it would be counted
38     * as week 1.)
39     */
40
41    // The week number is the number of days since the start of week 1,
42    // divided by 7 and rounded up. Week 1 is the week containing the first
43    // Thursday of the year.
44    // Thus, the week number of any day is the same as the number of days
45    // between the Thursday of that week and the Thursday of week 1, divided
46    // by 7 and rounded up. (This takes care of days at end/start of a year
47    // which may be part of first/last week in the other year.)
48    // The Thursday of a week is the Thursday that follows the first day
49    // of the week.
50    // The week number of a day is the same as the week number of the first
51    // day of the week. (This takes care of days near the start of the year,
52    // which may be part of the week counted in the previous year.) So we
53    // need the startWeekday.
54
55    // The number of days since the start of the week.
56    // Notice that the result of the subtraction might be negative.
57    // We correct for that by adding 7, and then using the remainder operator.
58    let sinceStartOfWeek = (aDateTime.weekday - startWeekday + 7) % 7;
59
60    // The number of days to Thursday is the difference between Thursday
61    // and the start-day of the week (again corrected for negative values).
62    let startToThursday = (THURSDAY - startWeekday + 7) % 7;
63
64    // The yearday number of the Thursday this week.
65    let thisWeeksThursday = aDateTime.yearday - sinceStartOfWeek + startToThursday;
66
67    if (thisWeeksThursday < 1) {
68      // For the first few days of the year, we still are in week 52 or 53.
69      let lastYearDate = aDateTime.clone();
70      lastYearDate.year -= 1;
71      thisWeeksThursday += lastYearDate.endOfYear.yearday;
72    } else if (thisWeeksThursday > aDateTime.endOfYear.yearday) {
73      // For the last few days of the year, we already are in week 1.
74      thisWeeksThursday -= aDateTime.endOfYear.yearday;
75    }
76
77    let weekNumber = Math.ceil(thisWeeksThursday / 7);
78    return weekNumber;
79  },
80
81  /**
82   * gets the first day of a week of a passed day under consideration
83   * of the preference setting "calendar.week.start"
84   *
85   * @param aDate     a date time object
86   * @return          a dateTime-object denoting the first day of the week
87   */
88  getStartOfWeek(aDate) {
89    let date = aDate.clone();
90    date.isDate = true;
91    let offset = startWeekday - aDate.weekday;
92    date.day += offset;
93    if (offset > 0) {
94      date.day -= 7;
95    }
96    return date;
97  },
98
99  /**
100   * gets the last day of a week of a passed day under consideration
101   * of the preference setting "calendar.week.start"
102   *
103   * @param aDate     a date time object
104   * @return          a dateTime-object denoting the last day of the week
105   */
106  getEndOfWeek(aDate) {
107    let date = this.getStartOfWeek(aDate);
108    date.day += 6;
109    return date;
110  },
111};
112