Display an Exact Date in JavaScript Regardless of TimeZone - javascript

I'm writing some simple code to display birthdays of some friends. I've got the birthdays stored in a JSON file and I'm pulling them in and initializing them as Date objects like so:
birthday: new Date(p.birthday)
Then I display those dates using moment to format them, like so:
let formatted = moment(birthdayDate).format(BirthdayFormat);
This applies an automatic local time zone, probably from when I set up the initial date object, and depending on the time of day might put the date a few hours in the past, thus changing the date to the previous day since it defaults to midnight.
Basically, I just want to display that date unchanging at any time since it's just stating that person's birthday and time zones aren't relevant at all. I use it elsewhere as a Date so I don't really want to store it in the JSON as formatted, so how can I set this up such that it just acknowledges the date and doesn't adjust it for a time zone?

From your comment, the dates are in YYYY-MM-DD format. Unfortunately, ECMAScript parses such dates as UTC.
If the date has already been parsed as UTC, then you just need to display UTC values to your users. You can use momentjs's utc function (I guess this is one of its main uses):
// Built-in parser treats YYYY-MM-DD as UTC
let d = new Date('2020-12-30');
// m inherits the same time value, so is also "UTC"
let m = moment(d);
// Include hour H in format to show effect of utc setting later
let birthdayFormat = 'dddd, D MMMM, YYYY [at] H';
// Default is local timezone, H reflects local offset
// Date might be 29 or 30, depends on whether offset is - or + respectively
console.log('Local: ' + m.format(birthdayFormat));
// Toggle UTC switch, all output will now be UTC, not local
m.utc();
// Values are now UTC, so offset is zero and so is H
// Displays Wednesday, 30 December, 2020 at 0 for all users
console.log('UTC : ' + m.format(birthdayFormat));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>

Convert the date to the date string so that the date does not include the timezone specific value.
birthday: new Date(p.birthday).toDateString()
Then display with the momentjs
let formatted = moment(birthdayDate).format(BirthdayFormat);

Related

Angular 6 Typescript new Date is created in UTC, but I need in my local timezone

In my file HomeComponent.ts (not in template html). I create a new Date and show it in console like this:
var fecha = new Date();
console.log(fecha);
the time in my country now is 16:09 (UTC -3) but the console output shows the date in UTC:
Date 2018-12-20T19:09:32.910Z // the time is 19:09
I need to compare and do some operations with "this new date" and other dates saved in a DB so I need the new Date to be created in my local timezone. How can I create a new Date in my local timezone?
How can I create a new Date in my local timezone?
Dates don't have a timezone, they are simply an offset from 1970-01-01T00:00:00Z (a time value) so are effectively always UTC. They represent a particular moment in time and can be used to generate a string representing an equivalent date and time in any timezone.
The local offset comes from the host system, it's used (if necessary) when creating a date and when working with local date and time values. There are equivalent UTC methods for doing operations that don't consider the local timezone.
The default toString method will generate a timestamp for the host timezone, toISOString will use UTC, toLocaleString can be used to generate a timestamp for any timezone. All will represent the same UTC date and time, just in different timezones.
When comparing dates, it's the UTC time value that is compared as it provides a common factor for all dates.
the time in my country now is 16:09 (utc -3) but the console output show the date in utc
A Date or DateTime is a structure, it does not have a format. If you want to display a formatted date string using the timezone of the browser then call toLocaleString.
var fecha = new Date();
console.log("As ISO8601 in utc:", fecha);
console.log("As local:", fecha.toLocaleString());

In javascript, how to get timezone value in UTC format for new Date(2017,05,31).toISOString()?

How to get timezone value for new Date(2017,05,31).toISOString()? It always comes as 000Z for any Date when the date is passed to the Date constructor. But for new Date().toISOString(), it gives the the timezone value.
new Date(2017,05,31).toISOString() gives "2017-05-30T18:30:00.000Z"
and new Date().toISOString() gives "2017-06-07T15:29:23.692Z". How to get timezone in UTC format for the past dates?
If you want the time to default to midnight in UTC, you can use Date.UTC(year, month, ...) to first create a timestamp based in UTC.
var utcMay31 = Date.UTC(2017, 4, 31); // note: 4 = May (0 = January)
Then, create the Date from that timestamp.
new Date(utcMay31).toUTCString(); // "Wed, 31 May 2017 00:00:00 GMT"
However, if you're wanting to know the timezone stored in the Date object, it doesn't actually have that. Dates represent an "instant" in time as the total number of milliseconds that have passed since Jan 1, 1970 00:00:00.000 UTC.
new Date().getTime(); // 1496851...
A Date can tell you the user's local offset from UTC in minutes at that instant.
new Date().getTimezoneOffset(); // e.g. 0, -480, 300
Otherwise, the timezone is limited to two choices when creating date strings, and the choice is based on the method used – user's local timezone or UTC.
new Date().toString(); // "now" in user's local time
new Date().toUTCString(); // "now" in UTC time
new Date().toISOString(); // "now" also in UTC time, alternate format
// etc.
You're confused ISO date values do not show the "time zone" instead they show the UTC time. Z stand for Zulu (UTC time).
2017-06-07T15:29:23.692Z
The bold part is not the time zone. It is the milli-seconds, the full time is in UTC. The reason it shows a 000Z in the set Date is because you didnt' set the milli-seconds.
If you want to display the time zone use toUTCString(). However it will display GMT which is UTC/Greenwich Time. To display the local time zone in a the date format you can use date.toLocaleString('en-US',{timeZoneName:'short'}) for example will display the date plus the local US time zone. Or you can use toString() which will display the GMT offset + the long local time zone.
In javascript, parsing, rendering and constructing dates will always assume local. It will convert to a timestamp, the number of milliseconds since 1-1-1970 00:00:00. JSON.stringify will convert to a UTC string, but legacy framworks use local dates. Always beware of this.
var myDate = new Date(); // this is now.
you can get your timezoneoffset (in minutes) with myDate.getTimezoneOffset(), but this will return the same offset for every date (aside from daylight saving time)
You shouldn't do this:
var utcDate = new Date(+d+60000*d.getTimezoneOffset());
// +d convert the date to a timespan.
// getTimezoneOffset() is in minutes
// *60000 makes that in milliseconds, the scale timespans operate upon
Date has a few methods to format dates, but always as local or UTC date. You need to do it manually if you want different time zones.
Note: the Date.UTC(...) function returns a timestamp. You sometimes see shifted dates, so they behave like UTC. But this causes problems later on.
var date = new Date(2000,1,1,12,0,0);
// DO NOT USE (breaks at start of daylight saving time)
// these are date/times that have the UTC-value,
// but Javascript treats them like local dates with this value.
utcDate1 = (+date-60000*d.getTimeZoneOffset()); // minus!!
utcDate2 = new Date(Date.UTC(2000,1,1,12,0,0));
// DO NOT USE (breaks at start of daylight saving time)
BTW
Edge, Chrome and Firefox display dates differently in the console: Edge and Firefox always shows local date, Chrome shows UTC. Also, if you change your timezone, Edge will screw up.

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)

How to get hours and minutes in desired timezone without creating new moment object?

I have to display a string on the web page in this format: 16:00 HH:mm
I'm using a moment object to represent a date/time and timezone.
var day = moment().tz('GMT');
day.hours(16).minutes(0).seconds(0).milliseconds(0);
So this is 16:00 in GMT time.
On my web page I want to change the time zone and then collect the hours and minutes.
If I make a new moment object
var day2 = moment().tz('PST); //this is 8 AM since gmt was 16
console.log(day2.get('hours'));
it is 16 not 8!
and try to get the hours and minutes they are in GMT not in PST.
How can I get it in PST? Do I have to keep wrapping it?
// initialize a new moment object to midnight UTC of the current UTC day
var m1 = moment.utc().startOf('day');
// set the time you desire, in UTC
m1.hours(16).minutes(0);
// clone the existing moment object to create a new one
var m2 = moment(m1); // OR var m2 = m1.clone(); (both do the same thing)
// set the time zone of the new object
m2.tz('America/Los_Angeles');
// format the output for display
console.log(m2.format('HH:mm'));
Working jsFiddle here.
If you can't get it to work, then you haven't correctly loaded moment, moment-timezone, and the required time zone data. For the data, you either need to call moment.tz.add with the zone data for the zones you care about, or you need to use one of the moment-timezone-with-data files available on the site.
In the fiddle, you can see the moment-files I'm loading by expanding the External Resources section.
PST can mean different things in different regions. In the moment-timezone docs, I see nothing referring to "PST" or similar abbreviations.
Perhaps try:
var day2 = moment().tz('PST');
// 16 with Error: Moment Timezone has no data for PST. See http://momentjs.com/timezone/docs/#/data-loading/.
var day2 = moment().tz('America/Los_Angeles');
// 15
I don't know about using moment.js, but it's fairly simple using POJS and the same algorithm should work. Just subtract 8 hours from the UTC time of a date object and return a formatted string based on the adjusted UTC time.
Assuming PST is "Pacific Standard Time", also known as "Pacific Time" (PT), and is UTC -8:00:
/* #param {Date} date - input date object
** #returns {string} - time as hh:mm:ss
**
** Subtract 8 hours from date UTC time and return a formatted times string
*/
function getPSTTime(date) {
var d = new Date(+date);
d.setUTCHours(d.getUTCHours() - 8);
return ('0' + d.getUTCHours()).slice(-2) + ':' +
('0' + d.getUTCMinutes()).slice(-2) + ':' +
('0' + d.getUTCSeconds()).slice(-2);
}
document.write('Current PST time: ' + getPSTTime(new Date));
There is moment-timezone which adds functionality to moment.js for IANA time zones. For PST you can use America/Los_Angeles, however it might also automatically adjust for daylight saving so you'll get PDT when that applies. If you want ignore daylight saving, use the above or find a location with the offset you need and use that.

How do you preserve a JavaScript date's time zone from browser to server, and back?

For example, using a date and time control, the user selects a date and time, such that the string representation is the following:
"6-25-2012 12:00:00 PM"
It so happens that this user is in the EST time zone. The string is passed to the server, which translates it into a .NET DateTime object, and then stores it in SQL Server in a datetime column.
When the date is returned later to the browser, it needs to be converted back into a date, however when the above string is fed into a date it is losing 4 hours of time. I believe this is because when not specifying a timezone while creating a JavaScript date, it defaults to local time, and since EST is -400 from GMT, it subtracts 4 hours from 12pm, even though that 12pm was meant to be specified as EST when the user selected it on a machine in the EST time zone.
Clearly something needs to be added to the original datetime string before its passed to the server to be persisted. What is the recommended way of doing this?
Don't rely on JavaScript's Date constructor to parse a string. The behavior and supported formats vary wildly per browser and locale. Here are just some of the default behaviors if you use the Date object directly.
If you must come from a string, try using a standardized format such as ISO8601. The date you gave in that format would be "2012-06-25T12:00:00". The easiest way to work with these in JavaScript is with moment.js.
Also, be careful about what you are actually meaning to represent. Right now, you are passing a local date/time, saving a local/date/time, and returning a local date/time. Along the way, the idea of what is "local" could change.
In many cases, the date/time is intended to represent an exact moment in time. To make that work, you need to convert from the local time entered to UTC on the client. Send UTC to your server, and store it. Later, retrieve UTC and send it back to your client, process it as UTC and convert back to local time. You can do all of this easily with moment.js:
// I'll assume these are the inputs you have. Adjust accordingly.
var dateString = "6-25-2012";
var timeString = "12:00:00 PM";
// Construct a moment in the default local time zone, using a specific format.
var m = moment(dateString + " " + timeString, "M-D-YYYY h:mm:ss A");
// Get the value in UTC as an ISO8601 formatted string
var utc = m.toISOString(); // output: "2012-06-25T19:00:00.000Z"
On the server in .Net:
var dt = DateTime.Parse("2012-06-25T19:00:00.000Z", // from the input variable
CultureInfo.InvariantCulture, // recommended for ISO
DateTimeStyles.RoundtripKind) // honor the Z for UTC kind
Store that in the database. Later retrieve it and send it back:
// when you pull it from your database, set it to UTC kind
var dt = DateTime.SpecifyKind((DateTime)reader["yourfield"], DateTimeKind.Utc);
// send it back in ISO format:
var s = dt.ToString("o"); // "o" is the ISO8601 "round-trip" pattern.
Pass it back to the javascript in moment.js:
// construct a moment:
var m = moment("2012-06-25T19:00:00.000Z"); // use the value from the server
// display it in this user's local time zone, in whatever format you want
var s = m.format("LLL"); // "June 25 2012 12:00 PM"
// or if you need a Date object
var dt = m.toDate();
See - that was easy, and you didn't need to get into anything fancy with time zones.
Here, I think this is what you are looking for:
How to ignore user's time zone and force Date() use specific time zone
It seems to me that you can do something like this:
var date = new Date("6-25-2012 12:00:00 PM");
var offset = date.getTimezoneOffset(); // returns offset from GMT in minutes
// to convert the minutes to milliseconds
offset *= 60000;
// the js primitive value is unix time in milliseconds so this retrieves the
// unix time in milliseconds and adds our offset.
// Now we can put this all back in a date object
date = new Date(date.valueOf() + offset);
// to get back your sting you can maybe now do something like this:
var dateString = date.toLocaleString().replace(/\//g,'-').replace(',','');
Blame the JSON.Stringfy()... and do:
x = (your_date);
x.setHours(x.getHours() - x.getTimezoneOffset() / 60);
I am using a filter before sending the date to the server:
vm.dateFormat = 'yyyy-MM-dd';
dateToSendToServer = $filter('date')(dateFromTheJavaScript, vm.dateFormat);

Categories

Resources