How to format date for display


#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.


#21

I like the formatter, but I decided to just use moment directly which seems simpler and more straight-forward to me (I’m new to Vue, so I reserve the right to change my mind :slight_smile:).

I started with npm install --save moment.

Then, in my .vue file,

<template>
<div>
	The date was set {{moment(myDate).fromNow()}}
</div>
</template>
<script>
  import moment from 'moment'

  export default {
	data () {
	  return {
		myDate: null // Set to whatever
	  }
	},

	methods: {
	  moment
	}
  }

</script>

NOTE: This code isn’t tested (the date isn’t even actually set), but something very similar to it is working for me.


#22

Just wanted to point out very minor syntax error in Linus’s first code block: it is missing the closing paren for his call to Vue.filter(…). Just in case someone is copy-pasting and confused about why it doesn’t work :slightly_smiling_face:

    import moment from 'moment'

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

#23

Does it validate leap years ?