I am having one website in which it has functionality to Login with specific timezone regardless what's the timezone on client side.
Now,
In website when user selects a date in dialog.I am sending it to server side using JSON.stringify with several other properties.
But whenever it is received at server side date is changed.
Example :-
I logged in using (+05 : 30) India time zone "01/08/2015 00:00:00" and server is having Casablanca Timezone.
When the date is received at server side the date is reduced by One "31/08/2015".
I think it is because of timezone conversion.
I already checked following link :-
JSON Stringify changes time of date because of UTC
I already tried that answer :- https://stackoverflow.com/a/1486612/2592727
But i am unable to understand how that formula works. So it's better to get more details and work with some specific solution.
Requirement :-
I am allowing user to select only date.
I want same date to be received over server side.
How can i accomplish this? Please describe with more details if possible.
Is there any simple way to avoid this collision?
The JSON.stringify method stored the date as UTC in the string, and when you parse that in .NET you will get a DateTime that contains the exact same point in time, but converted to the local time of the server.
You can handle this in two ways, you can either convert the time back to the original time zone, or you can avoid using the Date data type.
Converting to the original time zone of course requires you to know what the time zone is. Example:
var zone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
DateTime userTime = TimeZoneInfo.ConvertTimeFromUtc(date.ToUniversalTime(), zone);
To avoid using the Date type, you would format the date into a string before serialising it. Example:
var s = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
On the server side you would parse the string using the same format:
DateTime userTime = DateTime.ParseExact(date, "yyyy-M-d", CultureInfo.InvariantCulture);
Use the format yyyy-mm-dd hh:mm:ss and you will never get this ever again, regardless of timezone
Related
How to convert date like '2021-06-01T11:17:00-07:00' to ISO standard? What is this format?
let date = new Date('2021-06-01T11:17:00-07:00');
console.log(date.getHours() + " :" + date.getMinutes());
I should get 11:17 but I am getting back 23:47
So something going wrong in understanding the correct format of date?
To reverse engineer,
If I convert date my expected date which is "2021-06-01 11:17:00" to IsoString then the value which I get is 2021-06-01T05:47:00.000Z
which is not equal to 2021-06-01T11:17:00-07:00
PS - So from comments I got to know this format is in MST which is 7 hours behind UTC
The input specifies a time zone, so it specifies a time at which in Salt Lake City it is 11:17. That same moment corresponds to 23:47 in New Delhi, which is your time zone.
So when you tell JavaScript to read the input, it will know it is a specification in Mountain Standard Time (-07:00), and will store the date in UTC. When you output the date as you do, JavaScript will use your locale and output it as 23:47, which is the exact same moment that the input specifies.
If you want the time to output as 11:17, then apparently you don't want to consider that it is a local time in Salt Lake City, but ignore that, and just consider it to be 11:17 in your time zone.
In that case, you should change the input, and remove the time zone specification:
let date = new Date('2021-06-01T11:17:00'); // No time zone specified -> is interpreted as local time
console.log(date.getHours() + " :" + date.getMinutes());
If the input string is variable, you can strip the time zone by keeping only the first 19 characters of the input before passing it to the Date constructor.
But be aware that when you strip the time zone, you actually change the time specification in the input to a different one. It is no longer the same time.
Have you tried using the Vanilla javascript Date class? Should be able to pass that into the constructor and then convert it to the desired format. For example:
const date2 = new Date('1995-12-17T03:24:00');
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date
You could also try using the Moment library in Javascript, although many people are trying to move away from this.
I am using moment-timezone so I can convert from selected timezone to timezone of a client.
I wasn't able to implement it in a better way than this:
convertSelectedTimeZoneToClients() {
let timeZoneInfo = {
usersTimeZone: this.$rootScope.mtz.tz.guess(),
utcOffset: this.formData.timeZone.offset,
selectedDateTime: this.toJSONLocal(this.formData.sessionDate) + " " + this.formData.sessionTime
};
let utcTime = this.$rootScope.mtz.utc(timeZoneInfo.selectedDateTime).utcOffset(timeZoneInfo.utcOffset).format("YYYY-MM-DD HH:mm");
let convertedTime = this.$rootScope.mtz.tz(utcTime, timeZoneInfo.usersTimeZone).format("Z");
return convertedTime;
}
So basically I am using usersTimeZone: this.$rootScope.mtz.tz.guess(), guess() function to find out timezone from the browser.
Then I get values from datetime picker and dropdown and convert them to UTC value by using utcOffset.
At the end I want to convert that utc value to user timezone value.
I get object like this:
_d represent correct value after conversion. I have tried adding bunch of different .format() paterns on convertedTime variable, but I am not able to retrive time in this format: "YYYY-MM-DD HH:mm". I guess it works differentlly than when using .utcOffset() function.
Can anybody help me with this?
You don't need to guess the client time zone to convert to local time. Just use the local function.
For example:
moment.tz('2016-01-01 00:00', 'America/New_York').local().format('YYYY-MM-DD HH:mm')
For users located in the Pacific time zone, this converts from Eastern to Pacific and you get an output string of "2015-12-31 21:00". For users in other time zones, the output would be different, as expected.
You don't need to format to a string and re-parse it, or manually manipulate the UTC offset either. That is almost never warranted.
Hi im using moment js to convert this string 20:00 I tried:
var a = moment("20:00", "HH:mm")
console.log(a.format()) // 2016-09-08T20:00:00+01:00
the problem when I store in mongodb it become
2016-09-10T19:00:00.000Z
I want to store 2016-09-10T20:00:00.000Z
anyway can explain why please ?
When you say that you want to store 2016-09-10T20:00:00.000Z what you are saying is that you want to assume that your date and time is UTC.
To assume that the date you are parsing is a UTC value, use moment.utc
var a = moment.utc("20:00", "HH:mm")
console.log(a.format()) // 2016-09-08T20:00:00Z
Note that when you parse a time without a date, moment assumes the current date. This may not be the behavior that you want.
I'm also not sure if you want a UTC date (which is what you are saying), or a local date without an offset indicator. If you want a local date without an offset indicator, simply use a format without an offset:
moment.utc("20:00", "HH:mm").format('YYYY-MM-DDTHH:mm:ss.SSS')
"2016-09-08T20:00:00.000"
If you are dealing with local dates that do not have a time zone association, I recommend using moment.utc to parse, as this will ensure that the time does not get shifted to account for DST in the current time zone.
For more information about how to parse dates into the time zone or offset that you would like in moment, see my blog post on the subject.
This it how it should look:
var a = moment("20:00", "HH:mm")
console.log(a.utcOffset('+0000').format())
<script src="http://momentjs.com/downloads/moment.min.js"></script>
Doe, the problem is that you are using timezones when you create the date.
MomentJS uses your current timezone automatically.
Mongo however saves the time as it would be in another timezone.
Therefore, if you want the two strings to format the same way, you need to set the timezone.
I would like to know whether the following is the right method to handle datetime data type in WebApi 2, Javascript and database.
DateTime from Javascript to WebApi:
var date = new Date();
var datestring = date.toISOString();
//Send datestring to WebApi
DateTime from WebApi to Javascript:
//on getting datetime value from `http.get` call
var dateFromServer = new Date(dateFromServer);
WebApi:
Incoming date
do nothing simply store the datestring returned in database column with datatype datetime
Getting date from database and Returning date to client:
no datetime manipulation (simply return as per WebApi Json serializer ex: 2015-10-23T18:30:00). Client would automatically convert the UTC datetime to local datetime
Yes if you don't want to handle any information about user Timezone etc... this is an acceptable way.
Just make sure that any time you want a date produced from the server for a comparison or something else to use the c# DateTime.UtcNow
method.
I think Having a "Global UTC Convention" its a quite safe and good solution but it has some limits.
For example if you want to Alert all of your users located in different timezones at 09:00 am (on each user's country) then its impossible to know when its "09:00" for each one.
One way to solve this(and it's the one i prefer), is to store manually each user's timezone info separately on the database, and every time you want to make a comparison simply convert the time.
TimeZoneInfo.ConvertTimeFromUtc(time, this.userTimezone);
Alternatively if you want to store all timezone information on the server you can :
Send your date from javascript to the server using the following format :
"2014-02-01T09:28:56.321-10:00" ISO 8601 also supports time zones by replacing the Z with + or – value for the timezone offset.
Declare your WEB API 2 Date types with the "DateTimeOffset" type.
Finally store your dates within the database using the "datetimeoffset" type.
This way any time on the server or the database you have all the information about the user's time and timezone.
You will find this article useful
I'm wondering if it's possible to use AngularStrap's datepicker without it keeping the user's locale's timezone information. In our application we want to handle Contract objects that have an expiration date.
When adding or editing the contract object, there is a datepicker field for selecting the date. The following thing happens:
The user selects the date (e.g. 2013-10-24)
Angular binds the javascript date object to the ng-model field
The binded date object is in the user's timezone (e.g. GMT+3)
The user submits the form
The date gets sent to the server using Angular's $http service
In step 5 the date is converted to UTC format. The selected date was GMT+3 2013-10-24 at midnight, but the UTC conversion changes the date to 2013-10-23 at 9pm.
How could we prevent the conversion, or use UTC dates during the whole process? We don't want the contract's date to change based on the user's local timezone. Instead, we want the date to be always 2013-10-24, no matter what timezone.
Our current solution was to make small changes to the AngularStrap library so that the date won't change when sent to the server.
If we could get the user's selected timezone in the server, we could make another conversion there, but the server doesn't have that information.
All ideas are appreciated!
The issue isn't AngularStrap. Its just how javascript dates work and how JSON formats them for transmission. When you turn a javascript date object into a JSON string, it formats the string as UTC.
For example, I'm in Utah and it is now 07:41 on 2013-10-24. If I create a new javascript date and print it to the console it will say:
Thu Oct 24 2013 07:41:19 GMT-0600 (MDT)
If I stringify that same date (using JSON.stringify(date), I get:
"2013-10-24T13:41:47.656Z"
which you can see is not in my current timezone, but is in UTC. So the conversion is happening just before the form gets sent to the server when it gets converted from a javascript object to a JSON string.
The easiest way to do it would be to just change the date to a string of your own choosing prior to sending the date to the server. So instead of letting JSON change the date to UTC, (assuming you don't care about the time of day) you could just do something like this:
var dateStrToSend = $scope.date.getUTCFullYear() + '-' + ($scope.date.getUTCMonth() + 1) + '-' + $scope.date.getUTCDate();
That will give you a UTC-based string that looks like '2013-10-24' and then you can send that to the server, instead of the JSON format which includes the time info. Hopefully that helps.
UPDATE: As #Matt Johnson said, there are two ways to do it. You said: How could we prevent the conversion, or use UTC dates during the whole process?. If you want to use UTC, then use my above explanation. If you want to just "prevent the conversion", you could use the following:
var dateStrToSend = $scope.date.getFullYear() + '-' + ($scope.date.getMonth() + 1) + '-' + $scope.date.getDate();
A bit late but I spent my afternoon on this and someone might find it useful.
Another way to do this declaratively is to use the dateType, dateFormat and modelDateFormat attributes. Set these in either the config or the HTML e.g
angular.module('app').config(function ($datepickerProvider) {
angular.extend($datepickerProvider.defaults, {
dateFormat: 'dd-MMMM-yyyy',
modelDateFormat: "yyyy-MM-ddTHH:mm:ss",
dateType: "string"
});
});
DateFormat is the format the date will be displayed to the user in the date picker while modelDateFormat is the format it will be converted to before being bound to your model.
I also had default values coming from the server which I needed to be bound to the datepicker on page load. I therefore had to update the format the server serialized dates in JSON to match the modelDateFormat. I am using Web API so I used the below.
var jsonSettings = Formatters.JsonFormatter.SerializerSettings;
jsonSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss";
The "Angular way" is to use the $filter service to format the date returned by the datepicker.
Example (HTML):
{{inpDate | date: 'dd-MM-yyyy'}}
Example (JS):
$scope.processDate = function(dt) {
return $filter('date')(dt, 'dd-MM-yyyy');
}
Plunker here