mk_yo
mk_yo

Reputation: 770

javascript doesn't convert angular ui datepicker date to UTC correctly

I'm using angular ui datepicker in my project(asp.net web api + angularjs). All works fine but when I'm trying to save date to Db it doesn't convert it to UTC format correctly and substructs 1 day(actually a few hours but it affects for a day too).

For example when I choose 01/11/2014 in the datepicker:

Angularjs object:
Sat Nov 01 2014 00:00:00 GMT+0200 (FLE Standard Time)

In request: 
2014-10-31T22:00:00.000Z

In asp.net api controller:
{31-Oct-14 10:00:00 PM}

Datepicker controller:

app.controller('DatepickerCtrl', function ($scope) {
    $scope.today = function () {
        $scope.dt = new Date();
    };
    $scope.today();
    $scope.clear = function () {
        $scope.dt = null;
    };
    $scope.open = function ($event) {
        $event.preventDefault();
        $event.stopPropagation();

        $scope.opened = true;
    };
    $scope.format = 'dd/MM/yyyy';
    $scope.dateOptions = {
        'starting-day': 1
    };
});

hnml:

<div class="form-group inputGroupContainer" ng-controller="DatepickerCtrl">
                    <label for="date">Date of Birth</label>
                    <p class="input-group">
                        <input type="text" name="date1" ui-date="{dateFormat: 'yy-mm-dd'}" ui-date-format="yy-mm-dd" placeholder="DD/MM/YYYY" class="form-control" datepicker-popup="{{format}}" ng-model="user.Personal.BirthDate" max-date="currentDate" is-open="opened" close-text="Close" />
                        <span class="input-group-btn">
                            <button type="button"   class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
                        </span>
                    </p>
                </div>

But seems like angular datepicker highlight the correct date:

enter image description here

I've tried to manually convert date to UTC format but unsuccessfully as well

   toUTCDate: function (d) {
            var date = new Date(d);
            var _utc = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate());//, date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()
            return _utc;
        }

Should I specify timezone or use angular js filter?

Upvotes: 15

Views: 13540

Answers (3)

frhd
frhd

Reputation: 10244

Just to add the coffeescript version of Entre's answer, which works for me in "angular": "~1.3.14",:

app.directive 'dateToIso', [ () ->

  restrict: 'A',
  require: 'ngModel'

  link: (scope, el, attrs, ngModel) ->
    if (angular.isUndefined(attrs.ngModel))
      console.log 'ngModel attribute missing for date-to-iso'
    else
      ngModel.$parsers.push (datePickerValue) ->
        return moment(datePickerValue).format("YYYY-MM-DD")
]

Upvotes: 3

harishr
harishr

Reputation: 18055

I have had the exact same problem, the solution was to remove the timezone component of the date part. To solve the problem in a more generic way I had written a directive

csapp.directive("csDateToIso", function () {

    var linkFunction = function (scope, element, attrs, ngModelCtrl) {

        ngModelCtrl.$parsers.push(function (datepickerValue) {
            return moment(datepickerValue).format("YYYY-MM-DD");
        });
    };

    return {
        restrict: "A",
        require: "ngModel",
        link: linkFunction
    };
});

above directive removes the timezone part and only considers the date part of the ISO date format input.

I do use moment.js for date manipulations. But you can easily convert above to not use moment.js

EDIT

use it like below

  <input ng-model='abc' cs-date-to-iso ui-datepicker>

Upvotes: 19

agusluc
agusluc

Reputation: 1465

Don't send the javascript object in the json request, javascript add the browsers timezone in the string representation of the object that is used in the JSON. You can use something like this to extract the date into an string without the timezone:

myApp.service('dateService', function(){
    this.parse = function(date) {
        if(!date){
            return ""
        }
        var day = (date.getDate() < 10 ? '0' : '') + date.getDate();
        var month = ((date.getMonth() + 1) < 10 ? '0' : '') + (date.getMonth() + 1);
        var hours = (date.getHours() < 10 ? '0' : '') + date.getHours();
        var minutes = (date.getMinutes() < 10 ? '0' : '') + date.getMinutes();
        var seconds = (date.getSeconds() < 10 ? '0' : '') + date.getSeconds();
        return date.getFullYear() + "-" + month + "-" + day + " " + hours + ":" + minutes + ":" + seconds
    }
});

Then in your backend you only have to parse the string into a date object using the format "yyyy-MM-dd HH:mm:ss" in the timezone of your choosing. I don't know about .NET but in java you can do something like this:

def jsCalendarFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
jsCalendarFormat.setTimeZone(user.timezone)
Date dateObj = jsCalendarFormat.parse(date)

Upvotes: 2

Related Questions