Skip to content

Instantly share code, notes, and snippets.

@wizard04wsu
Created February 6, 2014 21:30
Show Gist options
  • Save wizard04wsu/8852848 to your computer and use it in GitHub Desktop.
Save wizard04wsu/8852848 to your computer and use it in GitHub Desktop.
JavaScript Date methods
//month names, weekday names, and ordinal indicators are in English
// Date.now()
// Date.fromISOString(isoStr)
// Date.timeBetween(date1, date2)
// dat.isLeapYear()
// dat.isUTCLeapYear()
// dat.getDaysInMonth()
// dat.getUTCDaysInMonth()
// dat.getMonthName()
// dat.getUTCMonthName()
// dat.getDayName()
// dat.getUTCDayName()
// dat.format(formatStr, useUTC)
// dat.toISOString()
(function (){
"use strict";
//note that JavaScript always calculates dates/times in UTC, even for dates occurring before UTC was introduced
if(!Date.now) Date.now = function now(){ return (new Date()).getTime(); };
var monthNames = ["January","February","March","April","May","June","July","August","September","October","November","December"],
dayNames = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
function isLeapYear(year){ return year%400 === 0 || (year%4 === 0 && year%100 !== 0); }
if(!Date.prototype.isLeapYear)
Date.prototype.isLeapYear = function isLeapYear(){ return isLeapYear(this.getFullYear()); };
if(!Date.prototype.isUTCLeapYear)
Date.prototype.isUTCLeapYear = function isUTCLeapYear(){ return isLeapYear(this.getUTCFullYear()); };
if(!Date.prototype.getDaysInMonth)
Date.prototype.getDaysInMonth = function getDaysInMonth(){ return ([31, (isLeapYear(this.getFullYear())?29:28), 31,30,31,30,31,31,30,31,30,31])[this.getMonth()]; };
if(!Date.prototype.getUTCDaysInMonth)
Date.prototype.getUTCDaysInMonth = function getUTCDaysInMonth(){ return ([31, (isLeapYear(this.getUTCFullYear())?29:28), 31,30,31,30,31,31,30,31,30,31])[this.getUTCMonth()]; };
if(!Date.prototype.getMonthName)
Date.prototype.getMonthName = function getMonthName(){ return monthNames[this.getMonth()]; };
if(!Date.prototype.getUTCMonthName)
Date.prototype.getUTCMonthName = function getUTCMonthName(){ return monthNames[this.getUTCMonth()]; };
if(!Date.prototype.getDayName)
Date.prototype.getDayName = function getDayName(){ return dayNames[this.getDay()]; };
if(!Date.prototype.getUTCDayName)
Date.prototype.getUTCDayName = function getUTCDayName(){ return dayNames[this.getUTCDay()]; };
//if useUTC is true, UTC values will be used instead of local time values
function formatDate(formatStr, useUTC){
/*
Format string variables:
%Y 4-digit year (0000-9999)
%y 2-digit year (00-99)
%M 2-digit month (01-12)
%m month (1-12)
%B full month name (January-December)
%b abbreviated month name (Jan-Dec)
%D 2-digit day of month (01-31)
%d day of month (1-31)
%o ordinal indicator of the day of month (st, nd, rd, th)
%W full weekday name (Sunday-Saturday)
%w abbreviated weekday name (Sun-Sat)
%I hour in 24-hour format (00-23)
%H 2-digit hour in 12-hour format (01-12)
%h hour in 12-hour format (1-12)
%P AM/PM
%p am/pm
%q a/p
%N 2-digit minute (00-59)
%n minute (0-59)
%S 2-digit second (00-59)
%s second (0-59)
%Z 3-digit milliseconds (000-999)
%z milliseconds (0-999)
%e UTC offset +/-
%F 2-digit hour offset (00-23)
%f hour offset (0-23)
%G 2-digit minute offset (00-59)
%g minute offset (0-59)
%% percent sign
*/
var theDate = this;
function pad(numStr, digits){
numStr = numStr.toString();
while(numStr.length < digits) numStr = "0"+numStr;
return numStr;
}
function replacer(match, p1){
var d, h;
switch(p1){
case "Y": return useUTC ? theDate.getUTCFullYear() : theDate.getFullYear();
case "y": return (useUTC ? theDate.getUTCFullYear() : theDate.getFullYear()).toString().slice(-2);
case "M": return pad((useUTC ? theDate.getUTCMonth() : theDate.getMonth())+1, 2);
case "m": return (useUTC ? theDate.getUTCMonth() : theDate.getMonth())+1;
case "B": return useUTC ? theDate.getUTCMonthName() : theDate.getMonthName();
case "b": return (useUTC ? theDate.getUTCMonthName() : theDate.getMonthName()).slice(0,3);
case "D": return pad((useUTC ? theDate.getUTCDate() : theDate.getDate()), 2);
case "d": return useUTC ? theDate.getUTCDate() : theDate.getDate();
case "o":
d = useUTC ? theDate.getUTCDate() : theDate.getDate();
return (d===1 || d===21 || d===31) ? "st" : (d===2 || d===22) ? "nd" : (d===3 || d===23) ? "rd" : "th";
case "W": return useUTC ? theDate.getUTCDayName() : theDate.getDayName();
case "w": return (useUTC ? theDate.getUTCDayName() : theDate.getDayName()).slice(0,3);
case "I": return pad((useUTC ? theDate.getUTCHours() : theDate.getHours()), 2);
case "H":
h = (useUTC ? theDate.getUTCHours() : theDate.getHours()) % 12;
return pad((h===0 ? 12 : h), 2);
case "h":
h = (useUTC ? theDate.getUTCHours() : theDate.getHours()) % 12;
return h===0 ? 12 : h;
case "P": return (useUTC ? theDate.getUTCHours() : theDate.getHours())<12 ? "AM" : "PM";
case "p": return (useUTC ? theDate.getUTCHours() : theDate.getHours())<12 ? "am" : "pm";
case "q": return (useUTC ? theDate.getUTCHours() : theDate.getHours())<12 ? "a" : "p";
case "N": return pad((useUTC ? theDate.getUTCMinutes() : theDate.getMinutes()), 2);
case "n": return useUTC ? theDate.getUTCMinutes() : theDate.getMinutes();
case "S": return pad((useUTC ? theDate.getUTCSeconds() : theDate.getSeconds()), 2);
case "s": return useUTC ? theDate.getUTCSeconds() : theDate.getSeconds();
case "Z": return pad((useUTC ? theDate.getUTCMilliseconds() : theDate.getMilliseconds()), 3);
case "z": return useUTC ? theDate.getUTCMilliseconds() : theDate.getMilliseconds();
case "e": return (useUTC ? 0 : -theDate.getTimezoneOffset())<0 ? "-" : "+"; //if offset is 0, theDate will be "+"
case "F": return pad(Math.floor(Math.abs(useUTC ? 0 : -theDate.getTimezoneOffset())/60), 2);
case "f": return Math.floor(Math.abs(useUTC ? 0 : -theDate.getTimezoneOffset())/60);
case "G": return pad((useUTC ? 0 : -theDate.getTimezoneOffset())%60, 2);
case "g": return (useUTC ? 0 : -theDate.getTimezoneOffset())%60;
case "%": return "%";
default: return match;
}
}
return formatStr.replace(/%(.)/g, replacer);
}
if(!Date.prototype.format)
Date.prototype.format = formatDate;
//formats the Date into a string according to the Internet profile of ISO 8601 described in RFC 3339
//see http://tools.ietf.org/html/rfc3339
//time zone is always UTC
if(!Date.prototype.toISOString)
Date.prototype.toISOString = function toISOString(){ return formatDate.call(this, "%Y-%M-%DT%I:%N:%S.%ZZ", true); };
//creates a Date object from a basic ISO 8601 formatted string
//expanded years are not supported
//see http://tools.ietf.org/html/rfc3339#section-5.6
// http://en.wikipedia.org/wiki/Iso8601
if(!Date.fromISOString){
Date.fromISOString = function fromISOString(isoStr){
var rxpCalendarDate = "(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?",
rxpWeekDate = "(\\d{4})(-?)[Ww](\\d{2})(?:\\2(\\d))?",
rxpOrdinalDate = "(\\d{4})-?(\\d{3})",
rxpTime = "(\\d{2})(?:(:?)(\\d{2})(?:\\2(\\d{2}))?)?(?:[.,](\\d+))?",
rxpOffset = "(?:([Zz])|([+-])(\\d{2})(?::?(\\d{2}))?)",
rxpFullDate = "^(?:(\\d{4})(?:(-?)(\\d{2})(?:\\2(\\d{2}))?)?|(\\d{4})(-?)[Ww](\\d{2})(?:\\6(\\d))?|(\\d{4})-?(\\d{3}))(?=[Tt]|$)",
rxpFullTime = rxpTime+rxpOffset+"?$",
now, parts, rxp, isoDate, isoTime, date;
if(!( RegExp(rxpFullDate+"$").test(isoStr) ||
RegExp("^"+rxpFullTime).test(isoStr) ||
(RegExp(rxpFullDate+"[Tt].*").test(isoStr) && RegExp("^[^Tt]+[Tt]"+rxpFullTime).test(isoStr)) )) return null; //not a supported ISO 8601 string
now = new Date();
parts = {year:now.getFullYear(), month:now.getMonth(), day:now.getDate(), hour:0, minute:0, second:0, fraction:0}; //default is midnight this morning, local time
rxp;
isoDate = RegExp(rxpFullDate).exec(isoStr);
if(isoDate){ //string includes a date
try{
isoDate = isoDate[0];
if((rxp = RegExp("^"+rxpCalendarDate+"$")).exec(isoDate)){ //calendar date
isoDate.replace(rxp, function (match, y, dash, m, d){
if(m!="" && (m<1 || m>12)) throw new RangeError("Month is out of range");
if(d!="" && (d<1 || d>31)) throw new RangeError("Day is out of range");
parts.year = y;
parts.month = m=="" ? 0 : m-1;
parts.day = d=="" ? 1 : d;
if(parts.day > daysInMonth(parts.year, parts.month)) throw new RangeError("Day is out of range");
});
}
else if((rxp = RegExp("^"+rxpWeekDate+"$")).exec(isoDate)){ //week date
isoDate.replace(rxp, function (match, y, dash, w, d){
var jan4th, dayOfJan4th, firstMonday, mondayAfter52Weeks, weekday, date;
if(w<1 || w>53) throw new RangeError("Week number is out of range");
if(d!="" && (d<1 || d>7)) throw new RangeError("Weekday number is out of range");
jan4th = new Date(y, 0, 4);
dayOfJan4th = (jan4th.getDay()+6)%7; //0-6 == Mon-Sun
firstMonday = new Date(jan4th.valueOf() - dayOfJan4th*86400000);
if(w == 53)
{
mondayAfter52Weeks = (new Date(firstMonday.valueOf() + 52*7*86400000)).getDate();
//if the 53rd week is actually the first week of next year (i.e., it includes Jan 4th), throw range error
if(!(mondayAfter52Weeks > 4 && mondayAfter52Weeks < 29)) throw new RangeError("Week number is out of range");
}
weekday = d=="" ? 0 : d-1; //0-6 == Mon-Sun
date = new Date(firstMonday.valueOf() + weekday*86400000 + (w-1)*7*86400000);
parts.year = date.getFullYear();
parts.month = date.getMonth();
parts.day = date.getDate();
});
}
else{ //ordinal date
isoDate.replace(RegExp("^"+rxpOrdinalDate+"$"), function (match, y, d){
var date;
if(d > (isLeapYear(y)?366:365)) throw new RangeError("Day number is out of range");
parts.year = y;
date = new Date((new Date(y, 0, 1)).valueOf() + (d-1)*86400000);
parts.month = date.getMonth();
parts.day = date.getDate();
});
}
}catch(err){
return null; //date string is invalid
}
}
isoTime = RegExp("(?:^|[Tt])"+rxpFullTime).exec(isoStr);
if(isoTime){ //string includes a time
try{
isoTime = isoTime[0];
if(isoTime[0].toUpperCase() == "T") isoTime = isoTime.slice(1);
if(RegExp("^"+rxpTime+"$").exec(isoTime)){ //if there is no time zone designator
//use local time
date = new Date(parts.year, parts.month, parts.day);
//add hours, minutes, and seconds to date
isoTime.replace(RegExp("^"+rxpTime+"$"), function (match, h, colon, m, s, f){
var val;
if(h>24) throw new RangeError("Hour is out of range");
if(m!="" && m>59) throw new RangeError("Minute is out of range");
if(s!="" && s>60) throw new RangeError("Second is out of range");
val = date.valueOf();
val += h*3600000;
if(m) val += m*60000;
if(s) val += s*1000;
if(f) val += 1000*("."+f.substr(0,3));
date = new Date(val);
});
}
else{ //there is a time zone designator
//use UTC time as base
date = new Date(Date.UTC(parts.year, parts.month, parts.day));
//add hours, minutes, seconds, and offset to date
isoTime.replace(RegExp("^"+rxpTime+rxpOffset+"$"), function (match, h, colon, m, s, f, z, sign, oh, om){
var val;
if(h>24) throw new RangeError("Hour is out of range");
if(m!="" && m>59) throw new RangeError("Minute is out of range");
if(s!="" && s>60) throw new RangeError("Second is out of range");
if(oh!="" && oh>23) throw new RangeError("Offset hour is out of range");
if(om!="" && om>59) throw new RangeError("Offset minute is out of range");
val = date.valueOf();
val += h*3600000;
if(m) val += m*60000;
if(s) val += s*1000;
if(f) val += 1000*("."+f.substr(0,3));
if(!z) //if there is an offset from UTC time
{
//adjust time according to offset (i.e., convert to UTC time)
sign = sign=="-" ? 1 : -1;
val += sign*oh*3600000;
if(om != "") val += sign*om*60000;
}
date = new Date(val);
});
}
parts.year = date.getFullYear();
parts.month = date.getMonth();
parts.day = date.getDate();
parts.hour = date.getHours();
parts.minute = date.getMinutes();
parts.second = date.getSeconds();
parts.fraction = date.getMilliseconds();
}catch(err){
return null; //time string is invalid
}
}
return new Date(parts.year, parts.month, parts.day, parts.hour, parts.minute, parts.second, parts.fraction);
};
}
//returns an object with time intervals between two Dates
//Date objects, milliseconds, or date strings are accepted arguments
//object properties: years, months, weeks, days, hours, minutes, seconds, milliseconds
//each part is *in addition* to the sum of the larger parts; e.g., if there are 17 days between the two dates, .weeks==2 and .days==3
if(!Date.timeBetween){
Date.timeBetween = function timeBetween(date1, date2){
var tmp, parts = {};
date1 = new Date(date1);
date2 = new Date(date2);
if(isNaN(date1.valueOf()+date2.valueOf())) return null; //invalid date(s)
if(date1.valueOf() > date2.valueOf()){
tmp = date1;
date1 = date2;
date2 = tmp;
}
//years
parts.years = date2.getFullYear() - date1.getFullYear();
//months
date1.setFullYear(date2.getFullYear());
parts.months = date2.getMonth() - date1.getMonth();
//days
date1.setMonth(date2.getMonth());
if(date1.valueOf() > date2.valueOf()){
date1.setMonth(date1.getMonth()-1);
parts.months--;
}
parts.days = Math.floor((date2.valueOf()-date1.valueOf())/86400000);
//weeks
parts.weeks = Math.floor(parts.days/7);
parts.days = parts.days%7;
//time
parts.hours = date2.getHours() - date1.getHours();
parts.minutes = date2.getMinutes() - date1.getMinutes();
parts.seconds = date2.getSeconds() - date1.getSeconds();
parts.milliseconds = date2.getMilliseconds() - date1.getMilliseconds();
//adjust for negative values
if(parts.milliseconds < 0){ parts.milliseconds = 1000+parts.milliseconds; parts.seconds--; }
if(parts.seconds < 0){ parts.seconds = 60+parts.seconds; parts.minutes--; }
if(parts.minutes < 0){ parts.minutes = 60+parts.minutes; parts.hours--; }
if(parts.hours < 0) parts.hours = 24+parts.hours;
if(parts.months < 0){ parts.months = 12+parts.months; parts.years--; }
return parts;
};
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment