Taking UTC time from database and displaying local time in browser - javascript

I have a table that contains DateTimes in UTC. I'm using PHP to return these date/time strings to an AJAX request in JSON. An example of one of these strings I am receiving on the front end is "2014-12-22 09:36:54". I would like to display this to the user in their local time. For instance I am 8 hours behind UTC time in California, so I would like to see something like "2014-12-22 01:36:54".
In javascript I tried new Date("2014-12-22T09:36:54").toLocaleString() and got "12/22/2014, 9:36:54 AM"---basically an unchanged date/time.
I tried new Date("2014-12-22T09:36:54").toUTCString() and I got "Mon, 22 Dec 2014 17:36:54 GMT", which is pretty much the opposite of what I wanted. But I guess that should have been obvious.
Last thoughts...:
Am I going to have to do some manipulation involving getTimezoneOffset()?
Would this be easier solved on the PHP backend?
One last note is that I included jstz.js thinking it would help but all it does is return the timezone name, and I don't know how that is particularly useful. Does any function take the name of a timezone as an argument which would be helpful in this situation?

To reliably convert a UTC string like "2014-12-22 09:36:54" to local, manually parse it, e.g.:
function parseISOAsLocal(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0], b[1]-1, b[2], b[3], b[4], b[5]));
}
An ISO 8601 compliant string without a timezone must be treated as UTC according to the current ECMA-262 standard (ed5). However, the draft version 6 changes that to treat them as local (per ISO 8601). Most browsers treat it as UTC, however Chrome treats it as local (and IE 8 as NaN). Much better to manually parse date strings and avoid browser vagaries.

Related

Javascript - Display date time and ignore locale/timezone

I am having a bit of a nightmare working with a CMS that saves datetimes without timezones. For a wide variety of infrastructure reasons I am unable to adjust core files, I can only adjust some of the javascript of the CMS field itself, and not include external libraries (or the dayjs UTC plugin).
How it currently works:
CMS Saves datetime string like so: 2020-10-29 05:00 which is missing the timezone
When reloading, the dayjs parses the string 2020-10-29 05:00 as UTC and changes the time based on the browser locale.
If you are using a browser that it not UTC, the time displayed will not correspond to the saved string
My hacky idea:
When loading the string, get the browser's timezone
Modify the string 2020-10-29 05:00 to include the browser's timezone, or offset the date object so that when it is parsed as 'local', it will display correctly
My initial thought was just to add/subtract the offset before displaying but it still didn't seem to work (I think due to getTimezoneOffset not adjusting for daylight savings?):
let date = new Date('2020-10-29 05:00')
console.log(new Date(date.setMinutes(date.getMinutes() + new Date().getTimezoneOffset())))
I suppose an alternate form of this question is: Is there a way to parse a UTC datetime string as though it were local?
If the string is UTC, you should parse it as UTC and then do everything in UTC. I think the easiest way is to parse the string as UTC with your own function or library.
Also, given:
new Date('2020-10-29 05:00')
some browsers will return an invalid date (they treat it as a malformed version of the supported format YYYY-MM-DDTHH:mm:ss).
Generally, using the built–in parser is strongly discouraged because of browser inconsistencies. Also, messing with timezone offsets can also lead to difficult to find issues (like when applying the offset causes the date to cross a DST boundary).
A simple function to do the job:
function parseAsUTC(s) {
let [y, m, d, H, M] = s.split(/\D/);
return new Date(Date.UTC(y, m-1, d, H, M));
}
let s = '2020-10-29 05:00';
console.log(parseAsUTC(s));

How to change only timezone without modifying the time in momentz

I have date and time in 2016-06-21T10:00:00-07:00 format which represets 06/21/2016 5 PM in PST, I just want to change this to 06/21/2016 5 PM in EST and vice versa. How can I do it with momentz?
JSFiddle
debugger;
var dateTime = moment('2016-06-21T10:00:00-07:00');
var newDateTime = dateTime.clone();
newDateTime.tz('US/Eastern');
//dateTime = dateTime.utc();
console.log(dateTime.utcOffset());
console.log(newDateTime.utcOffset());
console.log(newDateTime.utcOffset() - dateTime.utcOffset());
//console.log(utc.format());
dateTime = dateTime.add(newDateTime.utcOffset(), 'minutes');
console.log(dateTime.format());
console.log(new Date(Date.parse(dateTime.format())).toJSON());
EDIT:
given input = 2016-06-21T08:00:00-07:00 (PST)
expected output = 2016-06-21T08:00:00-04:00 (EST)
So when I convert that to UTC then it should become
2016-06-22T15:00:00Z for PST
2016-06-22T12:00:00Z for EST
I think you are confused about how ISO8601 format works. This format always represents local time with a time zone offset. Thus 2016-06-21T10:00:00-07:00 represents June 21 2016 at 10 AM in a timezone that is currently UTC-7 (this could be US pacific, among many others).
It sounds like you want to take the local time, but put it in a new timezone. This opens up some interesting questions about why you are receiving the date in the format that you are. If the date is meant to be interpreted as an exact point on the global timeline, then the format you are receiving it in is good. If however, the date is meant to be interpreted as a local time (not relative to UTC), it might be worth considering the possibility that the format of the date needs to be changed at the source. For instance, if you are making an ajax request to an API, and it is returning a date in this format, but that date actually has no relationship to UTC, it would be good to try to change that API to only send the local time (without the offset). If you were able to do that, then the following code would work:
moment.tz('2016-06-21T10:00:00', 'America/New_York').format()
"2016-06-21T10:00:00-04:00"
If you are unable to do that, or if the date is meant to be interpreted as an exact point on the global timeline, but you wish to ignore that in your specific use case, that can be done. You will need to specify a parse format that ignores the timezone offset on your initial time stamp. The code would be as follows:
moment.tz('2016-06-21T10:00:00-07:00', 'YYYY-MM-DDTHH:mm:ss', 'America/New_York').format()
"2016-06-21T10:00:00-04:00"
You might benefit from the material in this blog post, as it covers how ISO8601 format works, and how all of moment's constructor functions work.
Checkout moment().utcOffset() You can pass in the offset as parameter to this function and the date would use that locale.
Assuming you know beforehand the utcOffsets required which in your case are -420 and -240 or -300(EST with DayLightSaving). Below can be done
var dateTime = moment('2016-06-21T10:00:00-07:00');
dateTime.utcOffset(-420).format();
"2016-06-21T10:00:00-07:00"
dateTime.utcOffset(-240).format()
"2016-06-21T13:00:00-04:00"
NOTE: With -04:00, it should 13:00:00 and not 07:00:00 - http://www.timeanddate.com/time/zones/est
EDIT: This answer was posted to the earlier version of question, where same time was needed in different timezones. If it is incorrect, kindly please elaborate on how it is.
Thanks!

JS Date() - Leading zero on days

A leading zero for the day within a string seems to break the Javascript Date object in Chrome. There are also some inconsistencies between browsers, since Firefox handles the leading zero correctly, but fails when the zero is not included. See this example: https://jsfiddle.net/3m6ovh1f/3/
Date('2015-11-01'); // works in Firefox, not in Chrome
Date('2015-11-1'); // works in Chrome, not in Firefox
Why? Is there a good way to work around/with the leading zero?
Please note, the strings are coming from MySQL via AJAX and all dates will contain the leading zero, and I can fix this by formating the dates server-side. What format would work the best?
EDIT
Just to specify what my problem was, it looks like Chrome is applying a time zone to the YYYY-MM-DD format, which reverts the Nov. 1st date back to the Oct. 31st date (because of my EDT local time).
According to ECMA-262 (5.1):
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.
The date/time string format as described in 15.9.1.15 is YYYY-MM-DDTHH:mm:ss.sssZ. It can also be a shorter representation of this format, like YYYY-MM-DD.
2015-11-1 is not a valid date/time string for Javascript (note it's YYYY-MM-D and not YYYY-MM-DD). Thus, the implementation (browser) is able to do whatever it wants with that string. It can attempt to parse the string in a different format, or it can simply say that the string is an invalid date. Chrome chooses the former (see DateParser::Parse) and attempts to parse it as a "legacy" date. Firefox seems to choose the latter, and refuses to parse it.
Now, your claim that new Date('2015-11-01') doesn't work in Chrome is incorrect. As the string conforms to the date/time string format, Chrome must parse it to be specification compliant. In fact, I just tried it myself -- it works in Chrome.
So, what are your options here?
Use the correct date/time format (i.e. YYYY-MM-DD or some extension of it).
Use the new Date (year, month, date) constructor, i.e. new Date(2015, 10, 1) (months go from 0-11) in this case.
Whichever option is up to you, but there is a date/time string format that all specification compliant browsers should agree on.
As an alternative, why not use unix timestamps instead? In JavaScript, you would would multiply the timestamp value by 1000,
e.g
var _t = { time: 1446220558 };
var _d = new Date( _t.time*1000 );
Test in your browser console:
new Date( 14462205581000 );
// prints Fri Oct 30 2015 11:55:58 GMT-0400 (EDT)
There's a little benefit in it as well (if data comes via JS) - you'd save 2 bytes on every date element '2015-10-30' VS 1446220558 :)

javascript timezone format

I need to format a javascript Date to send via json to the server. The server expects the time to be in the format according to this example
2011-08-31T06:49:28.931 -0700
which it conveniently tells me when I try to submit something like
2011-08-31T06:49:28.931 -07:00
The trouble I am having is with the timezone part, -0700. I've been looking at the Date API, and don't see a way to specify the timezone format. I can do d.getTimezoneOffset, but it returns 240 (Im in EDT I think) for me.
So, I can convert 240 to 0400 to represent 4 hours. I am worried however about correctness for other timezones. My questions are
1) How to convert the result of the getTimezoneOffset() into the required format, and how to determine what the sign should be (thats the part I am worried about)?
2) Is there a way to get the format off the date object itself so I don't have to do anything custom? If i do d.toString() I get "Wed Aug 31 2011 09:48:27 GMT-0400 (EDT)", so here the timezone part is in the format I want. So it might be possible. Maybe the best solution is to just use a regex to grab the timezone off d.toString()...
3) Extra credit: is the format the server requires some sort of standard?
Update: using match(/^.*GMT(-?\d*)/) returns "-0400" at index 1 of the array. Perhaps I should just use that? Im wondering if that regex will work for all timezones in the context of the sign.
Try this code:
var d=new Date(Date.now()); // sets your date to variable d
function repeat(str,count) { // EXTENSION
return new Array(count+1).join(str);
};
function padLeft(str,length,char) { // EXTENSION
return length<=str.length ? str.substr(0,length) : repeat(String(char||" ").substr(0,1),length-str.length)+str;
};
var str=padLeft(String(d.getFullYear()),4,"0")+"-"+
padLeft(String(d.getMonth()),2,"0")+"-"+
padLeft(String(d.getDate()),2,"0")+"T"+
padLeft(String(d.getHours()),2,"0")+":"+
padLeft(String(d.getMinutes()),2,"0")+":"+
padLeft(String(d.getSeconds()),2,"0")+"."+
d.getMilliseconds();
//str+=" GMT";
var o=d.getTimezoneOffset(),s=o<0?"+":"-",h,m;
h=Math.floor(Math.abs(o)/60);
m=Math.abs(o)-h*60;
str+=" "+s+padLeft(String(h),2,"0")+padLeft(String(m),2,"0");
alert(str);
You might want to use one of the date/time formatting libraries that bakes in support for this timezone format (such as http://jacwright.com/projects/javascript/date_format/). In any case, you're right: there really is no good way to control the format output.
As far as the regex goes I don't know that all browsers consistently use the GMT string format, so that may not be the best path forward.

json dates and timezones

I have the following code:
$(function () {
var thedate = "/Date(1198908717056)/";
var thedate2 = ProcessDate(thedate)
alert(thedate2);
});
function ProcessDate(DateString) {
var TheDate = eval(DateString.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
return TheDate;
}
When it runs, it returns an alert with December 29 and the time is showing as Eastern Time. When I change the timezone on my computer, it's still showing the date in the Eastern timezone.
My question is this: does the string "/Date(1198908717056)/" contain the timezone information or is the timezone displayed in the alert the result of the browser determining my timezone?
Thanks.
JSON doesn't have dates at all (it's one of JSON's flaws). Those strings are just strings.
Some frameworks, like ASP.Net, use that syntax to indicate dates. What timezone they're in will be dictated by the framework. I believe the dates are in UTC and so you can just use the new Date(Number) constructor to create them (more in this other answer). That creates the date by directly setting its internal "milliseconds since The Epoch UTC" value, more in section 15.9 of the specification. Mind you, that only works if, in fact, whatever it is creating these pseudo-date strings is using UTC.
Update: Looking at your code, although it works, this line:
var TheDate = eval(DateString.replace(/\/Date\((\d+)\)\//gi, "new Date($1)"));
...is an abuse of eval. eval should be avoided whenever possible. Instead, if you want to keep it as a one-liner:
var TheDate = new Date(Number(DateString.replace(/\/Date\((\d+)\)\//gi, "$1")));
...or somewhat more readably:
var Match = /\/Date\((\d+)\)\//gi.exec(DateString);
var TheDate;
if (Match) {
TheDate = new Date(Number(Match[1]));
}
In all of those cases, the Date will be initialized with the UTC time value embedded in the date string. But then when you ask JavaScript to format the date (for instance, via toString), it will use your local timezone to do that. You haven't shown how you're outputting the date, so I can't tell you why the timezone seems not to change if you change your timezone (perhaps the browser didn't pick up the change?). When I do it, if I output the date as a string, it shows it in British Summer Time (which is my current timezone) if I use toString, or UTC if I use toUTCString. Here's a live example using both your original date, and a date (today's date, as I write this) that's in daylight savings time so even in the UK you can see the difference between UTC and local time.
Off-topic: In JavaScript, the overwhelming convention is to use camelCased names starting with a lower-case letter for both local variables and function names. So, theDate rather than TheDate. Initial caps are reserved for constructor functions (like Date). You're free to ignore the convention, of course, but it will tend to make it difficult for others to read your code.
The timezone is taken from your current system setting. Have a look at the Date class.
The given value is in milliseconds and does not contain a timezone. The constructor of Date() expects the milliseconds to be given in UTC. If you have values with a known timezone, you should use the dateString constructor version.
However, as far as I know, there is no way convert between timezones in JavaScript, except for UTC and the local system timezone.

Categories

Resources