1
0
Fork 0
forked from 0x2620/oxjs

much better formatting of date ranges and their duration

This commit is contained in:
rolux 2011-05-26 19:10:32 +02:00
commit f0052d3e3c
4 changed files with 247 additions and 97 deletions

View file

@ -1063,8 +1063,11 @@ Ox.rgb = function(hsl) {
//@ Ox.AMPM <[str]> ['AM', 'PM']
Ox.AMPM = ['AM', 'PM'];
//@ Ox.DURATIONS <[str]> ['year', 'month', 'day', 'minute', 'second']
Ox.DURATIONS = ['year', 'month', 'day', 'minute', 'second'];
//@ Ox.BCAD <[str]> ['BC', 'AD']
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
// see http://en.wikipedia.org/wiki/WGS-84
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"??
Ox.getDateInWeek = function(date, weekday, utc) {
/*
*/
date = Ox.makeDate(date);
Ox.print(date, Ox.getDate(date, utc), Ox.formatDate(date, '%u', utc), date)
var sourceWeekday = Ox.getISODay(date, utc),
@ -1208,7 +1209,6 @@ Ox.getDateInWeek = function(date, weekday, utc) {
Ox.map(Ox.WEEKDAYS, function(v, i) {
return v.substr(0, 3) == weekday.substr(0, 3) ? i + 1 : null;
})[0];
Ox.print(date, Ox.getDate(date, utc), sourceWeekday, targetWeekday)
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'
@*/
Ox.makeDate = function(date) {
return Ox.isDate(date) ? date :
Ox.isUndefined(date) ? new Date() : new Date(date);
// if date is a date, new Date(date) makes a clone
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);
};
/*@
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
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
> +Ox.parseDate('1970', true)
0
@ -1458,9 +1457,9 @@ Ox.parseDate(f) Takes a string ('YYYY-MM-DD HH:MM:SS') and returns a date
50
@*/
Ox.parseDate = function(str, utc) {
var date = new Date(),
var date = new Date(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 = values.map(function(v, i) {
return v || defaults[i];
@ -1469,11 +1468,29 @@ Ox.parseDate = function(str, utc) {
[
'FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'
].forEach(function(part, i) {
date = Ox['set' + part](date, values[i], utc);
Ox['set' + part](date, values[i], utc);
});
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
// see Ox.setSeconds for source code
//@ Ox.setDay <f> Set the weekday of a date, optionally UTC
@ -1493,14 +1510,15 @@ Ox.parseDate = function(str, utc) {
[
'FullYear', 'Month', 'Date', 'Day',
'Hours', 'Minutes', 'Seconds', 'Milliseconds'
].forEach(function(noun) {
Ox['get' + noun] = function(date, utc) {
return Ox.makeDate(date)['get' + (utc ? 'UTC' : '') + noun]()
].forEach(function(part) {
Ox['get' + part] = function(date, utc) {
return Ox.makeDate(date)['get' + (utc ? 'UTC' : '') + part]()
}
Ox['set' + noun] = function(date, num, utc) {
return new Date(
Ox.makeDate(date)['set' + (utc ? 'UTC' : '') + noun](num)
);
// Ox.setPart(date) modifies date
Ox['set' + part] = function(date, num, utc) {
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
<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>.
'%Q' (quarter) and '%X' (year with 'BC'/'AD') are non-standard
<script>
Ox.test.date = new Date('2005-01-02 00:03:04');
</script>
@ -2169,10 +2188,8 @@ Ox.formatDate <f> Formats a date according to a format string
'00'
> Ox.formatDate(Ox.test.date, '%w') // Decimal weekday (0-6, Sunday as first day)
'0'
> Ox.formatDate(Ox.test.date, '%X') // US time
'12:03:04 AM'
> Ox.formatDate(Ox.test.date, '%x') // US date
'01/02/05'
> Ox.formatDate(Ox.test.date, '%X') // Full year with BC or AD
'2005 AD'
> Ox.formatDate(Ox.test.date, '%Y') // Full year
'2005'
> Ox.formatDate(Ox.test.date, '%y') // Abbreviated year
@ -2192,9 +2209,7 @@ Ox.formatDate = function(date, str, utc) {
date = Ox.makeDate(date);
var format = [
['%', function() {return '%{%}';}],
['c', function() {return '%x %X';}],
['X', function() {return '%r';}],
['x', function() {return '%D';}],
['c', function() {return '%D %r';}],
['D', function() {return '%m/%d/%y';}],
['F', function() {return '%Y-%m-%d';}],
['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.getISODay(d, utc);}],
['V', function(d) {return Ox.pad(Ox.getISOWeek(d, utc), 2);}],
['W', function(d) {return Ox.pad(Math.floor((Ox.getDayOfTheYear(d, utc) +
(Ox.getFirstDayOfTheYear(d, utc) || 7) - 2) / 7), 2);}],
['W', function(d) {
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);}],
['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).toString().substr(-2);}],
['Z', function(d) {return d.toString().split('(')[1].replace(')', '');}],
@ -2246,6 +2267,163 @@ Ox.formatDate = function(date, str, utc) {
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(123456.789, 3)