JavaScript strtotime
Convert string representation of date and time to a timestamp
1 2 3 4 56 7 8 9 1011 12 13 14 1516 17 18 19 2021 22 23 24 2526 27 28 29 3031 32 33 34 3536 37 38 39 4041 42 43 44 4546 47 48 49 5051 52 53 54 5556 57 58 59 6061 62 63 64 6566 67 68 69 7071 72 73 74 7576 77 78 79 8081 82 83 84 8586 87 88 89 9091 92 93 94 9596 97 98 99 100101 102 103 104 105106 107 108 109 110111 112 113 114 115116 117 118 119 120121 122 123 124 125126 127 128 129 130131 132 133 134 135136 137 138 139 140141 142 143 144 145146 147 148 149 150151 152 153 154 155156 157 158 159 160161 162 163 164 165166 167 168 169 170171 172 173 174 175176 177 178 179 180181 182 183 184 185 | function strtotime (str, now) { // Convert string representation of date and time to a timestamp // // version: 1109.2015 // discuss at: http://phpjs.org/functions/strtotime // + original by: Caio Ariede (http://caioariede.com) // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) // + input by: David // + improved by: Caio Ariede (http://caioariede.com) // + improved by: Brett Zamir (http://brett-zamir.me) // + bugfixed by: Wagner B. Soares // + bugfixed by: Artur Tchernychev // % note 1: Examples all have a fixed timestamp to prevent tests to fail because of variable time(zones) // * example 1: strtotime('+1 day', 1129633200); // * returns 1: 1129719600 // * example 2: strtotime('+1 week 2 days 4 hours 2 seconds', 1129633200); // * returns 2: 1130425202 // * example 3: strtotime('last month', 1129633200); // * returns 3: 1127041200 // * example 4: strtotime('2009-05-04 08:30:00'); // * returns 4: 1241418600 var i, match, s, strTmp = '', parse = ''; strTmp = str; strTmp = strTmp.replace(/\s{2,}|^\s|\s$/g, ' '); // unecessary spaces strTmp = strTmp.replace(/[\t\r\n]/g, ''); // unecessary chars if (strTmp == 'now') { return (new Date()).getTime() / 1000; // Return seconds, not milli-seconds } else if (!isNaN(parse = Date.parse(strTmp))) { return (parse / 1000); } else if (now) { now = new Date(now * 1000); // Accept PHP-style seconds } else { now = new Date(); } strTmp = strTmp.toLowerCase(); var __is = { day: { 'sun': 0, 'mon': 1, 'tue': 2, 'wed': 3, 'thu': 4, 'fri': 5, 'sat': 6 }, mon: { 'jan': 0, 'feb': 1, 'mar': 2, 'apr': 3, 'may': 4, 'jun': 5, 'jul': 6, 'aug': 7, 'sep': 8, 'oct': 9, 'nov': 10, 'dec': 11 } }; var process = function (m) { var ago = (m[2] && m[2] == 'ago'); var num = (num = m[0] == 'last' ? -1 : 1) * (ago ? -1 : 1); switch (m[0]) { case 'last': case 'next': switch (m[1].substring(0, 3)) { case 'yea': now.setFullYear(now.getFullYear() + num); break; case 'mon': now.setMonth(now.getMonth() + num); break; case 'wee': now.setDate(now.getDate() + (num * 7)); break; case 'day': now.setDate(now.getDate() + num); break; case 'hou': now.setHours(now.getHours() + num); break; case 'min': now.setMinutes(now.getMinutes() + num); break; case 'sec': now.setSeconds(now.getSeconds() + num); break; default: var day; if (typeof(day = __is.day[m[1].substring(0, 3)]) != 'undefined') { var diff = day - now.getDay(); if (diff == 0) { diff = 7 * num; } else if (diff > 0) { if (m[0] == 'last') { diff -= 7; } } else { if (m[0] == 'next') { diff += 7; } } now.setDate(now.getDate() + diff); } } break; default: if (/\d+/.test(m[0])) { num *= parseInt(m[0], 10); switch (m[1].substring(0, 3)) { case 'yea': now.setFullYear(now.getFullYear() + num); break; case 'mon': now.setMonth(now.getMonth() + num); break; case 'wee': now.setDate(now.getDate() + (num * 7)); break; case 'day': now.setDate(now.getDate() + num); break; case 'hou': now.setHours(now.getHours() + num); break; case 'min': now.setMinutes(now.getMinutes() + num); break; case 'sec': now.setSeconds(now.getSeconds() + num); break; } } else { return false; } break; } return true; }; match = strTmp.match(/^(\d{2,4}-\d{2}-\d{2})(?:\s(\d{1,2}:\d{2}(:\d{2})?)?(?:\.(\d+))?)?$/); if (match != null) { if (!match[2]) { match[2] = '00:00:00'; } else if (!match[3]) { match[2] += ':00'; } s = match[1].split(/-/g); for (i in __is.mon) { if (__is.mon[i] == s[1] - 1) { s[1] = i; } } s[0] = parseInt(s[0], 10); s[0] = (s[0] >= 0 && s[0] <= 69) ? '20' + (s[0] < 10 ? '0' + s[0] : s[0] + '') : (s[0] >= 70 && s[0] <= 99) ? '19' + s[0] : s[0] + ''; return parseInt(this.strtotime(s[2] + ' ' + s[1] + ' ' + s[0] + ' ' + match[2]) + (match[4] ? match[4] / 1000 : ''), 10); } var regex = '([+-]?\\d+\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday)' + '|(last|next)\\s' + '(years?|months?|weeks?|days?|hours?|min|minutes?|sec|seconds?' + '|sun\\.?|sunday|mon\\.?|monday|tue\\.?|tuesday|wed\\.?|wednesday' + '|thu\\.?|thursday|fri\\.?|friday|sat\\.?|saturday))' + '(\\sago)?'; match = strTmp.match(new RegExp(regex, 'gi')); // Brett: seems should be case insensitive per docs, so added 'i' if (match == null) { return false; } for (i = 0; i < match.length; i++) { if (!process(match[i].split(' '))) { return false; } } return (now.getTime() / 1000); } |
Examples
» Example 1
Running
1 | strtotime('+1 day', 1129633200); |
Should return
1 | 1129719600 |
» Example 2
Running
1 | strtotime('+1 week 2 days 4 hours 2 seconds', 1129633200); |
Should return
1 | 1130425202 |
Dependencies
No dependencies, you can use this function standalone.
Open syntax issues
php.js uses JsLint to help us keep our code consistent and prevent some common bugs.
Eventually we want all code to pass or at least take into consideration most fixes suggested by JsLint, following this JsLint configuration we’ve decided on.
Authors
Thanks to the following developers, you get to have strtotime goodness in JavaScript.
I am using this function on something mission-critical for the user (an online task manager and calendar) so I need it to be flawless.
I am trying to find bugs and fix them myself. If you want to help me, please contact me.
I would also like to contribute to the Github repo with my fixes - how can I do that?
Here is another bug:
date("Y-m-d", strtotime('+3 days')); // returns 2011-10-14
date("Y-m-d", strtotime('+3 days', 1324815132)); // returns 2011-10-14
I have fixed the bug by replacing line 30 of the version version: 1109.2015 with:
} else if ((!now) && !isNaN(parse = Date.parse(strTmp))) {
I hope that won't introduce new bugs.
Any ideas?
This function would be so useful if it was reliable
An example:
PHP
date("Y-m-d", strtotime('second Monday October 2011'));
returns: 2011-10-10
(which is right)
JS:
date("Y-m-d", strtotime('second Monday October 2011'));
returns: 1970-01-01
(which is obviously wrong)
Any solution, suggestion, work around?
Is this function still maintained? If not, maybe I can start working with somebody to maintain it back.
I don't understand why 2011-10-03 is not the same as 10/03/2011... so I patched the function after line 25:
[CODE]
match = strTmp.match(/^(\d{4})-(\d{2})-(\d{2})$/);
if (match != null) {
strTmp = match[2] + '/' + match[3] + '/' + match[1];
}
[CODE]
Worked for me.
Hi everybody
Nice function, I've used it a lot, but encountered a few issues :
- it seems unable to decode YYYYMMDD format (not really bad, just use a regex)
- in French, there are accented chars in month names. But when using short names, it will truncate the html char, i.e. AO& instead of AOÛ. I came up with this fix, using html_entity_decode (you may want to apply it to week days, too) :
M: function () { // Shorthand month name; Jan...Dec
// Romaric : using html_entity_decode to avoid bugs with accented chars
var _month = f.F();
_month = html_entity_decode(_month);
return _month.slice(0, 3);
},
Yeah. Date.parse() is now apparently treating "11" as 1911. And since Date.parse() might vary across browsers, we should I think be using our own implementation anyways rather than allowing for different behavior by browser. Thoughts?
Try this in Firefox 5:
console.log(strtotime("06/28/2011"));
console.log(strtotime("06/28/11"));
You get
1309237200 -1846522800
It isn't properly detecting 2 digit years.
There seems to be a bug where different date formats return different values, try:
strtotime('2011-06-24'); //1308873600
strtotime('06/24/2011'); //1308891600
date('D M j, Y', strtotime('2011-06-24')); //Thu Jun 23, 2011
date('D M j, Y', strtotime('06/24/2011')); //Fri Jun 24, 2011
When parsing ISO 8601 dates, PHP's strtotime() doesn't care if there's a colon in the GMT-06:00. php.js's version requires the colon to be there. This most notably comes into play with Facebook's open social graph dates, it won't parse them unless you insert the colon.
@Brad: I think it is most likely a timezone issue. Our date function currently does not support the setting of a default timezone (as PHP also allows and recommends), so there may be some problem in setting date values according to the browser locale and then using such values across our functions.
You can see "raw js source", note #2, on the date function for the latest notes about how this could be implemented if you are able to make the changes to our code yourself (sorry, I have no time at the moment). Anyone else feel free to help out if you can.
@Jack: The syntax highlighting code here is buggy, so when you copy-paste it directly, some lines will be commented out. Go to "raw js source" to make sure you have a good copy...It is working with the right code...
hmm - couple of bugs in strtotime...
1) strtotime('last Monday',now) returns last month not last monday - first 3 letters of month is the same as monday!
work around :
strtotime('last Tuesday, -1 day',now); // = last monday
2) strtotime('d-m-Y',now) isn't handled correctly (only 'Y-m-d' is) (as mentioned in other comments)
3) in 2 above, the d and m have to be zero padded to work I.E. strtotime('2010-3-1') has to be replaced with ('2010-03-01')
work around :
//examples from variable passed into function perhaps
day = 2;
month = 5;
year = 2010;
if (day < 10) dayzeropad = '0'; else dayzeropad = '';
if (month < 10) monthzeropad = '0'; else monthzeropad = '';
var tstring = year + '-' + monthzeropad + month + '-' + dayzeropad + day;
unixtime = strtotime(tstring);
bugs work-aroundable... cool stuff - thanks.
Is it possible to add support for german-like Dates ?
in PHP (5.3+), strototime('22.01.2010'); works as expected, but not with this js strtotime-method.
@ rav3n: You might be better off parsing your string first before feeding it to strtotime cause I believe PHP wouldn't support your format either.
@ iwosz: Sorry no IE7 on my machine. So unless someone else can get to the bottom of this I may have to see if I can find some WinXP virtual image with IE7 installed or sth like that
this function is great. however i need to format the string not as %Y-%m-%d but as %d-%m-%Y.
i understand that it's around line 150-170
@ Daniel Janesch & Theriault: Thanks for pointing out these problems. I've contacted the original author by mail.
First of all: Great work :-)
I have figured out that the following is not working correctly:
$d = new Date(2012, 11, 1, 7, 0, 0);
$r = strtotime('3 Wednesday', $d.getTime()/1000); // 2012-11-01 07:00:00
The correct result with php is 2012-11-21 00:00:00 but with phpjs I get 1351753200 wich is 2012-11-01 07:00:00.
Any clues?
PHP seems to apply the string as a whole and not from left-to-right as in this function. In the following PHP example, both $a and $b will be the same date. If PHP applied them from left-to-right, $b would be 2012-03-01, not 2012-02-29.
$d = strtotime('2011-02-22');
$a = strtotime('+1 year, +7 days', $d); // 2012-02-29
$b= strtotime('+7 days, +1 year', $d); // 2012-02-29
This function applies the string from left-to-right, which seems more logical, but is incorrect.
I noticed that none of the following work with this function:
today (same as 'now' but resets to 12:00:00AM), tomorrow (same as '+1 day' but also resets to 12), yesterday (same as '-1 day' but also resets to 12).
next week, last week (Currently returns date plus/minus seven days, should return next monday if I remember correctly on how it works in PHP).
last sunday of next month (returns next month, but not last sun/sat/mon/day... of that month)
YYYY-Wnn-d (Basically, sets year to YYYY, week number to nn, and then day of that week to d (0-6). Day of week may be omitted and also overflow, such as 7 for next week.)
00:00:00 (Changes time to 12:00:00 AM or anything else entered here.)
Does anyone else see anything missing from this function? I may recode it. I would like to see it complete -- it is a great function.
@majak: Yeah, thanks, it seemed that way from the code snippet (figured out what was the problem by finding that code by Google). Be careful using Prototype or other libraries that overload the prototype objects--it causes problems like these...
@Brett Zamir: Thank you for your help. Your fix works.
Just for reference, I'm using Prototype framework.
@majak, it appears you are using a library which overloads the Object prototype with its own functions which this PHP.JS function then iterates... You can solve this problem by adding right after line 184 (see above) the following line (and then the closing brace after line 187):
if (match.hasOwnProperty(i)) {
If you need to work with older browsers like IE 5, you can add this instead:
if (typeof match[i] !== 'function') {
See http://yuiblog.com/blog/2006/09/26/for-in-intrigue/ for a fuller explanation of why.
All of our for...in statements should really use such a test, though since it is cumbersome, and libraries should, imo, really not be altering the prototype in the first place, I think it is a toss-up as to whether we should add these checks ourselves. What do you think, Kevin? Perhaps we should in order to be most compatible...
I'm using the latest (2.85) minified and namespaced version of this function. This snippet:
$P.strtotime('+1 day');
produces TypeError. I have tested it in both FF and Chrome, here are their error messages:
FF:
TypeError: match[i].split is not a function
Chrome:
TypeError: Object function (inline) {
return (inline !== false ? this : this.toArray())._reverse();
} has no method 'split'
I suppose it happens on every relative date string input, like "-3 months".
The function expects a string--you are mostly passing something to the function which is not a string.
Getting an error --
Error: strTmp.replace is not a function
The debugger is pointing to this line --
strTmp = strTmp.replace(/\s{2,}|^\s|\s$/g, ' '); // unecessary spaces


Tom
28 Dec '11
gives: 2011-11-28 06:34:46
expected: 2011-12-26 00:00:00