2011年10月31日 星期一

在前端程式中去計算一個時間與現在時間的差距


基本上計算日期的差距可以在後端的程式裡或是在資料庫中就可以解決,

但有些時候資料只會在前端出現而未後送到Server Side,或是說不想增加資料庫或是Server Side的負載,

所以就會將這種單純的顯示日期時間差距的計算工作給放到前端去做,

這樣做其實也是有好處的,好處就是讓Client Side去做這類瑣碎的計算,

因為不牽涉到太複雜的邏輯計算,也算是分擔後端的壓力。

所以接下來就會介紹三種方式來達成在Client Side去計算日期時間差距的功能。


 

方式一:我自己寫的…

一開始我所寫的這一段程式相當簡單,因為客戶那邊只需要去知道兩個日期的差距是有多少天,

而我在準備這篇文當的前置作業時,就順手多加了一些功能,讓這個功能看起來會比較完整一點,

不過也只是堪用而已,下面的程式中,後端產生一組的JSON資料,而要算的就是每一筆資料與目前時間的差距,

 

程式內容:

程式中首先去擴充Date的Property「dateDiff」,傳入另一組日期時間物件以及要計算差距的單位,

我又在程式中去增加一個CalculateDiff(recentDate)的function,使用這個function就是會把傳入的日期參數與現在時間去做計算。

為了確保輸出的計算結果會有值,所以從年、月、週、日、時、分、秒的順序算下去。

  function LoadJsonDataStandalone()
  {
    $.ajax({
      url: '<%= Url.Action("GetNodesJsonByCutsomJson", "Test") %>',
      type: 'post',
      dataType: 'json',
      async: false,
      cache: false,
      success: function (data)
      {
        if (data)
        {
          var jsonData = JSON.parseWithDate(JSON.stringifyWcf(data));
          var content = $('#Button1').val() + " <br/><br/>";
          $.each(jsonData, function (i, item)
          {
            content += "Name: " + item.Name;
            content += " || CreateDate: " + item.CreateDate;
            content += " || CreateDate(Formatted): " + item.CreateDate.f("yyyy-MM-dd HH:mm:ss");
            content += " || DateDiff: " + CalculateDateDiff(item.CreateDate);
            content += "<br/>";
          });
          $('#JsonContent').html(content);
        }
      }
    });
  }
  function CalculateDateDiff(recentDate)
  {
    if (recentDate != "" && !isNaN(Date.parse(recentDate)))
    {
      var startDate = new Date(recentDate);
      var thisDate = new Date();
      var d = startDate.getDate();
      var day = (d < 10) ? '0' + d : d;
      var m = startDate.getMonth() + 1;
      var month = (m < 10) ? '0' + m : m;
      var yy = startDate.getYear();
      var year = (yy < 1000) ? yy + 1900 : yy;
      var formatDate = year + "-" + month + "-" + day;
      var dateDiff = startDate.dateDiff("y", thisDate);
      var diffUnit = "";
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("m", thisDate);
        diffUnit = "個月";
      }
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("w", thisDate);
        diffUnit = "";
      }
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("d", thisDate);
        diffUnit = "";
      }
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("h", thisDate);
        diffUnit = "小時";
      }
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("n", thisDate);
        diffUnit = "分鐘";
      }
      if (dateDiff == 0)
      {
        dateDiff = startDate.dateDiff("s", thisDate);
        diffUnit = "";
      }
      return formatDate + ' 距今 ' + dateDiff + ' ' + diffUnit;
    }
    return false;
  }
  Date.prototype.dateDiff = function (interval, objDate)
  {
    //若參數不足或 objDate 不是日期物件則回傳 undefined
    if (arguments.length < 2 || objDate.constructor != Date) return undefined;
    switch (interval)
    {
      case "s":
        //計算秒差 
        return parseInt((objDate - this) / 1000);
      case "n":
        //計算分差
        return parseInt((objDate - this) / 60000);
      case "h":
        //計算時差
        return parseInt((objDate - this) / 3600000);
      case "d":
        //計算日差
        return parseInt((objDate - this) / 86400000);
      case "w":
        //計算週差
        return parseInt((objDate - this) / (86400000 * 7));
      case "m":
        //計算月差
        return (objDate.getMonth() + 1) + ((objDate.getFullYear() - this.getFullYear()) * 12) - (this.getMonth() + 1);
      case "y":
        //計算年差
        return objDate.getFullYear() - this.getFullYear();
      default:
        //輸入有誤
        return undefined;
    }
  }
執行結果:

image

看仔細一點,

image

這個程式只會去抓取符合單位值的數字,例如未滿一日但是有在一個小時以上,就會顯示小時單位的數值,

未滿一個月但是有在一天以上的,就會顯示以天數為單位的數值,

所以如果只要抓一個大約的數值,那麼這樣的方式我想應該是可以達到需求的。

 

方法二:使用 jQuery plugin – timeago

timeago – a jQuery plugin

官方網站:http://timeago.yarp.com/

Download;http://timeago.yarp.com/jquery.timeago.js

github:https://github.com/rmm5t/jquery-timeago

這個套件的使用方式相當的簡單,只需要在 jQuery.timeago() 的函式中去傳入日期物件或是符合日期格式的字串即可。

例如我直接傳入已經解析過但是還沒做日期字串格式化的JSON日期資料:

function LoadJsonDataStandalone()
{
    $.ajax({
        url: '<%= Url.Action("GetNodesJsonByCutsomJson", "Test") %>',
        type: 'post',
        dataType: 'json',
        async: false,
        cache: false,
        success: function (data)
        {
            if (data)
            {
                var jsonData = JSON.parseWithDate(JSON.stringifyWcf(data));
 
                var content = $('#Button1').val() + " <br/><br/>";
 
                $.each(jsonData, function (i, item)
                {
                    content += "Name: " + item.Name;
                    content += " || CreateDate: " + item.CreateDate;
                    content += " || CreateDate(Formatted): " + item.CreateDate.f("yyyy-MM-dd HH:mm:ss");
                    content += " || TimeAgo: " + jQuery.timeago(item.CreateDate);
                    content += "<br/>";
                });
 
                $('#JsonContent').html(content);
            }
        }
    });
}

執行結果:

image

如果是傳入已經格式化過的日期字串:

function LoadJsonDataStandalone()
{
    $.ajax({
        url: '<%= Url.Action("GetNodesJsonByCutsomJson", "Test") %>',
        type: 'post',
        dataType: 'json',
        async: false,
        cache: false,
        success: function (data)
        {
            if (data)
            {
                var jsonData = JSON.parseWithDate(JSON.stringifyWcf(data));
 
                var content = $('#Button1').val() + " <br/><br/>";
 
                $.each(jsonData, function (i, item)
                {
                    content += "Name: " + item.Name;
                    content += " || CreateDate: " + item.CreateDate;
                    content += " || CreateDate(Formatted): " + item.CreateDate.f("yyyy-MM-dd HH:mm:ss");
                    content += " || TimeAgo: " + jQuery.timeago(item.CreateDate.f("yyyy-MM-dd HH:mm:ss"));
                    content += "<br/>";
                });
 
                $('#JsonContent').html(content);
            }
        }
    });
}

執行結果:

image

如果你對顯示的結果都是用英文的會有點不習慣,沒關係,我們也可以去更改原始碼裡面的相關程式,

而在timeago的github中有提供各種語言的替換,連結位置:https://gist.github.com/6251

其中我也依據上面有人提供的簡體中文內容而作了修改,提供了正體中文的替換:https://gist.github.com/6251#gistcomment-59879

// Traditional Chinese, zh-tw
jQuery.timeago.settings.strings = {
prefixAgo: null,
prefixFromNow: "從現在開始",
suffixAgo: "之前",
suffixFromNow: null,
seconds: "不到 1 分鐘",
minute: "大約 1 分鐘",
minutes: "%d 分鐘",
hour: "大約 1 小時",
hours: "大約 %d 小時",
day: "1 天",
days: "%d 天",
month: "大約 1 個月",
months: "%d 月",
year: "大約 1 年",
years: "%d 年",
numbers: []
};

我在這邊也順便提供有替換過正體中文的原始碼:

jquery.timeago.zh-tw.js

/*
* timeago: a jQuery plugin, version: 0.9.3 (2011-01-21)
* @requires jQuery v1.2.3 or later
*
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
*/
(function ($)
{
    $.timeago = function (timestamp)
    {
        if (timestamp instanceof Date)
        {
            return inWords(timestamp);
        } 
        else if (typeof timestamp === "string")
        {
            return inWords($.timeago.parse(timestamp));
        } 
        else
        {
            return inWords($.timeago.datetime(timestamp));
        }
    };
    var $t = $.timeago;
 
    $.extend($.timeago, {
        settings: {
            refreshMillis: 60000,
            allowFuture: false,
            strings: {
                // Traditional Chinese, zh-tw
                prefixAgo: null,
                prefixFromNow: "從現在開始",
                suffixAgo: "之前",
                suffixFromNow: null,
                seconds: "不到 1 分鐘",
                minute: "大約 1 分鐘",
                minutes: "%d 分鐘",
                hour: "大約 1 小時",
                hours: "大約 %d 小時",
                day: "1 天",
                days: "%d 天",
                month: "大約 1 個月",
                months: "%d 月",
                year: "大約 1 年",
                years: "%d 年",
                numbers: []
            }
        },
        inWords: function (distanceMillis)
        {
            var $l = this.settings.strings;
            var prefix = $l.prefixAgo;
            var suffix = $l.suffixAgo;
            if (this.settings.allowFuture)
            {
                if (distanceMillis < 0)
                {
                    prefix = $l.prefixFromNow;
                    suffix = $l.suffixFromNow;
                }
                distanceMillis = Math.abs(distanceMillis);
            }
 
            var seconds = distanceMillis / 1000;
            var minutes = seconds / 60;
            var hours = minutes / 60;
            var days = hours / 24;
            var years = days / 365;
 
            function substitute(stringOrFunction, number)
            {
                var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
                var value = ($l.numbers && $l.numbers[number]) || number;
                return string.replace(/%d/i, value);
            }
 
            var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
                seconds < 90 && substitute($l.minute, 1) ||
                minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
                minutes < 90 && substitute($l.hour, 1) ||
                hours < 24 && substitute($l.hours, Math.round(hours)) ||
                hours < 48 && substitute($l.day, 1) ||
                days < 30 && substitute($l.days, Math.floor(days)) ||
                days < 60 && substitute($l.month, 1) ||
                days < 365 && substitute($l.months, Math.floor(days / 30)) ||
                years < 2 && substitute($l.year, 1) ||
                substitute($l.years, Math.floor(years));
 
            return $.trim([prefix, words, suffix].join(" "));
        },
        parse: function (iso8601)
        {
            var s = $.trim(iso8601);
            s = s.replace(/\.\d\d\d+/, ""); // remove milliseconds
            s = s.replace(/-/, "/").replace(/-/, "/");
            s = s.replace(/T/, " ").replace(/Z/, " UTC");
            s = s.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2"); // -04:00 -> -0400
            return new Date(s);
        },
        datetime: function (elem)
        {
            // jQuery's `is()` doesn't play well with HTML5 in IE
            var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
            var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
            return $t.parse(iso8601);
        }
    });
 
    $.fn.timeago = function ()
    {
        var self = this;
        self.each(refresh);
 
        var $s = $t.settings;
        if ($s.refreshMillis > 0)
        {
            setInterval(function () { self.each(refresh); }, $s.refreshMillis);
        }
        return self;
    };
 
    function refresh()
    {
        var data = prepareData(this);
        if (!isNaN(data.datetime))
        {
            $(this).text(inWords(data.datetime));
        }
        return this;
    }
 
    function prepareData(element)
    {
        element = $(element);
        if (!element.data("timeago"))
        {
            element.data("timeago", { datetime: $t.datetime(element) });
            var text = $.trim(element.text());
            if (text.length > 0)
            {
                element.attr("title", text);
            }
        }
        return element.data("timeago");
    }
 
    function inWords(date)
    {
        return $t.inWords(distance(date));
    }
 
    function distance(date)
    {
        return (new Date().getTime() - date.getTime());
    }
 
    // fix for IE6 suckage
    document.createElement("abbr");
    document.createElement("time");
} 
(jQuery));

執行結果;

image

 

 

方式三:使用「f」

在「ASP.NET MVC, JSON資料的日期轉換與格式化 1」這邊文章中有介紹到「f」這個函式庫可以用來對日期物件的輸出字串做格式化,

而「f」也是有提供計算日期時間差距的function,

"f" is for Format & WHAT THE diff??http://fisforformat.sourceforge.net/

WHAT THE diff??  - Date.diff Method

而根據官網上面的範例:

var oldDate = new Date("03/22/2009 23:23:12");
var curDate = new Date();
var theDiff = curDate.diff(oldDate);
//is the same as
var theDiff = curDate.diff(oldDate, "TCDYMWdHmSN");
alert("And the difference is: " + theDiff);

而其中比較關鍵的地方就是,「f」的diff可以讓我們指定要輸出的時間格式,而不是只有單一個時間單位,

例如上面範例所使用的「TCDYMWdHmSN」就表示以下的所以時間單位都會輸出,

T: Millenia
C: Centuries
D: Decades
Y: Years
M: Months
W: Weeks
d: Days
H: Hours
m: Minutes
S: Seconds
N: Miliseconds
*: All (default)

上面範例的執行結果:

image

不過這邊要說明一下,如果你是直接拿官網的原始碼來執行功能,那麼會出現以下的錯誤:

(Firefox 7.0.1 + Firebug 1.8.3)

image

查看原始碼,發現到從Line:234 ~ 241 這幾行會去計算所謂的日光節約時間,

何謂「Daylight Saving time 日光節約時間」就看 Wiki 怎麼說:http://zh.wikipedia.org/wiki/%E5%A4%8F%E6%97%B6%E5%88%B6

image

不想追根究柢去改程式,所以就一不做二不休的把Line:234 ~ 241 給註解掉或是刪除也可以,修改之後就可以正常顯示了。

那…一樣,如果對英文顯示有意見的人,可以參考下面我所修改後的原始碼,除了將時間單位給改為正體中文外,

包含上面的Daylight Saving問題也做了修改。

date.f-0.5.0-modified.js

/*!
* "f" is for Format & WHAT THE diff?? v0.5.0
*
* Copyright (c) 2009 Joshua Faulkenberry
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
* Date: 2009-03-20 22:15:23 -0700 (Fri, 20 Mar 2009)
* Revision: 6
*/
 
/*
* Date: 2011-10-31
* Modified by : kevintsengtw
*/
 
/************** "f" is for Format ***************
* Outputs a JavaScript Date Object in various
* customizable formats
**********************************************
*/
window.Date.prototype.f = function (format)
{
    if (format == "@")
    {
        return this.getTime();
    }
    else if (format == "REL")
    {
        var diff = (((new Date()).getTime() - this.getTime()) / 1000), day_diff = Math.floor(diff / 86400);
        return day_diff == 0 && (
             diff > -60 && "right now" ||
            diff > -120 && "1 minute from now" ||
            diff > -3600 && -(Math.floor(diff / 60)) + " minutes from now" ||
            diff > -7200 && "1 hour ago" ||
            diff > -86400 && -(Math.floor(diff / 3600)) + " hours from now" ||
 
            diff < 60 && "just now" ||
            diff < 120 && "1 minute ago" ||
            diff < 3600 && Math.floor(diff / 60) + " minutes ago" ||
            diff < 7200 && "1 hour ago" ||
            diff < 86400 && Math.floor(diff / 3600) + " hours ago") ||
 
            day_diff == 0 && "Tomorrow" ||
            day_diff > -7 && -(day_diff) + " days from now" ||
            -(Math.ceil(day_diff / 7)) == 1 && "1 week from now" ||
            day_diff > -78 && -(Math.ceil(day_diff / 7)) + " weeks from now" ||
            day_diff > -730 && -(Math.ceil(day_diff / 30)) + " months from now" ||
            day_diff <= -730 && -(Math.ceil(day_diff / 365)) + " years from now" ||
 
            day_diff == 1 && "Yesterday" ||
            day_diff < 7 && day_diff + " days ago" ||
            (Math.ceil(day_diff / 7)) == 1 && "1 week ago" ||
            day_diff < 78 && Math.ceil(day_diff / 7) + " weeks ago" ||
            day_diff < 730 && Math.ceil(day_diff / 30) + " months ago" ||
            Math.ceil(day_diff / 365) + " years ago";
    }
    var MONTH_NAMES = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
       DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
       LZ = function (x) { return (x < 0 || x > 9 ? "" : "0") + x },
       date = this,
        format = format + "",
        result = "",
        i_format = 0,
        c = "",
        token = "",
        y = date.getYear() + "",
        M = date.getMonth() + 1,
        d = date.getDate(),
        E = date.getDay(),
        H = date.getHours(),
        m = date.getMinutes(),
        s = date.getSeconds(),
        yyyy, yy, MMM, MM, dd, hh, h, mm, ss, ampm, HH, H, KK, K, kk, k,
        value = new Object();
    // Convert real date parts into formatted versions
    if (y.length < 4) { y = "" + (y - 0 + 1900); }
    value["y"] = "" + y;
    value["yyyy"] = y;
    value["yy"] = y.substr(2, 4);
    value["M"] = M;
    value["MM"] = LZ(M);
    value["MMM"] = MONTH_NAMES[M - 1];
    value["NNN"] = MONTH_NAMES[M - 1].substr(0, 3);
    value["N"] = MONTH_NAMES[M - 1].substr(0, 1);
    value["d"] = d;
    value["dd"] = LZ(d);
    value["e"] = DAY_NAMES[E].substr(0, 1);
    value["ee"] = DAY_NAMES[E].substr(0, 2);
    value["E"] = DAY_NAMES[E].substr(0, 3);
    value["EE"] = DAY_NAMES[E];
    value["H"] = H;
    value["HH"] = LZ(H);
    if (H == 0) { value["h"] = 12; }
    else if (H > 12) { value["h"] = H - 12; }
    else { value["h"] = H; }
    value["hh"] = LZ(value["h"]);
    if (H > 11) { value["K"] = H - 12; } else { value["K"] = H; }
    value["k"] = H + 1;
    value["KK"] = LZ(value["K"]);
    value["kk"] = LZ(value["k"]);
    if (H > 11) { value["a"] = "PM"; }
    else { value["a"] = "AM"; }
    value["m"] = m;
    value["mm"] = LZ(m);
    value["s"] = s;
    value["ss"] = LZ(s);
    while (i_format < format.length)
    {
        c = format.charAt(i_format);
        token = "";
        while ((format.charAt(i_format) == c) && (i_format < format.length))
        {
            token += format.charAt(i_format++);
        }
        if (value[token] != null) { result = result + value[token]; }
        else { result = result + token; }
    }
    return result;
}
 
/************* WHAT THE diff?? *************
* Calculates the exact difference between
* any two dates and outputs the results in
* a customizable incremental breakdown
*******************************************
*/
window.Date.prototype.diff = function (date, breakdown)
{
    var options = {};
    if (typeof date == "string")
    {
        if ((new Date(date)) != "Invalid Date" && (new Date(date)) != "NaN")
        {
            date = new Date(date);
        }
        else
        {
            breakdown = date;
            date = new Date();
        }
    }
    else if (typeof date == "object" && !date.getTime)
    {
        options = date;
        date = new Date();
    }
    if (typeof breakdown == "object")
    {
        options = breakdown;
        breakdown = options.breakdown || "*";
    }
    options.labels = options.labels || {};
    if (breakdown)
    {
        function processTime(trg)
        {
            var result = null;
            if (diff >= tl[trg])
            {
                if (trg == "Y" || trg == "D" || trg == "C" || trg == "T")
                {
                    //Catch leap years
                    for (var yr = (min); yr.getFullYear() <= max.getFullYear(); yr.setYear(yr.getFullYear() + 1))
                    {
                        if (yr.isLeapYear())
                        {
                            diff -= tl["d"];
                        }
                    }
                }
                if (diff >= tl[trg])
                {
                    result = Math.floor(diff / tl[trg]) + " " + (Math.floor(diff / tl[trg]) == 1 && names[trg][0] || names[trg][1]);
                    diff = diff % tl[trg];
                }
            }
            eval('breakdown = breakdown.replace(/' + trg + '/g, "")');
            return result;
        }
 
        var min = date <= this && date || date > this && this,
         max = date > this && date || date <= this && this,
         diff = (max.getTime() - min.getTime()),
         tl = {
             T: 1000 * 60 * 60 * 24 * 365 * 100 * 10,
             C: 1000 * 60 * 60 * 24 * 365 * 100,
             D: 1000 * 60 * 60 * 24 * 365 * 10,
             Y: 1000 * 60 * 60 * 24 * 365,
             M: 1000 * 60 * 60 * 24 * 28,
             W: 1000 * 60 * 60 * 24 * 7,
             d: 1000 * 60 * 60 * 24,
             H: 1000 * 60 * 60,
             m: 1000 * 60,
             S: 1000,
             N: 1
         },
         names = {
             T: options.labels.T || ["Mellinium", "Mellinia"],
             C: options.labels.C || ["Century", "Centuries"],
             D: options.labels.D || ["Decade", "Decades"],
             Y: options.labels.Y || ["年", "年"],
             M: options.labels.M || ["個月", "個月"],
             W: options.labels.W || ["週", "週"],
             d: options.labels.d || ["天", "天"],
             H: options.labels.H || ["小時", "小時"],
             m: options.labels.m || ["分鐘", "分鐘"],
             S: options.labels.S || ["秒", "秒"],
             N: options.labels.N || ["毫秒", "毫秒"]
         };
        if (options.len)
        {
            for (var x in names)
            {
                names[x] = names[x].substr(0, options.len);
            }
        }
 
        //Catch daylight savings year by year
        var testDt = new Date(min.toString());
        if (max.getFullYear() - testDt.getFullYear() > 1)
        {
            testDt.setYear(max.getFullYear() - 1);
        }
        while (testDt < max)
        {
            if (testDt.isDayLightSavingsDay() && testDt.getMonth() < 5)
            {
                diff += tl["H"];
            }
            else if (testDt.isDayLightSavingsDay())
            {
                diff -= tl["H"];
            }
            testDt.setDate(testDt.getDate() + 1);
        }
 
        var result = [], out;
        while (diff > 0)
        {
            if (breakdown == "*")
            {
                breakdown = "TCDYMWdHmSN";
            }
            else if (breakdown.indexOf("T") > -1)
            {
                if (out = processTime("T")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("C") > -1)
            {
                if (out = processTime("C")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("D") > -1)
            {
                if (out = processTime("D")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("Y") > -1)
            {
                if (out = processTime("Y")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("M") > -1)
            {
                if (diff >= tl["M"])
                {
                    var cur = (new Date(max.getTime() - diff));
                    var monthCount = 0;
                    var lastVal = 0;
                    //Step through each year
                    for (var yr = cur.getFullYear(); yr <= max.getFullYear(); yr++)
                    {
                        //Step through each month
                        while (cur.getFullYear() == yr)
                        {
                            lastVal = cur.getTime();
                            cur.setMonth(cur.getMonth() + 1);
                            if (diff - (cur.getTime() - lastVal) >= 0)
                            {
                                monthCount++;
                                diff -= (cur.getTime() - lastVal);
                            }
                            if (yr == max.getFullYear() && cur.getMonth() == max.getMonth())
                            {
                                break;
                            }
                        }
                    }
                    if (monthCount)
                    {
                        result[result.length] = monthCount + " " + (monthCount == 1 && names["M"][0] || names["M"][1]);
                    }
                }
                breakdown = breakdown.replace(/M/g, "");
            }
            else if (breakdown.indexOf("W") > -1)
            {
                if (out = processTime("W")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("d") > -1)
            {
                if (out = processTime("d")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("H") > -1)
            {
                if (out = processTime("H")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("m") > -1)
            {
                if (out = processTime("m")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("S") > -1)
            {
                if (out = processTime("S")) { result[result.length] = out };
            }
            else if (breakdown.indexOf("N") > -1)
            {
                if (out = processTime("N")) { result[result.length] = out };
            }
            else
            {
                diff = 0;
            }
        }
        options.divider = options.divider || " ";
        if (options.divider == " " && result.length > 1 && !options.hideAnd)
        {
            result[result.length - 1] = result[result.length - 1];
        }
        diff = result.join(options.divider);
    }
    if (diff == "")
    {
        diff = "Same";
    }
    if (options.lc)
    {
        diff = diff.toLowerCase();
    }
    return diff;
}
 
/********* Date.getDaysInMonth() *************
* Returns the number of days in the selected
* month
*********************************************
*/
window.Date.prototype.getDaysInMonth = function ()
{
    return [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][this.getMonth()];
};
 
/************* Date.isLeapYear() ***************
* Returns true if the selected year is a leap
* year
***********************************************
*/
window.Date.prototype.isLeapYear = function ()
{
    return (new Date(this.getFullYear(), 2 - 1, 29)).getDate() == 29;
};
 
/******* Date.getDayLightSavingsDays() *********
* Returns an array containing date objects for
* the two daylight savings change days within
* the selected year
***********************************************
*/
window.Date.prototype.getDayLightSavingsDays = function ()
{
    var result = [];
    var day1 = new Date("03/07/" + this.getFullYear());
    var day2 = new Date("03/06/" + this.getFullYear());
    while (day1.getMonth() < 3 || (day1.getMonth() == 3 && day1.getDate() < 16))
    {
        if ((day1.getTime() - day2.getTime()) / 1000 / 60 / 60 != 24)
        {
            result[result.length] = new Date(day2.getTime());
        }
        day1.setDate(day1.getDate() + 1);
        day2.setDate(day2.getDate() + 1);
    }
    var day1 = new Date("10/31/" + this.getFullYear());
    var day2 = new Date("10/30/" + this.getFullYear());
    while (day1.getMonth() < 11 || (day1.getMonth() == 10 && day1.getDate() < 9))
    {
        if ((day1.getTime() - day2.getTime()) / 1000 / 60 / 60 != 24)
        {
            result[result.length] = new Date(day2.getTime());
        }
        day1.setDate(day1.getDate() + 1);
        day2.setDate(day2.getDate() + 1);
    }
    return result;
};
 
/******** Date.isDayLightSavingsDay() **********
* Returns true if the selected day is a
* daylight savings change day
***********************************************
*/
window.Date.prototype.isDayLightSavingsDay = function ()
{
    var comp = new Date(this.getTime());
    comp.setDate(comp.getDate() + 1);
    return (comp.getTime() - this.getTime()) / 1000 / 60 / 60 != 24;
};

看看使用修改後的函式庫的執行結果:

image

接下來就拿來套用在程式之中:

function LoadJsonDataStandalone()
{
    $.ajax({
        url: '<%= Url.Action("GetNodesJsonByCutsomJson", "Test") %>',
        type: 'post',
        dataType: 'json',
        async: false,
        cache: false,
        success: function (data)
        {
            if (data)
            {
                var jsonData = JSON.parseWithDate(JSON.stringifyWcf(data));
 
                var content = $('#Button1').val() + " <br/><br/>";
 
                $.each(jsonData, function (i, item)
                {
                    content += "Name: " + item.Name;
                    content += " || CreateDate: " + item.CreateDate;
                    content += " || CreateDate(Formatted): " + item.CreateDate.f("yyyy-MM-dd HH:mm:ss");
                    content += " || Date Diff: " + (new Date()).diff(item.CreateDate, "TCDYMWdHmSN");
                    content += "<br/>";
                });
 
                $('#JsonContent').html(content);
            }
        }
    });
}

執行結果:

image

如果覺得毫秒不必要去顯示出來,反正格式可以自己設定,我就改成這樣:

(new Date()).diff(item.CreateDate, "YMdHmS")

原本的T, C, D都不太可能需要用到(除非你是做一些具有歷史性的需求)再加上W 週數與N 毫秒也很少用到,所以都移除,

看看執行的結果:

image

 

提供三種在前端程式裡去處理日期差距的方法給大家做個參考,

以上

沒有留言:

張貼留言

提醒

千萬不要使用 Google Talk (Hangouts) 或 Facebook 及時通訊與我聯繫、提問,因為會掉訊息甚至我是過了好幾天之後才發現到你曾經傳給我訊息過,請多多使用「詢問與建議」(在左邊,就在左邊),另外比較深入的問題討論,或是有牽涉到你實作程式碼的內容,不適合在留言板裡留言討論,請務必使用「詢問與建議」功能(可以夾帶檔案),謝謝。