I have an ejs file displaying a date that is coming from my node server and mongoose database. In the server and database, the date is correct, I set a console.log for the date, and it returns:
2020-06-10T00:00:00.000Z
June 10th, as expected. However, when I have it display in the ejs file, it displays as June 9th:
<p><%= ticket.due_date.toDateString() %></p>
and it displays on the page as
Tue Jun 09 2020
This also seems to be a problem when I use moment to refactor the date format for sending to the ejs file:
console.log(ticket.due_date);
date = moment(ticket.due_date).format("YYYY-MM-DD");
console.log(date);
and this outputs into the console as:
2020-06-10T00:00:00.000Z
2020-06-09
Is there some formatting issue I am missing, or is it inherent with the system and if so, how do I simply add a day in the ejs file to make it correct? Thank you.
A Date is not a string; it's an object that encapsulates a moment in time (internally, a big number). It doesn't carry any other interesting details like how the string you used to create it was originally formatted. So when you output a Date with .toDateString(), will simply output a string for the timestamp according to the JavaScript spec for .toDateString().
There are numerous valid ways to format a Date as a string. I'd look through the docs on Date. For example, one option is .toISOString() which seems to be the format you're expecting. If you want to output user-friendly dates in a multitude of formats, you'll need to look to libraries like Moment.js.
Update:
You seem to be working with a misconception about dates. An ISO 8601 date like the example 2020-06-10T00:00:00.000Z means midnight UTC (a.k.a. GMT, Zulu, etc). a Date doesn't represent a local calendar date, it represents a moment in time, specifically the number of milliseconds since 1 January, 1970, UTC. This means when you deal with JavaScript dates, you should be intentional to construct them with the appropriate understanding that they represent a moment in time. For example, if you want a date to reflect midnight in your local time zone, you can use the constructor:
const date = new Date(2020, 5, 10);
...and when you output the date, you should remember that the person viewing the moment in time may be in a different time zone, so the date may not reflect as the exact same thing.
If you're wanting to deal with a calendar date instead of a timestamp (which would have been a better name for Date), then you can use UTC dates throughout and make sure when you output strings that you specify you want to format the date using the UTC time offset. Alternately, you might want to stick with strings if you don't want any of the semantics of timestamps.
Related
My scenario is a Date object created using the browser timezone (just using new Date()) and sent to the server, but I want to send this date with another specific timezone let's assume it's, Europe/Athens.
What would be the best representation of the actual date string so I can convert it back to a Date object in the backend in the actual Europe/Athens date?
I have the timezone info but not sure how to get a Fri Feb 05 2021 05:30:00 GMT-0500 (Eastern Standard Time) and convert it to Europe/Athens date.
I have tried to use date-fns but didn't get far.
You've got a few different questions and misconceptions, so I will attempt to address each of them, starting with question in the title:
How to convert a Date in specific Timezone and send to server
If you mean a date like 2021-01-18, that cannot be in a particular time zone. It is, by definition, just a date. Think about a printed calendar you might hang on your wall that has a square for each date. There are no time zones associated with such calendars. One can ask "what date is it now in a particular time zone", but the answer itself has no time zone.
If instead you meant a JavaScript Date object, the answer is again "you can't". The Date object is not actually a date, nor does it have a time zone, but rather it is a timestamp. Internally, a Date object only holds one value - the number of milliseconds that have elapsed since 1970-01-01 00:00:00.000 UTC (not considering leap seconds). It has no time zone. Instead, some functions such as .toString() will apply the system-local time zone while operating. That time zone comes from the operating system (in most cases). It is not stored inside the Date object itself.
My scenario is a Date object created using the browser timezone (just using new Date()) ...
That will use the system clock where the browser is running, but the time zone is not relevant. The Date object will be constructed from the Unix timestamp that represents "now". Such timestamps are inherently UTC based. The browser fetches the UTC time directly from the operating system, without considering time zone.
... and sent to the server
One cannot send an object to a server without going through deserialization on one side and serialization on the other.
... but I want to send this date with another specific timezone let's assume it's, Europe/Athens.
What would be the best representation of the actual date string so I can convert it back to a Date object in the backend in the actual Europe/Athens date?
Since the object only represents "now", you don't need to send it in a time zone specific format. Just send the UTC time. The ideal format is ISO 8601, which can be obtained directly using the .toISOString() function from the Date object.
Depending on your use case, you might also consider whether you might instead just take the UTC time from the server instead. At least you will have some control over the clock.
On the server side, if you need the time in a specific time zone, then convert from UTC to that time zone on the server, not on the client.
Also, from comments:
I believe even EPOCH is different between timezones. I could just get the EPOCh and then try to work with converting to specific timezones.
That is incorrect on a few levels. First, understand that epoch is just an English word meaning essentially "a representation of a starting point". It isn't a format, nor is it an acronym. In JavaScript, Date objects use Unix timestamps, which use an epoch of 1970-01-01T00:00:00.000Z. In other words, Midnight Jan 1st 1970 UTC is the 0 timestamp. Sometimes, such timestamps are referred to as "epoch time". That's a misnomer in my opinion, but even still - they are always UTC based. There is no time zone, and thus they are the same for the whole world.
Try to use toLocaleString:
let date = (new Date()).toLocaleString("en-US", {timeZone: "Europe/Athens"});
I'm processing some data with dates in the format YYYY-MM-DD hh:mm:ss zz. For example:
2019-04-06 08:24:51 Central Daylight Time
2018-09-06 12:16:12 Central Standard Time
2020-02-14 17:57:33 Central Standard Time
I want to be able to convert these dates to a Date object in browser JavaScript. However, the Date constructor does not recognize this sort of date format, and moment.js isn't much help (unless I'm missing something).
In practice, I'll probably only ever deal with Central Standard Time and Central Daylight Time, but is there a general solution that would allow me to convert this date format to a Date object?
Assuming that Central Standard Time can also be written as CST, you can try
new Date('2020-02-14 17:57:33 CST'); // default date output
which will give you the full date representation.
Or you could use Date.parse() to get the actual timestamp
Date.parse('2020-02-14 17:57:33 CST'); // 1581724653000 etc
Another thought - have you tried Moment timezone?
My app (back-end in C# & front-end in Angular Materials) has a search screen allowing user to specify the date period using datepickers. The problem is that some of the users are not in UK while all the data they view has been created with GMT date. So if someone in Germany selects date 01/01/2017 in datepicker, my back-end reads it as 31/12/2016 23:00:00 resulting in incorrect search results.
Can someone advise me how to deal with this? I'd like to still use the Angular Material datepicker but be sure that I'm passing the date selected by the user. I know I can transform the date before posting it like this:
moment(myDate).format('MM/DD/YYYY'))
but I have a lot of cases like this and would prefer some generic solution.
For transmission and storage, I advise using UTC for everything. Only at the point of display should the time be converted to whatever locale the user has selected. Despite this being an old problem, running into time conversion issues is still quite common. Most places I've worked at will store everything as UTC timestamps or Unix epoch time with respect to UTC, that way there is no question what the meaning is anywhere in the system. If/when it needs to be rendered to something local, we do it on the client side.
For example, to get the local time converted to UTC as a string:
var noTimeZone = new Date().toUTCString();
-or-
var noTimeZone = new Date().toISOString();
Or, if you want a numeric value so you don't have to deal with funky format parsing between client/server, you can get the Unix epoch:
var unixEpochMS = new Date().getTime();
Mind you, Date.getTime() will return milliseconds rather than seconds. Also note that the Unix epoch is defined in terms of UTC. That is, any numeric value that is a timestamp is expected to be UTC. If you want a different timezone, you need to parse the value and then set the timezone to what you want.
Solution 1:
I think the solution is to get your user's timezone. You can use Javascript to get timezone from user's computer and send it to server with the request.
var d = new Date();
var tz = d.getTimezoneOffset()/-60;
tz will be 2 if user's timezone is GM+2
Soution 2:
You send and receive Unix timestamp. But then you need to convert the timestamp to readable date/time based on user's timezone.
I am formatting a given date using momentjs. The following behaves differently in different timezones:
moment(new Date("2016" + "-" + "06" + "-01").toISOString()).format('MMMM YYYY')
It gives me May 2016 in timezone of America/Denver and June 2016 in Asia/Karachi. I tested by changing the browser timezone to different timezones. It should be June 2016 in both.
When i change the format in new Date() to use slashes instead of hyphens like below, it gives me correct result in both timezones i.e. May 2016.
moment(new Date("2016" + "/" + "06" + "/01").toISOString()).format('MMMM YYYY')
Both seem to be valid ISO strings, what would cause this inconsistency?
The short answer to your question is that parser for javascript date doesn't work in a way that makes sense to anybody. Instead, you should just use Moment's parser to get the result you want. Parsing dates in a way that makes sense is about 50% of the reason that moment exists.
If you eliminate the date call and use Moment to parse your date, you will observe that the following code will result in June 2016 in any browser, because your string will be interpreted as local time if you are using Moment's default constructor:
moment('2016-06-01').format()
If you wanted to use slashes instead, it would be:
moment('2016/06/01', 'YYYY/MM/DD').format()
See moment's parsing guide for more information about how moment interprets times with it's different constructor methods.
The long answer is that when you pass a string in ISO8601 format that is date only to the JavaScript date constructor, it will interpret that string as UTC. Because Denver is UTC -6 on daylight time, and Karachi is UTC +5 all the time, when moment then displays that timestamp as local time you see the result that you do. You can observe the following:
var a = new Date('2016-06-01');
a.toISOString();
"2016-06-01T00:00:00.000Z"
Note that the 'Z' in the above timestamp indicates that it is UTC, as toISOString always returns a UTC timestamp. That timestamp is June in Karachi because Karachi is ahead of UTC, while May in Denver because Denver is behind UTC.
Observe this as well:
var a = new Date('2016-06-01T00:00');
a.toISOString();
"2016-06-01T05:00:00.000Z"
If I put a time on my string, it is interpreted as local time. Because my timezone was UTC-5 on January 1, the point on the global timeline is appropriately five hours ahead of the string I passed.
The behavior you are seeing - interpreting 2016-06-01 as UTC, but 2016-06-01T00:00 as local, is actually an effort to accommodate technical debt across browsers. It has been made the standard behavior in the 7th edition of the ECMA 262 specification, so expect for that not to change. See this link as well.
Alternately, when you use the slashes (2016/06/01) the JS implementation that you are using is choosing to interpret that format as local time, as it does not conform to any of the formats in the ECMA standard. This is NOT a valid ISO8601 format. It is very important to note that this behavior is implementation specific, and will vary across browsers/environments. The ECMA standard does not define a behavior for parsing that date format. Other browsers may parse this string in other ways.
As general advice, don't use the JavaScript date parser. It doesn't work right. You can use Moment.js, one of moment's several competitors, or manually parse strings yourself. All of these are better options.
I pick some date and time in javascript and then want to store it on server (.NET). Dates are supposed to be in future from the current moment (so they won't be before 1970).
Having read topics here on SO I learnt it's better to store date as a string and people suggest using Date.prototype.toISOString() or Date.prototype.toUTCString().
I've read that toISOString() is not available in IE 7. And I'd like to know other differences, when I should choose one or another function.
They're for different purposes.
UTC is the primary time standard by which the world regulates clocks and time.
ISO is standard format time. ISO also supports ms in its format.
So if you want to send data to the server, send the ISO, because ISO is the standard format:
var date = new Date();
sendDate(date.toISOString());
You can also use toISOString in IE7 polyfill.
I hope it will helpful to you.
Summary About toISOString() :-
The toISOString() method returns a string in ISO format (ISO 8601 Extended Format), which can be described as follows: YYYY-MM-DDTHH:mm:ss.sssZ. The timezone is always UTC as denoted by the suffix "Z".
Refer Below link for more information about toISOString().
Date.prototype.toISOString()
Summary About toUTCString() :-
The toUTCString() method converts a date to a string, using the UTC time zone.
Refer Below link for more information about toUTCString()
Date.prototype.toUTCString()
Always use .toISOString()
They give almost the same information, but in different formats. Here is what I get on my machine.
new Date().toISOString()
"2019-10-11T18:56:08.984Z"
new Date().toUTCString()
"Fri, 11 Oct 2019 18:56:08 GMT"
There are 4 reasons .toISOString() is more often what you want than .toUTCString().
A. More convenient sorting
When you sort alphabetically, the "2019-10-11T18:56:08.984Z" pattern of .toISOString() gives you the correct date order.
B. Millisecond precision
.toISOString() provides millisecond values, whereas .toUTCString() does not.
C. Any user can interpret correctly
The .toUTCString() value may be more familiar to human end-users, but only if the language settings are suitable for them. In contrast, the .toISOString() is the same regardless of language settings.
D. Reproducibly regeneratable by software
You can easily convert the ISO date string to a Javascript Date object, and then back again, regenerating exactly the same string. This is regardless of who gave you the ISO date string, where the server is, and where you are.
This is not automatically true for the UTC string. For example, if a second instance of your app system is running in a different time zone, or language, it's .toUTCstring() may use different numbers or words (respectively) to represent the same instant in time. It will be difficult for it to create a UTCString that matches what was made by the first instance of the app, since in general it will not know the language or timezone in which the first UTC string was produced.
I think nobody needs .toUTCString()
I don't know why `.toUTCString()` exists. Its word-heavy format makes it useless for internal storage of dates in your program, because it varies depending on your language and timezone setting etc.
So maybe it is to produce something nice to display externally for the user to see? Well, not really. Anyone who is not in the London time zone will not find it very helpful.
I live in London. And even I, even if I was writing an app purely for use by me, solely on my system, and only in my home, would still not want to use .toUTCString(). Because it is showing UTC (also known as GMT). London is not always on GMT. In summer, we move to GMT+1, so the .toUTCString() result would mislead anyone who didn't notice the "GMT" and do the time adjustment in their head.
If I wanted a natural-language time, to make non-computer literate users comfortable, I would construct it manually from parts, using a library like moment.js. If I wanted a quick-and-dirty solution, I would use .toString() which at least will move to Summer time when appropriate.