Merge "Add timezones and UTC offsets to timestamps"
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
index a817068..afa5163 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.html
@@ -157,8 +157,8 @@
               <select
                   is="gr-select"
                   bind-value="{{_localPrefs.time_format}}">
-                <option value="HHMM_12">4:10 PM</option>
-                <option value="HHMM_24">16:10</option>
+                <option value="HHMM_12">4:10 PM (PST)</option>
+                <option value="HHMM_24">16:10 (PST)</option>
               </select>
             </span>
           </section>
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
index 3d0cf5a..ae6bb75 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.html
@@ -26,8 +26,9 @@
         display: inline;
       }
     </style>
-    <span title$="[[_computeFullDateStr(dateStr, _timeFormat)]]"
-        >[[_computeDateStr(dateStr, _timeFormat, _relative)]]</span>
+    <span title$="[[_computeFullDateStr(dateStr, _timeFormat)]]">
+      [[_computeDateStr(dateStr, _timeFormat, _relative)]]
+    </span>
     <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   </template>
   <script src="gr-date-formatter.js"></script>
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
index f6117e4..a8c9010 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.js
@@ -21,7 +21,9 @@
 
   var TimeFormats = {
     TIME_12: 'h:mm A', // 2:14 PM
+    TIME_12_WITH_SEC: 'h:mm:ss A', // 2:14:00 PM
     TIME_24: 'HH:mm', // 14:14
+    TIME_24_WITH_SEC: 'HH:mm:ss', // 14:14:00
     MONTH_DAY: 'MMM DD', // Aug 29
     MONTH_DAY_YEAR: 'MMM DD, YYYY', // Aug 29, 1997
   };
@@ -44,6 +46,14 @@
       this._loadPreferences();
     },
 
+    _getTzString: function() {
+      return ' ' + new Date().toString().split(' ').pop();
+    },
+
+    _getUtcOffsetString: function() {
+      return ' UTC' + moment().format('Z');
+    },
+
     _loadPreferences: function() {
       return this._getLoggedIn().then(function(loggedIn) {
         if (!loggedIn) {
@@ -121,18 +131,26 @@
       var now = new Date();
       var format = TimeFormats.MONTH_DAY_YEAR;
       if (this._isWithinDay(now, date)) {
-        format = timeFormat;
+        return date.format(timeFormat) + this._getTzString();
       } else if (this._isWithinHalfYear(now, date)) {
         format = TimeFormats.MONTH_DAY;
       }
       return date.format(format);
     },
 
+    _timeToSecondsFormat: function(timeFormat) {
+      return timeFormat === TimeFormats.TIME_12 ?
+          TimeFormats.TIME_12_WITH_SEC :
+          TimeFormats.TIME_24_WITH_SEC;
+    },
+
     _computeFullDateStr: function(dateStr, timeFormat) {
       if (!dateStr) { return ''; }
       var date = moment(util.parseDate(dateStr));
       if (!date.isValid()) { return ''; }
-      return date.format(TimeFormats.MONTH_DAY_YEAR + ', ' + timeFormat);
+      var format = TimeFormats.MONTH_DAY_YEAR + ', ';
+      format += this._timeToSecondsFormat(timeFormat);
+      return date.format(format) + this._getUtcOffsetString();
     },
   });
 })();
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
index 8d65bc3..0faf102 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_test.html
@@ -33,6 +33,15 @@
 <script>
   suite('gr-date-formatter tests', function() {
     var element;
+    var sandbox;
+
+    setup(function() {
+      sandbox = sinon.sandbox.create();
+    });
+
+    teardown(function() {
+      sandbox.restore();
+    });
 
     /**
      * Parse server-formatter date and normalize into current timezone.
@@ -47,13 +56,12 @@
       // Normalize and convert the date to mimic server response.
       dateStr = normalizedDate(dateStr)
           .toJSON().replace('T', ' ').slice(0, -1);
-      var clock = sinon.useFakeTimers(normalizedDate(nowStr).getTime());
+      sandbox.useFakeTimers(normalizedDate(nowStr).getTime());
       element.dateStr = dateStr;
       flush(function() {
         var span = element.$$('span');
-        assert.equal(span.textContent, expected);
+        assert.equal(span.textContent.trim(), expected);
         assert.equal(span.title, expectedTooltip);
-        clock.restore();
         done();
       });
     }
@@ -74,6 +82,8 @@
           {time_format: 'HHMM_24', relative_date_in_change_table: false}
         ).then(function() {
           element = fixture('basic');
+          sandbox.stub(element, '_getTzString').returns('');
+          sandbox.stub(element, '_getUtcOffsetString').returns('');
           element._loadPreferences().then(function() { done(); });
         });
       });
@@ -85,26 +95,26 @@
 
       test('Within 24 hours on same day', function(done) {
         testDates('2015-07-29 20:34:14.985000000',
-                  '2015-07-29 15:34:14.985000000',
-                  '15:34', 'Jul 29, 2015, 15:34', done);
+            '2015-07-29 15:34:14.985000000',
+            '15:34', 'Jul 29, 2015, 15:34:14', done);
       });
 
       test('Within 24 hours on different days', function(done) {
         testDates('2015-07-29 03:34:14.985000000',
-                  '2015-07-28 20:25:14.985000000',
-                  'Jul 28', 'Jul 28, 2015, 20:25', done);
+            '2015-07-28 20:25:14.985000000',
+            'Jul 28', 'Jul 28, 2015, 20:25:14', done);
       });
 
       test('More than 24 hours but less than six months', function(done) {
         testDates('2015-07-29 20:34:14.985000000',
-                  '2015-06-15 03:25:14.985000000',
-                  'Jun 15', 'Jun 15, 2015, 03:25', done);
+            '2015-06-15 03:25:14.985000000',
+            'Jun 15', 'Jun 15, 2015, 03:25:14', done);
       });
 
       test('More than six months', function(done) {
         testDates('2015-09-15 20:34:00.000000000',
-                  '2015-01-15 03:25:00.000000000',
-                  'Jan 15, 2015', 'Jan 15, 2015, 03:25', done);
+            '2015-01-15 03:25:00.000000000',
+            'Jan 15, 2015', 'Jan 15, 2015, 03:25:00', done);
       });
     });
 
@@ -115,14 +125,16 @@
           {time_format: 'HHMM_12'}
         ).then(function() {
           element = fixture('basic');
+          sandbox.stub(element, '_getTzString').returns('');
+          sandbox.stub(element, '_getUtcOffsetString').returns('');
           element._loadPreferences().then(function() { done(); });
         });
       });
 
       test('Within 24 hours on same day', function(done) {
         testDates('2015-07-29 20:34:14.985000000',
-                  '2015-07-29 15:34:14.985000000',
-                  '3:34 PM', 'Jul 29, 2015, 3:34 PM', done);
+            '2015-07-29 15:34:14.985000000',
+            '3:34 PM', 'Jul 29, 2015, 3:34:14 PM', done);
       });
     });
 
@@ -132,20 +144,22 @@
           {time_format: 'HHMM_12', relative_date_in_change_table: true}
         ).then(function() {
           element = fixture('basic');
+          sandbox.stub(element, '_getTzString').returns('');
+          sandbox.stub(element, '_getUtcOffsetString').returns('');
           element._loadPreferences().then(function() { done(); });
         });
       });
 
       test('Within 24 hours on same day', function(done) {
         testDates('2015-07-29 20:34:14.985000000',
-                  '2015-07-29 15:34:14.985000000',
-                  '5 hours ago', 'Jul 29, 2015, 3:34 PM', done);
+            '2015-07-29 15:34:14.985000000',
+            '5 hours ago', 'Jul 29, 2015, 3:34:14 PM', done);
       });
 
       test('More than six months', function(done) {
         testDates('2015-09-15 20:34:00.000000000',
-                  '2015-01-15 03:25:00.000000000',
-                  '8 months ago', 'Jan 15, 2015, 3:25 AM', done);
+            '2015-01-15 03:25:00.000000000',
+            '8 months ago', 'Jan 15, 2015, 3:25:00 AM', done);
       });
     });
 
@@ -155,6 +169,7 @@
           {time_format: 'HHMM_12', relative_date_in_change_table: true}
         ).then(function() {
           element = fixture('basic');
+          sandbox.stub(element, '_getTzString').returns('');
           element._loadPreferences().then(function() { done(); });
         });
       });
@@ -169,6 +184,7 @@
       setup(function(done) {
         return stubRestAPI(null).then(function() {
           element = fixture('basic');
+          sandbox.stub(element, '_getTzString').returns('');
           element._loadPreferences().then(function() { done(); });
         });
       });