How to parse date string from database without time shift? - javascript

I am getting 2016-07-13T00:00:00.000Z string from database and converting it to MM/DD/YYYY format with moment.js like this:
result = moment('2016-07-13T00:00:00.000Z').format('MM/DD/YYYY');
which prints 07/12/2016 but I was expecting 07/13/2016.
Local Linux timezone is America/New_York. date command prints this Mon Jul 4 04:28:19 EDT 2016

The date that you have is in UTC, as signified by the z at the end.
When you use the default moment constructor, moment(), it converts the time you pass it from the specified offset (in this case UTC) to the local time of the machine. This is why your date is changing. Because this is a UTC date, to keep it exactly the same you can use moment.utc():
moment.utc('2016-07-13T00:00:00.000Z').format('MM/DD/YYYY');
"07/13/2016"
Alternately, parseZone would work as well:
moment.parseZone('2016-07-13T00:00:00.000Z').format('MM/DD/YYYY');
"07/13/2016"
For more information about all of the constructor functions in moment, see the parsing guide
or this blog post

You should use momentjs timezone : http://momentjs.com/timezone/
yourdate = moment.tz("2016-07-13T00:00:00.000Z", "America/New_York");
alert(yourdate.format('MM/DD/YYYY'));
This should give you the correct date in output.

Related

Javascript wrong/different date time is extracted from the UTC converted date

I have a date in local format , I changed it to UTC format . After UTC i want to extract date and time in UTC . But whenever I am trying to extract time or date for that matter , it is considering local time only , why is that ?
this.utcDate = this.datePipe.transform(this.onceDate,'medium');
console.log('+=timezonenene=+', this.utcDate);
this.utcDateStr = new Date(this.utcDate).toUTCString();
console.log('++ date is ++', this.utcDateStr);
this.utcDateStr = new Date(this.utcDateStr).toISOString();
console.log('++ date is ++', this.utcDateStr);
this.showDate = this.datePipe.transform(this.utcDateStr, 'yyyy-MM-dd');
this.showTime = this.datePipe.transform(this.utcDateStr, 'HH:mm');
console.log('+=time date zonenene date str =+', this.showDate);
console.log('+=timezonenene date str=+', this.showTime);
output :
+=timezonenene=+ Apr 7, 2020, 5:41:16 PM
++ date is ++ Tue, 07 Apr 2020 12:11:16 GMT
++ date is ++ 2020-04-07T12:11:16.000Z
+=time date zonenene date str =+ 2020-04-07
+=timezonenene date str=+ 17:41
I want last logged time as : 12:11 not 17:41
Your question appears to be about the Angular DatePipe (though you're calling the transform function directly).
From the docs about the timezone parameter:
When not supplied, uses the end-user's local system timezone.
Thus, to get UTC output, you can change your code to provide the time zone parameter 'UTC' after the format parameter, on each call to datePipe.transform.
Also, I'd reconsider why you are producing strings just to parse them again. Usually this is unnecessary, and can lead to errors. if this.onceDate is a Date object, you should be able to use that throughout your code, rather than creating this.utcDateStr just to parse and transform it again. (Though it's difficult to tell from your code if that is the case. In the future, please supply a minimal, reproducible example.)

Alternative to casting UTC Date in Javascript?

I wish to create a new Date in JS, but have it be cast as UTC time. For example, suppose castAsUTC() produces the following desired effect:
var x = new Date('2019-01-01T00:00:00') // In local time (PST)
castAsUTC(x).toISOString(); // => '2019-01-01T00:00:00Z'
// x.toISOString() gives us '2019-01-01T08:00:00Z', which is undesired
Currently, my function looks like this:
function castAsUTC(date) {
return new Date(x.toLocaleString() + '+00:00');
}
Is there a cleaner/nicer way of producing the same effect? Thanks in advance!
EDIT: To be more specific, I'm interested in transforming the date's timezone, without changing its actual value with as little arithmetic as possible. So calling .toISOString() will produce the same date as it is in local time.
I am currently using the moment-timezone library, but I can't seem to get the desired effect using that, either. I would definitely accept an answer that uses Moment.js
You can switch a Moment instance to UTC using the utc function. Then just use format to get whatever the specific output you want from it.
If indeed the string you have is like the one shown, then the easiest thing to do would be to append a Z to indicate UTC.
var input = '2019-01-01T00:00:00';
var date = new Date(input + 'Z');
var output = date.toISOString();
Or, if you would like to use Moment.js, then do this:
var input = '2019-01-01T00:00:00';
var m = moment.utc(input);
var output = m.format();
You do not need moment-timezone for this.
tl;dr;
You formatted the date wrong. Add the letter "Z" to the end of your date string and it will be treated as UTC.
var x = new Date('2019-01-01T00:00:00Z') // Jan 1, 2019 12 AM UTC
These formatting issues are easier to manage with a library like momentjs (utc and format functions) as described in other answers. If you want to use vanilla javascript, you'll need to subtract out the timezone offset before calling toISOString (see warnings in the longer answer below).
Details
Date in javascript deals with timezones in a somewhat counter intuitive way. Internally, the date is stored as the number of milliseconds since the Unix epoch (Jan 1, 1970). That's the number you get when you call getTime() and it's the number that's used for math and comparisons.
However - when you use the standard string formatting functions (toString, toTimeString, toDateString, etc) javascript automatically applies the timezone offset for the local computers timezone before formatting. In a browser, that means it will apply the offset for the end users computer, not the server. The toISOString and toUTCString functions will not apply the offset - they print the actual UTC value stored in the Date. This will probably still look "wrong" to you because it won't match the value you see in the console or when calling toString.
Here's where things really get interesting. You can create Date's in javascript by specifying the number of milliseconds since the Unix epoch using new Date(milliseconds) or by using a parser with either new Date(dateString). With the milliseconds method, there's no timezone to worry about - it's defined as UTC. The question is, with the parse method, how does javascript determine which timezone you intended? Before ES5 (released 2009) the answer was different depending on the browser! Post ES5, the answer depends on how you format the string! If you use a simplified version of ISO 8601 (with only the date, no time), javascript considers the date to be UTC. Otherwise, if you specify the time in ISO 8601 format, or you use a "human readable" format, it considers the date to be local timezone. Check out MDN for more.
Some examples. I've indicated for each if javascript treats it as a UTC or a local date. In UTC, the value would be Jan 1, 1970 at midnight. In local it depends on the timezone. For OP in pacfic time (UTC-8), the UTC value would be Jan 1, 1970 at 8 AM.
new Date(0) // UTC (milliseconds is always UTC)
new Date("1/1/1970"); // Local - (human readable string)
new Date("1970-1-1"); // Local (invalid ISO 8601 - missing leading zeros on the month and day)
new Date("1970-01-01"); // UTC (valid simplified ISO 8601)
new Date("1970-01-01T00:00"); // Local (valid ISO 8601 with time and no timezone)
new Date("1970-01-01T00:00Z"); // UTC (valid ISO 8601 with UTC specified)
You cannot change this behavior - but you can be pedantic about the formats you use to parse dates. In your case, the problem was you provided an ISO-8601 string with the time component but no timezone. Adding the letter "Z" to the end of your string, or removing the time would both work for you.
Or, always use a library like momentjs to avoid these complexities.
Vanilla JS Workaround
As discussed, the real issue here is knowing whether a date will be treated as local or UTC. You can't "cast" from local to UTC because all Date's are UTC already - it's just formatting. However, if you're sure a date was parsed as local and it should really be UTC, you can work around it by manually adjusting the timezone offset. This is referred to as "epoch shifting" (thanks #MattJohnson for the term!) and it's dangerous. You actually create a brand new Date that refers to a different point in time! If you use it in other parts of your code, you can end up with incorrect values!
Here's a sample epoch shift method (renamed from castAsUtc for clarity). First get the timezone offset from the object, then subtract it and create a new date with the new value. If you combine this with toISOString you'll get a date formatted as you wanted.
function epochShiftToUtc(date) {
var timezoneOffsetMinutes = date.getTimezoneOffset();
var timezoneOffsetMill = timezoneOffsetMinutes * 1000 * 60;
var buffer = new Date(date.getTime() - timezoneOffsetMill);
return buffer;
}
epochShiftToUtc(date).toUTCString();

moment-timezones.js, how to convert date in spesific timezone to utc, disregarding my local timezone?

my system uses timezone UTC+03:00 ,
im trying to get a date in string format, represented by NY timezone,
and convert it to a Date object in utc
const dateInNY = moment.tz(xlsxDate, "M/D/YYYY h:mm a", "America/New_York")
.tz("Z").toDate();
doesnt work correctly
how am i even suppose to convert to utc time?
-----------edit---------------
i got it to work, using the timezone "Africa/Accra" , where UTC offset is 0, and ther is no daylight savings time:
moment.tz(xlsxDate, "M/D/YYYY h:mm a", "America/New_York").tz("Africa/Accra")
but this solution is a bad workaround, and if the government of Accra decide to change the time laws, will stop working!
is there a way to set the utc offset to 0 in momentjs-timezones?
As Álvaro González mentioned, that Date object does not contain Time zone information.
I do the following:
new Date(moment.tz(date, currentTimezone).tz(newTimezone).format('YYYY/MM/DD HH:mm:ss'))
where date is a date object or a string (e.g. '2017-10-30 16:30:00.0000')
so, I change date from currentTimezone to newTimezone and after that new Date object will be returned
Let's change '2017-10-30 16:30:00.0000' from UTC to America/Toronto (UTC-4)
new Date(moment.tz(date, 'UTC').tz('America/Toronto').format('YYYY/MM/DD HH:mm:ss'))
And I got
Mon Oct 30 2017 12:30:00 GMT+0400
GMT+0400 is my timezone and console.log() just shows it with any
date object and it can mislead you. Please, don't look at the this
timezone.
Let's change '2017-10-30 16:30:00.0000' from Europe/Samara (UTC+4) to America/Toronto (UTC-4)
new Date(moment.tz('2017-10-30 16:30:00.0000', 'Europe/Samara').tz('America/Toronto').format('YYYY/MM/DD HH:mm:ss'))
Firstly, moment.tz undertands that date has no timezone information and associate with Europe/Samara (UTC+4)
timezone. After that computes difference between new and old
timezone (it's -8 hours in this case)
And returns result
Mon Oct 30 2017 08:30:00 GMT+0400
And answer on your question
If xsltDate is a date object or string which do not contain timezone information
dateUTC = new Date(moment.tz(xlsxDate, "America/New_York").tz("UTC").format('YYYY/MM/DD HH:mm:ss'));
If xsltDate contain timezone information (e.g.'2013-06-01T00:00:00-04:00'), then no need to tell moment.tz which timezone xlsxDate has, just mention a new timezone
dateUTC = new Date(moment.tz(xlsxDate, "UTC").format('YYYY/MM/DD HH:mm:ss'));
Short answer is that you cannot.
The .toDate() method of the Moment library returns a native Date object. Such objects do not keep memory of any specific time zone (that's one of the reasons to use Moment in the first place), they just keep track of the exact time moment represented and merely pick a time zone when formatting to string, which is either UTC or the browser's time zone (not an arbitrary one).
The long answer is that you're probably getting correct results but are printing them with a method that uses the browser's time zone.
i found a function that does what i was trying to do, it belongs to the momentjs library itself: utcOffset(n) sets the offset to n.
(i also had to explicitly write the date string format correctly, thanks VincenzoC)
this is the code i was trying to write:
const dateInNY = moment.tz(xlsxDate, "M/D/YYYY h:mm a", "America/New_York");
const dateUTC = dateInNY.utcOffset(0).toDate();
however, the toDate function changes the timezone to my local timezone anyway, so .utcOffset(0) is redundat, and i can just use moment this way:
const dateInNY = moment.tz(xlsxDate, "M/D/YYYY h:mm a", "America/New_York");
const dateUTC = dateInNY.toDate();
and change the Date objects date to utc time later (in my case, the JSON.stringify stuff i use later does that for me)

JavaScript displaying correct date from dates stored as UTC on server

I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing. How do I go about displaying the correct time from UTC?
It appears that your json response contains a string valued which are in ISO8601 format in UTC, and then you are creating Date objects from them.
This part of your code is fine:
if (element.createdDate) element.createdDate = new Date(element.createdDate.toString());
You parse the string, and the resulting Date object is correct.
However, you don't need to use .toString() here, as the value is already a string. That is redundant.
This part of your code is the problem:
console.log("javascript date: " + new Date(element.depositDate.getUTCDate().toString()));
The getUTCDate function returns just the date of the month. Don't use that.
No matter what you do to create the Date object, ultimately you create a Date object and you're relying upon an implicit string conversion to output it. This will have different behavior in different browsers.
Consider console.log(new Date()):
In Chrome, this logs something like Fri Mar 17 2017 12:14:29 GMT-0700 (Pacific Daylight Time) on my computer. This is as if I called console.log(new Date().toString()); It is in an RFC 2822 like format (but not quite), and is represented in local time.
In Firefox, this logs something like 2017-03-17T19:14:46.535Z. This is as if I called console.log(new Date().toISOString()); It is in ISO8601 format, and is represented in UTC.
The point is, don't rely on implicit undefined behavior. If you must work with Date objects, then you should use console.log(element.createdDate.toISOString()) to see the ISO8601 representation of the UTC time.
If you're going to be doing a lot of things with dates and times, you may prefer to use a library, such as Moment.js, which can make tasks such as this more clear.
I have dates stored in my database in UTC format and calling
element.createdDate = new Date(element.createdDate.toString());
results in displaying the wrong date.
2016-10-11T00:00:00Z and Mon Oct 10 2016 20:00:00 GMT-04:00 (EDT) are exactly the same moment in time. The only difference is that one is displayed in ISO 8601 extended format with timezone offset 00:00 and the other is displayed in an RFC 2822 (like) format with timezone offset -04:00 (and assumes a locality in the EDT region).
calling
element.createdDate = new Date(element.createdDate.toUTCString());
returns nothing.
That is unusual. Typically it would return either a string or an error, but without a working example or any code to provide context it's impossible to say why.
How do I go about displaying the correct time from UTC?
You haven't specified what "correct" is. You are displaying a date and time for the same moment in time, just in a different format and time zone.

Convert ISO Date string to date in JavaScript

Need help to convert exactly from ISO Date string to Date:
I have an ISO string date: "2016-01-23T22:23:32.927".
But when I use new Date(dateString) to convert Date, the result is wrong:
var date = new Date("2016-01-23T22:23:32.927");
The result is: Sun Jan 24 2016 05:23:32 GMT+0700. It's not true. I want the date is 23 not 24.
Please help me. Thanks a lot!
You need to supply a timezone offset with your iso date. Since there isn't one, it assumes the date to be in GMT and when you log it out, it prints it in the timezone of your browser. I think that if you pass "2016-01-23T22:23:32.927+07:00" to new Date() you would get the value you are expecting.
JavaScript environments (browser, node,...) use a single timezone for formatting dates as strings. Usually this is your system's timezone. Based on the output you get, yours is GMT+0700.
So what happened:
The string you passed as ISO format to the Date constructor doesn't specify a timezone. In this case it is treated as UTC.
When you then output the date (I'll assume with console.log), it is converted to the timezone of your environment. In this case 7 hours where added.
If that doesn't suit you, you can change the way you output the date. This depends on what output you want, e.g.:
If you just want the UTC timezone again, you can use date.toISOString().
If you want to output it in another timezone, you can call date.getTimezoneOffset() and figure out the difference between both timezones. You'd then probably need to get the individual date parts and add/subtract the timezone difference accordingly. At this point you could consider using an existing library, taking into account their possible disadvantages.
If you're willing and able to add a dependency, I recommend using moment.js for this. It makes date handling in Javascript much more straightforward and a lot safer, and fixes your specific problem right out of the box.
To do this, 1st load it from a CDN, e.g. Moment.JS 2.14.1 minified. Then use it as follows:
var date = moment("2016-01-23T22:23:32.927");
console.log(date);
// output: Sat Jan 23 2016 22:23:32 GMT-0500
...i.e. your desired result :)
Here's a jsfiddle demonstrating this.
Use date.toUTCString()
it'll give you 23 instead of 24 as it Convert a date object to a string, according to universal time

Categories

Resources