Javascript fuzzy time (например, "10 минут назад" ), что в точные секунды
Я делаю счетчик javascript, который считается секундой назад. У меня есть время в объекте времени JS, и я нашел фрагмент функции разницы во времени здесь при переполнении стека, но он отображает "2 часа назад". Как я могу заставить его отображать "5 часов, 10 минут и 37 секунд назад".
Вот с чем я работаю:
Эта функция преобразует текущее время и временную метку чего-то в "20 секунд назад" вместо загадочной даты:
function timeDifference(current, previous) {
var msPerMinute = 60 * 1000;
var msPerHour = msPerMinute * 60;
var msPerDay = msPerHour * 24;
var msPerMonth = msPerDay * 30;
var msPerYear = msPerDay * 365;
var elapsed = current - previous;
if (elapsed < msPerMinute) {
return Math.round(elapsed/1000) + ' seconds ago';
} else if (elapsed < msPerHour) {
return Math.round(elapsed/msPerMinute) + ' minutes ago';
} else if (elapsed < msPerDay ) {
return Math.round(elapsed/msPerHour ) + ' hours ago';
} else if (elapsed < msPerMonth) {
return 'approximately ' + Math.round(elapsed/msPerDay) + ' days ago';
} else if (elapsed < msPerYear) {
return 'approximately ' + Math.round(elapsed/msPerMonth) + ' months ago';
} else {
return 'approximately ' + Math.round(elapsed/msPerYear ) + ' years ago';
}
}
И вот что я использую, чтобы "подсчитывать" время каждую секунду. Я бы хотел сказать "5 часов, 3 минуты, 10 секунд назад", а затем через 1 секунду "5 часов, 3 минуты, 11 секунд назад"
var newTime = new Date(data.popular[i].timestamp*1000)
var relTime = timeDifference(new Date(),newTime)
setInterval(function(){
var theTimeEl = $('.timestamp-large').filter(function(){
return $(this).html() == relTime
});
newTime.setSeconds(newTime.getSeconds() + 1);
var relTime = timeDifference(new Date(), newTime);
$(theTimeEl).html(relTime);
console.log(relTime)
}, 1000)
Переменная newTime - это время в формате даты javascript UTC. relTime - это то, что в формате "секунды назад". Интервал проходит через кучу элементов временной метки и выбирает правильный для каждой отметки времени. Затем он добавляет секунду к времени, преобразует его обратно в "нечеткое время" (несколько секунд назад), заменяет html новым временем и записывает его в консоль.
Как мне изменить "5 часов назад" на "5 часов, 37 минут, 10 секунд назад"? Функция временной разницы должна быть изменена.
Ответы
Ответ 1
Здесь функция, близкая к тому, что вы просите.
var timeparts = [
{name: 'year', div: 31536000000, mod: 10000},
{name: 'day', div: 86400000, mod: 365},
{name: 'hour', div: 3600000, mod: 24},
{name: 'minute', div: 60000, mod: 60},
{name: 'second', div: 1000, mod: 60}
];
function timeAgoNaive(comparisonDate) {
var
i = 0,
l = timeparts.length,
calc,
values = [],
interval = new Date().getTime() - comparisonDate.getTime();
while (i < l) {
calc = Math.floor(interval / timeparts[i].div) % timeparts[i].mod;
if (calc) {
values.push(calc + ' ' + timeparts[i].name + (calc != 1 ? 's' : ''));
}
i += 1;
}
if (values.length === 0) { values.push('0 seconds'); }
return values.join(', ') + ' ago';
}
console.log(timeAgoNaive(new Date(Date.parse('Jun 12 2006 11:52:33'))));
console.log(timeAgoNaive(new Date(new Date().getTime() - 3600000)));
console.log(timeAgoNaive(new Date()));
Результаты:
6 years, 33 days, 4 hours, 52 minutes, 22 seconds ago
1 hour ago
0 seconds ago
Я назвал его "наивным", потому что на самом деле он не обращает внимания на человеческий путь, который мы вычисляем. Если это "1/1/2013 12:01:00 утра" точно, по сравнению с "1/1/2012 12:01:00 утра" должно уступить "1 год, 0 месяцев, 0 дней, 0 часов, 0 минут, 0 секунд назад". Но это не будет сделано, расширяя логику в функции, которую вы представили, и она не будет делать это в моей функции (плюс моя функция не будет использовать месяцы). Лучшее приближение лет 365 дней - 365,24, но это также игнорируется.
Я исключил пустые временные части по вашему запросу, оставив "0 секунд" как минимум, когда нет временных частей.
Теперь, если вы хотите, чтобы человекоподобный способ расчета, вам нужно решить некоторые вещи. Вы не можете просто использовать границы, пересеченные, потому что с 28 февраля по 1 марта не целый месяц. Во-вторых, здесь возникает вопрос о реальной проблеме:
- Сколько месяцев и дней с 2 по 31 марта?
Если вы вычисляете 2 февраля по 2 марта как один месяц, то это 1 месяц 29 дней. Но что, если бы было 2 января до 1 марта? То же самое количество дней прошло между ними. Это сейчас 1 месяц (за весь апрель) + 1 день в марте + 31 день в январе за 1 месяц 32 дня? Вы хотите, чтобы ваши месяцы совпадали с физическим календарем, чтобы человек мог отследить пальцем и получить правильную дату? Это намного сложнее, чем вы думаете.
Если вы можете ответить разумными и полными правилами о том, как вы будете делать "человекоподобное истекшее время", то, возможно, я могу написать вам другую функцию, чтобы сделать это.
Обновление
Здесь новая функция, которая делает месяцы и имеет 365,24 дня в году (30.43666666 дней в месяц):
var timeparts = [
{name: 'millenni', div: 31556736000, p: 'a', s: 'um'},
{name: 'centur', div: 3155673600, p: 'ies', s: 'y'},
{name: 'decade', div: 315567360},
{name: 'year', div: 31556736},
{name: 'month', div: 2629728},
{name: 'day', div: 86400},
{name: 'hour', div: 3600},
{name: 'minute', div: 60},
{name: 'second', div: 1}
];
function timeAgoNaive2(comparisonDate) {
var i = 0,
parts = [],
interval = Math.floor((new Date().getTime() - comparisonDate.getTime()) / 1000);
for ( ; interval > 0; i += 1) {
value = Math.floor(interval / timeparts[i].div);
interval = interval - (value * timeparts[i].div);
if (value) {
parts.push(value + ' ' + timeparts[i].name + (value !== 1 ? timeparts[i].p || 's' : timeparts[i].s || ''));
}
}
if (parts.length === 0) { return 'now'; }
return parts.join(', ') + ' ago';
}
console.log(timeAgoNaive2(new Date(Date.parse('Jun 12 2006 11:52:33'))));
console.log(timeAgoNaive2(new Date(new Date().getTime() - 3600000)));
console.log(timeAgoNaive2(new Date()));
console.log(timeAgoNaive2(new Date(-92709631247000)));
Вывод:
6 years, 1 month, 1 day, 10 hours, 53 minutes, 44 seconds ago
1 hour ago
now
2 millennia, 9 centuries, 8 decades, 4 months, 26 days, 22 hours, 41 minutes, 47 seconds ago
Это все еще наивно, но он немного лучше работает. Плюс это будет работать для ДЕЙСТВИТЕЛЬНО старых дат, таких как B.C. из них.:)
Ответ 2
Измените логику, чтобы вместо того, чтобы просто найти самую большую единицу измерения, она делает что-то с остатком.
В основном то, что вам нужно сделать, это начать с наибольшего приращения, найти значение, а затем вычесть его из общей суммы, чтобы получить остаток. Затем повторите.
Что-то вроде этого, может быть, я его не тестировал.
var elapsed = current - previous;
var remainder = elapsed;
int years;
int months;
years = Math.floor(remainder/msPerYear);
remainder = remainder % msPerYear;
months = Math.floor(remainder/msPerMonth);
remainder = remainder % msPerMonth;
// repeat
Затем просто создайте строку с переменными.
Ответ 3
Это должно сделать трюк:
var msPerMinute = 60 * 1000;
var msPerHour = msPerMinute * 60;
var msPerDay = msPerHour * 24;
var msPerMonth = msPerDay * 30;
var msPerYear = msPerDay * 365;
function timeDifference(current, previous) {
var remainder = current - previous;
var message = "";
var sep = "";
var years = Math.floor(remainder/msPerYear);
remainder = remainder - years * msPerYear;
if (years > 0) {
message += years + " years";
sep = ", ";
console.log(message);
}
var months = Math.floor(remainder/msPerMonth);
remainder = remainder - months * msPerMonth;
if (months > 0) {
message += sep + months + " months";
sep = ", ";
console.log(message);
}
var days = Math.floor(remainder/msPerDay);
remainder = remainder - days * msPerDay;
if (days > 0) {
message += sep + days + " days";
sep = ", ";
console.log(message);
}
var hours = Math.floor(remainder/msPerHour);
remainder = remainder - hours * msPerHour;
if (hours > 0) {
message += sep + hours + " hours";
sep = ", ";
console.log(message);
}
var minutes = Math.floor(remainder/msPerMinute);
remainder = remainder - minutes * msPerMinute;
if (months > 0) {
message += sep + minutes + " minutes";
sep = ", ";
console.log(message);
}
var seconds = Math.floor(remainder/1000);
remainder = remainder - seconds * 1000;
if (months > 0) {
message += sep + seconds + " seconds";
sep = ", ";
console.log(message);
}
message += " ago";
var pos = message.lastIndexOf(',');
message = message.substring(0,pos) + ' and' + message.substring(pos+1)
return message;
};
var output = timeDifference(new Date(2012, 10, 20, 12, 0, 59), new Date(2012, 2, 13, 10, 15, 12));
console.log(output);
Результат: 8 месяцев, 12 дней, 1 час, 45 минут и 47 секунд назад
Это можно было бы, конечно, реорганизовать, чтобы быть немного менее повторяющимся.
Вы можете попробовать эту скрипку с ней: http://jsfiddle.net/vawEf/