VulpesOS/gaia/apps/calendar/js/common/calc.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

578 lines
13 KiB
JavaScript
Executable file

/* global mozIntl */
define(function(require, exports) {
'use strict';
var Timespan = require('./timespan');
var co = require('ext/co');
const SECOND = 1000;
const MINUTE = (SECOND * 60);
const HOUR = MINUTE * 60;
exports._hourDate = new Date();
exports.startDay = 0;
exports.FLOATING = 'floating';
exports.ALLDAY = 'allday';
exports.SECOND = SECOND;
exports.MINUTE = MINUTE;
exports.HOUR = HOUR;
exports.PAST = 'past';
exports.NEXT_MONTH = 'next-month';
exports.OTHER_MONTH = 'other-month';
exports.PRESENT = 'present';
exports.FUTURE = 'future';
Object.defineProperty(exports, 'today', {
get: function() {
return new Date();
}
});
exports.daysInWeek = function() {
// XXX: We need to add this to mozIntl.calendarInfo
return 7;
};
/**
* Calculates day of week when starting day is Monday.
*/
exports.dayOfWeekFromMonday = function(numeric) {
var day = numeric - 1;
if (day < 0) {
return 6;
}
return day;
};
/**
* Calculates day of week from startDay value
* passed by the locale currently being used
*/
exports.dayOfWeekFromStartDay = function(numeric) {
var day = numeric - exports.startDay;
if (day < 0) {
return 7 + day;
}
return day;
};
/**
* Checks is given date is today.
*
* @param {Date} date compare.
* @return {Boolean} true when today.
*/
exports.isToday = function(date) {
return exports.isSameDate(date, exports.today);
};
/**
* Checks if date object only contains date information (not time).
*
* Example:
*
* var time = new Date(2012, 0, 1, 1);
* this._isOnlyDate(time); // false
*
* var time = new Date(2012, 0, 1);
* this._isOnlyDate(time); // true
*
* @param {Date} date to verify.
* @return {Boolean} see above.
*/
exports.isOnlyDate = function(date) {
if (
date.getHours() === 0 &&
date.getMinutes() === 0 &&
date.getSeconds() === 0
) {
return true;
}
return false;
};
/**
* Calculates the difference between
* two points in hours.
*
* @param {Date|Numeric} start start hour.
* @param {Date|Numeric} end end hour.
*/
exports.hourDiff = function(start, end) {
start = (start instanceof Date) ? start.valueOf() : start;
end = (end instanceof Date) ? end.valueOf() : end;
start = start / HOUR;
end = end / HOUR;
return end - start;
};
/**
* Creates timespan for given day.
*
* @param {Date} date date of span.
* @param {Boolean} includeTime uses given date
* as the start time of the timespan
* rather then the absolute start of
* the day of the given date.
*/
exports.spanOfDay = function(date, includeTime) {
if (typeof(includeTime) === 'undefined') {
date = exports.createDay(date);
}
var end = exports.createDay(date);
end.setDate(end.getDate() + 1);
return new Timespan(date, end);
};
/**
* Creates timespan for a given month.
* Starts at the first week that occurs
* in the given month. Ends at the
* last day, minute, second of given month.
*/
exports.spanOfMonth = function(month) {
month = exports.monthStart(month);
var startDay = exports.getWeekStartDate(month);
var endDay = exports.monthEnd(month);
endDay = exports.getWeekEndDate(endDay);
return new Timespan(startDay, endDay);
};
exports.monthEnd = function(date, diff = 0) {
var endDay = new Date(
date.getFullYear(),
date.getMonth() + diff + 1,
1
);
endDay.setMilliseconds(-1);
return endDay;
};
/**
* Converts a date to UTC
*/
exports.getUTC = function(date) {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds(),
date.getUTCMilliseconds()
);
};
/**
* Converts transport time into a JS Date object.
*
* @param {Object} transport date in transport format.
* @return {Date} javascript date converts the transport into
* the current time.
*/
exports.dateFromTransport = function(transport) {
var utc = transport.utc;
var offset = transport.offset;
var zone = transport.tzid;
var date = new Date(
// offset is expected to be 0 in the floating case
parseInt(utc) - parseInt(offset)
);
if (zone && zone === exports.FLOATING) {
return exports.getUTC(date);
}
return date;
};
/**
* Converts a date object into a transport value
* which can be stored in the database or sent
* to a service.
*
* When the tzid value is given an is the string
* value of "floating" it will convert the local
* time directly to UTC zero and record no offset.
* This along with the tzid is understood to be
* a "floating" time which will occur at that position
* regardless of the current tzid's offset.
*
* @param {Date} date js date object.
* @param {String} [tzid] optional tzid.
* @param {Boolean} isDate true when is a "date" representation.
*/
exports.dateToTransport = function(date, tzid, isDate) {
var result = Object.create(null);
if (isDate) {
result.isDate = isDate;
}
if (tzid) {
result.tzid = tzid;
}
var utc = Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()
);
// remember a "date" is always a floating
// point in time otherwise we don't use it...
if (isDate || tzid && tzid === exports.FLOATING) {
result.utc = utc;
result.offset = 0;
result.tzid = exports.FLOATING;
} else {
var localUtc = date.valueOf();
var offset = utc - localUtc;
result.utc = utc;
result.offset = offset;
}
return result;
};
/**
* Checks if two date objects occur
* on the same date (in the same month, year, day).
* Disregards time.
*
* @param {Date} first date.
* @param {Date} second date.
* @return {Boolean} true when they are the same date.
*/
exports.isSameDate = function(first, second) {
return first.getMonth() == second.getMonth() &&
first.getDate() == second.getDate() &&
first.getFullYear() == second.getFullYear();
};
/**
* Returns an identifier for a specific
* date in time for a given date
*
* @param {Date} date to get id for.
* @return {String} identifier.
*/
exports.getDayId = function(date) {
return [
'd',
date.getFullYear(),
date.getMonth(),
date.getDate()
].join('-');
};
/**
* Returns a date object from
* a string id for a date.
*
* @param {String} id identifier for date.
* @return {Date} date output.
*/
exports.dateFromId = function(id) {
var parts = id.split('-'),
date,
type;
if (parts.length > 1) {
type = parts.shift();
switch (type) {
case 'd':
date = new Date(parts[0], parts[1], parts[2]);
break;
case 'm':
date = new Date(parts[0], parts[1]);
break;
}
}
return date;
};
/**
* Returns an identifier for a specific
* month in time for a given date.
*
* @return {String} identifier.
*/
exports.getMonthId = function(date) {
return [
'm',
date.getFullYear(),
date.getMonth()
].join('-');
};
exports.createDay = function(date, day, month, year) {
return new Date(
year != null ? year : date.getFullYear(),
month != null ? month : date.getMonth(),
day != null ? day : date.getDate()
);
};
exports.endOfDay = function(date) {
var day = exports.createDay(date, date.getDate() + 1);
day.setMilliseconds(-1);
return day;
};
exports.monthStart = function(date, diff = 0) {
return new Date(date.getFullYear(), date.getMonth() + diff, 1);
};
/**
* Returns localized day of week.
*
* @param {Date|Number} date numeric or date object.
*/
exports.dayOfWeek = function(date) {
var number = date;
if (typeof(date) !== 'number') {
number = date.getDay();
}
return exports.dayOfWeekFromStartDay(number);
};
/**
* Finds localized week start date of given date.
*
* @param {Date} date any day the week.
* @return {Date} first date in the week of given date.
*/
exports.getWeekStartDate = function(date) {
var currentDay = exports.dayOfWeek(date);
var startDay = (date.getDate() - currentDay);
return exports.createDay(date, startDay);
};
exports.getWeekEndDate = function(date) {
// TODO: There are localization problems
// with this approach as we assume a 7 day week.
var start = exports.getWeekStartDate(date);
start.setDate(start.getDate() + 7);
start.setMilliseconds(-1);
return start;
};
/**
* Returns an array of dates objects.
* Inclusive. First and last are
* the given instances.
*
* @param {Date} start starting day.
* @param {Date} end ending day.
* @param {Boolean} includeTime include times start/end ?
*/
exports.daysBetween = function(start, end, includeTime) {
if (start instanceof Timespan) {
if (end) {
includeTime = end;
}
end = new Date(start.end);
start = new Date(start.start);
}
if (start > end) {
var tmp = end;
end = start;
start = tmp;
tmp = null;
}
var list = [];
var last = start.getDate();
// handle the case where start & end dates
// are the same date.
if (exports.isSameDate(start, end)) {
if (includeTime) {
list.push(end);
} else {
list.push(exports.createDay(start));
}
return list;
}
while (true) {
var next = new Date(
start.getFullYear(),
start.getMonth(),
++last
);
if (next > end) {
throw new Error(
'sanity fails next is greater then end'
);
}
if (!exports.isSameDate(next, end)) {
list.push(next);
continue;
}
break;
}
if (includeTime) {
list.unshift(start);
list.push(end);
} else {
list.unshift(exports.createDay(start));
list.push(exports.createDay(end));
}
return list;
},
/**
* Returns an array of weekdays based on the start date.
* Will always return the 7 daysof that week regardless of
* what the start date isbut they will be returned
* in the order of their localized getDay function.
*
* @param {Date} startDate point of origin.
* @return {Array} a list of dates in order of getDay().
*/
exports.getWeeksDays = function(startDate) {
//local day position
var weeksDayStart = exports.getWeekStartDate(startDate);
var result = [weeksDayStart];
for (var i = 1; i < 7; i++) {
result.push(exports.createDay(weeksDayStart, weeksDayStart.getDate() + i));
}
return result;
};
/**
* Checks if date is in the past
*
* @param {Date} date to check.
* @return {Boolean} true when date is in the past.
*/
exports.isPast = function(date) {
return (date.valueOf() < exports.today.valueOf());
};
/**
* Checks if date is in the future
*
* @param {Date} date to check.
* @return {Boolean} true when date is in the future.
*/
exports.isFuture = function(date) {
return !exports.isPast(date);
};
/**
* Based on the input date
* will return one of the following states
*
* past, present, future
*
* @param {Date} day for compare.
* @param {Date} month comparison month.
* @return {String} state.
*/
exports.relativeState = function(day, month) {
var states;
//var today = exports.today;
// 1. the date is today (real time)
if (exports.isToday(day)) {
return exports.PRESENT;
}
// 2. the date is in the past (real time)
if (exports.isPast(day)) {
states = exports.PAST;
// 3. the date is in the future (real time)
} else {
states = exports.FUTURE;
}
// 4. the date is not in the current month (relative time)
if (day.getMonth() !== month.getMonth()) {
states += ' ' + exports.OTHER_MONTH;
}
return states;
};
/**
* Computes the relative hour (0...23.9999) inside the given day.
* If `date` is on a different day than `baseDate` it will return `0`.
* Used by week view to compute the position of the busytimes relative to
* the top of the view.
*/
exports.relativeOffset = function(baseDate, date) {
if (exports.isSameDate(baseDate, date)) {
return date.getHours() + (date.getMinutes() / 60);
}
// different day!
return 0;
};
/**
* Computes the relative duration between startDate and endDate inside
* a given baseDate. Returns a number between 0 and 24.
* Used by MultiDay view to compute the height of the busytimes relative to
* the length inside the baseDate.
*/
exports.relativeDuration = function(baseDate, startDate, endDate) {
if (!exports.isSameDate(startDate, endDate)) {
if (exports.isSameDate(baseDate, startDate)) {
endDate = exports.endOfDay(baseDate);
} else if (exports.isSameDate(baseDate, endDate)) {
startDate = exports.createDay(endDate);
} else {
// started before baseDate and ends on a different day
return 24;
}
}
return exports.hourDiff(startDate, endDate);
};
/**
* Check if event spans thru the whole day.
*/
exports.isAllDay = function(baseDate, startDate, endDate) {
// beginning reference point (start of given date)
var refStart = exports.createDay(baseDate);
var refEnd = exports.endOfDay(baseDate);
var startBefore = startDate <= refStart;
var endsAfter = endDate >= refEnd;
// yahoo uses same start/end date for recurring all day events!!!
return (startBefore && endsAfter) || Number(startDate) === Number(endDate);
};
if (typeof(window) !== 'undefined') {
window.addEventListener('localized', co.wrap(function *() {
exports.startDay = yield mozIntl.calendarInfo('firstDayOfTheWeek');
}));
}
});