Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript date 01/01/0001

I want to create a Date object in javascript, which represents the year 0001, 2014 years ago.

I tried with

d = new Date(); d.setYear(1); console.log(d); 

but it gives the year 1901

with

d = new Date(1,1,1) console.log(d); 

no way.

How can I create this date?

like image 579
Naramsim Avatar asked Apr 30 '15 12:04

Naramsim


1 Answers

First of all it's not a Y2K issue at all! ( UPDATE: in some cases - it's related to Y2K issues, but it's not the problem here )

The correct answer is that you can't do that reliably. Does Daylight saving time apply to year 1? How many Leap Years were there? Were there any? Etc. But the answer by @Daniel will use it!

UPDATE: not to mention @MattJohnson post about DST. DST in year 1, actually JS (ES5 anyway) will lie and use the current DST rule for all years

So please don't fool yourself with the idea that you can reliably work with dates lower than 1970. (You will have a lot of problems and surprises even in that time range.)

But if you really, really need to you can use new Date('0001-01-01') (ISO 8601 format) or @Daniel's method:

var d = new Date(); d.setFullYear(1); 

But before you use it read this...


There are 4 ways to create a Date in JS:

new Date() new Date(milliseconds) new Date(dateString) new Date(year, month, day, hours, minutes, seconds, milliseconds) 

1) new Date() creates current date ( in your local timezone ) so we are not interested in it for now.


2) new Date(number) creates a new date object as zero time plus the number. Zero time is 01 January 1970 00:00:00 UTC.

So in this case time in JS counting from year 1970.

(new Date(0)).toUTCString() "Thu, 01 Jan 1970 00:00:00 GMT 

If you use negative number you can go "back" it time before 1970

(new Date(-62167219200000)).toUTCString() "Sat, 01 Jan 0 00:00:00 GMT" -62167219200000             <- milliseconds -62167219200000 / 1000 -62167219200             <- seconds -62167219200 / 60 -1036120320             <- minutes -1036120320 / 60 -17268672             <- hours -17268672 / 24 -719528             <- days -719528 / 365 -1971.309589041096 <- years ( this is roughly calculated value ) 

The problem is that it's not reliable. How many Leap Years were there? Were there any? Daylight saving time? Etc. And I don't like it because of this magic number -62167219200000


3) new Date(dateString) This is most 'reliable' way. DateString - A string representing an RFC2822 or ISO 8601 date.

RFC2822 / IETF date syntax (RFC2822 Section 3.3), e.g. "Mon, 25 Dec 1995 13:30:00 GMT"

The problem with it is that if you use negative number you will get an incorrect Date with NaN in a result of all methods

(new Date('01 January -1 00:00:00 UTC')).getFullYear() NaN 

If you use year higher or equal 0 and lower then 50 then 2000 will be added automatically.

(new Date('01 January 0 00:00:00 UTC')).getFullYear() 2000 (new Date('01 January 1 00:00:00 UTC')).getFullYear() 2001 (new Date('01 January 10 00:00:00 UTC')).getFullYear() 2010 (new Date('01 January 01 00:00:00 UTC')).getFullYear() 2001 (new Date('01 January 30 00:00:00 UTC')).getFullYear() 2030 (new Date('01 January 49 00:00:00 UTC')).getFullYear() 2049 

And if you use year higher or equal 50 and lower then 100 then 1900 will be added.

(new Date('01 January 50 00:00:00 UTC')).getFullYear() 1950 (new Date('01 January 51 00:00:00 UTC')).getFullYear() 1951 (new Date('01 January 90 00:00:00 UTC')).getFullYear() 1990 (new Date('01 January 99 00:00:00 UTC')).getFullYear() 1999 

Years equal 100 or higher will get correct year number

(new Date('01 January 100 00:00:00 UTC')).getFullYear() 100 (new Date('01 January 101 00:00:00 UTC')).getFullYear() 101 (new Date('01 January 999 00:00:00 UTC')).getFullYear() 999 (new Date('01 January 9999 00:00:00 UTC')).getFullYear() 9999 

So we can't create year 1 using RFC2822 / IETF date syntax

About ISO 8601:

http://www.w3.org/TR/NOTE-datetime

The actual formats are

Year:       YYYY (eg 1997) Year and month:       YYYY-MM (eg 1997-07) Complete date:       YYYY-MM-DD (eg 1997-07-16) Complete date plus hours and minutes:       YYYY-MM-DDThh:mmTZD (eg 1997-07-16T19:20+01:00) Complete date plus hours, minutes and seconds:       YYYY-MM-DDThh:mm:ssTZD (eg 1997-07-16T19:20:30+01:00) Complete date plus hours, minutes, seconds and a decimal fraction of a second       YYYY-MM-DDThh:mm:ss.sTZD (eg 1997-07-16T19:20:30.45+01:00) 

We are most interested in 'Complete date'

(new Date('0001-01-01')).toUTCString() "Mon, 01 Jan 1 00:00:00 GMT" 

Yahoo!!! ( or it is better to say Google! :) ), we can use ISO 8601 to create date with year 1

But be careful and do not try to use negative numbers or short year numbers, as parsing of those will may vary on localization or just insanity :)

(new Date('-0001-01-01')).toUTCString() "Sun, 31 Dec 2000 21:00:00 GMT" (new Date('01-01-01')).toUTCString() "Sun, 31 Dec 2000 21:00:00 GMT" (new Date('02-01-01')).toUTCString() "Wed, 31 Jan 2001 21:00:00 GMT" (new Date('02-01-05')).toUTCString() "Mon, 31 Jan 2005 21:00:00 GMT" 

4) new Date(year, month, day, hours, minutes, seconds, milliseconds)

To use this one you have to pass two parameters ( year, and month ), all other will be optional. Be careful because here month will start from 0 to 11, not like everywhere else. WAT? o_O

WARNING! This date will be created in your current time zone!!! So be careful using it!

UPD: clarification by @matt-johnson

...actually the Date object always reflects the local time zone. You can't place it in another time zone, and even if you initialize it with a UTC timestamp, it will still reflect back the local time zone in most of the functions. Internally it tracks UTC by the numeric timestamp, and there are functions that expose UTC values explicitly, but everything else is local.

The negative numbers will be interpreted as negative years

(new Date(-1, 0)).toString() "Fri Jan 01 -1 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(-234, 0)).toString() "Wed Jan 01 -234 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" 

The numbers from 0 to 99 will be incremented by 1900 automatically

(new Date(0, 0)).toString() "Mon Jan 01 1900 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(1, 0)).toString() "Tue Jan 01 1901 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(11, 0)).toString() "Sun Jan 01 1911 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(50, 0)).toString() "Sun Jan 01 1950 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(99, 0)).toString() "Fri Jan 01 1999 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" 

The numbers from 100 to 275760 will be interpreted as year numbers

(new Date(100, 0)).toString() "Fri Jan 01 100 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(102, 0)).toString() "Sun Jan 01 102 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(2002, 0)).toString() "Tue Jan 01 2002 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" 

And numbers higher then 275760 will be Invalid date

(new Date(275760, 0)).toString() "Tue Jan 01 275760 00:00:00 GMT+0300 (Russia TZ 2 Standard Time)" (new Date(275761, 0)).toString() "Invalid Date" 

UPD:

new Date(Date.UTC(1,1,1)) will safer from same symptoms as new Date(year, month, day, hours, minutes, seconds, milliseconds). Because of Date.UTC function.

like image 174
obenjiro Avatar answered Oct 07 '22 17:10

obenjiro