Displaying time as per user timezone (#899)

* Displaying time as per user timezone

* Refactor

* Fixing annotation created time

* Adding comments

* Fix typo
diff --git a/src/components/view/DetailsTab.vue b/src/components/view/DetailsTab.vue
index 78c85a6..64809b2 100644
--- a/src/components/view/DetailsTab.vue
+++ b/src/components/view/DetailsTab.vue
@@ -37,6 +37,9 @@
           <span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(resource[item])">{{ $t(resource[item].toLowerCase()) }}</span>
           <span v-else>{{ resource[item] }}</span>
         </div>
+        <div v-else-if="['created', 'sent', 'lastannotated'].includes(item)">
+          {{ $toLocaleDate(resource[item]) }}
+        </div>
         <div v-else>
           {{ resource[item] }}
         </div>
diff --git a/src/components/view/InfoCard.vue b/src/components/view/InfoCard.vue
index aa778d6..8200b81 100644
--- a/src/components/view/InfoCard.vue
+++ b/src/components/view/InfoCard.vue
@@ -533,7 +533,7 @@
         <div class="resource-detail-item" v-if="resource.created">
           <div class="resource-detail-item__label">{{ $t('label.created') }}</div>
           <div class="resource-detail-item__details">
-            <a-icon type="calendar" />{{ resource.created }}
+            <a-icon type="calendar" />{{ $toLocaleDate(resource.created) }}
           </div>
         </div>
       </div>
@@ -639,7 +639,7 @@
             <a-list-item slot="renderItem" slot-scope="item">
               <a-comment
                 :content="item.annotation"
-                :datetime="item.created" >
+                :datetime="$toLocaleDate(item.created)" >
                 <a-button
                   v-if="'removeAnnotation' in $store.getters.apis"
                   slot="avatar"
diff --git a/src/components/view/ListView.vue b/src/components/view/ListView.vue
index 7ff0b34..bd191ef 100644
--- a/src/components/view/ListView.vue
+++ b/src/components/view/ListView.vue
@@ -224,6 +224,12 @@
     <a slot="readonly" slot-scope="text, record">
       <status :text="record.readonly ? 'ReadOnly' : 'ReadWrite'" />
     </a>
+    <span slot="created" slot-scope="text">
+      {{ $toLocaleDate(text) }}
+    </span>
+    <span slot="sent" slot-scope="text">
+      {{ $toLocaleDate(text) }}
+    </span>
     <div slot="order" slot-scope="text, record" class="shift-btns">
       <a-tooltip placement="top">
         <template slot="title">{{ $t('label.move.to.top') }}</template>
diff --git a/src/main.js b/src/main.js
index 11ee548..e1aeb5f 100644
--- a/src/main.js
+++ b/src/main.js
@@ -26,13 +26,14 @@
 import './core/ext'
 import './permission' // permission control
 import './utils/filter' // global filter
-import { pollJobPlugin, notifierPlugin } from './utils/plugins'
+import { pollJobPlugin, notifierPlugin, toLocaleDatePlugin } from './utils/plugins'
 import { VueAxios } from './utils/request'
 
 Vue.config.productionTip = false
 Vue.use(VueAxios, router)
 Vue.use(pollJobPlugin)
 Vue.use(notifierPlugin)
+Vue.use(toLocaleDatePlugin)
 
 fetch('config.json').then(response => response.json()).then(config => {
   Vue.prototype.$config = config
diff --git a/src/store/getters.js b/src/store/getters.js
index 73042aa..189d6e4 100644
--- a/src/store/getters.js
+++ b/src/store/getters.js
@@ -33,7 +33,8 @@
   asyncJobIds: state => state.user.asyncJobIds,
   isLdapEnabled: state => state.user.isLdapEnabled,
   cloudian: state => state.user.cloudian,
-  zones: state => state.user.zones
+  zones: state => state.user.zones,
+  timezoneoffset: state => state.user.timezoneoffset
 }
 
 export default getters
diff --git a/src/store/modules/user.js b/src/store/modules/user.js
index 988f7a8..7638eb0 100644
--- a/src/store/modules/user.js
+++ b/src/store/modules/user.js
@@ -24,7 +24,7 @@
 import store from '@/store'
 import { login, logout, api } from '@/api'
 import i18n from '@/locales'
-import { ACCESS_TOKEN, CURRENT_PROJECT, DEFAULT_THEME, APIS, ASYNC_JOB_IDS, ZONES } from '@/store/mutation-types'
+import { ACCESS_TOKEN, CURRENT_PROJECT, DEFAULT_THEME, APIS, ASYNC_JOB_IDS, ZONES, TIMEZONE_OFFSET } from '@/store/mutation-types'
 
 const user = {
   state: {
@@ -38,13 +38,18 @@
     asyncJobIds: [],
     isLdapEnabled: false,
     cloudian: {},
-    zones: {}
+    zones: {},
+    timezoneoffset: '0.0'
   },
 
   mutations: {
     SET_TOKEN: (state, token) => {
       state.token = token
     },
+    SET_TIMEZONE_OFFSET: (state, timezoneoffset) => {
+      Vue.ls.set(TIMEZONE_OFFSET, timezoneoffset)
+      state.timezoneoffset = timezoneoffset
+    },
     SET_PROJECT: (state, project = {}) => {
       Vue.ls.set(CURRENT_PROJECT, project)
       state.project = project
@@ -102,6 +107,7 @@
           Cookies.set('username', result.username, { expires: 1 })
           Vue.ls.set(ACCESS_TOKEN, result.sessionkey, 24 * 60 * 60 * 1000)
           commit('SET_TOKEN', result.sessionkey)
+          commit('SET_TIMEZONE_OFFSET', result.timezoneoffset)
 
           commit('SET_APIS', {})
           commit('SET_NAME', '')
@@ -126,11 +132,13 @@
       return new Promise((resolve, reject) => {
         const cachedApis = Vue.ls.get(APIS, {})
         const cachedZones = Vue.ls.get(ZONES, [])
+        const cachedTimezoneOffset = Vue.ls.get(TIMEZONE_OFFSET, 0.0)
         const hasAuth = Object.keys(cachedApis).length > 0
         if (hasAuth) {
           console.log('Login detected, using cached APIs')
           commit('SET_ZONES', cachedZones)
           commit('SET_APIS', cachedApis)
+          commit('SET_TIMEZONE_OFFSET', cachedTimezoneOffset)
 
           // Ensuring we get the user info so that store.getters.user is never empty when the page is freshly loaded
           api('listUsers', { username: Cookies.get('username'), listall: true }).then(response => {
diff --git a/src/store/mutation-types.js b/src/store/mutation-types.js
index caec6a4..53f193a 100644
--- a/src/store/mutation-types.js
+++ b/src/store/mutation-types.js
@@ -30,6 +30,7 @@
 export const APIS = 'APIS'
 export const ZONES = 'ZONES'
 export const ASYNC_JOB_IDS = 'ASYNC_JOB_IDS'
+export const TIMEZONE_OFFSET = 'TIMEZONE_OFFSET'
 
 export const CONTENT_WIDTH_TYPE = {
   Fluid: 'Fluid',
diff --git a/src/utils/plugins.js b/src/utils/plugins.js
index b3a911c..97bcaf4 100644
--- a/src/utils/plugins.js
+++ b/src/utils/plugins.js
@@ -147,3 +147,19 @@
     }
   }
 }
+
+export const toLocaleDatePlugin = {
+  install (Vue) {
+    Vue.prototype.$toLocaleDate = function (date) {
+      var milliseconds = Date.parse(date)
+      var timezoneOffset = this.$store.getters.timezoneoffset
+      // e.g. "Tue, 08 Jun 2010 19:13:49 GMT", "Tue, 25 May 2010 12:07:01 UTC"
+      var dateWithOffset = new Date(milliseconds + (timezoneOffset * 60 * 60 * 1000)).toUTCString()
+      // e.g. "08 Jun 2010 19:13:49 GMT", "25 May 2010 12:07:01 UTC"
+      dateWithOffset = dateWithOffset.substring(dateWithOffset.indexOf(', ') + 2)
+      // e.g. "08 Jun 2010 19:13:49", "25 May 2010 12:10:16"
+      dateWithOffset = dateWithOffset.substring(0, dateWithOffset.length - 4)
+      return dateWithOffset
+    }
+  }
+}
diff --git a/src/views/dashboard/CapacityDashboard.vue b/src/views/dashboard/CapacityDashboard.vue
index 6111475..9f38299 100644
--- a/src/views/dashboard/CapacityDashboard.vue
+++ b/src/views/dashboard/CapacityDashboard.vue
@@ -108,7 +108,7 @@
                 v-for="event in events"
                 :key="event.id"
                 :color="getEventColour(event)">
-                <span :style="{ color: '#999' }"><small>{{ event.created }}</small></span><br/>
+                <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(event.created) }}</small></span><br/>
                 <span :style="{ color: '#666' }"><small><router-link :to="{ path: 'event/' + event.id }">{{ event.type }}</router-link></small></span><br/>
                 <span :style="{ color: '#aaa' }">({{ event.username }}) {{ event.description }}</span>
               </a-timeline-item>
diff --git a/src/views/dashboard/UsageDashboard.vue b/src/views/dashboard/UsageDashboard.vue
index b29fc8d..ef4d964 100644
--- a/src/views/dashboard/UsageDashboard.vue
+++ b/src/views/dashboard/UsageDashboard.vue
@@ -81,7 +81,7 @@
                 v-for="event in events"
                 :key="event.id"
                 :color="getEventColour(event)">
-                <span :style="{ color: '#999' }"><small>{{ event.created }}</small></span><br/>
+                <span :style="{ color: '#999' }"><small>{{ $toLocaleDate(event.created) }}</small></span><br/>
                 <span :style="{ color: '#666' }"><small><router-link :to="{ path: 'event/' + event.id }">{{ event.type }}</router-link></small></span><br/>
                 <span :style="{ color: '#aaa' }">({{ event.username }}) {{ event.description }}</span>
               </a-timeline-item>