Thư viện Javascript để định dạng ngày tương đối thân thiện với con người [đã đóng]


94

Tôi muốn hiển thị một số ngày tương đối với ngày hiện tại ở định dạng thân thiện với con người.

Ví dụ về ngày tháng thân thiện với con người:

  • 10 giây trước
  • 20 phút kể từ bây giờ
  • 1 ngày trước
  • 5 tuần trước
  • 2 tháng trước

Về cơ bản, duy trì trung thực thứ tự cường độ cao nhất (và theo sở thích, chỉ tăng đơn vị khi vượt qua 2 trong số các đơn vị đó - 5 tuần thay vì 1 tháng).

Mặc dù tôi có thể sống với một thư viện ít kiểm soát hơn và thậm chí còn thân thiện hơn với những ngày tháng như:

  • hôm qua
  • Ngày mai
  • tuần trước
  • một vài phút trước
  • trong một vài giờ

Bất kỳ thư viện phổ biến cho điều này?


Tại sao "1 ngày trước" lại "thân thiện với con người" hơn là chỉ trình bày ngày và giờ thực tế?
RobG

5
@RobG Tôi muốn nói đó là việc tránh chuyển đổi ngữ cảnh, ví dụ: trong một trang chủ yếu là văn bản và đang được đọc, việc chuyển ngữ cảnh sang ví dụ: mm / dd / yy có thể gây ra tạm dừng. Trong bảng dữ liệu, sử dụng định dạng đó có thể dễ đọc hơn. Nó cũng phụ thuộc vào những gì người đọc cần làm với ngày tháng, ví dụ như "việc này xảy ra cách đây n ngày" hoặc "việc này xảy ra trước ngày 1/1/1972" là có thể hành động hay phù hợp với ngữ cảnh của người đọc.
wprl

Có lẽ, nhưng thật khó hiểu khi thấy danh sách các sự kiện là "Hôm qua ... 3 ngày trước ... 10/5 ...". Tôi vẫn cần chuyển đổi tất cả chúng thành ngày tháng trong đầu để có hình ảnh về thời điểm chúng xảy ra. Ngày tháng ngắn gọn và chính xác, các giá trị "thời gian trước" mang tính chất đàm thoại, thiếu độ chính xác và thường chỉ hữu ích với ngày liên quan. Có lẽ đó chỉ là tôi, nhưng có thể không. :-)
RobG

6
Tôi sẽ nói nó phụ thuộc vào ngữ cảnh. Rốt cuộc, bạn sẽ không nói "Tôi đã đi câu cá vào ngày 17 tháng 2 năm 2014" nếu đó thực sự là ngày hôm qua. Ở đó còn nhiều sự tạm dừng của não. Loại văn bản này là hoàn hảo cho danh sách các sự kiện gần đây.
Simon Williams

2
@RobG Chỉ có những kẻ mọt sách như chúng tôi mới nghĩ như vậy chứ không phải những người bình thường.

Câu trả lời:


92

Kể từ khi tôi viết câu trả lời này, một thư viện nổi tiếng có sẵn là moment.js .


các thư viện có sẵn , nhưng việc tự triển khai nó là một việc nhỏ. Chỉ cần sử dụng một số điều kiện.

Giả sử datelà một Dateđối tượng được khởi tạo cho thời điểm bạn muốn so sánh.

// Make a fuzzy time
var delta = Math.round((+new Date - date) / 1000);

var minute = 60,
    hour = minute * 60,
    day = hour * 24,
    week = day * 7;

var fuzzy;

if (delta < 30) {
    fuzzy = 'just then.';
} else if (delta < minute) {
    fuzzy = delta + ' seconds ago.';
} else if (delta < 2 * minute) {
    fuzzy = 'a minute ago.'
} else if (delta < hour) {
    fuzzy = Math.floor(delta / minute) + ' minutes ago.';
} else if (Math.floor(delta / hour) == 1) {
    fuzzy = '1 hour ago.'
} else if (delta < day) {
    fuzzy = Math.floor(delta / hour) + ' hours ago.';
} else if (delta < day * 2) {
    fuzzy = 'yesterday';
}

Bạn sẽ cần phải điều chỉnh điều này để xử lý các ngày trong tương lai.


9
Hôm qua là trước nửa đêm cuối cùng, không phải từ 24 giờ đến 48 giờ trước.
mxcl

@mmaclaurin Mine không bao giờ có nghĩa là một giải pháp hoàn chỉnh, chỉ là một con trỏ đi đúng hướng. Tôi sẽ ghi chú để cập nhật nó sau, hoặc nếu bạn muốn, vui lòng chỉnh sửa câu trả lời.
alex

Hãy cũng xem xét date-fns ! Đó là một thư viện tuyệt vời nếu bạn muốn giữ cơ sở mã của mình nhỏ, vì nó có dấu ấn thấp hơn nhiều so với momentjs!
mesqueeb

1
Tôi đã thay đổi mã này để tạo một getTimeAgohàm kiểu twitter gist.github.com/pomber/6195066a9258d1fb93bb59c206345b38
pomber

85

Tôi đã viết moment.js , một thư viện ngày tháng thực hiện điều này. Nó khoảng 5KB (2011) 52KB (2019), và hoạt động trong các trình duyệt và trong Node. Nó cũng có lẽ là thư viện ngày phổ biến và nổi tiếng nhất cho JavaScript.

Nó hỗ trợ timeago, định dạng, phân tích cú pháp, truy vấn, thao tác, i18n, v.v.

Timeago (thời gian tương đối) cho các ngày trong quá khứ được thực hiện với moment().fromNow(). Ví dụ: để hiển thị ngày 1 tháng 1 năm 2019 ở định dạng thời gian:

let date = moment("2019-01-01", "YYYY-MM-DD");
console.log(date.fromNow());
<script src="https://momentjs.com/downloads/moment.min.js"></script>

Các dây timeago có thể tùy chỉnh moment.updateLocale(), vì vậy bạn có thể thay đổi chúng theo cách bạn thấy phù hợp.

Các ngưỡng giới hạn không phải là những gì câu hỏi yêu cầu ("5 tuần" so với "1 tháng"), nhưng nó được ghi lại về chuỗi nào được sử dụng cho phạm vi thời gian nào.


1
Kudo để làm cho nó hoạt động trong trình duyệt và nút !!!!
wprl

48
ha mà kích thước cập nhật mặc dù!
Askdesigners

1
Hãy cũng xem xét date-fns ! Đó là một thư viện tuyệt vời nếu bạn muốn giữ cơ sở mã của mình nhỏ, vì nó có dấu ấn thấp hơn nhiều so với momentjs!
mesqueeb

Tốt như thư viện này là, câu trả lời không bao gồm một lời giải thích về cách định dạng một số một cách thân thiện với con người sử dụng nó
Mã Whisperer

16

Đây là thông tin từ John Resig - http://ejohn.org/blog/javascript-pretty-date/

EDIT (27/6/2014): Theo dõi nhận xét từ Sumurai8 - mặc dù trang được liên kết vẫn hoạt động, đây là đoạn trích cho pretty.jsliên kết đến từ bài viết trên:

khá.js

/*
 * JavaScript Pretty Date
 * Copyright (c) 2011 John Resig (ejohn.org)
 * Licensed under the MIT and GPL licenses.
 */

// Takes an ISO time and returns a string representing how
// long ago the date represents.
function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) return;

    return day_diff == 0 && (
    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 == 1 && "Yesterday" || day_diff < 7 && day_diff + " days ago" || day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago";
}

// If jQuery is included in the page, adds a jQuery plugin to handle it as well
if (typeof jQuery != "undefined") jQuery.fn.prettyDate = function() {
    return this.each(function() {
        var date = prettyDate(this.title);
        if (date) jQuery(this).text(date);
    });
};

Sử dụng:

prettyDate("2008-01-28T20:24:17Z") // => "2 hours ago"
prettyDate("2008-01-27T22:24:17Z") // => "Yesterday"
prettyDate("2008-01-26T22:24:17Z") // => "2 days ago"
prettyDate("2008-01-14T22:24:17Z") // => "2 weeks ago"
prettyDate("2007-12-15T22:24:17Z") // => undefined

Trích bài về cách sử dụng:

Ví dụ sử dụng

Trong các ví dụ sau, tôi tạo tất cả các neo trên trang web, có tiêu đề với ngày tháng, có một ngày đẹp làm văn bản bên trong của chúng. Ngoài ra, tôi tiếp tục cập nhật các liên kết sau mỗi 5 giây sau khi trang được tải.

Với JavaScript:

function prettyLinks(){
    var links = document.getElementsByTagName("a");
    for ( var i = 0; i < links.length; i++ )
        if ( links[i].title ) {
            var date = prettyDate(links[i].title);
            if ( date )
                links[i].innerHTML = date;
        }
}
prettyLinks();
setInterval(prettyLinks, 5000);

Với jQuery:

$("a").prettyDate();
setInterval(function(){ $("a").prettyDate(); }, 5000);

Faiz: Đã thực hiện một số thay đổi đối với mã gốc, sửa lỗi và cải tiến.

function prettyDate(time) {
    var date = new Date((time || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
        diff = (((new Date()).getTime() - date.getTime()) / 1000),
        day_diff = Math.floor(diff / 86400);
    var year = date.getFullYear(),
        month = date.getMonth()+1,
        day = date.getDate();

    if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31)
        return (
            year.toString()+'-'
            +((month<10) ? '0'+month.toString() : month.toString())+'-'
            +((day<10) ? '0'+day.toString() : day.toString())
        );

    var r =
    ( 
        (
            day_diff == 0 && 
            (
                (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 == 1 && "Yesterday")
        || (day_diff < 7 && day_diff + " days ago")
        || (day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago")
    );
    return r;
}

1
Xin chào Floyd, tôi đã thêm một số thay đổi (sửa lỗi, cải tiến) cho câu trả lời của bạn. Hy vọng bạn không phiền ..
Faiz

Tốt! Nhưng không hoạt động với loại số dấu thời gian, có thể cần một bộ lọc tốt hơn như if (typeof time == 'string') {time = time.replace (/ - / g, "/").replace(/[TZ]/ g, "")); }
Arthur Araújo

15

sugar.js có các chức năng định dạng ngày tháng tuyệt vời.

Không chỉ vậy, nó còn cung cấp các chức năng thông dụng cho mục đích chung như định dạng chuỗi, định dạng số,… rất tiện lợi khi sử dụng.


1
đồng ý, sugar.js đáng được chú ý hơn ở đây.
citykid,

5

đây là một ví dụ về đường so với thời điểm: đối với lịch hiển thị các tuần, tôi cần giá trị thứ hai cuối cùng:

moment.js

var m = moment().subtract("days", 1).sod().day(1) // returns a "moment"

sugar.js

var d = Date.past("monday") // returns a js Date object

Tôi thích ăn nhiều đường hơn và sau vài tháng dùng moment.js thì giờ chuyển sang sugar.js. nó rõ ràng hơn và tích hợp độc đáo với lớp Ngày của Javascrip.

Vỏ OP được bảo vệ bởi cả hai libs, đối với sugar.js, hãy xem http://sugarjs.com/dates


4

Kịch bản js này rất hay. Tất cả những gì bạn phải làm là thực hiện nó. Tất cả<time> các thẻ sẽ được thay đổi thành ngày tháng tương đối và được cập nhật vài phút một lần, vì vậy thời gian tương đối sẽ luôn được cập nhật.

http://timeago.yarp.com/


1
Tôi nghĩ đây là giải pháp tốt nhất. Thư viện được duy trì rất tích cực, nó dựa trên / lấy cảm hứng từ mã của Resig, nó rất nhỏ, nó có rất nhiều bản địa hóa, việc tích hợp thật là nhỏ.
John Bachir

4

Có vẻ như bạn có thể sử dụng http://www.datejs.com/

Họ có một ví dụ trên trang chính thực hiện chính xác những gì bạn đang mô tả!

CHỈNH SỬA: Thực ra, tôi nghĩ rằng tôi đã đảo ngược câu hỏi của bạn trong đầu. Trong mọi trường hợp, tôi nghĩ bạn có thể kiểm tra nó vì dù sao nó cũng là một thư viện thực sự tuyệt vời!

CHỈNH SỬA x2: Tôi sẽ lặp lại những gì những người khác đã nói http://momentjs.com/ có lẽ là lựa chọn tốt nhất hiện có.

CHỈNH SỬA x3: Tôi đã không sử dụng date.js trong hơn một năm. Tôi chỉ sử dụng khoảnh khắc cho tất cả các nhu cầu liên quan đến ngày của tôi.


Đề nghị tốt đẹp. Quốc tế hóa chắc chắn là một điểm cộng.
Stephen

Date.js cũng là suy nghĩ đầu tiên của tôi, nhưng tôi không thấy có cách nào để chuyển từ số sang định dạng với nó - mặc dù nó có thể bị ẩn trong tài liệu ở đâu đó.
rapter

Date.js được biết là có nhiều lỗi nghiêm trọng và không thể tin cậy trong môi trường sản xuất. Nhiều khuôn khổ đang chuyển từ Date.js sang Moment.js
John Zabroski

Tôi đã học được cách cứng mà datejs không hoạt động trên Linux :(
Fantasma mỡ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.