miscoded

the web is a hack

getYear. No, not that year!

, ,

The great thing about JavaScript's Date.getYear()? It makes reading source code fun again..

Date and time calculation is hard. JavaScript's getYear (specified as "returns the number of years since 1900") doesn't make it easier. And then there are the browser differences - quick recap: Opera, Netscape and Firefox follow the spec while IE and Safari don't, they return a full four-digit year (unless the year is between 1900 and 1999, in which case they follow the spec).

Confusing? No match for the web's JavaScript authors! Here are some actual workarounds for this problem - taken from real websites:

The habitual sniffer approach

var year=time.getYear();
if ((navigator.appName == "Microsoft Internet Explorer") && (year < 2000))		
year="19" + year;
if (navigator.appName == "Netscape")
year=1900 + year;
Source

The "I'll never forget when I wrote that code" approach

var year=RightNow.getYear();
if (year==106){year="2006";}
Source

The "string length" approach (well, it works until 2900!)
var y=date.getYear()+"";
if (y.length < 4) {y=""+(y-0+1900);}
Source

Both above approaches at the same time!

var anyo = ''+fecha.getYear();
var ano;
if (anyo == "99") {
ano=1999;
}
else if (anyo.length!=4) {
ano=1900 + parseInt(anyo,10);
}
else {
ano=anyo;
}
Source

The "let's implement some Y2K bugs" approach

var cc_year = today.getYear();
if (cc_year > 99 && cc_year < 200) {cc_year += 1900} else { if (cc_year < 100) {cc_year = 2000 + cc_year}}
(Works as expected for years between 2000 and 2100 only) Source

The "Y2K bugs are OK for dates before 1970" approach
	a=new Date(document.lastModified);
	lm_year=a.getYear();
	if (lm_year<1000){ 				//just in case date is delivered with 4 digits
		if (lm_year<70){
		lm_year=2000+lm_year;
		}
		else lm_year=1900+lm_year;
	}								//end workaround
Source

The "1793 correct years to go ought to be enough for anybody" approach

var Y = time.getYear();
if(Y<1900){Y+=1900;
Source

Off-topic, another gem from the same script - I really wonder what the Mac IE bug was..
//This will need to be adjusted every year
if(MAC_tz && IE_tz && (time<Date.parse('Sun Oct 31 01:00:00 EDT 2004') || time>Date.parse('Sun Apr 3 01:00:00 EDT 2005')) && tzOffset != -1 && tzOffset!=4)


The "well, let's just hardcode it" approach

copyright=new Date();
update=copyright.getYear();
//---write copyright 
document.write("Copyright © 1998/2006 Brightwater Engineers  - All rights reserved.");
Source

And finally, the priceless "string concatenation" approach
var today = new Date()
var theYear = parseInt(today.getYear(),10)

if (mthIdx < today.getMonth()) {
    theYear = (parseInt(today.getYear(), 10) + 1)
}
if(theYear<100){
    theYear = "19" + theYear
}
else{
    if((theYear-100) < 10){
        theYear = "0" + (theYear-100)
    }
    else{
        theYear = (theYear-100)+""
    }
    theYear = "20" + theYear
}
Source

Fun.

ECMAScript's FunctionDeclaration versus FunctionExpressionreal *nix devs don't test in IE

Comments

Simon Houstonshoust Wednesday, February 7, 2007 7:41:54 PM

var year=time.getYear();
if(year <1000)
{year+=1900}


Confusing enough to find the correct code p 2nd edit.
Whats your way to doing it correctly? smile

ok I think I got it smile

var year=time.getYear();
if(100<year)
{year+=1900}


There p

GKiller Wednesday, February 7, 2007 8:27:29 PM

@Hallvord:
So what do you recommend?

@shoust:
*edit, here stood a wrong statement*
Your code does not work for years between 1900 and 2000 (for spec-compliant browsers) and 1900 - 1999 (IE-like).

Jere Wednesday, February 7, 2007 8:34:05 PM

@shoust and GKiller...

Just use .getFullYear()

GKiller Wednesday, February 7, 2007 8:44:32 PM

@Jere:

Hehe, great advice smile I now remember reading that using getFullYear is always recommended, but since I don't code that much JS, I had already forgotten that again. But AFAIK getFullYear is not supported by old (how old?) browsers.

I think the maximum with getYear you can get is a modification from an example above:

var Y = time.getYear();
if (Y < 2000) { Y+=1900; }

wink

Simon Houstonshoust Wednesday, February 7, 2007 9:11:39 PM

var time=new Date(); var year=time.getFullYear()?time.getFullYear():time.getYear(); if(year<1900){year+=1900};


Just was working with the context of older browsers, knew there was getFullYear, but that above should be pretty much cross browser compatible I think smile

Edit: Changed less than sign to more than sign, oops smile , again changed code, I should experiment with it more right edit: me gives up

GKiller Wednesday, February 7, 2007 10:15:42 PM

@shoust:
The problem with your trinary operator is, that if a browser does not implement getFullYear, it does not return "null" or false or something like that, but throws a javascript error.

That may be caught with a try-catch statement, but, of course, browsers that do not support getFullYear certainly don't support try-catch smile

Hallvord R. M. Steenhallvors Wednesday, February 7, 2007 10:40:23 PM

The trinary version above would be my preferred way, fixed with a proper object detection:

var year=time.getFullYear ? time.getFullYear() : time.getYear();


Naturally, in pre-getFullYear browsers that support getYear correctly, "year" would now be years since 1900.

If one can trust that the browsers that do not support getFullYear also implement getYear according to the spec this is the perfect solution:

var year=time.getFullYear ? time.getFullYear() : time.getYear()+1900;


However, I don't know if this assumption holds. I guess older IE version is a possible headache - I don't know if they started violating the getYear spec before implementing getFullYear. In such a browser, you might end up with a value that is 1900 years in the future.

David Håsätherhzr Wednesday, February 7, 2007 11:22:29 PM

I remember shortly after new year 1999/2000 where "19100" started to show up at several places smile

Rijk Wednesday, February 7, 2007 11:40:04 PM

http://www.quirksmode.org/js/datecompat.html tells about getYear support in historical browsers (until year 2000). According to this site, Op2+ and NS2 and NS4+ and WinIE3 follow the spec, NS3 and MacIE3 and IE4+ and WebTV break it.

It is NS3 and WebTV that break the spec while also do not supporting getFullYear...

James Justin HarrellHeroreV Thursday, February 8, 2007 1:28:39 AM

"Trinary"? I've never seen it called that before. I usually see "ternary". I myself prefer to be more specific and always call it the "conditional operator". Both the ECMAScript and C++ specifications call it the "conditional operator".

João EirasxErath Thursday, February 8, 2007 3:55:05 AM

Originally posted by Andrew Gregory:

It just reinforces my view that most people building web sites have no idea what they're doing!

spock

Originally posted by GKiller:

So what do you recommend?

You are joking right ?
right

johnnysaucepn Thursday, February 8, 2007 9:34:13 AM

Originally posted by HeroreV:

"Trinary"? I've never seen it called that before. I usually see "ternary". I myself prefer to be more specific and always call it the "conditional operator". Both the ECMAScript and C++ specifications call it the "conditional operator".



Maybe Hallvord likes to code in dolphin poetry. I must admit, I think I've called it the trinary operator more than once - never would have noticed that!

GKiller Thursday, February 8, 2007 6:15:40 PM

Yeah, it should be "ternary", as you can see in http://en.wikipedia.org/wiki/Ternary_operation

@xErath:
No, I was not joking, why?

Andrew Gregory Friday, February 9, 2007 2:29:40 AM

if (year==106){year="2006";}


yikes (runs away screaming...)

xErath has quoted me from another blog post, and I couldn't agree with myself more! p

cry

ZeroJ Wednesday, March 28, 2007 1:25:46 AM

var today = new Date();
if(navigator.appName == "Opera"){
var yearNow = today.getFullYear();
}else{
var yearNow = today.getYear();
}
Check if browser is Opera, use getFullYear instead of getYear..
No need to fix date.

Hallvord R. M. Steenhallvors Wednesday, March 28, 2007 1:55:22 PM

ZeroJ: NO. Please Do NOT use browser sniffing unless absolutely necessary. sniffing is a last resort, see http://dev.opera.com/articles/view/using-capability-detection/ for better approaches.

On this specific issue look at the "perfect solution" a few comments up. If WebTV compliance is required, sniff specifically for the problematic WebTV versions and amend the value as required.

Random832 Tuesday, May 22, 2007 6:11:49 PM

The problem is that the spec for getYear actually _changed_ between javascript 1.2 and 1.3 (netscape 4 or somesuch), and IE just didn't change with it. So any browser that does _not_ implement getFullYear is guaranteed to have the sequence "...1898, 1899, 0, 1, ... 99, 2000, 2001..." as with IE.

Real perfect solution:

(function () {
var orig_getYear = Date.prototype.getYear;
if(!Date.prototype.getFullYear) {
Date.prototype.getFullYear = function() {
// won't work for years that are actually 0..99 AD
var x = orig_getYear.call(this);
return ((x >= 0 && x < 100 )? 1900 : 0 ) + x;
}
}
Date.prototype.getYear = function() { return this.getFullYear() - 1900; }
}) ()

FataL Monday, June 4, 2007 4:23:27 PM

My wife have stuck trying to fill out this online application for E-ZPass in Opera. See PAYMENT METHOD section for problemmatic Expiration Date fields.

ZeroJ Thursday, October 18, 2007 6:15:02 AM

As I know, Internet Explorer work difference Opera and FireFox. I use filter browser because almost people use Internet Eplorer, Opera and Firefox, of course it have another way to fix this line.

(function () {
var orig_getYear = Date.prototype.getYear;
if(!Date.prototype.getFullYear) {
Date.prototype.getFullYear = function() {
// won't work for years that are actually 0..99 AD
var x = orig_getYear.call(this);
return ((x >= 0 && x < 100 )? 1900 : 0 ) + x;
}
}
Date.prototype.getYear = function() { return this.getFullYear() - 1900; }
}) ()

Greate. I'll try another way to fix this solution

Write a comment

You must be logged in to write a comment. If you're not a registered member, please sign up.