Milliseconds from Epoch directive

When you're underlying data source is bound to a milliseconds from epoch value it requires some work to both display and edit it. The display is fairly easy because of the AngularJS date filter.

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.1/css/bootstrap.min.css">
<!--
The purpose of this fiddle is to show how you might use $formatters and $parsers to allow users to edit a date, specifically one that has a raw value of milliseconds from epoch.

NOTE: There is one caveat. The new HTML5 editing controls that show up (e.g. input[type="date"]) really shouldn't be used here. Chrome for example requires that you return it a Date object. This however won't work right when the HTML5 control falls back to a text box. The string representation of the date is not what you'd want.
--->
<div ng-app="app">
    <div ng-controller="ctrl">
        <input type="text" ng-model="milliseconds" app-datetime2="" />
        <!--
        <input type="date" ng-model="milliseconds" app-datetime="" no-validate />
        -->
        <div ng-bind="milliseconds | date:'MM/dd/yyyy'"></div>
        <div>Raw value: {{milliseconds}}</div>
    </div>
</div>

CSS

body {
    margin: 1em;
}

input, div {
    margin: 0.5em;
}

JavaScript

/*************
 ** POLYFILL **
 *************/
if (!String.prototype.includes) {
    String.prototype.includes = function () {
        'use strict';
        return String.prototype.indexOf.apply(this, arguments) !== -1;
    };
}

var app = angular.module('app', []);

app.directive("appDatetime", function () {
    return {
        require: 'ngModel',
        scope: {
            format: '@'
        },
        link: function (scope, element, attrs, ngModelController) {
            function padInt(val) {
                var concat = '0' + val.toString();
                var startIndex = concat.length - 2;
                var retVal = concat.substr(startIndex, 2);
                return retVal;
            }

            ngModelController.$parsers.push(function (data) {
                //convert data from view format to model format
                return Date.parse(data);
            });

            ngModelController.$formatters.push(function (data) {
                //convert data from model format to view format
                var val = new Date(data);
                return padInt(val.getMonth() + 1) + '/' +
                    padInt(val.getDate()) + '/' +
                    val.getFullYear().toString();
            });
        }
    };
});

app.controller('ctrl', function ($scope) {
    $scope.milliseconds = 2421260768155;
});