much better formatting of date ranges and their duration
This commit is contained in:
parent
13669aec63
commit
f0052d3e3c
4 changed files with 247 additions and 97 deletions
|
@ -36,14 +36,19 @@ Ox.load('UI', {debug: true, hideScreen: true, showScreen: true, theme: 'modern'}
|
||||||
{name: 'Summer 1968', start: '1968-06', end: '1968-09', type: 'date'},
|
{name: 'Summer 1968', start: '1968-06', end: '1968-09', type: 'date'},
|
||||||
{name: '1969', start: '1969', end: '1970', type: 'date'},
|
{name: '1969', start: '1969', end: '1970', type: 'date'},
|
||||||
{name: '1970s', start: '1970', end: '1980', type: 'date'},
|
{name: '1970s', start: '1970', end: '1980', type: 'date'},
|
||||||
|
{name: '1970', start: '1970', end: '1971', type: 'date'},
|
||||||
{name: '1980s', start: '1980', end: '1990', type: 'date'},
|
{name: '1980s', start: '1980', end: '1990', type: 'date'},
|
||||||
{name: '1990s', start: '1990', end: '2000', type: 'date'},
|
{name: '1990s', start: '1990', end: '2000', type: 'date'},
|
||||||
|
{name: '3rd Millennium', start: '2000', end: '3000', type: 'date'},
|
||||||
{name: '21st Century', start: '2000', end: '2100', type: 'date'},
|
{name: '21st Century', start: '2000', end: '2100', type: 'date'},
|
||||||
{name: '2000s', start: '2000', end: '2010', type: 'date'},
|
{name: '2000s', start: '2000', end: '2010', type: 'date'},
|
||||||
|
{name: '2000', start: '2000', end: '2001', type: 'date'},
|
||||||
|
{name: '2001', start: '2001', end: '2002', type: 'date'},
|
||||||
{name: '2010s', start: '2010', end: '2020', type: 'date'},
|
{name: '2010s', start: '2010', end: '2020', type: 'date'},
|
||||||
{name: '2020s', start: '2020', end: '2030', type: 'date'},
|
{name: '2020s', start: '2020', end: '2030', type: 'date'},
|
||||||
|
|
||||||
|
|
||||||
|
{name: 'Julius Caesar', start: '-100-07-13', end: '-44-03-15', type: 'person'},
|
||||||
{name: 'Barbarossa', start: '1122', end: '1190-06-10', type: 'person'},
|
{name: 'Barbarossa', start: '1122', end: '1190-06-10', type: 'person'},
|
||||||
{name: 'Genghis Khan', start: '1162', end: '1228', type: 'person'},
|
{name: 'Genghis Khan', start: '1162', end: '1228', type: 'person'},
|
||||||
{name: 'Marco Polo', start: '1254', end: '1324-01-08', type: 'person'},
|
{name: 'Marco Polo', start: '1254', end: '1324-01-08', type: 'person'},
|
||||||
|
|
|
@ -95,9 +95,6 @@ Ox.load('UI', {
|
||||||
WebkitUserSelect: 'text'
|
WebkitUserSelect: 'text'
|
||||||
});
|
});
|
||||||
['moz', 'webkit'].forEach(function(browser) {
|
['moz', 'webkit'].forEach(function(browser) {
|
||||||
Ox.print('-' + browser + '-linear-gradient(left top, left bottom, rgb(' +
|
|
||||||
getColor(success, 0) + '), rgb(' +
|
|
||||||
getColor(success, 1) + '))')
|
|
||||||
$div.css({
|
$div.css({
|
||||||
background: '-' + browser + '-linear-gradient(top, rgb(' +
|
background: '-' + browser + '-linear-gradient(top, rgb(' +
|
||||||
getColor(success, 0) + '), rgb(' +
|
getColor(success, 0) + '), rgb(' +
|
||||||
|
|
|
@ -74,12 +74,26 @@ Ox.Calendar = function(options, self) {
|
||||||
|
|
||||||
self.options.events.forEach(function(event) {
|
self.options.events.forEach(function(event) {
|
||||||
event.id = Ox.isUndefined(event.id) ? Ox.uid() : event.id;
|
event.id = Ox.isUndefined(event.id) ? Ox.uid() : event.id;
|
||||||
event.start = Ox.parseDate(event.start, true);
|
event.startTime = Ox.parseDate(event.start, true);
|
||||||
event.end = Ox.parseDate(event.end, true);
|
event.endTime = Ox.parseDate(event.end, true);
|
||||||
|
event.rangeText = Ox.formatDateRange(event.start, event.end, true);
|
||||||
|
event.durationText = Ox.formatDateRangeDuration(event.start, event.end, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.maxZoom = 32;
|
self.maxZoom = 32;
|
||||||
self.minLabelWidth = 80;
|
self.minLabelWidth = 80;
|
||||||
|
|
||||||
|
/*
|
||||||
|
We need to iterate over irregular intervals, like months or years.
|
||||||
|
The idea is to put this logic into a data structure, the units.
|
||||||
|
Just like the 0-th second is 1970-01-01 00:00:00, the 0th month
|
||||||
|
is 1970-01, or the 0-th century is the 20th century.
|
||||||
|
A month unit, for example, has the following properties:
|
||||||
|
- seconds: average number of seconds
|
||||||
|
- date: returns the start date of the index-th month
|
||||||
|
- name: returns a string representation of the index-th month
|
||||||
|
- value: returns the month index for a given date
|
||||||
|
*/
|
||||||
self.units = [
|
self.units = [
|
||||||
{
|
{
|
||||||
id: 'millennium',
|
id: 'millennium',
|
||||||
|
@ -93,8 +107,8 @@ Ox.Calendar = function(options, self) {
|
||||||
},
|
},
|
||||||
name: function(i) {
|
name: function(i) {
|
||||||
return i > -2
|
return i > -2
|
||||||
? Ox.formatOrdinal(i + 2) + ' millennium'
|
? Ox.formatOrdinal(i + 2) + ' Millennium'
|
||||||
: Ox.formatOrdinal(-i - 1) + ' millennium BC'
|
: Ox.formatOrdinal(-i - 1) + ' Millennium BC'
|
||||||
},
|
},
|
||||||
value: function(date) {
|
value: function(date) {
|
||||||
return Math.floor(date.getUTCFullYear() / 1000) - 1;
|
return Math.floor(date.getUTCFullYear() / 1000) - 1;
|
||||||
|
@ -112,8 +126,8 @@ Ox.Calendar = function(options, self) {
|
||||||
},
|
},
|
||||||
name: function(i) {
|
name: function(i) {
|
||||||
return i > -20
|
return i > -20
|
||||||
? Ox.formatOrdinal(i + 20) + ' century'
|
? Ox.formatOrdinal(i + 20) + ' Century'
|
||||||
: Ox.formatOrdinal(-i - 19) + ' century BC'
|
: Ox.formatOrdinal(-i - 19) + ' Century BC'
|
||||||
},
|
},
|
||||||
value: function(date) {
|
value: function(date) {
|
||||||
return Math.floor(date.getUTCFullYear() / 100) - 19;
|
return Math.floor(date.getUTCFullYear() / 100) - 19;
|
||||||
|
@ -506,55 +520,11 @@ Ox.Calendar = function(options, self) {
|
||||||
renderCalendar();
|
renderCalendar();
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatEvent(event) {
|
|
||||||
return formatEventRange(event) + '<br/>' + formatEventDuration(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEventDuration(event) {
|
|
||||||
// fixme: still wrong because of different number of leap days
|
|
||||||
var date = new Date(getEventDuration(event)),
|
|
||||||
strings = [],
|
|
||||||
values = {
|
|
||||||
years: date.getUTCFullYear() - 1970,
|
|
||||||
days: Ox.getDayOfTheYear(date, true) - 1,
|
|
||||||
hours: date.getUTCHours(),
|
|
||||||
minutes: date.getUTCMinutes(),
|
|
||||||
seconds: date.getUTCMilliseconds()
|
|
||||||
};
|
|
||||||
//Ox.print('****', values);
|
|
||||||
['year', 'day', 'hour', 'minute', 'second'].forEach(function(key) {
|
|
||||||
var value = values[key + 's'];
|
|
||||||
value && strings.push(value + ' ' + key + (value > 1 ? 's' : ''));
|
|
||||||
});
|
|
||||||
return strings.join(' ');
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEventRange(event) {
|
|
||||||
var isFullDays = Ox.formatDate(event.start, '%H:%M:%S', true) == '00:00:00' &&
|
|
||||||
Ox.formatDate(event.end, '%H:%M:%S', true) == '00:00:00',
|
|
||||||
isOneDay = isFullDays && getEventDuration(event) == 86400000, // fixme: wrong, DST
|
|
||||||
isSameDay = Ox.formatDate(event.start, '%Y-%m-%d', true) ==
|
|
||||||
Ox.formatDate(event.end, '%Y-%m-%d', true),
|
|
||||||
isSameYear = event.start.getUTCFullYear() == event.end.getUTCFullYear(),
|
|
||||||
timeFormat = isFullDays ? '' : ', %H:%M:%S',
|
|
||||||
string = Ox.formatDate(event.start, '%a, %b %e', true);
|
|
||||||
if (isOneDay || isSameDay || !isSameYear) {
|
|
||||||
string += Ox.formatDate(event.start, ', %Y' + timeFormat, true);
|
|
||||||
}
|
|
||||||
if (!isOneDay && !isSameDay) {
|
|
||||||
string += Ox.formatDate(event.end, ' - %a, %b %e, %Y' + timeFormat, true);
|
|
||||||
}
|
|
||||||
if (isSameDay) {
|
|
||||||
string += Ox.formatDate(event.end, ' - ' + timeFormat.replace(', ', ''), true);
|
|
||||||
}
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCalendarEvent(zoom) {
|
function getCalendarEvent(zoom) {
|
||||||
var ms = self.options.width * getSecondsPerPixel(zoom) * 1000;
|
var ms = self.options.width * getSecondsPerPixel(zoom) * 1000;
|
||||||
return {
|
return {
|
||||||
start: new Date(+self.options.date - ms / 2),
|
startTime: new Date(+self.options.date - ms / 2),
|
||||||
end: new Date(+self.options.date + ms / 2)
|
endTime: new Date(+self.options.date + ms / 2)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,17 +540,17 @@ Ox.Calendar = function(options, self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEventCenter(event) {
|
function getEventCenter(event) {
|
||||||
return new Date(+event.start + getEventDuration(event) / 2);
|
return new Date(+event.startTime + getEventDuration(event) / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEventDuration(event) {
|
function getEventDuration(event) {
|
||||||
return event.end - event.start;
|
return event.endTime - event.startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEventElement(event, zoom) {
|
function getEventElement(event, zoom) {
|
||||||
var left = Math.max(getPosition(event.start, zoom), -10000),
|
var left = Math.max(getPosition(event.startTime, zoom), -10000),
|
||||||
paddingLeft = (event.type && left < 0 ? -left : 0),
|
paddingLeft = (event.type && left < 0 ? -left : 0),
|
||||||
width = Ox.limit(getPosition(event.end, zoom) - left, 1, 20000) - paddingLeft;
|
width = Ox.limit(getPosition(event.endTime, zoom) - left, 1, 20000) - paddingLeft;
|
||||||
return new Ox.Element()
|
return new Ox.Element()
|
||||||
.addClass('OxEvent' +
|
.addClass('OxEvent' +
|
||||||
(event.type ? ' Ox' + Ox.toTitleCase(event.type) : '' ) +
|
(event.type ? ' Ox' + Ox.toTitleCase(event.type) : '' ) +
|
||||||
|
@ -692,8 +662,8 @@ Ox.Calendar = function(options, self) {
|
||||||
$elements.push(
|
$elements.push(
|
||||||
getEventElement({
|
getEventElement({
|
||||||
name: unit.name(value + i),
|
name: unit.name(value + i),
|
||||||
start: unit.date(value + i),
|
startTime: unit.date(value + i),
|
||||||
end: unit.date(value + i + 1)
|
endTime: unit.date(value + i + 1)
|
||||||
}, zoom)
|
}, zoom)
|
||||||
.addClass(Ox.mod(value + i, 2) == 0 ? 'even' : 'odd')
|
.addClass(Ox.mod(value + i, 2) == 0 ? 'even' : 'odd')
|
||||||
);
|
);
|
||||||
|
@ -729,7 +699,7 @@ Ox.Calendar = function(options, self) {
|
||||||
if ($target.is('.OxLine > .OxEvent')) {
|
if ($target.is('.OxLine > .OxEvent')) {
|
||||||
event = getEventById($target.data('id'));
|
event = getEventById($target.data('id'));
|
||||||
title = '<span class="OxBright">' + event.name + '</span><br/>' +
|
title = '<span class="OxBright">' + event.name + '</span><br/>' +
|
||||||
formatEvent(event);
|
event.rangeText + '<br>' + event.durationText;
|
||||||
} else {
|
} else {
|
||||||
title = Ox.formatDate(getMouseDate(e), '%a, %b %e, %Y, %H:%M:%S', true);
|
title = Ox.formatDate(getMouseDate(e), '%a, %b %e, %Y, %H:%M:%S', true);
|
||||||
}
|
}
|
||||||
|
@ -763,9 +733,9 @@ Ox.Calendar = function(options, self) {
|
||||||
|
|
||||||
function overlaps(eventA, eventB) {
|
function overlaps(eventA, eventB) {
|
||||||
return (
|
return (
|
||||||
eventA.start >= eventB.start && eventA.start < eventB.end
|
eventA.startTime >= eventB.startTime && eventA.startTime < eventB.endTime
|
||||||
) || (
|
) || (
|
||||||
eventB.start >= eventA.start && eventB.start < eventA.end
|
eventB.startTime >= eventA.startTime && eventB.startTime < eventA.endTime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,10 +797,10 @@ Ox.Calendar = function(options, self) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (a.type != 'date' && b.type == 'date') {
|
} else if (a.type != 'date' && b.type == 'date') {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (a.start < b.start || a.start > b.start) {
|
} else if (a.startTime < b.startTime || a.startTime > b.startTime) {
|
||||||
return a.start - b.start;
|
return a.startTime - b.startTime;
|
||||||
} else {
|
} else {
|
||||||
return (b.end - b.start) - (a.end - a.start);
|
return (b.endTime - b.startTime) - (a.endTime - a.startTime);
|
||||||
}
|
}
|
||||||
}).forEach(function(event, i) {
|
}).forEach(function(event, i) {
|
||||||
var line = lineEvents.length;
|
var line = lineEvents.length;
|
||||||
|
@ -865,7 +835,7 @@ Ox.Calendar = function(options, self) {
|
||||||
.appendTo(self.$content);
|
.appendTo(self.$content);
|
||||||
events.sort(function(a, b) {
|
events.sort(function(a, b) {
|
||||||
// sort events by start, ascending
|
// sort events by start, ascending
|
||||||
return a.start - b.start;
|
return a.startTime - b.startTime;
|
||||||
}).forEach(function(event) {
|
}).forEach(function(event) {
|
||||||
overlaps(event, calendarEvent) &&
|
overlaps(event, calendarEvent) &&
|
||||||
getEventElement(event).appendTo($line);
|
getEventElement(event).appendTo($line);
|
||||||
|
|
236
source/Ox.js
236
source/Ox.js
|
@ -1063,8 +1063,11 @@ Ox.rgb = function(hsl) {
|
||||||
|
|
||||||
//@ Ox.AMPM <[str]> ['AM', 'PM']
|
//@ Ox.AMPM <[str]> ['AM', 'PM']
|
||||||
Ox.AMPM = ['AM', 'PM'];
|
Ox.AMPM = ['AM', 'PM'];
|
||||||
//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'minute', 'second']
|
//@ Ox.BCAD <[str]> ['BC', 'AD']
|
||||||
Ox.DURATIONS = ['year', 'month', 'day', 'minute', 'second'];
|
Ox.BCAD = ['BC', 'AD'];
|
||||||
|
// fixme: this is unused, and probably unneeded
|
||||||
|
//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'hour', 'minute', 'second']
|
||||||
|
Ox.DURATIONS = ['year', 'month', 'day', 'hour', 'minute', 'second'];
|
||||||
//@ Ox.EARTH_RADIUS <number> Radius of the earth in meters
|
//@ Ox.EARTH_RADIUS <number> Radius of the earth in meters
|
||||||
// see http://en.wikipedia.org/wiki/WGS-84
|
// see http://en.wikipedia.org/wiki/WGS-84
|
||||||
Ox.EARTH_RADIUS = 6378137;
|
Ox.EARTH_RADIUS = 6378137;
|
||||||
|
@ -1199,8 +1202,6 @@ Ox.getDateInWeek <f> Get the date that falls on a given weekday in the same week
|
||||||
@*/
|
@*/
|
||||||
// fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"??
|
// fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"??
|
||||||
Ox.getDateInWeek = function(date, weekday, utc) {
|
Ox.getDateInWeek = function(date, weekday, utc) {
|
||||||
/*
|
|
||||||
*/
|
|
||||||
date = Ox.makeDate(date);
|
date = Ox.makeDate(date);
|
||||||
Ox.print(date, Ox.getDate(date, utc), Ox.formatDate(date, '%u', utc), date)
|
Ox.print(date, Ox.getDate(date, utc), Ox.formatDate(date, '%u', utc), date)
|
||||||
var sourceWeekday = Ox.getISODay(date, utc),
|
var sourceWeekday = Ox.getISODay(date, utc),
|
||||||
|
@ -1208,7 +1209,6 @@ Ox.getDateInWeek = function(date, weekday, utc) {
|
||||||
Ox.map(Ox.WEEKDAYS, function(v, i) {
|
Ox.map(Ox.WEEKDAYS, function(v, i) {
|
||||||
return v.substr(0, 3) == weekday.substr(0, 3) ? i + 1 : null;
|
return v.substr(0, 3) == weekday.substr(0, 3) ? i + 1 : null;
|
||||||
})[0];
|
})[0];
|
||||||
Ox.print(date, Ox.getDate(date, utc), sourceWeekday, targetWeekday)
|
|
||||||
return Ox.setDate(date, Ox.getDate(date, utc) - sourceWeekday + targetWeekday, utc);
|
return Ox.setDate(date, Ox.getDate(date, utc) - sourceWeekday + targetWeekday, utc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1428,8 +1428,8 @@ Ox.makeDate <f> Takes a date, number or string, returns a date
|
||||||
'01/01/1970'
|
'01/01/1970'
|
||||||
@*/
|
@*/
|
||||||
Ox.makeDate = function(date) {
|
Ox.makeDate = function(date) {
|
||||||
return Ox.isDate(date) ? date :
|
// if date is a date, new Date(date) makes a clone
|
||||||
Ox.isUndefined(date) ? new Date() : new Date(date);
|
return Ox.isUndefined(date) ? new Date() : new Date(date);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
|
@ -1445,12 +1445,11 @@ Ox.makeYear = function(date, utc) {
|
||||||
return Ox.isDate(date) ? Ox.getFullYear(date, utc) : parseInt(date);
|
return Ox.isDate(date) ? Ox.getFullYear(date, utc) : parseInt(date);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
Ox.parseDate(f) Takes a string ('YYYY-MM-DD HH:MM:SS') and returns a date
|
Ox.parseDate <f> Takes a string ('YYYY-MM-DD HH:MM:SS') and returns a date
|
||||||
str <s> string
|
str <s> string
|
||||||
utc <b|false> If true, Date is UTC
|
utc <b|false> If true, Date is UTC
|
||||||
> +Ox.parseDate('1970-01-01 01:01:01')
|
> +Ox.parseDate('1970-01-01 01:01:01', true)
|
||||||
3661000
|
3661000
|
||||||
> +Ox.parseDate('1970', true)
|
> +Ox.parseDate('1970', true)
|
||||||
0
|
0
|
||||||
|
@ -1458,9 +1457,9 @@ Ox.parseDate(f) Takes a string ('YYYY-MM-DD HH:MM:SS') and returns a date
|
||||||
50
|
50
|
||||||
@*/
|
@*/
|
||||||
Ox.parseDate = function(str, utc) {
|
Ox.parseDate = function(str, utc) {
|
||||||
var date = new Date(),
|
var date = new Date(0),
|
||||||
defaults = [, 1, 1, 0, 0, 0],
|
defaults = [, 1, 1, 0, 0, 0],
|
||||||
values = /(\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/(str);
|
values = /(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/(str);
|
||||||
values.shift();
|
values.shift();
|
||||||
values = values.map(function(v, i) {
|
values = values.map(function(v, i) {
|
||||||
return v || defaults[i];
|
return v || defaults[i];
|
||||||
|
@ -1469,11 +1468,29 @@ Ox.parseDate = function(str, utc) {
|
||||||
[
|
[
|
||||||
'FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'
|
'FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'
|
||||||
].forEach(function(part, i) {
|
].forEach(function(part, i) {
|
||||||
date = Ox['set' + part](date, values[i], utc);
|
Ox['set' + part](date, values[i], utc);
|
||||||
});
|
});
|
||||||
return date;
|
return date;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Ox.parseDateRange = function(start, end, utc) {
|
||||||
|
var dates = [
|
||||||
|
Ox.parseDate(start, utc),
|
||||||
|
Ox.parseDate(end, utc)
|
||||||
|
],
|
||||||
|
part = [
|
||||||
|
'FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'
|
||||||
|
][
|
||||||
|
Ox.compact(
|
||||||
|
/(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/(end)
|
||||||
|
).length - 2
|
||||||
|
];
|
||||||
|
Ox['set' + part](dates[1], Ox['get' + part](dates[1], utc) + 1, utc);
|
||||||
|
return dates;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
//@ Ox.setDate <f> Set the day of a date, optionally UTC
|
//@ Ox.setDate <f> Set the day of a date, optionally UTC
|
||||||
// see Ox.setSeconds for source code
|
// see Ox.setSeconds for source code
|
||||||
//@ Ox.setDay <f> Set the weekday of a date, optionally UTC
|
//@ Ox.setDay <f> Set the weekday of a date, optionally UTC
|
||||||
|
@ -1493,14 +1510,15 @@ Ox.parseDate = function(str, utc) {
|
||||||
[
|
[
|
||||||
'FullYear', 'Month', 'Date', 'Day',
|
'FullYear', 'Month', 'Date', 'Day',
|
||||||
'Hours', 'Minutes', 'Seconds', 'Milliseconds'
|
'Hours', 'Minutes', 'Seconds', 'Milliseconds'
|
||||||
].forEach(function(noun) {
|
].forEach(function(part) {
|
||||||
Ox['get' + noun] = function(date, utc) {
|
Ox['get' + part] = function(date, utc) {
|
||||||
return Ox.makeDate(date)['get' + (utc ? 'UTC' : '') + noun]()
|
return Ox.makeDate(date)['get' + (utc ? 'UTC' : '') + part]()
|
||||||
}
|
}
|
||||||
Ox['set' + noun] = function(date, num, utc) {
|
// Ox.setPart(date) modifies date
|
||||||
return new Date(
|
Ox['set' + part] = function(date, num, utc) {
|
||||||
Ox.makeDate(date)['set' + (utc ? 'UTC' : '') + noun](num)
|
return (
|
||||||
);
|
Ox.isDate(date) ? date : new Date(date)
|
||||||
|
)['set' + (utc ? 'UTC' : '') + part](num);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2096,6 +2114,7 @@ Ox.formatDate <f> Formats a date according to a format string
|
||||||
See
|
See
|
||||||
<a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/strftime.3.html">strftime</a>
|
<a href="http://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/strftime.3.html">strftime</a>
|
||||||
and <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>.
|
and <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>.
|
||||||
|
'%Q' (quarter) and '%X' (year with 'BC'/'AD') are non-standard
|
||||||
<script>
|
<script>
|
||||||
Ox.test.date = new Date('2005-01-02 00:03:04');
|
Ox.test.date = new Date('2005-01-02 00:03:04');
|
||||||
</script>
|
</script>
|
||||||
|
@ -2169,10 +2188,8 @@ Ox.formatDate <f> Formats a date according to a format string
|
||||||
'00'
|
'00'
|
||||||
> Ox.formatDate(Ox.test.date, '%w') // Decimal weekday (0-6, Sunday as first day)
|
> Ox.formatDate(Ox.test.date, '%w') // Decimal weekday (0-6, Sunday as first day)
|
||||||
'0'
|
'0'
|
||||||
> Ox.formatDate(Ox.test.date, '%X') // US time
|
> Ox.formatDate(Ox.test.date, '%X') // Full year with BC or AD
|
||||||
'12:03:04 AM'
|
'2005 AD'
|
||||||
> Ox.formatDate(Ox.test.date, '%x') // US date
|
|
||||||
'01/02/05'
|
|
||||||
> Ox.formatDate(Ox.test.date, '%Y') // Full year
|
> Ox.formatDate(Ox.test.date, '%Y') // Full year
|
||||||
'2005'
|
'2005'
|
||||||
> Ox.formatDate(Ox.test.date, '%y') // Abbreviated year
|
> Ox.formatDate(Ox.test.date, '%y') // Abbreviated year
|
||||||
|
@ -2192,9 +2209,7 @@ Ox.formatDate = function(date, str, utc) {
|
||||||
date = Ox.makeDate(date);
|
date = Ox.makeDate(date);
|
||||||
var format = [
|
var format = [
|
||||||
['%', function() {return '%{%}';}],
|
['%', function() {return '%{%}';}],
|
||||||
['c', function() {return '%x %X';}],
|
['c', function() {return '%D %r';}],
|
||||||
['X', function() {return '%r';}],
|
|
||||||
['x', function() {return '%D';}],
|
|
||||||
['D', function() {return '%m/%d/%y';}],
|
['D', function() {return '%m/%d/%y';}],
|
||||||
['F', function() {return '%Y-%m-%d';}],
|
['F', function() {return '%Y-%m-%d';}],
|
||||||
['h', function() {return '%b';}],
|
['h', function() {return '%b';}],
|
||||||
|
@ -2226,9 +2241,15 @@ Ox.formatDate = function(date, str, utc) {
|
||||||
['U', function(d) {return Ox.pad(Ox.getWeek(d, utc), 2);}],
|
['U', function(d) {return Ox.pad(Ox.getWeek(d, utc), 2);}],
|
||||||
['u', function(d) {return Ox.getISODay(d, utc);}],
|
['u', function(d) {return Ox.getISODay(d, utc);}],
|
||||||
['V', function(d) {return Ox.pad(Ox.getISOWeek(d, utc), 2);}],
|
['V', function(d) {return Ox.pad(Ox.getISOWeek(d, utc), 2);}],
|
||||||
['W', function(d) {return Ox.pad(Math.floor((Ox.getDayOfTheYear(d, utc) +
|
['W', function(d) {
|
||||||
(Ox.getFirstDayOfTheYear(d, utc) || 7) - 2) / 7), 2);}],
|
return Ox.pad(Math.floor((Ox.getDayOfTheYear(d, utc) +
|
||||||
|
(Ox.getFirstDayOfTheYear(d, utc) || 7) - 2) / 7), 2);
|
||||||
|
}],
|
||||||
['w', function(d) {return Ox.getDay(d, utc);}],
|
['w', function(d) {return Ox.getDay(d, utc);}],
|
||||||
|
['X', function(d) {
|
||||||
|
var y = Ox.getFullYear(d, utc);
|
||||||
|
return Math.abs(y) + ' ' + Ox.BCAD[y < 0 ? 0 : 1];
|
||||||
|
}],
|
||||||
['Y', function(d) {return Ox.getFullYear(d, utc);}],
|
['Y', function(d) {return Ox.getFullYear(d, utc);}],
|
||||||
['y', function(d) {return Ox.getFullYear(d, utc).toString().substr(-2);}],
|
['y', function(d) {return Ox.getFullYear(d, utc).toString().substr(-2);}],
|
||||||
['Z', function(d) {return d.toString().split('(')[1].replace(')', '');}],
|
['Z', function(d) {return d.toString().split('(')[1].replace(')', '');}],
|
||||||
|
@ -2246,6 +2267,163 @@ Ox.formatDate = function(date, str, utc) {
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*@
|
||||||
|
Ox.formatDateRange <f> Formats a date range as a string
|
||||||
|
A date range is a pair of arbitrary-presicion date strings
|
||||||
|
> Ox.formatDateRange('2000', '2001')
|
||||||
|
'2000'
|
||||||
|
> Ox.formatDateRange('2000', '2002')
|
||||||
|
'2000 - 2002'
|
||||||
|
> Ox.formatDateRange('2000-01', '2000-02')
|
||||||
|
'January 2000'
|
||||||
|
> Ox.formatDateRange('2000-01', '2000-03')
|
||||||
|
'January - March 2000'
|
||||||
|
> Ox.formatDateRange('2000-01-01', '2000-01-02')
|
||||||
|
'Sat, Jan 1, 2000'
|
||||||
|
> Ox.formatDateRange('2000-01-01', '2000-01-03')
|
||||||
|
'Sat, Jan 1 - Mon, Jan 3, 2000'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00', '2000-01-01 01')
|
||||||
|
'Sat, Jan 1, 2000, 00:00'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00', '2000-01-01 02')
|
||||||
|
'Sat, Jan 1, 2000, 00:00 - 02:00'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00:00', '2000-01-01 00:01')
|
||||||
|
'Sat, Jan 1, 2000, 00:00'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00:00', '2000-01-01 00:02')
|
||||||
|
'Sat, Jan 1, 2000, 00:00 - 00:02'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00:00:00', '2000-01-01 00:00:01')
|
||||||
|
'Sat, Jan 1, 2000, 00:00:00'
|
||||||
|
> Ox.formatDateRange('2000-01-01 00:00:00', '2000-01-01 00:00:02')
|
||||||
|
'Sat, Jan 1, 2000, 00:00:00 - 00:00:02'
|
||||||
|
> Ox.formatDateRange('-50', '50')
|
||||||
|
'50 BC - 50 AD'
|
||||||
|
> Ox.formatDateRange('-50-01-01', '-50-12-31')
|
||||||
|
'Sun, Jan 1 - Sun, Dec 31, 50 BC'
|
||||||
|
> Ox.formatDateRange('-50-01-01 00:00:00', '-50-01-01 23:59:59')
|
||||||
|
'Sun, Jan 1, 50 BC, 00:00:00 - 23:59:59'
|
||||||
|
@*/
|
||||||
|
Ox.formatDateRange = function(start, end, utc) {
|
||||||
|
var isOneUnit = false,
|
||||||
|
range = [start, end],
|
||||||
|
strings,
|
||||||
|
dates = range.map(function(str){
|
||||||
|
return Ox.parseDate(str, utc);
|
||||||
|
}),
|
||||||
|
parts = range.map(function(str) {
|
||||||
|
var parts = Ox.compact(
|
||||||
|
/(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/(str)
|
||||||
|
);
|
||||||
|
parts.shift();
|
||||||
|
return parts.map(function(part) {
|
||||||
|
return parseInt(part);
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
precision = parts.map(function(parts) {
|
||||||
|
return parts.length;
|
||||||
|
}),
|
||||||
|
y = parts[0][0] < 0 ? '%X' : '%Y',
|
||||||
|
formats = [
|
||||||
|
y,
|
||||||
|
'%B ' + y,
|
||||||
|
'%a, %b %e, ' + y,
|
||||||
|
'%a, %b %e, ' + y + ', %H:%M',
|
||||||
|
'%a, %b %e, ' + y + ', %H:%M',
|
||||||
|
'%a, %b %e, ' + y + ', %H:%M:%S',
|
||||||
|
];
|
||||||
|
if (precision[0] == precision[1]) {
|
||||||
|
isOneUnit = true;
|
||||||
|
Ox.loop(precision[0], function(i) {
|
||||||
|
if (i < precision[0] - 1 && parts[0][i] != parts[1][i]) {
|
||||||
|
isOneUnit = false;
|
||||||
|
}
|
||||||
|
if (i == precision[0] - 1 && parts[0][i] != parts[1][i] - 1) {
|
||||||
|
isOneUnit = false;
|
||||||
|
}
|
||||||
|
return isOneUnit;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (isOneUnit) {
|
||||||
|
strings = [Ox.formatDate(dates[0], formats[precision[0] - 1], utc)];
|
||||||
|
} else {
|
||||||
|
format = formats[precision[0] - 1];
|
||||||
|
strings = [
|
||||||
|
Ox.formatDate(dates[0], formats[precision[0] - 1], utc),
|
||||||
|
Ox.formatDate(dates[1], formats[precision[1] - 1], utc)
|
||||||
|
];
|
||||||
|
// if same year, and neither date is more precise than day, then omit first year
|
||||||
|
if (
|
||||||
|
parts[0][0] == parts[1][0]
|
||||||
|
&& precision[0] <= 3
|
||||||
|
&& precision[1] <= 3
|
||||||
|
) {
|
||||||
|
strings[0] = Ox.formatDate(
|
||||||
|
dates[0], formats[precision[0] - 1].replace(
|
||||||
|
new RegExp(',? ' + y), ''
|
||||||
|
), utc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// if same day then omit second day
|
||||||
|
if (
|
||||||
|
parts[0][0] == parts[1][0]
|
||||||
|
&& parts[0][1] == parts[1][1]
|
||||||
|
&& parts[0][2] == parts[1][2]
|
||||||
|
) {
|
||||||
|
strings[1] = strings[1].split(', ').pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.map(function(string) {
|
||||||
|
// %e is a space-padded day
|
||||||
|
return string.replace(' ', ' ');
|
||||||
|
}).join(' - ');
|
||||||
|
};
|
||||||
|
|
||||||
|
/*@
|
||||||
|
Ox.formatDateRangeDuration <f> Formats the duration of a date range as a string
|
||||||
|
A date range is a pair of arbitrary-presicion date strings
|
||||||
|
> Ox.formatDateRangeDuration('2000-01-01 00:00:00', '2001-01-03 03:04:05')
|
||||||
|
'1 year 2 days 3 hours 4 minutes 5 seconds'
|
||||||
|
> Ox.formatDateRangeDuration('1999', '2000', true)
|
||||||
|
'1 year'
|
||||||
|
> Ox.formatDateRangeDuration('2000', '2001', true)
|
||||||
|
'1 year'
|
||||||
|
> Ox.formatDateRangeDuration('1999-02', '1999-03', true)
|
||||||
|
'1 month'
|
||||||
|
> Ox.formatDateRangeDuration('2000-02', '2000-03', true)
|
||||||
|
'1 month'
|
||||||
|
@*/
|
||||||
|
Ox.formatDateRangeDuration = function(start, end, utc) {
|
||||||
|
var date = Ox.parseDate(start, utc),
|
||||||
|
dates = [start, end].map(function(str) {
|
||||||
|
return Ox.parseDate(str, utc);
|
||||||
|
}),
|
||||||
|
keys = ['year', 'month', 'day', 'hour', 'minute', 'second'],
|
||||||
|
parts = ['FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'],
|
||||||
|
values = [];
|
||||||
|
Ox.forEach(keys, function(key, i) {
|
||||||
|
while (true) {
|
||||||
|
if (key == 'month') {
|
||||||
|
Ox.setDate(date, Math.min(
|
||||||
|
Ox.getDate(date, utc),
|
||||||
|
Ox.getDaysInMonth(
|
||||||
|
Ox.getFullYear(date, utc),
|
||||||
|
Ox.getMonth(date, utc) + 2
|
||||||
|
)
|
||||||
|
), utc);
|
||||||
|
}
|
||||||
|
Ox['set' + parts[i]](date, Ox['get' + parts[i]](date, utc) + 1, utc);
|
||||||
|
if (date <= dates[1]) {
|
||||||
|
values[i] = (values[i] || 0) + 1;
|
||||||
|
} else {
|
||||||
|
Ox['set' + parts[i]](date, Ox['get' + parts[i]](date, utc) - 1, utc);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Ox.map(values, function(value, i) {
|
||||||
|
return value ? value + ' ' + keys[i] + (value > 1 ? 's' : '') : null;
|
||||||
|
}).join(' ');
|
||||||
|
};
|
||||||
|
|
||||||
/*@
|
/*@
|
||||||
Ox.formatDuration <f> Formats a duration as a string
|
Ox.formatDuration <f> Formats a duration as a string
|
||||||
> Ox.formatDuration(123456.789, 3)
|
> Ox.formatDuration(123456.789, 3)
|
||||||
|
|
Loading…
Reference in a new issue