I'm having trouble formatting the birthday date in the format 2021-04-13T00:00:00.000Z the date is sent correctly, but after this formatting it always has 1 day less. Can anyone help?
export function format(date): string {
const mydate = new Date(date);
return new Intl.DateTimeFormat().format(mydate);
}
Using the basic Date methods .getUTCYear(), .getUTCMonth(), and .getUTCDay() will enable you to get the date as it appears in your UTC-relative source string. As noted in a comment, your apparent date when rendered in your local time zone is one day earlier, as is correct for time zones west of UTC.
You can still make use of Intl.DateTimeFormat() if you pass in an option to use UTC as the time zone:
return new Intl.DateTimeFormat("pt-BR", { timeZone: "UTC" }).format(dateInput);
However, that's not supported by IE11 (if that's important to you).
Related
I have a JavaScript function that takes a number (1-31), creates a Date and sends it to a server via an AJAX request:
sendDate(d) {
let date = new Date(this.year, this.month, d);
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
The problem is, that JavaScript is doing some timezone correction which has the effect, that if I create a date like new Date(2022, 09, 14) I get a date Wed Sep 14 2022 00:00:00 GMT+0200 (Central European Summer Time) which when converted to ISO format becomes 2022-09-13T22:00:00.000Z, ie. the previous day.
I know I can use .toLocaleDateString(), but I would like to stick to the ISO-format and I would also like to avoid hacky solutions such as always creating the date with some specified time at the middle of the day or whatever.
Is there a simple way to create a regular date object and pass it on to a server without timezone shenanigans?
Values passed to the Date constructor are treated as local, toISOString uses UTC. Unfortunately ECMAScript doesn't have a timezone–free, date–only form.
If you want to use toISOString to format the timestamp, then one solution is to parse the values as UTC initially, e.g.
sendDate(d) {
let date = new Date(Date.UTC(this.year, this.month, d));
htmx.ajax("GET", "/some/url", { values: { "date": date.toISOString() } });
}
Example:
let d = new Date()
let year = d.getFullYear();
let month = d.getMonth()
let day = d.getDate();
let date = new Date(Date.UTC(year, month, day))
// Always shows the current local date as 00:00:00Z
console.log( date.toISOString() );
You should also trim the Z from the end since the timestamp really is local.
There’s a way to do that: store the date as the UNIX timestamp. I do it this way and when it’s needed, I pass the timestamp from server to client and convert it into local date.
That said, I don’t think it’s a good idea to build the date on client and pass it to the server, since it could be modified on client. I believe it’s mostly done this way (and that’s also how it’s done in my projects): on the server side, you check the current timestamp (at the time request is sent) and do with it whatever you want.
It appears that you allow your user to pick a date. It would be a good approach to convert it then to timestamp and pass it to the server.
How would you do that? If I return date.getTime() and then parse it (in python) with datetime.fromtimestamp(int(request.GET['date']) / 1000) I still get the same timezone issue...
You won't have any issues in this case - apart from the fact your server just could happen to have a different local time. A time-zone independent solution would have to use utcfromtimestamp instead of fromtimestamp.
Either way, the timestamp itself can't have any timezone problems by definition.
See RobG's Answer... using the new Date(Date.UTC(year, month, day)) formatting is much better.
This question already has answers here:
How to initialize a JavaScript Date to a particular time zone
(20 answers)
How do I specify the time zone when creating a JavaScript Date?
(1 answer)
Closed 1 year ago.
I have developed a page where users can filter records based on their selections in the filters.
The datetime picker allows users to select a specific datetime and a dropdown allows the user to select the time zone in which they want that selected date to be converted to UTC.
For example, on my computer the time zone set is Asia/Karachi which has an offset of +5 UTC.
But I want to select Europe/Prague from the dropdown and 09/14/2021 3.30pm as the date time. The time should be converted to 1.20 PM as Europe/Prague has a time offset of +2 from UTC using below code.
var ddate = new Date(date.toLocaleString('en-US', {
timeZone: 'Europe/Prague'
}));
However, this yields 12.30 PM as the time. Apparently it is converting from Asia/Karachi(my computer time zone) to Europe/Prague. But I want the selected datetime to be converted to UTC based on the time zone the user selects from the dropdown of available time zones.
Is there any possible solution? I have tried researching and coding a lot but haven't found any yet.
Have you tried moment & moment-timezone?
maybe something like this:
import moment from "moment";
const myDate = "09/14/2021 3:30 PM";
const myTimeZone = "Europe/Prague";
let convertedTime = moment.tz(myDate, time_zone).format();
and you can set your format to be ("HH:mm A")
If you want a date constructor for specific timezones make use of new Date('YYYY-MM-DDTHH:NN:SS.sss±HH:NN').
What you describe and want, is what Date already does if you generate a Date using new Date('YYYY-MM-DDTHH:NN:SS.sss±HH:NN'). You simply have to use it in this format.
±HH:NN is timezone information from your timezone-dropdown. It can either start with a + or a -. (Take a look at the 3rd snippet)
Other formats as the ones i mentioned, are invalid if passed to the Date constructor and you may get unexpected results.
The dropdown (the one about the timezone) requires the information of +hrs:mins and -hrs:mins respective to the timezone selected.
The following describes the Date constructor.
Don't pass a formated string like this to new Date() - it's invalid.
If you use new Date() you either have to pass a time value in milliseconds, a date only or an ISO Timestamp.
new Date(date.valueOf()) results in a copy
new Date(date.toISOString()) results in a copy
new Date(date.toJSON()) results in a copy
new Date(date.toDateString()) results in a copy of the date only => no hour GMT +0 on the current day.
All examples above (except the last one) are a copy of the original date.
For more information on the arguments supported by the Date-constructor take a look at Date.parse()#Date Time String Format
There is no need to change anything. If it's midnight at Asia/Karachi, it will be 9pm (21:00) in Europe/Prague.
As you can see on this example, use GMT+0 or any other accepted Time-Zone String.
Examples of different arguments
1
const date = new Date("2021-02-14T00:00:05.000+00:00"); // 5 seconds after midnight on February 14th, 2021 GMT+0
["GMT+0", "UTC", "America/New_York", "Europe/Madrid", "Europe/Prague", "Europe/Moscow", "Asia/Karachi", "Asia/Tokyo", "PRC"].forEach(timeZone => {
console.log(timeZone, date.toLocaleString('en-US', { timeZone }))
});
2
const date = new Date("2021-09-14");
["GMT+0", "UTC", "America/New_York", "Europe/Madrid", "Europe/Prague", "Europe/Moscow", "Asia/Karachi", "Asia/Tokyo", "PRC"].forEach(timeZone => {
console.log(timeZone, date.toLocaleString('en-US', { timeZone }))
});
3
// 16:00 at timezone +9 is 7 am at gmt
const date = new Date("2021-09-14T16:00:00.000+09:00");
["GMT+0", "UTC", "America/New_York", "Europe/Madrid", "Europe/Prague", "Europe/Moscow", "Asia/Karachi", "Asia/Tokyo", "PRC"].forEach(timeZone => {
console.log(timeZone, date.toLocaleString('en-US', { timeZone }))
});
Given a date (without time) e.g. 2021-08-11, how could I get its day name (e.g. Wednesday) regardless of the user's timezone?
Note that trying to use:
new Date("2021-08-11").toLocaleString('en-AU', { weekday:'long' })
or date-fns's format:
format(new Date("2021-08-11"), "EEEE")
results in the wrong day (Tuesday) if the user's timezone is GMT-7, for example.
You can use date-fns-tz as suggested by the other comment. It interally uses Intl. If you only care about getting the day you can just use Intl directly:
let formatter = new Intl.DateTimeFormat('en-US', {
timeZone: 'UTC',
weekday: 'long',
});
formatter.format(new Date("2021-08-11")) // outputs: "Wednesday"
I would recommend that you also format your dates to ISO i.e. "2021-08-11T00:00:00.000Z" as the Z at the end will ensure that the date is parsed in UTC before formatting.
I haven't surveyed the latest data-fns. But when I used it a couple of years ago, it didn't have a timezone support. Since the Date class does not keep the timezone information internally, it causes some problems when the location of time acquisition is different from where it is used. See this stackoverflow post for details.
There are some libraries available to solve this problem. Since you are using date-fns you might want to try date-fns-tz.
I have a date I want to convert based on their timezone.
For example, I want to set it in EST time (America/New_York)
2019-04-24 12:00:00
and if the user comes across the site from America/Los_Angeles, it will appear:
2019-04-24 09:00:00
I need to be able to return the hour, so in that example: 9.
I tried using https://github.com/iansinnott/jstz to determine their timezone and https://moment.github.io/luxon in hopes of handling the conversion w/o any luck.
I was testing by changing the timezone on my computer w/o any luck.
It sounds like you're asking to convert from a specific time zone to the user's local time zone (whatever it may be). You do not need time zone detection for that, but at present you do need a library. (Answers that suggest using toLocaleString with a time zone parameter are incorrect, as that function converts to a specific time zone, but cannot go the other direction.)
Since you mentioned Luxon, I'll provide a Luxon specific answer:
luxon.DateTime.fromFormat('2019-04-24 12:00:00', // the input string
'yyyy-MM-dd HH:mm:ss', // the format of the input string
{ zone: 'America/New_York'}) // the time zone of the input
.toLocal() // convert to the user's local time
.toFormat('yyyy-MM-dd HH:mm:ss') // return a string in the same format
//=> "2019-04-24 09:00:00"
This capability is also provided by other libraries, such as date-fns-timezone, js-Joda, or Moment-Timezone, but it is not yet something built in to JavaScript.
Converting date based on the time can be done like this. reference convert date to another time zone example snippet is under.
var usaTime = new Date().toLocaleString("en-US", {timeZone: "America/New_York"});
usaTime = new Date(usaTime);
console.log('USA time: '+usaTime.toLocaleString())
var usaTime = new Date().toLocaleString("en-US", {timeZone: "America/Los_Angeles"});
usaTime = new Date(usaTime);
console.log('USA time: '+usaTime.toLocaleString())
You could keep a list of timzeone identifiers and a list of their corresponding +/- number of hours with respect to your local time (which is returned by your time function).
Once you have a user's time zone, and you have extracted the current hour from the local timestamp simply look up the timezone in your list and use it's index to access the second list to find how many hours to add or subtract from the users time.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
var date = new Date(Date.UTC(2012, 11, 12, 3, 0, 0));
// toLocaleString() without arguments depends on the implementation,
// the default locale, and the default time zone
console.log(date.toLocaleString());
// → "12/11/2012, 7:00:00 PM" if run in en-US locale with time zone America/Los_Angeles
Or you can use getYear, getMonth, getDate, getHours, getMinutes, getSeconds to format your own representation of the date. These methods all return values according to the user's local timezone.
I think the question may need more clarification - my first impression was you refer to a date-time that you already have and serve from the server. Doesn't this problem boil down to the Date object being "user-timezone-aware"? or not? But it is (some methods are, to be exact)
Your date/time is 2019-04-24 12:00:00 EDT (i assume P.M.)
This means the Unix timestamp of this in milliseconds is 1556121600000
(i assume daylight is on for April so not pure EST but EDT and an offset of UTC-4:00)
When you call
console.log(new Date(1556121600000).getHours())
doesn't this return 9 as you suggest, for Javascript executed on a browser from America/Los_Angeles with PDT timezone?
As suggested at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getHours :
The getHours() method returns the hour for the specified date,
according to local time.
on my UI, I try to display a date based on a specific timezone. In this example, I will use Americas/New_York as the timezone. This is how I did it.
$scope.getStartTime = function(){
var date = new Date();
return moment(date).tz("Americas/New_York").format('YYYY-MM-DD HH:mm:ss');
};
Afterwards, I want to send this data and send it to my server. In my server however, I want it so that it is always serialized into UTC time instead of in the New York Timezone (EST).
For example, if the time was 12:00 P.M. in New York, then the time would be serialized to 4:00 P.M. in UTC time before it was sent to the backend. This was my attempt:
var date = getStartTime();
....
// Display the date in the UI
....
$scope.revertStartTime(date);
$scope.revertStartTime = function(startTime) {
console.log("Start time: ", startTime);
console.log("Moment: ", moment(startTime).format());
console.log("Converted to utc time: ", moment().utc(startTime).format());
return moment.utc(startTime).format("YYYY-MM-DD'T'HH:mm:ss.SSSZ");
}
I tried to revert the start time by using the moment().utc() function and hoped that the date would change to a UTC based date but unfortunately it keeps turning my date into the localized date instead of UTC date and I'm not sure why. Any help would be appreciated. Thanks!
Edit:
Tried to follow the below method and here is what I did:
$scope.getStartTime = function(){
var date = new Date();
var startTime = new moment(date).tz($rootScope.userinfo.timeZone).format('YYYY-MM-DD HH:mm:ss');
$rootScope.offset = moment().utcOffset(startTime);
console.log("offset: ", $rootScope.offset);
return startTime;
};
$scope.revertStartTime = function(startTime) {
console.log("User Selected Time: ", moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss'));
return moment().utcOffset(startTime).format('YYYY-MM-DD HH:mm:ss');
}
But all I get is an error saying that revertStartTime returns an Invalid Date.
A few things:
Hoping it's a typo, but just to point out, the zone ID is America/New_York, not Americas/New_York.
You can pass a value as moment.utc(foo), or moment(foo).utc(), but not moment().utc(foo). The difference is that one interprets the input as UTC and stays in UTC mode, while they other just switches to UTC mode. You can also think of this as "converting to UTC", but really the underlying timestamp value doesn't change.
Yes, you can switch to UTC mode and call format, but you can also just call .toISOString() regardless of what mode you're in. That's already in the ISO format you're looking for.
Note that if you start with a unique point in time, and you end with converting to UTC, no amount of switching time zones or offsets in the middle will change the result. In other words, these are all equivalent:
moment().toISOString()
moment.utc().toISOString()
moment(new Date()).toISOString()
moment.utc(new Date()).toISOString()
moment(new Date()).utc().toISOString()
moment().tz('America/New_York').toISOString()
moment.tz('America/New_York').toISOString()
moment().utcOffset(1234).toISOString()
moment.utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
moment().utc().format('YYYY-MM-DD[T]HH:mm:ss.SSS[Z]')
Only the last two even need to be in UTC mode, because the format function would produce different output if in local mode or in a particular time zone.
In order to accomplish this you'd want to use .utcOffset(). It is the preferred method as of Moment 2.9.0. This function uses the real offset from UTC, not the reverse offset (e.g., -240 for New York during DST). Offset strings like "+0400" work the same as before:
// always "2013-05-23 00:55"
moment(1369266934311).utcOffset(60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).utcOffset('+0100').format('YYYY-MM-DD HH:mm')
The older .zone() as a setter was deprecated in Moment.js 2.9.0. It accepted a string containing a timezone identifier (e.g., "-0400" or "-04:00" for -4 hours) or a number representing minutes behind UTC (e.g., 240 for New York during DST).
// always "2013-05-23 00:55"
moment(1369266934311).zone(-60).format('YYYY-MM-DD HH:mm')
moment(1369266934311).zone('+0100').format('YYYY-MM-DD HH:mm')
To work with named timezones instead of numeric offsets, include Moment Timezone and use .tz() instead:
// determines the correct offset for America/Phoenix at the given moment
// always "2013-05-22 16:55"
moment(1369266934311).tz('America/Phoenix').format('YYYY-MM-DD HH:mm')