I receive a date time as a string from the server that might look like this:
07/08/2012 13:17:32
This is a UTC time.
Or it might have timezone in format:
07/08/2012 13:17:32 UTC+01:00
I need a general way to parse this into a Date object for display. If I do a var d = new Date(str) then the first example it assumes is a local time.
Edit:
It might not always be 'UTC' in the string, I think it could be GMT, or Z, or any other timezone signifier.
Any ideas?
If your timezone is always in format UTC+nn, and strings with explicit UTC TZ are parsed correctly, as I assume from your question, then simple
if (date_string.search(/a-z/i) == -1) {
date_string += 'UTC+00:00'
}
will do.
As a quick and dirty solution, it looks like the timezone is a final "part" of the format separated by whitespace. So you could count the number of "parts" in the input string and add a default timezone if none is found. For example:
function parseDateDefaultUTC(str) {
var parts = str.split(/\s+/);
return new Date((parts.length===3) ? str : str + ' UTC');
}
var d;
d = parseDateDefaultUTC("07/08/2012 13:17:32");
d; // => Sun Jul 08 2012 07:17:32 GMT-0600 (MDT)
d = parseDateDefaultUTC("07/08/2012 13:17:32 UTC+01:00");
d; // => Sun Jul 08 2012 06:17:32 GMT-0600 (MDT)
Related
I receive Date in 3 formats from different APIs
UTC format: 2014-01-01T00:00:00.000Z (String)
GMTformat: Thu, 29 Nov 2018 17:30:56 GMT (String)
unixTimeStamp: 1558606726 (number)
Also the UTC format sometimes might not have Z in the end so the normal parsing will give a time difference.
function formatDate(dateString) {
var dateTime, utcFormatRegex, zeroHourOffsetRegex;
// Some APIs return a Date in standard ISO UTC format may not have Z at the end
utcFormatRegex = /^\d{4}-\d{2}-\d{2}T.*$/;
zeroHourOffsetRegex = /^.*Z$/;
if (utcFormatRegex.test(dateString) && !zeroHourOffsetRegex.test(dateString)) {
dateString+='Z';
}
dateTime = new Date(dateString);
}
Given that there are parsing functions for all of the different formats, i need a function that determines which parsing function we should be using based on a regex and parse it accordingly. If regex is not the ideal solution then how can i approach this?
What I'm getting at is there should probably be a more robust solution than 'if there isn't a Z then add one' to get it to parse through the single date time parser. What if we get another date time format that doesn't play nicely with a Z on the end? We'll be making multiple changes at that point in time.
Using a regular expression is OK, but you need to test strictly for the formats you're expecting. If you get something you don't expect, throw an error. It's one of the failings of current built–in parsers is that there's no way to specify strict parsing, e.g. where a format is supplied and the parser throws an error if the input string doesn't match.
There are libraries that can help, a search will reveal quite a few.
But if you only have to support the 3 formats in the OP, something like the following may suit:
/* Return a Date where the input may be:
** string: ISO 8601 timestamp that should be treated as UTC
** whether it has a trailing Z or not
** string: Timestamp in the format (using moment.js tokens):
** ddd, DD MMM YYYY HH:mm:ss GMT
** nunber: UNIX time value, seconds since 1970-01-01 UTC
*/
function toDate(value) {
// Parse the string & fail early if it fails
let d = new Date(value);
// Throw error if couldn't parse value
if (isNaN(d.getTime())) {
throw 'Invalid timestamp: ' + value;
}
// Otherwise, do the work
let days = 'Sun Mon Tue Wed Thu Fri Sat'.split(' ');
let months = 'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ');
// Test for time value first as that's the easiest
if (typeof value == 'number' && !isNaN(value)) {
return new Date(value * 1000);
// Test for ISO 8601 next
} else if (/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ?$/.test(value)) {
return new Date(/Z$/.test(value)? value : value + 'Z');
// Test for random format
} else if (/^[a-z]{3}, \d?\d [a-z]{3} \d{4} \d\d:\d\d:\d\d GMT$/i.test(value)) {
let b = value.split(/ |:/);
if (days.includes(b[0].substr(0,3)) && months.includes(b[2])) {
let x = new Date(Date.UTC(
b[3], // year
months.indexOf(b[2]), // month, zero indexed
b[1], // day
b[4], b[5], b[6] // hh:mm:ss
));
// Check value was a valid date, only need to check some parts
if (x.getUTCFullYear() == b[3] &&
x.getUTCDate() == b[1] &&
x.getUTCHours() == b[4] &&
x.getUTCSeconds() == b[6]) {
return x;
} else {
throw 'Invalid timestamp: ' + value;
}
}
// Throw error as must be unknown format
} else {
throw 'Unknown format: ' + value;
}
}
// Minimal testing
var isoString0 = '2014-01-01T00:00:00.000Z',
isoString1 = '2014-01-01T00:00:00.000', // no Z, parse as UTC anyway
randomString = 'Thu, 29 Nov 2018 17:30:56 GMT',
unixTimeValue = 1558606726, // Assume seconds
invalidDate0 = '2018-02-29T00:00:00.000Z', // no 29 Feb in 2018, fail built-in parse
invalidDate1 = 'Thu, 29 Feb 2018 17:30:56 GMT', // no 29 Feb in 2018, fail manual parse
invalidFormat = '6/6/2019'; // Unknown format
[isoString0, isoString1, randomString, unixTimeValue, invalidDate0,
invalidDate1, invalidFormat].forEach(s => {
var result;
try {
result = toDate(s);
console.log(s + ' =>\n' + result.toISOString());
} catch (e) {
console.log(e);
}
});
Currently the input is "12 09 2016 00:00:00" and should assume it is in inputted as GMT date and time. But rather, it accepts it as local and converts it as such. And when it is turned to ISOString(), it converts it to GMT, and adds the time difference.
How can I take an input in "12 09 2016 00:00:00" format, take it as GMT/UTC, and do .toISOString() to turn it into the ISO format, "2016-12-09T00:00:00.000Z"?
var dateAndTime = new Date("12 09 2016 00:00:00")
//Returns: "Fri Dec 09 2016 00:00:00 GMT-0800 (PST)"
//Want it to return: "Fri Dec 09 2016 00:00:00 (GMT)"
var gmtDateAndTime = dateAndTime.toISOString();
//Returns: "2016-12-09T08:00:00.000Z"
//Want it to return: "2016-12-09T00:00:00.000Z"
Thank you and will be sure to vote up and accept the answer.
How can I take an input in "12 09 2016 00:00:00" format, take it as
GMT/UTC, and do .toISOString() to turn it into the ISO format,
"2016-12-09T00:00:00.000Z"?
It seems you just want to reformat the string, so just do that:
// Reformat string in MM DD YYYY HH:mm:ss format to
// ISO 8601 UTC
function formatDateStringISO(s) {
var b = s.split(/\D/);
return b[2] + '-' + b[0] + '-' + b[1] +
'T' + b[3] + ':' + b[4] + ':' + b[5] + '.000Z';
}
console.log(formatDateStringISO('12 09 2016 00:00:00'))
If you want to parse the string to a Date then output an ISO 8601 format string, do that:
// Parse string in MM DD YYYY HH:mm:ss format
// If date string is invalid, returns an invalid Date
function parseDateAsUTC(s) {
var b = s.split(/\D/);
var d = new Date(Date.UTC(b[2], --b[0], b[1], b[3], b[4], b[5]));
// Validate date
return d && d.getMonth() == b[0]? d : new Date(NaN);
}
// Valid date Invalid date
['12 09 2016 00:00:00', '12 34 2016 00:00:00'].forEach(function(s) {
var d = parseDateAsUTC(s);
console.log(s + ' => ' + d[isNaN(d)? 'toString' : 'toISOString']());
});
You need to use another Date constructor. The default constructor creates time in your local timezone.
Replace this:
var dateAndTime = new Date("12 09 2016 00:00:00")
With this:
var dateAndTime = new Date(Date.UTC(2016, 09, 12, 0, 0, 0));
If you can't convert your string ("12 09 2016 00:00:00") manually to the individual UTC parameters, you can use this (but unreliable especially in IE):
var utcDate = Date.parse("12 09 2016 00:00:00");
Do not use Date to parse happenstance date strings. Date.parse only works in a well defined manner when the input is an ISO8061 string.
From "15.9.4.2 Date.parse" in the ECMA 5 standard:
The function first attempts to parse the format of the String according to the rules called out in Date Time String Format (15.9.1.15). If the String does not conform to that format the function may fall back to any implementation-specific heuristics or implementation-specific date formats.
and from 15.9.1.15 the string format recognized is
YYYY-MM-DDTHH:mm:ss.sssZ
which looks very much the ISO string you want to arrive at, not start with.
Alternative choices to solve the issue might include:
write your own function to parse a user input string. Has the problem that "12 09 2016" could mean "Dec 9 2016" or "Sep 12 2016" depending on user locale.
Use a date and time library. Moment.js is frequently mentioned in SO answers regarding such libraries.
Use the output of a date picker or validated data from a data base. Avoids issues with locale dependent formats.
Hard code conversion to ISO8061 format without parsing may be an option if the input string is absolutely guaranteed to be in "mm dd yyyy hh:mm:ss" format, as for example using
function isoFromZ( str) {
return str.substr(6,4) + "-" +
str.substr(0,2) + "-" +
str.substr(3,2) + "T" +
str.substring(11) + ".000Z";
}
In summary extract the UTC date and time components from a custom input string before creating a Date object. If extraction produced an ISO8061 date string it can be passed directly to the Date constructor as a parameter.
I have following datetime value in a json :
Fri Jan 22 2016 14:34:38 GMT-0500
I would like to display something like "January 22, 2016"
How could I achieve this in javascript. I have JQuery, Extjs libraries available.
Try creating object having properties of abbreviated months, values of full month, using for..in loop , String.prototype.slice(), String.prototype.replace()
var months = {
"Jan":"January",
"Feb":"February",
"Mar":"March",
"Apr":"April",
"May":"May",
"Jun":"June",
"Jul":"July",
"Aug":"August",
"Sep":"September",
"Oct":"October",
"Nov":"November",
"Dec":"December"
};
var date = "Fri Jan 22 2016 14:34:38 GMT-0500";
// extract "Jan 22 2016" from `date`
var d = date.slice(4, -18);
for (var prop in months) {
if (new RegExp(prop).test(d)) {
// replace abbreviated month with full month name
d = d.replace(prop, months[prop]);
// replace day with day followed by comma `,` character
d = d.replace(/(\d{2})(?=\s)/, "$1,")
}
}
document.body.textContent = d
This question is addressed to the same question of yours. You can use the functions shown here to construct the date string as you want.
// This could be any Date String
var str = "Fri Feb 08 2013 09:47:57 GMT +0530 (IST)";
var date = new Date(str);
This will then give you access to all the Date functions (MDN)
For example:
var day = date.getDate(); //Date of the month: 2 in our example
var month = date.getMonth(); //Month of the Year: 0-based index, so 1 in our example
var year = date.getFullYear() //Year: 2013
Extract date and time from string using Javascript
Found this crazy method here, but worked!
Converting milliseconds to a date (jQuery/JS)
Here is the fiddle that i'v done
https://jsfiddle.net/Ripper1992/hj6L2Lvz/
var now = new Date("Fri Jan 22 2016 14:34:38 GMT-0500");
alert(now.customFormat( "#MMMM# #DD#, #YYYY#" ) );
customFormat is the function called to get each part of the Data, parse and replace based on the #MMMM# or #DD# or #SS# defined by the user.
And here is the complete function with the documentation
http://phrogz.net/JS/FormatDateTime_JS.txt
I'm having a javascript object as below.
var obj = { pageSize:"25",asOfDate:"Thu Sep 25 00:00:00 UTC+0530 2014"};
when i stringify it,
var d = JSON.stringify(obj);
its giving me result as
{"pageSize":"25","asOfDate":"2014-09-24T18:30:00Z"}
what could be the reason that its giving date 2014-09-24 than 2014-09-25 ?
EDIT:
My deployment server is located in US (Eastern Time UTC -5:00).when i check the site from my local machine in india its giving me date as 24 Sept 2014
UTC+0530 declares a UTC time offset. Seems that 5:30 is around the India or Sri Lanka area.
"2014-09-24T18:30:00Z" is the same as "Thu Sep 25 00:00:00 UTC+0530 2014" in two different formats. The Z in the first format is resolving to UTC (GMT) time, which in this case is -5:30. So 18:30 is 24:00 - 5:30.
So, if you are stringify-ing in a timezone that is negative offset (say in the United States UTC−08:00) then it could push the date back by one day when parsing.
I think this is what you are seeing.
Related SO Question: JSON Stringify changes time of date because of UTC
Try this
var obj = { pageSize:"25",asOfDate:"Thu Sep 25 00:00:00 UTC+0530 2014"};
obj.asOfDate = reverseUTC(obj.asOfDate);
var d = JSON.stringify(obj);
function reverseUTC(updatedDate) {
if ($.isEmptyObject(updatedDate)) {
var offset = updatedDate.getTimezoneOffset();
var currentDateTime = new Date();
updatedDate.setHours((currentDateTime.getHours() * 60 + currentDateTime.getMinutes() - offset) / 60);
updatedDate.setMinutes((currentDateTime.getHours() * 60 + currentDateTime.getMinutes() - offset) % 60);
return updatedDate;
}
}
There is no standard format for passing dates in JSON, so JSON.stringify is just calling the default date.prototype.toString() method and that is taking the timezone into account.
You need to ensure that the date is converted into a string to your particular requirements and only convert to JSON format.
I have this - Tue, 03 Apr 2012 05:00:33 GMT
Need this - 20120323111106
Google has failed me, I think I just don't know exactly what im searching for so I kept it simple here with the question.
EDIT: The dates do not match obviously, just looking to get it in that format.
Good answer (later edited):
I think this is what you are looking for :
function addZero(val){
if (parseInt(val) < 10) return "0" + val;
return val;
}
var dt = new Date("Tue, 03 Apr 2012 05:00:33 GMT");
console.log(dt.getFullYear() + addZero(dt.getMonth()) + addZero(dt.getDay()) + addZero(dt.getHours()) + addZero(dt.getMinutes()) + addZero(dt.getSeconds()))
Initial wrong answer :
var dt = new Date("Tue, 03 Apr 2012 05:00:33 GMT")
var miliseconds = dt.getTime();
I've tested it and my computer converted it automatically to GMT +3 (my timezone), you can play with that according to your timezone.
Writing a function to parse a string should work for you. By the looks of it, any date string that you currently have will be the same length. If this is the case this should be relatively easy. Just make sure your strings are in this format before you pass them in as arguments.
function parse(string) {
var out = "yyyymmddhhmmss"
out.charAt(0) = string.charAt(13);
out.charAt(1) = string.charAt(14);
out.charAt(2) = string.charAt(15);
out.charAt(3) = string.charAt(16);
//if else statements for each month converting to numbers
if (string.substring(9,12).equals("Apr")) {
out.charAt(4) = '0';
out.charAt(5) = '4';
}
out.charAt(6) = string.charAt(18);
out.charAt(7) = string.charAt(19);
...etc for the remaining values
return out
}
My numbers for character indices may be off, but if you use this idea, it should set you straight. Define a function and pass in the dates in the format you have, and out will come the dates in the format you want.