Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using moment.js to format viewmodel dates in ASP.NET MVC

I am using Razor as a view engine in ASP.NET MVC 5. I have dates coming back from a back-end service that are in UTC. I want to format those using JavaScript (e. g. moment.js) on the client. I don't want to do it on the server, because I don't want to have to worry about what time zone the client is in on the server side (after all, the server doesn't really care).

I think from Locale Date formatting with MVC, AJAX and Moment.js that there's some way to do this server-side if I have to, although there's not enough information for me to get it worked out, and that's not what I want to do anyway.

Something like ASP.NET MVC ViewModel mapping with custom formatting or Where is the best place to format Model properties in ASP.NET MVC(3)? or How to format date in asp.net mvc 5 doesn't work because that's server side (or does it in some way I don't understand?)

What's the "best" / "right" way to do this cleanly and reliably?

EDIT: To be clear, I know all about the moment.js side. I wouldn't have named it if I didn't. What I'm asking about is the ASP.NET MVC view integration - how do I get that done the "right" way?

EDIT 2: I know how to do the script. What I don't know is if I have that output, from a script variable, how do I get the contents of that variable into the information displayed to the user in the view? I don't want to have to do something like edit the HTML element contents or something, if I can help it; that's not clean at all. Perhaps I should make this much simpler to make this very very clear:

Imagine a view in Razor. That view says:

@foreach (var item in Model) {
    <!-- something to do javascript manipulation of item -->
    <p>The result of manipulating @item.startDate is <!-- WHAT DO I DO HERE? --></p>
}

The comments are what I don't know how to do right now cleanly.

like image 200
MikeBaz - MSFT Avatar asked Mar 03 '15 22:03

MikeBaz - MSFT


2 Answers

You can try this (JS with razor) :

var date = moment('@YourDateTime.ToString( "s", System.Globalization.CultureInfo.InvariantCulture )');

From momentjs doc :

When creating a moment from a string, we first check if the string matches known ISO 8601 formats

(Source)

From .NET doc :

The "s" standard format specifier reflects a defined standard (ISO 8601)

(Source)

Edit

Solution to combine momentjs with Razor to display an array of DateTime

HTML/Razor :

@foreach (var item in Model) {
   <p data-utcdate="@item.startDate.ToString("s", System.Globalization.CultureInfo.InvariantCulture)"></p>
}

JS (with JQuery) :

<script type="text/javascript">
    $(function () {
        $('[data-utcdate]').each(function () {
            var d = moment($(this).attr('data-utcdate'));
            $(this).html(d.format());
        });
    });
</script>

If you want to display your date with a different format : http://momentjs.com/docs/#/displaying/format/

like image 188
Guy Avatar answered Sep 21 '22 09:09

Guy


If you have views that display some dates or timestamps in Razor and some in Javascript, here is a Javascript function that will translate a .NET format string like {0:MM/dd/yyyy} into a moment.js (actually moment-timezone.js) format string:

// Convert a single .NET date format to use with moment.js.
DotNetToMomentFormat = function (s0) {
    s0 = s0.replace(/\{\d+:(.*)\}/, "$1"); // remove placeholder
    var m = s0.match(/((.)\2*)/g);
    var s1 = m.reduce(function (a,s) {
            switch (s) {
                case "d": s = "MM/DD/YYYY"; break;
                case "dd": s = "DD"; break;
                case "ddd": s = "ddd"; break;
                case "dddd": s = "dddd"; break;
                case "D": s = "DD MMMM YYYY"; break;
                case "f": s = "DD MMMM YYYY HH:mm"; break;
                case "fff": s = "SSS"; break;
                case "F": s = "DD MMMM YYYY HH:mm:ss"; break;
                case "FFF": s = "SSS"; break; // no trailing 0s
                case "g": s = "DD/MM/YYYY HH:mm"; break;
                case "G": s = "DD/MM/YYYY HH:mm:ss"; break;
                case "hh": s = "hh"; break;
                case "HH": s = "HH"; break;
                case "m": s = "MMMM DD"; break;
                case "mm": s = "mm"; break;
                case "M": s = "MMMM DD"; break;
                case "MM": s = "MM"; break;
                case "MMM": s = "MMM"; break;
                case "MMMM": s = "MMMM"; break;
                case "o": s = "YYYY-MM-DD HH:mm:ssZ"; break;
                case "O": s = "YYYY-MM-DD HH:mm:ssZ"; break;
                case "r": s = "ddd, DD MMM YYYY, H:mm:ss z"; break;
                case "R": s = "ddd, DD MMM YYYY, H:mm:ss z"; break;
                case "s": s = "YYYY-MM-DDTHH:mm:ss"; break;
                case "ss": s = "ss"; break;
                case "t": s = "HH:mm"; break;
                case "tt": s = "A"; break;
                case "T": s = "HH:mm:ss"; break;
                case "u": s = "YYYY-MM-DD HH:mm:ssZ"; break;
                case "y": s = "MMMM, YYYY"; break;
                case "yy": s = "YY"; break;
                case "yyyy": s = "YYYY"; break;
                case "Y": s = "MMMM, YYYY"; break;
            }
            return a + s;
        },
        "");
    return s1;
}

Then, in Razor, some example code would be:

@{
    var today = DateTime.Today;
    string dateFormat = "{0:MM/dd/yyyy}";
}
<div>The MVC-formatted date is @(string.Format(dateFormat, today)).</div>
<div>The moment-formatted date is <span id="today"></span>.</div>

<script type="text/javascript">
    var x = window.document.getElementById("today");
    var y = moment("@today.ToString("O")");
    x.innerHTML = y.format(DotNetToMomentFormat("@dateFormat"));
</script>

As of this post, the relevant output would be:

The MVC-formatted date is 02/03/2017.
The moment-formatted date is 02/03/2017.

The other piece of information you would need is the user's local time zone and use moment-timezone's tz(timezonename) to set it before formatting.

like image 44
Suncat2000 Avatar answered Sep 21 '22 09:09

Suncat2000