Skip to content

Instantly share code, notes, and snippets.

@runfalk
Created June 8, 2017 15:49
Show Gist options
  • Save runfalk/11de6afc246c184216edb80320005340 to your computer and use it in GitHub Desktop.
Save runfalk/11de6afc246c184216edb80320005340 to your computer and use it in GitHub Desktop.
Old interval implementation for JavaScript
function InvalidSetException(message) {
this.message = message
}
function DateRange(lower, upper) {
this.empty = false;
this.lower = lower;
this.upper = upper;
if (this.lower) {
this.lower = this.lower.clone();
}
if (this.upper) {
this.upper = this.upper.clone();
}
this.normalize();
}
function IntRange(lower, upper) {
this.empty = false;
if (lower instanceof Array && typeof(upper) === "undefined") {
// Assume JSON serialization
this.lower = lower[0];
this.upper = lower[1];
} else {
this.lower = lower;
this.upper = upper;
}
this.normalize();
}
function complete_range_prototype(range_type) {
range_type.emptyRange = function () {
var out = new range_type();
out.empty = true;
return out;
}
range_type.prototype.normalize = function () {
if (this.lower >= this.upper) {
this.empty = true;
this.lower = undefined;
this.upper = undefined;
}
}
range_type.prototype.clone = function () {
return (this.empty ?
new range_type.emptyRange() :
new range_type(
this.lower.clone ? this.lower.clone() : this.lower,
this.upper.clone ? this.upper.clone() : this.upper));
}
range_type.prototype.isRange = function (other) {
return (
typeof other.empty == "boolean" &&
typeof other.lower == "object" &&
typeof other.upper == "object");
}
range_type.prototype.equal = function (other) {
return (
this.isRange(other) &&
this.empty == other.empty &&
this._equal(this.lower, other.lower) &&
this._equal(this.upper, other.upper)
);
}
range_type.prototype.lowerInf = function () {
return typeof this.lower == "undefined";
}
range_type.prototype.upperInf = function () {
return typeof this.upper == "undefined"
}
range_type.prototype.valueOf = function () {
return [this.lower.valueOf(), this.upper.valueOf()];
}
range_type.prototype._equal = function (a, b) {
if (typeof a == "undefined" || typeof b == "undefined") {
return a == b;
} else {
return a.valueOf() === b.valueOf();
}
}
range_type.prototype._min = function (a, b) {
if (typeof a == "undefined") {
return a;
} else if (typeof b == "undefined") {
return b;
} else {
return a.valueOf() < b.valueOf() ? a : b;
}
}
range_type.prototype._max = function (a, b) {
if (typeof a == "undefined") {
return a;
} else if (typeof b == "undefined") {
return b;
} else {
return a.valueOf() > b.valueOf() ? a : b;
}
}
range_type.prototype.intersection = function (other) {
if (this.empty || other.empty) {
return this.emptyRange()
} else {
return new range_type(
this._max(this.lower, other.lower),
this._min(this.upper, other.upper));
}
}
range_type.prototype.union = function (other) {
if (
this.overlap(other) ||
this._equal(this.lower, other.upper) ||
this._equal(this.upper, other.lower)) {
return new range_type(
this._min(this.lower, other.lower),
this._max(this.upper, other.upper));
} else {
throw new InvalidSetException("These sets can't be united.")
}
}
range_type.prototype.difference = function (other) {
if (
this.contains(other) &&
this._equal(this.lower, other.lower) &&
this._equal(this.upper, other.upper)) {
throw new InvalidSetException(
"Taking the difference of these sets would result in a discontinious set");
} else if (
!this.overlap(other) ||
other.contains(this) ||
this.empty) {
return range_type.emptyRange();
} else if (other.empty) {
return this;
} else {
var overlap = this.intersection(other);
if (this._equal(this.lower, overlap.lower)) {
return new range_type(overlap.upper, this.upper);
} else {
return new range_type(this.lower, overlap.lower);
}
}
}
range_type.prototype.overlap = function (other) {
return !this.intersection(other).empty;
}
range_type.prototype.contains = function (other) {
if (this.isRange(other)) {
var intersection = this.intersection(other);
if (intersection.empty) {
return false;
}
intersection = intersection.valueOf();
return intersection[0] == other.valueOf()[0] &&
intersection[1] == other.valueOf()[1];
} else if (other.empty || this.lowerInf() && this.upperInf()) {
return true
} else if (this.lowerInf()) {
return other < this.upper;
} else if (this.upperInf()) {
return other >= this.lower;
} else {
return other >= this.lower && other < this.upper;
}
}
}
complete_range_prototype(DateRange);
complete_range_prototype(IntRange);
DateRange.prototype.size = function () {
if (this.lowerInf() || this.upperInf()) {
return false;
}
return this.empty ? 0 : this.upper.diff(this.lower, "seconds");
}
DateRange.prototype.toJSON = function () {
return [
this.lower.format("YYYY-MM-DD HH:mm:ss"),
this.upper.format("YYYY-MM-DD HH:mm:ss")
];
}
DateRange.prototype.asString = function (long, sup) {
if (this.empty) {
return "";
}
var string = format_moment(this.lower, long, false, !sup) + " - ";
if (this.lower.dayOfYear() != this.upper.dayOfYear()) {
return string + format_moment(this.upper, long, false, !sup);
} else {
return string + format_moment(this.upper, false, false, !sup);
}
}
IntRange.prototype.asDateRange = function (reference_moment) {
var date_start = reference_moment.clone().add("s", this.lower);
var date_end = reference_moment.clone().add("s", this.upper);
return new DateRange(date_start, date_end);
}
IntRange.prototype.asTimeSpan = function () {
return (
pad(Math.floor(this.lower / 3600) % 24, 2) + ":" +
pad(Math.floor((this.lower % 3600) / 60), 2) +
" - " +
pad(Math.floor(this.upper / 3600) % 24, 2) + ":" +
pad(Math.floor((this.upper % 3600) / 60), 2));
}
/**
* The accepted formats are HH, HHMM, HH MM, HH:MM, (HH,MM), H, HMM, H:MM, H MM, (H,MM)
*/
IntRange.parseTimeSpan = function (input_string) {
// Remove all whitespace
input_string = input_string.replace(/\s+/g, "");
// There must be a "-" in it
if (input_string.indexOf("-") === -1) {
return false;
}
var start = input_string.split("-")[0];
var end = input_string.split("-")[1];
var format = /^([01]?[0-9]|2[0-4])[:,\.]?([0-5][0-9])?$/;
var parsed_start = start.match(format);
var parsed_end = end.match(format);
if (!parsed_start || !parsed_end) {
return false;
}
var start = (parsed_start[1] || 0) * 3600 + (parsed_start[2] || 0) * 60;
var end = (parsed_end[1] || 0) * 3600 + (parsed_end[2] || 0) * 60;
if (end < start) {
end += 86400;
}
return new IntRange(start, end);
}
IntRange.prototype.toJSON = function () {
return [this.lower, this.upper];
}
function DateRangeList(spans) {
this._spans = []
if (spans) {
for (var i = 0; i < spans.length; i++) {
this.add(spans[i]);
}
}
}
function IntRangeList(spans) {
this._spans = []
if (spans) {
for (var i = 0; i < spans.length; i++) {
this.add(spans[i]);
}
}
}
function complete_range_list_prototype(range_list_type, range_type) {
range_list_type.prototype.lower = function () {
return this.isEmpty() ?
"undefined" :
(this._spans[0].lower.clone ?
this._spans[0].lower.clone() : this._spans[0].lower);
}
range_list_type.prototype.upper = function () {
return this.isEmpty() ?
"undefined" :
(this._spans[this._spans.length - 1].upper.clone ?
this._spans[this._spans.length - 1].upper.clone() :
this._spans[this._spans.length - 1].upper);
}
range_list_type.prototype.add = function (span) {
// Assume serialized data
if (span instanceof Array) {
this._spans.push(new IntRange(span));
} else {
this._spans.push(span);
}
this.sort();
}
range_list_type.prototype.remove = function (span) {
for (var i = 0; i < this._spans.length; i++) {
if (this._spans[i].equal(span)) {
return this._spans.splice(i, 1);
}
}
}
range_list_type.prototype.sort = function () {
this._spans.sort(function (a, b) {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0
})
}
range_list_type.prototype.overlap = function (other) {
var overlap = false;
this.each(function (span_a) {
other.each(function (span_b) {
overlap = overlap || span_a.overlap(span_b);
});
});
return overlap;
}
range_list_type.prototype.intersection = function (other) {
var intersection_list = new range_list_type();
this.each(function (span) {
var intersection = span.clone().intersection(other.clone());
if (!intersection.empty) {
intersection_list.add(intersection);
}
});
return intersection_list;
}
range_list_type.prototype.clone = function () {
var clone = new range_list_type();
_.each(this._spans, function (span) {
clone.add(span.clone());
});
return clone;
}
range_list_type.prototype.each = function (loop_function) {
_.each(this._spans, function (span) {
loop_function(span);
});
}
range_list_type.prototype.isEmpty = function () {
return !this._spans.length;
}
range_list_type.prototype.asArray = function () {
return this.clone()._spans;
}
range_list_type.prototype.span = function () {
return new range_type(this.lower(), this.upper());
}
range_list_type.prototype.toJSON = function () {
var out = [];
for (var i = 0; i < this._spans.length; i++) {
out.push(this._spans[i].toJSON());
}
return out;
}
range_list_type.prototype.equal = function (other) {
if (
!other._spans ||
this._spans.length != other._spans.length) {
return false;
}
for (var i = 0; i < this._spans.length; i++) {
if (!this._spans[i].equal(other._spans[i])) {
return false;
}
}
return true;
}
range_list_type.prototype.union = function (other) {
union = new range_list_type();
this.each(function (span) {
union.add(span)
});
other.each(function (span) {
union.add(span)
});
// Merge all overlaping spans in spanlist
var i = 0;
while (i < union._spans.length) {
for (var j = 0; j < union._spans.length; j++) {
if (i != j && union._spans[i].overlap(union._spans[j])) {
var span_a = union._spans[i];
var span_b = union._spans[j];
union.remove(span_a);
union.remove(span_b);
union.add(span_a.union(span_b));
i = -1;
break;
}
}
i++;
}
return union;
}
range_list_type.prototype.size = function () {
var sum = 0
_.each(this._spans, function(span) {
sum += span.size();
});
return sum;
}
}
complete_range_list_prototype(DateRangeList, DateRange);
complete_range_list_prototype(IntRangeList, IntRange);
function format_date_range(date_range, long_date, span, text) {
var html_string = format_moment(date_range.lower, long_date, span, text) + " - ";
if (date_range.lower.dayOfYear() != date_range.upper.dayOfYear()) {
html_string += format_moment(date_range.upper, true, span, text);
} else {
html_string += format_moment(date_range.upper, false, span, text)
}
return html_string;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment