AngularJs $http sends date object to server without time offset

I have an AngularJs app, one of the pages has bootstrap datetime picker tool.
and this is what the input which is using it looks like:

<input class="form-control"
   is-open="vm.search.openFromYear"
   name="txtfromYear"
   ng-click="vm.search.openFromYear = !vm.search.openFromYear"
   ng-init="vm.search.openFromYear = false"
   ng-model="vm.searchModel.fromYear"
   placeholder="dd/MM/yyyy"
   show-button-bar="false"
   type="text"
   uib-datepicker-popup="dd/MM/yyyy" />

When I choose a date I see it correctly in the input, let's say I choosed 14/01/2017..

In vm.searchModel.fromYear it's saved as js date object, with the date value and timezone Sun Jan 14 2018 00:00:00 GMT+0300 (Turkey Standard Time).

The problem is when I send this to server it's converted by $http service and sent by ajax like: 2018-01-13T21:00:00.000Z.

As you see it's one day behind (because of converting to UTC format, but without the time offset +3 hours.

The API receives this string and bind it to a property of DateTime type but as it is, the date will be 2018-01-13, not 2018-01-14 as the user really choose it.

Any idea why is that happening ? I read some answers and didn't find an explanation or a solution.

2 answers

  • answered 2018-01-14 10:43 mkeremguc

    the ISO string that $http converts is correct. since you just need an explanation:

    time is 21:00 in a GMT zone at the time of 00:00 in a GMT+3 timezone. the ISO string represents the GMT zone time which is 3 hours behind the GMT+3 hence the date

  • answered 2018-01-14 10:43 davidkonrad

    I suggest you use momentjs and moment-timezone to solve this problem. Include the libraries, if you are using bower the recent versions is

    "momentjs": "~2.20.1",
    "moment-timezone": "0.5.14"
    

    Now setup your timezone (Turkey Standard Time) in app.config

    angular.module('myApp', [...] ).config(function(...) {
       moment.tz.setDefault("Europe/Istanbul"); 
    })
    

    When you need to pass the date with respect of timezone

    moment(date).format() //will convert to GMT+0300
    

    This also works of you need to pass back a formatted date

    moment(date).format('DD/MM/YYYY') // 14/01/2018
    

    It goes either way. You just convert the dates / timestamps received from the server to the local timezone the same way, i.e

    var localDate = moment(date).format()
    

    The above using Europe/Istanbul was just an example. I dont know what different timezones your users operates in, it is up to you to set moment.tz.setDefault() in .config() properly according to the users locale / timezone. If you not know that you can use

    moment.tz.guess();
    

    Read the documentation for how it works.

    tl;dr : Simply use moment.tz.setDefault() along with moment().format(), by that your app can operate in different timezones using the same dates, without corrupting the dates or showing wrong dates to the end user.