Dr John Stockton wrote:
You can't compare dates this way. Instead, you should probably
compare their .getTime() values. I can; why should he be unable to?
I was under the (probably mistaken) impression that the explicit conversion
failed in some browser versions for dates, and therefore wasn't good to use.
As this belief goes back a few years, I don't even remember where it
originated.
I've not looked at your library code recently (as you may recall, I
use News off-line), so don't know the style.
I've re-written my date code recently to extend Date using prototypes for
most functions. One thing you might not like is that I don't use regular
expressions to parse text. Instead, I still use the manual substring
approach. Someday I'll update it further, but it's solid as-is, and I don't
have a lot of time, so updating working code doesn't seem like the best use
of it :)
it might be
quite easy to produce, in javascript, a de-commenter and de-indenter.
Your library could be fetched in its full glory, but readily reduced
to the working parts without positive obfuscation.
...But perhaps you already have something better.
I do this in real-time in PHP, actually. I write my code with full comments
and in a style that can be easily reduced. It is then fetched via a PHP
script which either delivers the full code or compacted code. Also, if the
library has any dependencies it can detect this, prepend them into the
source, and deliver a "combined" version. In all my pages and test cases, I
link to the compacted version of the code to make sure that no bugs are
introduced during the compacting.
I also have a fairly extensive set of over 150 test cases at
http://www.javascripttoolbox.com/lib/date/test.php which runs the javascript
in the browser and makes assertions similar to XUnit test suites. It works
well for cross-browser testing of libs like this.
Since you read offline, I'll paste my source below in case you want to look
at it. I'm always open to suggestions, although I can probably already name
many of the same ones that you might offer ;) Hope the code isn't too long,
and of course beware of wrapping.
/*
Date functions
These functions are used to parse, format, and manipulate Date objects.
See documentation and examples at
http://www.JavascriptToolbox.com/lib/date/
*/
Date.$VERSION = 1.01;
// Utility function to append a 0 to single-digit numbers
Date.LZ = function(x) {return(x<0||x> 9?"":"0")+x};
// Full month names. Change this for local month names
Date.monthNames = new
Array('January' ,'February','Ma rch','April','M ay','June','Jul y','August','Se ptember','Octob er','November', 'December');
// Month abbreviations. Change this for local month names
Date.monthAbbre viations = new
Array('Jan','Fe b','Mar','Apr', 'May','Jun','Ju l','Aug','Sep', 'Oct','Nov','De c');
// Full day names. Change this for local month names
Date.dayNames = new
Array('Sunday', 'Monday','Tuesd ay','Wednesday' ,'Thursday','Fr iday','Saturday ');
// Day abbreviations. Change this for local month names
Date.dayAbbrevi ations = new
Array('Sun','Mo n','Tue','Wed', 'Thu','Fri','Sa t');
// Used for parsing ambiguous dates like 1/2/2000 - default to preferring
'American' format meaning Jan 2.
// Set to false to prefer 'European' format meaning Feb 1
Date.preferAmer icanFormat = true;
// If the getFullYear() method is not defined, create it
if (!Date.prototyp e.getFullYear) {
Date.prototype. getFullYear = function() { var yy=this.getYear (); return
(yy<1900?yy+190 0:yy); }
}
// Parse a string and convert it to a Date object.
// If no format is passed, try a list of common formats.
// If string cannot be parsed, return null.
// Avoids regular expressions to be more portable.
Date.parseStrin g = function(val, format) {
// If no format is specified, try a few common formats
if (typeof(format) =="undefined" || format==null || format=="") {
var generalFormats= new Array('y-M-d','MMM d, y','MMM
d,y','y-MMM-d','d-MMM-y','MMM d','MMM-d','d-MMM');
var monthFirst=new Array('M/d/y','M-d-y','M.d.y','M/d','M-d');
var dateFirst =new Array('d/M/y','d-M-y','d.M.y','d/M','d-M');
var checkList=new
Array(generalFo rmats,Date.pref erAmericanForma t?monthFirst:da teFirst,Date.pr eferAmericanFor mat?dateFirst:m onthFirst);
for (var i=0; i<checkList.len gth; i++) {
var l=checkList[i];
for (var j=0; j<l.length; j++) {
var d=Date.parseStr ing(val,l[j]);
if (d!=null) {
return d;
}
}
}
return null;
}
this.isInteger = function(val) {
for (var i=0; i < val.length; i++) {
if ("1234567890".i ndexOf(val.char At(i))==-1) {
return false;
}
}
return true;
};
this.getInt = function(str,i, minlength,maxle ngth) {
for (var x=maxlength; x>=minlength; x--) {
var token=str.subst ring(i,i+x);
if (token.length < minlength) {
return null;
}
if (this.isInteger (token)) {
return token;
}
}
return null;
};
val=val+"";
format=format+" ";
var i_val=0;
var i_format=0;
var c="";
var token="";
var token2="";
var x,y;
var year=new Date().getFullY ear();
var month=1;
var date=1;
var hh=0;
var mm=0;
var ss=0;
var ampm="";
while (i_format < format.length) {
// Get next token from format string
c=format.charAt (i_format);
token="";
while ((format.charAt (i_format)==c) && (i_format < format.length)) {
token += format.charAt(i _format++);
}
// Extract contents of value based on format token
if (token=="yyyy" || token=="yy" || token=="y") {
if (token=="yyyy") {
x=4;y=4;
}
if (token=="yy") {
x=2;y=2;
}
if (token=="y") {
x=2;y=4;
}
year=this.getIn t(val,i_val,x,y );
if (year==null) {
return null;
}
i_val += year.length;
if (year.length==2 ) {
if (year > 70) {
year=1900+(year-0);
}
else {
year=2000+(year-0);
}
}
}
else if (token=="MMM" || token=="NNN"){
month=0;
var names =
(token=="MMM"?( Date.monthNames .concat(Date.mo nthAbbreviation s)):Date.monthA bbreviations);
for (var i=0; i<names.length ; i++) {
var month_name=name s[i];
if
(val.substring( i_val,i_val+mon th_name.length) .toLowerCase()= =month_name.toL owerCase())
{
month=(i%12)+1;
i_val += month_name.leng th;
break;
}
}
if ((month < 1)||(month>12)) {
return null;
}
}
else if (token=="EE"||t oken=="E"){
var names = (token=="EE"?Da te.dayNames:Dat e.dayAbbreviati ons);
for (var i=0; i<names.length ; i++) {
var day_name=names[i];
if
(val.substring( i_val,i_val+day _name.length).t oLowerCase()==d ay_name.toLower Case())
{
i_val += day_name.length ;
break;
}
}
}
else if (token=="MM"||t oken=="M") {
month=this.getI nt(val,i_val,to ken.length,2);
if(month==null| |(month<1)||(mo nth>12)){
return null;
}
i_val+=month.le ngth;
}
else if (token=="dd"||t oken=="d") {
date=this.getIn t(val,i_val,tok en.length,2);
if(date==null|| (date<1)||(date >31)){
return null;
}
i_val+=date.len gth;
}
else if (token=="hh"||t oken=="h") {
hh=this.getInt( val,i_val,token .length,2);
if(hh==null||(h h<1)||(hh>12)) {
return null;
}
i_val+=hh.lengt h;
}
else if (token=="HH"||t oken=="H") {
hh=this.getInt( val,i_val,token .length,2);
if(hh==null||(h h<0)||(hh>23)) {
return null;
}
i_val+=hh.lengt h;
}
else if (token=="KK"||t oken=="K") {
hh=this.getInt( val,i_val,token .length,2);
if(hh==null||(h h<0)||(hh>11)) {
return null;
}
i_val+=hh.lengt h;
hh++;
}
else if (token=="kk"||t oken=="k") {
hh=this.getInt( val,i_val,token .length,2);
if(hh==null||(h h<1)||(hh>24)) {
return null;
}
i_val+=hh.lengt h;
hh--;
}
else if (token=="mm"||t oken=="m") {
mm=this.getInt( val,i_val,token .length,2);
if(mm==null||(m m<0)||(mm>59)) {
return null;
}
i_val+=mm.lengt h;
}
else if (token=="ss"||t oken=="s") {
ss=this.getInt( val,i_val,token .length,2);
if(ss==null||(s s<0)||(ss>59)) {
return null;
}
i_val+=ss.lengt h;
}
else if (token=="a") {
if (val.substring( i_val,i_val+2). toLowerCase()== "am") {
ampm="AM";
}
else if (val.substring( i_val,i_val+2). toLowerCase()== "pm") {
ampm="PM";
}
else {
return null;
}
i_val+=2;
}
else {
if (val.substring( i_val,i_val+tok en.length)!=tok en) {
return null;
}
else {
i_val+=token.le ngth;
}
}
}
// If there are any trailing characters left in the value, it doesn't
match
if (i_val != val.length) {
return null;
}
// Is date valid for month?
if (month==2) {
// Check for leap year
if ( ( (year%4==0)&&(y ear%100 != 0) ) || (year%400==0) ) { // leap year
if (date > 29){
return null;
}
}
else {
if (date > 28) {
return null;
}
}
}
if ((month==4)||(m onth==6)||(mont h==9)||(month== 11)) {
if (date > 30) {
return null;
}
}
// Correct hours value
if (hh<12 && ampm=="PM") {
hh=hh-0+12;
}
else if (hh>11 && ampm=="AM") {
hh-=12;
}
return new Date(year,month-1,date,hh,mm,ss );
}
// Check if a date string is valid
Date.isValid = function(val,fo rmat) {
return (Date.parseStri ng(val,format) != null);
}
// Check if a date object is before another date object
Date.prototype. isBefore = function(date2) {
if (date2==null) {
return false;
}
return (this.getTime() <date2.getTime( ));
}
// Check if a date object is after another date object
Date.prototype. isAfter = function(date2) {
if (date2==null) {
return false;
}
return (this.getTime() >date2.getTime( ));
}
// Check if two date objects have equal dates and times
Date.prototype. equals = function(date2) {
if (date2==null) {
return false;
}
return (this.getTime() ==date2.getTime ());
}
// Check if two date objects have equal dates, disregarding times
Date.prototype. equalsIgnoreTim e = function(date2) {
if (date2==null) {
return false;
}
var d1 = new Date(this.getTi me()).clearTime ();
var d2 = new Date(date2.getT ime()).clearTim e();
return (d1.getTime()== d2.getTime());
}
// Format a date into a string using a given format string
Date.prototype. format = function(format ) {
format=format+" ";
var result="";
var i_format=0;
var c="";
var token="";
var y=this.getYear( )+"";
var M=this.getMonth ()+1;
var d=this.getDate( );
var E=this.getDay() ;
var H=this.getHours ();
var m=this.getMinut es();
var s=this.getSecon ds();
var yyyy,yy,MMM,MM, dd,hh,h,mm,ss,a mpm,HH,H,KK,K,k k,k;
// Convert real date parts into formatted versions
var value=new Object();
if (y.length < 4) {
y=""+(+y+1900 );
}
value["y"]=""+y;
value["yyyy"]=y;
value["yy"]=y.substring(2, 4);
value["M"]=M;
value["MM"]=Date.LZ(M);
value["MMM"]=Date.monthName s[M-1];
value["NNN"]=Date.monthAbbr eviations[M-1];
value["d"]=d;
value["dd"]=Date.LZ(d);
value["E"]=Date.dayAbbrev iations[E];
value["EE"]=Date.dayNames[E];
value["H"]=H;
value["HH"]=Date.LZ(H);
if (H==0){
value["h"]=12;
}
else if (H>12){
value["h"]=H-12;
}
else {
value["h"]=H;
}
value["hh"]=Date.LZ(value["h"]);
value["K"]=value["h"]-1;
value["k"]=value["H"]+1;
value["KK"]=Date.LZ(value["K"]);
value["kk"]=Date.LZ(value["k"]);
if (H > 11) {
value["a"]="PM";
}
else {
value["a"]="AM";
}
value["m"]=m;
value["mm"]=Date.LZ(m);
value["s"]=s;
value["ss"]=Date.LZ(s);
while (i_format < format.length) {
c=format.charAt (i_format);
token="";
while ((format.charAt (i_format)==c) && (i_format < format.length)) {
token += format.charAt(i _format++);
}
if (value[token] != null) {
result=result + value[token];
}
else {
result=result + token;
}
}
return result;
}
// Get the full name of the day for a date
Date.prototype. getDayName = function() {
return Date.dayNames[this.getDay()];
}
// Get the abbreviation of the day for a date
Date.prototype. getDayAbbreviat ion = function() {
return Date.dayAbbrevi ations[this.getDay()];
}
// Get the full name of the month for a date
Date.prototype. getMonthName = function() {
return Date.monthNames[this.getMonth()];
}
// Get the abbreviation of the month for a date
Date.prototype. getMonthAbbrevi ation = function() {
return Date.monthAbbre viations[this.getMonth()];
}
// Clear all time information in a date object
Date.prototype. clearTime = function() {
this.setHours(0 );
this.setMinutes (0);
this.setSeconds (0);
this.setMillise conds(0);
return this;
}
// Add an amount of time to a date. Negative numbers can be passed to
subtract time.
Date.prototype. add = function(interv al, number) {
if (typeof(interva l)=="undefined" || interval==null ||
typeof(number)= ="undefined" || number==null) {
return this;
}
number = +number;
if (interval=='y') { // year
this.setFullYea r(this.getFullY ear()+number);
}
else if (interval=='M') { // Month
this.setMonth(t his.getMonth()+ number);
}
else if (interval=='d') { // Day
this.setDate(th is.getDate()+nu mber);
}
else if (interval=='w') { // Weekday
var step = (number>0)?1:-1;
while (number!=0) {
this.add('d',st ep);
while(this.getD ay()==0 || this.getDay()== 6) {
this.add('d',st ep);
}
number -= step;
}
}
else if (interval=='h') { // Hour
this.setHours(t his.getHours() + number);
}
else if (interval=='m') { // Minute
this.setMinutes (this.getMinute s() + number);
}
else if (interval=='s') { // Second
this.setSeconds (this.getSecond s() + number);
}
return this;
}
--
Matt Kruse
http://www.JavascriptToolbox.com http://www.AjaxToolbox.com