【问题标题】:Format timestamp in AngularJS to a custom requirement将 AngularJS 中的时间戳格式化为自定义要求
【发布时间】:2015-02-16 18:22:27
【问题描述】:

我有一个从新帖子返回的数字字符串,该帖子在其提交时以new Date().getTime() 格式添加时间戳。我希望输入一个持续时间时间戳,例如(new Date().getTime() of submitted post - current date time),或者本质上是从提交帖子时经过的日期时间。

如果持续时间或小时天前(但一个月的定义会有所不同,有些二月有28天?)。不确定是否有全球时区调整。如果它 > 一个月,则将其显示为 month (Jan, Mar, Dec etc)year 2014,例如不涉及任何持续时间。

我听说过 moment.JS,但不确定上面是否有这样的自定义。我应该如何处理转换?是否有示例代码可供参考。

非常感谢!

【问题讨论】:

  • new Date().getTime() 返回一个数字,time value。 “持续时间时间戳”将是一个类似的值,表示毫秒数。这不能“转换为月”,它只是几毫秒,可以简单地转换为天、小时、分钟和秒。如果提供了一些纪元,它可以转换为月、年。
  • @RobG 当我使用 new Date().toUTCString() 时,它也给出了月份和年份。这就是为什么我虽然字符串中有月份和年份。有什么解决方法吗?

标签: javascript angularjs date datetime momentjs


【解决方案1】:

是的,您可以使用 moment.js,它可以处理所有这些。你可以使用fromnow:

moment([2007, 0, 29]).fromNow(); // 4 years ago

如果你不喜欢它给你的东西,那就是customizable

moment.relativeTimeThreshold('d');  // 26

另见calendar,这是可自定义的。

或者,您可以使用diff

a.diff(b, 'days') // 1

最后,你也可以使用duration

moment.duration(2, 'weeks');

要格式化它的显示方式,你可以使用format

moment().format("dddd, MMMM Do YYYY, h:mm:ss a"); // "Sunday, February 14th 2010, 3:25:50 pm"

它还支持时区和UTC,以及本地化。

【讨论】:

  • 我认为 fromNow() 已经足够好了。如果持续时间超过 30 天,我希望显示为 MMM YYYY 格式(即不再有差异)怎么办?原因是我需要降低循环中过滤器监视的数量。如何自定义阈值?文档显示了它,但没有提及它是在 html 还是 js 中以及应该如何完成?是否需要指令或过滤器?
  • 您直接在控制器或指令中使用 moment js,它是在 javascript 中完成的。自定义阈值也是如此。要更改格式,请使用 if 语句,例如 - if
  • 感谢@edamon,感谢您的帮助。我似乎无法在 angularjs 项目中工作。错误说找不到模块。我在 (index.html) 中包含了 moment.js 的 src,并在全局变量 (app.js) 中包含了依赖项。
  • 或者我应该使用 angular-moment.js?
  • 你可以使用它,但我不认为它会做你想要的。它所做的只是将时刻包裹在一个角度指令中。我以前在一个真正的数据密集型应用程序中使用过它,但我们不得不把它撕掉,因为它性能不佳。我想你需要那个 if 语句。未找到模块是一个角度错误,您可以发布您的代码和错误吗?
【解决方案2】:

我有从 new Date().getTime() 返回的一串数字

这将是一个数字,表示自 1970-01-01T00:00:00Z(ECMAScript 纪元)以来的毫秒数和执行代码的 UTC 时间。

并保存在后端。我希望放置一个持续时间时间戳,例如 (new Date().getTime() - now())。

如果 now()Date.now() 的简写,则该表达式的结果将为零 (0),因为这两个表达式将代表同一时刻。

但是我希望过滤器将其显示为分钟、小时、天前

将毫秒值转换为天、小时、分钟、秒的值很简单。

如果不到一个月(但一个月的定义不同,二月有时有 28 天?)我不确定时间戳字符串是否考虑了全球时区调整。

日期对象核心的时间值是自纪元以来的 UTC 毫秒数。日期对象还具有由系统设置确定的偏移量,用于计算本地时间值。有获取 UTC 值的 UTC 方法和获取本地值的非 UTC 方法。

如果超过一个月,则显示为月份(1 月、3 月、12 月等)和 2014 年,例如不涉及任何持续时间。

两个时间值相减的结果是一个标量数,它没有月或年的概念,它只是表示一个持续时间,而不是一瞬间。因此,只有在有特定起点(时期)和方向的情况下,将数字转换为“月”才有意义。

例如

1 月 1 日 + 31 天 -> 2 月 1 日所以一个月,但 6 月 1 日 + 31 天 -> 7 月 2 日所以 1 个月零 1 天。

1 月 1 日 - 31 天 -> 12 月 1 日所以一个月,6 月 1 日 - 31 天 -> 5 月 1 日所以 1 个月。

我听说过 moment JS 但不确定是否有这样的自定义持续时间

我对 moment.js 了解不多,只是我从未发现需要它。

我应该如何处理转换?

首先阐明您的要求。也许您想将某个特定时间点(例如现在或 2014 年 6 月 1 日或其他任何时间)的持续时间表示为月、日、小时等?

上面有些是微不足道的,有些是相当困难的,并且取决于行政规则,例如是 2012 年 2 月 29 日 + 1 年 2013 年 2 月 28 日还是 2013 年 3 月 1 日?

编辑

下面的示例代码是确定两个日期之间的年、月和日的一种相当可靠的方法。它还执行时差小于 1 天(即 8.64e7 毫秒)的时:分:秒。

它可能看起来像很多代码,大部分是在做年、月、日部分。

/**
 * Return the number of days in the month for the given year.
 * Month is calendar month (Jan=1, Feb=2, etc.).
 * @param {number} [month]
 * @param {number} [year]
 * @returns {number}
 * Default is current month, current year
*/
function getDaysInMonth(month, year) {
  var d = new Date();
  d.setHours(12,0,0,0);
  if (typeof month == 'undefined') month = d.getMonth() + 1;
  if (typeof year  == 'undefined') year  = d.getFullYear();
  d.setFullYear(year, month, 0);
  return d.getDate();
}

/**
 * Add years to a given Date, modifies the Date.
 * If adding years to 29 Feb rolls over to March 1,
 * then the date is set to 28 Feb.
 * @param {Date} date - Date to add years to
 * @param {number} years - Number of years to add
 * @returns {Date} Modified original date object
*/
function addYears(date, years) {
  var m = date.getMonth();
  date.setFullYear(date.getFullYear() + years);

  // Deal with leap year: if 29 Feb -> 1 Mar set back to 28 Feb
  if (date.getMonth() != m) {
    date.setDate(0);
  }
  return date;
}

/**
 * Add months to a given Date, modifies the Date.
 * If adding months causes the date to roll over an extra month,
 * the date is set to last day of previous month.
 *
 * e.g. 31 May + 1 month -> 30 June, not 1 July
 *      31 Jan + 1 month -> 28 Feb or 29 Feb if leap year
 * @param {Date} date - Date to add months to
 * @param {number} months - Number of months to add
 * @returns {Date} Modified original
*/
function addMonths(date, months) {
    var n = date.getDate();
    date.setMonth(date.getMonth() + months);

    if (date.getDate() != n) {
        date.setDate(0);
    }
    return date;
}

/**
 * Add days to a given Date, modifies the Date.
 * @param {Date} date - Date to add days to
 * @param {number} days - Number of days to add
 * @returns {Date} Modified original
*/
function addDays(date, days) {
    date.setDate(date.getDate() + days);
    return date;
}

/**
 * Convert seconds to hh:mm:ss
 * @param {number|string} secs
 * @returns {number}
*/
function secondsToHMS(secs) {
  function z(n){return (n<10?'0':'') + n;}
  var sign = secs < 0? '-':'';
  secs = Math.abs(secs);
  return sign + z(secs/3600 |0) + ':' + z((secs%3600) / 60 |0) + ':' + z(secs%60);
}

/**
 * Get the time between two dates as years, months and days.
 * For startDate of 29 Feb, whole year is 28 Feb in following year or
 * 29 Feb if endDate is a leap year. Some systems use 1 Mar.
 * @param {Date} startDate
 * @param {Date} [endDate]
 * @returns {string} 'y years, m moths and d days'
 * If endDate not provided, current date is used.
 * endDate must be after startDate.
*/
function getAge(startDate, endDate) {

    // Return undefined if start date is after end date
    if (startDate > endDate) return;

    var d, d0, d1, years, months, days;
    var startMonth = startDate.getMonth();

    d1 = endDate? new Date(+endDate) : new Date();
    d1.setHours(0,0,0,0);

    d = new Date(+startDate);
    d.setHours(0,0,0,0);
    d0 = new Date(+d);

    years = d1.getFullYear() - d.getFullYear();
    addYears(d, years);

    if (d > d1) {
        --years;
        d = new Date(+d0);
        addYears(d, years);
    }

    months = d1.getMonth() - d.getMonth();

    // Deal with -ve month difference
    if (months < 0) {
        months += 12;

    // Deal with months the same and difference < 1 year
    } else if (months == 0 && d.getFullYear() != d1.getFullYear()) {
        months = 11;
    }

    addMonths(d, months);

    if (d > d1) {
        --months;
        d = new Date(+d0);
        addYears(d, years);
        addMonths(d, months);
    }

    days = d1.getDate() - d.getDate();

    if (days < 0 ) {
        days += getDaysInMonth(d.getMonth()+1, d.getFullYear());

    } else if (days == 0 && d1.getMonth() != d.getMonth()) {
        days = getDaysInMonth(d.getMonth()+1, d.getFullYear()) - 1;
    }

    // Helper to make words plural if num != 1
    function s(num, word) {return word + (num == 1? '' : 's')}

    return years  + s(years,  ' year' ) + ', ' +
           months + s(months, ' month') + ', ' +
           days   + s(days,   ' day'  );
}


// Basic function to parse an ISO 8601 format string as a
// local time. Any timezone is ignored.
// Honours 2 digit years, so 14 is not 1914.
function parseString(s) {
  var d = new Date();
  b = s.split(/\D+/);
  d.setFullYear(b[0], b[1] - 1, b[2]);
  d.setHours(b[3] || 0, b[4] || 0, b[5]);
  return d;
}


function showDuration() {
  var el = document.getElementById('d0');
  var now = new Date();

  // Convert date string to a Date object
  var then = parseString(document.getElementById('i0').value);

  // If not a valid date, do nothing
  if (!then) return;

  // If difference greater than 1 day, show years, months, etc.
  // Otherwise, show h:m:s
  el.innerHTML = ((now - then) > 8.64e7? getAge(then, now) :
                  secondsToHMS(Math.abs(then - now)/1000 | 0)) + ' ago.';
}

一些标记:

<input id="i0" value="2014-06-23T20:28:09">
<button onclick="showDuration()">Show duration</button>
<br>
<div id="d0"></div>

【讨论】:

  • 感谢您的澄清。我已经相应地更新了我的问题。基本上是当前日期/时间与提交帖子时的日期/时间之间的持续时间。因此,如果差异小于一个月,则将其显示为分钟、小时、天。如果 > 月,则显示为 MMM YYYY。由于两者都是从 1970 年开始的毫秒数,我认为这两个日期时间之间的差异将是持续时间与提交的日期时间。
  • 计算年、月、日、小时、分钟和秒的时差并非易事(实际上相当困难)。有很多很多简单的解决方案,但它们都有严重的缺陷,可能不会立即显现出来。这就是为什么大多数“时间前”函数只会说“大约 1 年前”或“大约 2 个月前”之类的内容,“大约”部分意味着它们不必准确。
猜你喜欢
  • 2016-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-03
相关资源
最近更新 更多