How to format date for display


#1

Hello,

We receive an array of objects and each object has ISO standard date like “2016-11-15T04:34:46.928Z”. When I loop through and display the date in the table, it obviously displays just like it was sent “2016-11-15T04:34:46.928Z”, but we need to do custom formatting when we display and make it local date for the user. For example, the desired output shall be “15/11/2016 04:34 AM”

I googled for hours but can’t find any way to display formatted date with vuejs. Here is my code snippet:

{{ lead.created}} {{ lead.name}} {{ lead.address.city }}, {{ lead.address.state }} {{ lead.address.zip }}

We get the “leads” array via AJAX call on page load, which returns simple JSON. I understand that I can loop through all array records and use javascript Date() object to create any format I need, but it will require me to do an extra unnecessary loop on returned array of records, which can be in thousands, just to format the date before displaying it.

What is a straight forward way to work with dates to display them formatted at the time when table is created, to avoid extra loops. Please point me to some code samples.

Thanks!


#2

You should consider dealing with functions in which you will do your formatting because Vue can’t natively format date.
However, I think that Moment JS could help you in this case, and it’s fully compatible with Vue.


#3

Vue itself does not offer any date formatting. There are great libs to do that, the most popular one be is called moment js.

You can then build a simple Vue filter (see our guide on filters) to format the date with moment js in the template.


#4

Do you know any links to a sample code or examples?


#5
import moment from 'moment'

Vue.filter('formatDate', function(value) {
  if (value) {
    return moment(String(value)).format('MM/DD/YYYY hh:mm')
  }
}
<span>{{yourDateString | formatDate}}</span>

#6

Thanks a lot, this is exactly what I was looking for!


#7

I have a similar issue. I just upgraded from vue v1 to v2. For v1, I had overridden moment.toString, so that I could just put {{ momentObj }}, and it would print the formatted date which worked great. This isn’t working in v2, instead it is showing a date like: “2016-11-15T04:34:46.928Z”, so apparently it’s not calling toString() anymore. Now when I try {{ momentObj.toString }} or {{ String(momentObj) }}, it shows formatted properly.

Is there a way I can easily change this so that {{ momentObj }} will use that toString() method like it did in v1? I don’t understand why this would be different in v2.

Thanks


#8

@LinusBorg in Vue 2.0, do you recommend the filter approach, or the computed property approach? And can you please explain why? Thanks a lot!


#9

I prefer to use filters in those situations. Computed properties don’t really work for this when you are inside of a v-for unless you clone/reformat all your data, which can be cumbersome.

Also, you can re-use filters pretty easily in methods/computed properties if you want/have to: this.$filters.myfilter(value, argument1, argument2, ...)


#10

@LinusBorg thanks for your explanation. Makes sense.

PS: can you please respond to @nlassiter also? I have hi-jacked his question? :slight_smile:


#11

I will when I know the answer :wink:


#12

Thanks a lot, it works.


#13

Hi @borov, where exactly do you put this code? In what part of the .vue file do you include it:

import moment from 'moment'

Vue.filter('formatDate', function(value) {
  if (value) {
    return moment(String(value)).format('MM/DD/YYYY hh:mm')
  }
}

Do I need to install / import something else? I mean, vue-filter or something…

Thanks


#14

The Vue.filter function registers the filter globally. You don’t need to include this as part of a .vue file. You just need to register the filter before the app starts, so you could easily put this in main.js.

If I have a lot of filters to register for a project I will usually put them all in a sub-folder and then have some kind of install function that I import in main js that imports each filter and registers it.


#15

I tried the filter approach, but the filter method is called on every render (like a method - I wish it would cache like a computed property).

Instead I ended up making a component that does the formatting.

var formatter = {
    date: function (value, format) { 
        if (value) {
            return moment(String(value)).format(format || 'MM/DD/YY')
        }
    },
    time: function (value, format) {
        if (value) {
            return moment(String(value)).format(format || 'h:mm A');
        }
    }
};

Vue.component('format', {
    template: `<span>{{ formatter[fn](value, format) }}</span>`,
    props: ['value', 'fn', 'format'],
    computed: {
        formatter() {
            return formatter;
        }
    }
});

And use the component inside a v-for like so:
<format :value="o.OrderDate" fn="date" />

Would love to hear your opinion on this solution and any suggestions to further optimize the performance.


#16

The downside of a component is that it’s heavier to initialize. It probably doesn’t matter much though.


#17

True, but it’s a one time cost. A filter is faster, but keeps running multiple times. That’s the tradeoff.
The best of both worlds would be if the filter would be smart enough to see that its dependencies haven’t changed - like a computed property. But alas, that doesn’t seem to be possible currently.


#18

You can use filters within computed properties though, so you get the speed of the filter with the efficiency of caching:

{
  computed: {
    formatted(){
      return Vue.filter('date')(this.value)
    }
  }
}

#19

Hi @jackmellis ,
Computed properties are only for top level properties. They don’t work recursively for items in an array.

See comment from @LinusBorg here
https://forum.vuejs.org/t/how-to-format-date-for-display/3586/9
and see this post
https://forum.vuejs.org/t/computed-property-for-array-element/3611


#20

Just be aware that there’s a missing closing ‘)’ in this code sample. It should be:

Vue.filter('formatDate', function(value) {
  if (value) {
    return moment(String(value)).format('MM/DD/YYYY hh:mm')
  }
});

BTW, thanks for this solution. I’m 2 weeks into learning Vue and this was exactly what I needed to solve one of my challenges.