Today I've encountered a problem with dates in JavaScript
I'm trying to display time is format: hour:minute. To do this i've written a test case:
var timeOpts = {hour: "2-digit", minute: "2-digit"};
var dt = new Date('2014-05-08T16:07:51+00:00');
console.log(dt.toLocaleTimeString('uk-UA',timeOpts))
This code works just fine in Chromium (displays 19:07) but in Firefox it does not output time in right format (displays 19:07:51)
If you're concerned about formatting dates correctly across several major browsers, I would go with Moment.js. You can format dates how you want and not worry about browser implementations of toLocaleTimeString(). If you want the format HH:mm, you would use this code:
var dt = new Date('2014-05-08T16:07:51+00:00');
var locale = moment(dt).format("HH:mm");
console.log(locale);
You may think that using Moment.js is a little more than you need, but it really is quite lightweight and it handles all the nitty gritty date manipulations for you and will take into effect browser differences and implementations.
Related
I have a date in UTC format `2020-06-19T03:55:12.000Z. Now i am converting into date of US timezone as
let syncDate = moment(date, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
.subtract(7, 'hours')
.format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
This gives me a date 7 hours behind which is date of US. But i want a date in below format
2020-06-18T21:00:24.523-07:00
Here if we can see the hours are defined as -7 so please guide how can we achieve the same ?
You can't extract a timezone out of your date because there is no timezone information in it. You said "I am converting into a date of US timezone as" But you didn't. You just reduced it for 7 hours. The timezone is still UTC.
You should use moment-timezone (not handling things the hard way and manually as #GetSet said). Here the solution:
const moment = require('moment');
const tz = require('moment-timezone');
let date = moment('2020-06-19T03:55:12.000Z');
let syncDate = date.tz('America/Los_Angeles')
console.log(syncDate.format());
But, I suggest you use Day.js. The code will be:
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
const dDate = dayjs('2020-06-19T03:55:12.000Z');
console.log(dDate.utcOffset(-7*60).format()); //2020-06-18T20:55:12-07:00
I used moment.js in the past. I tried Date-fnd for 24 hours. And finally, I moved to Day.js. It's new (start in late 2018) but it's growing so quick (take a look at this link and put the duration on 5 years). The great thing about it is that "IT ALWAYS DOES WHAT IT SAYS". Moment and Date-fns don't. (not always). It uses a wrapper and so you never work with the Date object directly. It solves difficulties and problems. It's immutable and always returns a new object and you can chain functions. Day.js has the smallest size (2kB).The documentation is awesome and you can up and running very fast. (It's more understandable that the way other libraries work.)
Here I have to say that Dayjs performance is not is good as Moment in calculations but is way better (than especially moment) in parsing and formating.
I strongly suggest you read this article: Why you shouldn't use Moment.js
Edit(1): As #GetSet mentioned in comments for OP that may need a solution in Moment.js I added it to the answer.
Edit(2): Adding the reason why you can't achieve your result the way OP solving it.
new Date() depends on local computer date setup - if any user has wrong date on his local computer - your system will take wrong dates from those users.
If you working with dates on background (storing in database or any other manipulations) - generate it on background (php, java etc.) and than send it to you html/javascript files.
you can use Date().toLocalString() method
// example:
var d = new Date().toLocalString("en-US", {
month: "long",
day: "2-digit",
year: "numeric",
});
for more information see:
https://www.w3schools.com/jsref/jsref_tolocalestring.asp
There are a couple of things it is vitally important to point out here.
There is no one US timezone, there are quite a few, for example America/Los_Angeles, America/Denver, America/Chicago, America/New_York, see the IANA Timezone list for all of them.
Please don't convert from one timezone to another using a fixed offset, this is really fragile. You wouldn't believe how many bugs I've seen in my career (from others, and yes, from myself!) due to this one mistake. Many timezones use Daylight Saving Time, so the UTC offset of the timezone varies by the date. For example, the Pacific Timezone currently varies between UTC-08:00 and UTC-07:00.
I would suggest using Moment Timezone to convert from one timezone to another.
For example:
const dateString = `2020-06-19T03:55:12.000Z`;
const timezones = ["America/New_York", "America/Chicago", "America/Denver", "America/Los_Angeles"];
console.log(`Time in UTC:`, moment(dateString).toISOString());
// Show the time in each timezone
timezones.forEach(timezone => {
let timeLocal = moment.tz(dateString, timezone);
console.log(`Time in ${timezone}:`, timeLocal.format('YYYY-MM-DD[T]HH:mm:ss.SSSZ'))
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js">
</script>
My service is returning this as date 7/14/2016 2:40 AM +00:00. How can I convert this to UTC in JS?
Tried:
new Date("7/14/2016 2:40 AM +00:00").toISOString();
In database the date has been stored as UTC so when I will display the date I want to display as Local time.
There are many ways to parse a string to produce a Date object.
One way is with the Date object itself, either by passing a string to the constructor, or by using Date.parse. However, only the ISO8601 formats are required in the ECMAScript specification. Any other input is implementation specific, and may or may not be recognized by the different JavaScript runtimes. With web browsers in particular, there are many differences in supported formats across browsers.
Additionally, the locale of the environment plays a factor in how the values are parsed. How should 1/2/2016 be parsed? January 2nd, or February 1st? You showed an example of 7/14/2016, which would be invalid input if ran in the UK (for example), where the date format is DD/MM/YYYY.
You can write custom code to split the string up into its parts, parse each part individually, and compose a result. The main problem with this approach is that the code tends to be rigid, and sometimes fragile. It should be well tested, and many edge cases need to be considered.
You can use a library, which is by far the easiest and most flexible approach (IMHO). With a good library, you can take comfort in the shared experiences of others, and in the unit tests that are (hopefully) part of the library you choose. Of course, using a library comes with several tradeoffs including increased file size, and relinquishing some degree of control. You should evaluate these tradeoffs carefully.
There are many date libraries available for JavaScript. The most popular is probably moment.js, though there are others to choose from, and some larger frameworks sometimes have similar functionality already included.
Here is an example using moment.js:
var i = "7/14/2016 2:40 AM +00:00";
var f = "M/D/YYYY h:mm A Z";
var m = moment(i, f);
var o = m.format(f); // will be in the local time, in the same format as the input
var d = m.toDate(); // if you really want a Date object
Assuming you can guarantee that format for all dates, the following code will suffice:
const datetime = '7/14/2016 2:40 PM +00:00'; // this is what your service returns
const pieces = datetime.split(/[/: ]/);
if (pieces[3] == 12) pieces[3] = 0; // fixes edge case for 12 AM/PM
const hours = pieces[5] === 'PM' ? Number(pieces[3]) + 12 : pieces[3];
const d = new Date(Date.UTC(pieces[2], pieces[0] - 1, pieces[1], hours, pieces[4]));
console.log(datetime); // prints "7/14/2016 2:40 PM +00:00"
console.log(d); // prints Date 2016-07-14T14:40:00.000Z
EDIT: There's a couple edge cases with this not handled correctly, namely 12 AM/PM, etc. but those can easily be worked around as well.
EDIT2: Accounted for that edge case.
EDIT3: As a comment stated, this will only work for UTC times. If the string you're receiving can have any offset, this will not work.
var str = "7\/15\/2016 1:00 AM +00:00".replace("+00:00","UTC");
console.log(new Date(str).toISOString()); // 2016-07-15T01:00:00.000Z
According to this answer, Firefox and Chrome accepts the format "YYYY MM DD" while creating a date object.
However, Edge doesn't allow new Date("YYYY MM DD") and wants to be initialized as: new Date("YYYY-MM-DD")
So, should i first check which browser is being used before creating a date object or is there a common pattern by which an date object can be created?
I'm not sure I understant your question because for what I've tried firefox allows you to use new Date("YYYY-MM-DD") and so you could use that and avoid the problem with Edge by using always that, anyway if you're getting an Invalid Date this is my solution by example:
var date;
date = new Date("10 01 01"); //invalid date
if(isNaN(date.getDay())){
date = new Date("2010-01-01")
}
Hope this helps you
As mentioned in the previous answer, new Date("YYYY-MM-DD") should work in Firefox. Test this sample code, for example: http://www.w3schools.com/js/tryit.asp?filename=tryjs_date_string_iso1.
There is a separate issue here related to dates that you may have run into, and that is the aligning of UTC dates with user time zones. This thread has more information about this issue and how to accommodate it: Javascript date object always one day off?
Hope this addresses your concerns!
I've got an odd situation going on here. I've got the following JSON being passed to the time line control:
[
{
"UserId": 2,
"ItemId": 3,
"ItemText": null,
"ItemDate": "2014-06-09T18:51:37",
"ItemDateEnd": null,
"OutcomeScore": null
},
...
]
This is a simple of array of items that I pass to the control to render. In Firefox this renders perfectly, no problems whatsoever. However, Every other browser I've tried it on shows the items +1 hour. I've tried it in Opera, Chrome and IE9 and they are all showing the same problem apart from Firefox. The now time displays as expected on all browsers.
Interestingly I'm in GMT summer time at the moment which is +1h ... but why would this selectively effect browsers differently?
Each browser is running exactly the same query and getting exactly the same JSON. I'm very confused and not even sure where to start looking.
I'm running v2.5.0 of the time line. I've tried updating to the latest version and the same thing occured so I rolled back to 2.5.0 to get the solved before working on getting the latest version integrated into the page.
Anyone seen this and have a solution?
First, note that the Timeline of the CHAP Links library does not support strings as Date, you should provided Dates or a timestamp with a Number (note that the successor of the Timeline, vis.js, does support strings as date). Strings as Date work nowadays because most browsers now support creating dates from an ISO date string.
The issue you have is because you provide an ISO Date String without time zone information. Apparently not all browsers have the same default behavior in that case. Enter the following in a JavaScript console in both Firefox and an other browser:
new Date("2014-06-09T18:51:37").toISOString()
// output is ambiguous, time zone information missing
and you will see them adding timezone information in different ways. To prevent these kind of ambiguities, you should provide timezone information yourself. To specify the time in UTC, add a Z to the end of the string:
new Date("2014-06-09T18:51:37Z").toISOString()
// output is unambiguous
Creating Date objects from strings is unreliable, as you have observed. You should manually parse those strings into Date objects, like this:
// assumes date string is in the format "yyyy-MM-ddTHH:mm:ss"
var dateMatch = dataItem.ItemDate.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/);
var year = parseInt(dateMatch[1], 10);
var month = parseInt(dateMatch[2], 10) - 1; // convert to javascript's 0-indexed months
var day = parseInt(dateMatch[3], 10);
var hours = parseInt(dateMatch[4], 10);
var minutes = parseInt(dateMatch[5], 10);
var seconds = parseInt(dateMatch[6], 10);
var date = new Date(year, month, day, hours, minutes, seconds);
I have a webpage that creates a date from a string. It works fine except for the iphone where I get invalid date.
I have read a small bit about IOS handling dates a little differnt but have not been able to see a fix.
I have opened the page in the stock browser and the latest release of Chrome and get the same error. Works on Android and PC.
dateString = "2013-08-06"
date = new Date(dateString);
I have tried this fix but same error
var arr = "2010-03-15 10:30:00".split(/[- :]/),
date = new Date(arr[0], arr[1]-1, arr[2], arr[3], arr[4], arr[5]);
I just had an issue like this yesterday, but with internet explorer. I found that using a cross-browser date library like moment.js helped alleviate the issue:
var date = "2013-03-15 10:30:00";
date = moment(date, "YYYY-MM-DD HH:mm:ss").toDate();
Its just a wrapper around the date object, so the toDate() function returns its date object. If you want to take advantage of the formatting options moment provides, just remove the toDate().