Javascript Dates - Removing Timezone Information - node.js

I have a web application where my users are in NYC but admins are spread across the world. The use case is simple. Admins click on a date and add some notes. Users when they log in to the app , click on the same date and sees the note
Problem is timezone. When an Admin from India adds data on January 1 2019 his data is getting added to Dec 31 2018 as the server is converting the incoming IST to EST. This is breaking the application.
I cant handle individual timezone. So I want to ensure that the frontend is always passing the date in EST irrespective of the local timezone
private normalizeDate(d)
{
let noTime = moment(d).format("L");
let m = moment(noTime).tz("America/New_York");
alert("no time :"+noTime);
alert("normalized :"+m.format("L"));
}
I tried this function where i get the date in local timezone (d) and remove all information. Convert into a string and then parse it back to my EST timezone.
Evidently whenever I call . moment().tz() it is converting the timezone again.
Any idea what is the best solution ?

Eventually I used this to resolve the problem
public static NormalizeDate(d, timezone = "America/New_York")
{
var a = moment(d);
var b = a.clone();
return b.tz(timezone, true).startOf("day");
}

Related

momentJS: Getting wrong timestamp from date in a different timezone

There is one time input i.e. start_time
I am trying to get timestamp in milliseconds for these inputs
let start_time = "17:05:00";
var start_date_moment = moment(start_time, "HH:mm:ss");
console.log(start_timestamp);
output is -> moment("2019-04-24T17:05:00.000")
This output remains same on server and local
But when I am trying to get unix timestamp in milliseconds in the same way
var start_timestamp = moment(start_time, "HH:mm:ss").valueOf();
On server at different timezone
console.log(start_timestamp);//1556125500000
console.log(moment(start_timestamp/1000).format('YYYY-MM-DD HH:mm:ss'); //2019-04-24 17:05:00
On local
console.log(start_timestamp);//1556105700000
console.log(moment(start_timestamp/1000).format('YYYY-MM-DD HH:mm:ss'); //2019-04-24 22:35:00
This start_timestamp value is different on local and server. But timestamp shouldn't change with timezone, it should remains same for all timezones. Please help me with this.
How to get the correct and same value at both places. I got this link some what related to this https://github.com/moment/moment/issues/2035
There is no issue with dates any particular format, issue is only with timestamp.
You need to take the offset into consideration when using moment (using timezones moment.js). Since no offset was passed in the input, the moment will be based on the time zone of the computer the code is running on, hence the different values..
Example:
var a = moment.tz("2013-11-18 11:55", "Asia/Taipei");
var b = moment.tz("2013-11-18 11:55", "America/Toronto");
a.format(); // 2013-11-18T11:55:00+08:00
b.format(); // 2013-11-18T11:55:00-05:00
a.utc().format(); // 2013-11-18T03:55Z
b.utc().format(); // 2013-11-18T16:55Z
If you change the time zone of a moment object using moment-timezone only affects the value of the local time. It does not change the moment in time being represented, and therefore does not change the underlying timestamp.
A Unix Timestamp is always based on UTC - you can see it as the same timestamp at any given location in the world.
Official Moment Docs on timezones
Edit:
If you use utcOffset you should pass an integer:
Example:
moment.utc("2015-10-01 01:24:21").utcOffset("-240").format('YYYYMMDD HHmmss ZZ')
// "20151001 012421 +0000"
moment.utc("2015-10-01 01:24:21").utcOffset(-240).format('YYYYMMDD HHmmss ZZ')
// "20150930 212421 -0400"
MomentJS allows offset-arguments to be passed as string, but it expects the string to be in one of the ISO8601 formats: [+/-]HH:mm or [+/-]HHmm.
To avoid this all together you could, if known, pass the location as an argument like
moment.tz(start_time, "HH:mm:ss", "Asia/Kolkata").valueOf();
as mentioned in the first example above..

Momentjs timezone - getting date at time in specific timezone

I am attempting to create a date from a UTC base in a user's specific timezone, in this case "America/Los Angeles" using momentjs/momentjs timezone. However, I'm not getting the results I expect:
var tempDate = moment(1448841600000); //moment("2015-11-30"); //monday 11/30 in UTC
var adjustedStart = moment.tz(tempDate, "America/Los_Angeles");
adjustedStart.hour(9);
adjustedStart.minute(30);
console.log("adjustedStart in milliseconds:" + adjustedStart.valueOf());
The console output is 1448875800000 which is 11/30/15 9:30AM in UTC/GMT, I was expecting 1448904600000 which is 11/30/15 9:30AM in Pacific Coast time. How can I translate this start date to the right time in the user's timezone?
Yes, 1448841600000 is the date you said:
moment(1448841600000).utc().format()
// "2015-11-30T00:00:00+00:00"
But that is a day earlier in Pacific time
moment(1448841600000).tz('America/Los_Angeles').format()
// "2015-11-29T16:00:00-08:00"
When you adjust it to 9:30 pacific, it's on the 29th, not the 30th.
moment(1448841600000).tz('America/Los_Angeles').hour(9).minute(30).format()
// "2015-11-29T09:30:00-08:00"
When you call valueOf, the result is:
moment(1448841600000).tz('America/Los_Angeles').hour(9).minute(30).valueOf()
// 1448818200000
This is the correct value, however it's different than the one you provided. However, it is indeed what I get when I run your code as well.
Screenshot from Chrome debug window, with your exact code:
Also, in comments you wrote:
//moment("2015-11-30"); //monday 11/30 in UTC
Actually, that would be in local time, not UTC. If you wanted UTC, you'd use:
moment.utc("2015-11-30")
Though it's unclear to me whether you are using this string input or the numeric timestamp.
If what you are asking is that you want the UTC date to be treated as if it were local and then have an arbitrary local time applied - that is a somewhat strange operation, but it would go something like this:
var tempDate = moment.utc(1448841600000);
var adjustedStart = moment.tz([tempDate.year(), tempDate.month(), tempDate.date(), 9, 30],
"America/Los_Angeles");
console.log("adjustedStart in milliseconds:" + adjustedStart.valueOf());
// adjustedStart in milliseconds:1448904600000
This gives the value you asked for, but to me - this is a smell that something is wrong with the expectation. I'd look a lot closer at the requirement and the other parts of the system.
From http://momentjs.com/docs/:
moment#valueOf simply outputs the number of milliseconds since the Unix Epoch
It is important to note that though the displays differ above, they are both the same moment in time.
var a = moment();
var b = moment.utc();
a.format(); // 2013-02-04T10:35:24-08:00
b.format(); // 2013-02-04T18:35:24+00:00
a.valueOf(); // 1360002924000
b.valueOf(); // 1360002924000
So it shouldn't differ for different timezones.
You should use adjustedStart.format(); to see the difference

MomentJS getting JavaScript Date in UTC

I am not able to get the JavaScript Date string for MongoDB record via the following. It keeps using my local time.
var utc = moment.utc().valueOf();
console.log(moment.utc(utc).toDate());
Output:
Tue Nov 11 2014 14:42:51 GMT-0500 (EST)
I need it to be in UTC, so I can stick this timestamp in Mongo so type would be Date.
How can I do that?
A timestamp is a point in time. Typically this can be represented by a number of milliseconds past an epoc (the Unix Epoc of Jan 1 1970 12AM UTC). The format of that point in time depends on the time zone. While it is the same point in time, the "hours value" is not the same among time zones and one must take into account the offset from the UTC.
Here's some code to illustrate. A point is time is captured in three different ways.
var moment = require( 'moment' );
var localDate = new Date();
var localMoment = moment();
var utcMoment = moment.utc();
var utcDate = new Date( utcMoment.format() );
//These are all the same
console.log( 'localData unix = ' + localDate.valueOf() );
console.log( 'localMoment unix = ' + localMoment.valueOf() );
console.log( 'utcMoment unix = ' + utcMoment.valueOf() );
//These formats are different
console.log( 'localDate = ' + localDate );
console.log( 'localMoment string = ' + localMoment.format() );
console.log( 'utcMoment string = ' + utcMoment.format() );
console.log( 'utcDate = ' + utcDate );
//One to show conversion
console.log( 'localDate as UTC format = ' + moment.utc( localDate ).format() );
console.log( 'localDate as UTC unix = ' + moment.utc( localDate ).valueOf() );
Which outputs this:
localData unix = 1415806206570
localMoment unix = 1415806206570
utcMoment unix = 1415806206570
localDate = Wed Nov 12 2014 10:30:06 GMT-0500 (EST)
localMoment string = 2014-11-12T10:30:06-05:00
utcMoment string = 2014-11-12T15:30:06+00:00
utcDate = Wed Nov 12 2014 10:30:06 GMT-0500 (EST)
localDate as UTC format = 2014-11-12T15:30:06+00:00
localDate as UTC unix = 1415806206570
In terms of milliseconds, each are the same. It is the exact same point in time (though in some runs, the later millisecond is one higher).
As far as format, each can be represented in a particular timezone. And the formatting of that timezone'd string looks different, for the exact same point in time!
Are you going to compare these time values? Just convert to milliseconds. One value of milliseconds is always less than, equal to or greater than another millisecond value.
Do you want to compare specific 'hour' or 'day' values and worried they "came from" different timezones? Convert to UTC first using moment.utc( existingDate ), and then do operations. Examples of those conversions, when coming out of the DB, are the last console.log calls in the example.
Calling toDate will create a copy (the documentation is down-right wrong about it not being a copy), of the underlying JS Date object. JS Date object is stored in UTC and will always print to eastern time. Without getting into whether .utc() modifies the underlying object that moment wraps use the code below.
You don't need moment for this.
new Date().getTime()
This works, because JS Date at its core is in UTC from the Unix Epoch. It's extraordinarily confusing and I believe a big flaw in the interface to mix local and UTC times like this with no descriptions in the methods.
This will give you the UTC timezone DateTime.
var convertedUtcDateTime = moment.utc(dateTimeToBeConverted);
When you call .utc(), all you're doing is setting a flag in the Moment object that says "this must format as UTC." You can see this change if you inspect the object's properties.
As another answer mentioned, the point in time remains the same. This ensures calculations etc. can be carried out without worrying about the time zone.
A JavaScript Date also stores timezone information, and similarly will format the value it represents as local or UTC depending on what method you call.
Option 1
Use the formatting methods as they were intended, and make the last thing you do before sending the value to the server a format into a UTC string.
For Moment, that's simply calling .toISOString() on any date local or otherwise, or the .format() method after calling .utc() if you want to specify a different format.
For JS dates, that's also a .toISOString() method.
If for some reason you don't have the ability to keep the dates in local time, or can't transform to a string for the data send, you have (at least) two further options:
Option 2
Use the JS Date constructor to manually create a datetime in the local timezone, pulling the components from your UTC Moment object.
let utc = moment().utc();
let date = new Date(utc.year(), utc.month(), utc.date(), utc.hour(), utc.minute(), utc.second(), utc.millisecond());
Alternatively, get the current datetime and then set the hours and minutes as appropriate for the timezone change.
You'll end up with a date representation of the UTC time marked as local time. This is not the correct time, as you're now offset by the time zone, but it might solve a problem in a pinch.
Option 3
Similar to option 2, this is another way to create an offset Date where UTC is marked as the local time zone.
Export the ISO string from either Moment or JS, strip off the Zulu flag at the end, and use the string constructor for Date to pull it back in.
new Date(new Date().toISOString().slice(0,-1));
Again, this is not actually the correct time and calculations against other datetimes may be incorrect. Your best option is still to send up a UTC ISO string to the server when you can.
Or simply:
Date.now
From MDN documentation:
The Date.now() method returns the number of milliseconds elapsed since January 1, 1970
Available since ECMAScript 5.1
It's the same as was mentioned above (new Date().getTime()), but more shortcutted version.

QueryScheduleRequest not working in Microsoft CRM 2011

I basically want to check if a particular user is free in a provided time range using QueryScheduleRequest. For this I am using the following piece of code to retrieve available timings of the user on today's date:
QueryScheduleRequest scheduleRequest = new QueryScheduleRequest
{
ResourceId = userResponse.UserId,
Start = DateTime.Today,
End = DateTime.Today,
TimeCodes = new TimeCode[] { TimeCode.Available}
};
QueryScheduleResponse scheduleResponse = (QueryScheduleResponse)serviceProxy.Execute(scheduleRequest);
However, I am not getting proper response in scheduleResponse as seen in CRM service calendar. The start and end dates are also getting changed in the response. For eg, say I enter Start and End date as 12th in scheduleRequest but in scheduleResponse they get changed to 12th and 13th respectively. I have checked that I am referring the correct user.
This is how the user's schedule looks like in CRM (Work Hours:10am to 7pm):
And this is how the result in scheduleResponse looks like:
Observe the dates and schedule getting changed. Is there any other way in which I can achieve this functionality?
Basically Dynamics CRM stores all dates in the database as UTC time.Crm Users has to convert into Users LocalTime.
After getting scheduleResponse. You can Use the below Code to get User Start time and End Time.
QueryScheduleResponse scheduleResponse = (QueryScheduleResponse)service.Execute(scheduleRequest);
foreach (var getTimings in scheduleResponse.TimeInfos)
{
DateTime startTime =Convert.ToDateTime(getTimings.Start.Value.ToLocalTime());
DateTime endTime = Convert.ToDateTime(getTimings.Start.Value.ToLocalTime());
}
Note:we have ExpandCalendarRequest Class also to Retrieve User Available Timings

Problem with application reliant on British Summer Time in Azure

Part of an on premise app I am moving to the cloud, displays TV Scheduling information from a json source. The core data uses an offset in seconds from a start date to get it's start times which is all fine as these are all int UTC format.
The problem arises in the movement to the cloud.
The on premise app was situated in the UK so the locale is UntedKingdom and the TV times were correctly output using
return programmeStart.AddHours(programmeStart.IsDaylightSavingTime() ? 1 : 0);
However, having now moved to the cloud, the functionality for IsDaylightSavingTime, no longer returns true due to data centers being BST Agnostic.
Been racking my brains for a way to try and sort this.
Is there a quick and easy way to set what locale your hosted service runs under in Azure, or is the best solution to create an extension method that reads the boundries of when BST runs from and to, and then return true or false from there for example
public static class DateTimeExtension
{
public static bool IsMyDaylightSavingTime(this DateTime timeToTest)
{
if(timeToTest >= GetConfig("bstStart") && timeToTest <= GetConfig("bstFinish"))
{
return true;
}
return false;
}
}
And the maintaing the config values of bst changing as they move?
Thanks
You can't change the timezone of the Azure servers - there's lots going on that assumes UTC is the current setting.
You should be able to get hold of the UK timezoneinfo by string, e.g.:
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
After you've done that, then you can use the framework method TimeZoneInfo.IsDaylightSavingTime http://msdn.microsoft.com/en-us/library/bb460642.aspx
tzi.IsDaylightSavingTime(DateTime.Now);
Why can't you simply return UTC and let the client translate that per their locale?
Edit: Here is code
var offset = TimeZoneInfo.GetSystemTimeZones()
.Where(z => z.Id == "GMT Standard Time")
.Single()
.GetUtcOffset(DateTime.UtcNow)

Resources