├── .babelrc ├── .gitignore ├── .travis.yml ├── src ├── index.js ├── translations.js └── filter.js ├── karma.conf.js ├── test ├── testApp.js └── spec │ └── relative-date-filter.js ├── translations ├── da.json ├── de.json ├── en.json └── es.json ├── package.json ├── gulpfile.babel.js ├── dist ├── angular-relative-date.min.js ├── angular-relative-date.js.map ├── angular-relative-date.js └── angular-relative-date.min.js.map └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | package-lock.json 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - 4 7 | - 6 8 | - node 9 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /* global angular */ 2 | 3 | import translations from './translations' 4 | import filter from './filter' 5 | 6 | const relativeDate = angular.module('relativeDate', []) 7 | 8 | relativeDate.value('now', null) 9 | relativeDate.value('relativeDateTranslations', translations) 10 | 11 | relativeDate.filter('relativeDate', ['$injector', 'now', 'relativeDateTranslations', filter]) 12 | 13 | export default relativeDate 14 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | basePath: '', 4 | frameworks: ['jasmine'], 5 | files: [ 6 | 'node_modules/angular/angular.js', 7 | 'node_modules/angular-mocks/angular-mocks.js', 8 | 'node_modules/angular-translate/dist/angular-translate.js', 9 | 'dist/angular-relative-date.js', 10 | 'test/testApp.js', 11 | 'test/spec/*.js', 12 | ], 13 | exclude: [], 14 | port: 8080, 15 | logLevel: config.LOG_INFO, 16 | autoWatch: false, 17 | browsers: ['PhantomJS'], 18 | singleRun: false 19 | }) 20 | } 21 | -------------------------------------------------------------------------------- /test/testApp.js: -------------------------------------------------------------------------------- 1 | var myApp = angular.module('myApp', ['pascalprecht.translate', 'relativeDate']) 2 | 3 | myApp.config(function($translateProvider) { 4 | $translateProvider.translations('en', { 5 | weeks_ago: '{{time}}週間前', 6 | a_year_ago: '一年前', 7 | hours_from_now: '{{time}}時間今から' 8 | }).preferredLanguage('en') 9 | }) 10 | 11 | myApp.controller('TestCtrl', function($scope, $filter) { 12 | var relativeDate = $filter('relativeDate') 13 | 14 | $scope.fourWeeksAgo = relativeDate('2013-08-09') 15 | $scope.aYearAgo = relativeDate('2012-09-07') 16 | $scope.twoHoursFromNow = relativeDate('2013-09-07T14:00:00Z') 17 | }) 18 | -------------------------------------------------------------------------------- /src/translations.js: -------------------------------------------------------------------------------- 1 | export default { 2 | just_now: 'just now', 3 | seconds_ago: '{{time}} seconds ago', 4 | a_minute_ago: 'a minute ago', 5 | minutes_ago: '{{time}} minutes ago', 6 | an_hour_ago: 'an hour ago', 7 | hours_ago: '{{time}} hours ago', 8 | a_day_ago: 'yesterday', 9 | days_ago: '{{time}} days ago', 10 | a_week_ago: 'a week ago', 11 | weeks_ago: '{{time}} weeks ago', 12 | a_month_ago: 'a month ago', 13 | months_ago: '{{time}} months ago', 14 | a_year_ago: 'a year ago', 15 | years_ago: '{{time}} years ago', 16 | over_a_year_ago: 'over a year ago', 17 | seconds_from_now: '{{time}} seconds from now', 18 | a_minute_from_now: 'a minute from now', 19 | minutes_from_now: '{{time}} minutes from now', 20 | an_hour_from_now: 'an hour from now', 21 | hours_from_now: '{{time}} hours from now', 22 | a_day_from_now: 'tomorrow', 23 | days_from_now: '{{time}} days from now', 24 | a_week_from_now: 'a week from now', 25 | weeks_from_now: '{{time}} weeks from now', 26 | a_month_from_now: 'a month from now', 27 | months_from_now: '{{time}} months from now', 28 | a_year_from_now: 'a year from now', 29 | years_from_now: '{{time}} years from now', 30 | over_a_year_from_now: 'over a year from now' 31 | } 32 | -------------------------------------------------------------------------------- /translations/da.json: -------------------------------------------------------------------------------- 1 | { 2 | "just_now" : "ligenu", 3 | "seconds_ago" : "{{time}} sekunder siden", 4 | "a_minute_ago" : "et minut siden", 5 | "minutes_ago" : "{{time}} minutter siden", 6 | "an_hour_ago" : "en time siden", 7 | "hours_ago" : "{{time}} timer siden", 8 | "a_day_ago" : "i går", 9 | "days_ago" : "{{time}} dage siden", 10 | "a_week_ago" : "en uge siden", 11 | "weeks_ago" : "{{time}} uger siden", 12 | "a_month_ago" : "en måned siden", 13 | "months_ago" : "{{time}} måneder siden", 14 | "a_year_ago" : "et år siden", 15 | "years_ago" : "{{time}} år siden", 16 | "over_a_year_ago" : "over et år siden", 17 | "seconds_from_now" : "om {{time}} sekunder", 18 | "a_minute_from_now" : "om et minut", 19 | "minutes_from_now" : "om {{time}} minutter", 20 | "an_hour_from_now" : "om en time", 21 | "hours_from_now" : "om {{time}} timer", 22 | "a_day_from_now" : "i morgen", 23 | "days_from_now" : "om {{time}} dage", 24 | "a_week_from_now" : "om en uge", 25 | "weeks_from_now" : "om {{time}} uger", 26 | "a_month_from_now" : "om en måned", 27 | "months_from_now" : "om {{time}} måneder", 28 | "a_year_from_now" : "om et år", 29 | "years_from_now" : "om {{time}} år", 30 | "over_a_year_from_now": "om over et år" 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /translations/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "just_now" : "gerade eben", 3 | "seconds_ago" : "vor {{time}} Sekunden", 4 | "a_minute_ago" : "vor einer Minute", 5 | "minutes_ago" : "vor {{time}} Minuten", 6 | "an_hour_ago" : "vor einer Stunde", 7 | "hours_ago" : "vor {{time}} Stunden", 8 | "a_day_ago" : "gestern", 9 | "days_ago" : "vor {{time}} Tagen", 10 | "a_week_ago" : "letzte Woche", 11 | "weeks_ago" : "vor {{time}} Wochen", 12 | "a_month_ago" : "letzten Monat", 13 | "months_ago" : "vor {{time}} Monaten", 14 | "a_year_ago" : "letztes Jahr", 15 | "years_ago" : "vor {{time}} Jahren", 16 | "over_a_year_ago" : "vor über einem Jahr", 17 | "seconds_from_now" : "in {{time}} Sekunden", 18 | "a_minute_from_now" : "in einer Minute", 19 | "minutes_from_now" : "in {{time}} Minuten", 20 | "an_hour_from_now" : "in einer Stunde", 21 | "hours_from_now" : "in {{time}} Stunden", 22 | "a_day_from_now" : "morgen", 23 | "days_from_now" : "in {{time}} Tagen", 24 | "a_week_from_now" : "nächste Woche", 25 | "weeks_from_now" : "in {{time}} Wochen", 26 | "a_month_from_now" : "nächsten Monat", 27 | "months_from_now" : "in {{time}} Monaten", 28 | "a_year_from_now" : "nächstes Jahr", 29 | "years_from_now" : "in {{time}} Jahren", 30 | "over_a_year_from_now": "in über einem Jahr" 31 | } 32 | -------------------------------------------------------------------------------- /translations/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "just_now" : "just now", 3 | "seconds_ago" : "{{time}} seconds ago", 4 | "a_minute_ago" : "a minute ago", 5 | "minutes_ago" : "{{time}} minutes ago", 6 | "an_hour_ago" : "an hour ago", 7 | "hours_ago" : "{{time}} hours ago", 8 | "a_day_ago" : "yesterday", 9 | "days_ago" : "{{time}} days ago", 10 | "a_week_ago" : "a week ago", 11 | "weeks_ago" : "{{time}} weeks ago", 12 | "a_month_ago" : "a month ago", 13 | "months_ago" : "{{time}} months ago", 14 | "a_year_ago" : "a year ago", 15 | "years_ago" : "{{time}} years ago", 16 | "over_a_year_ago" : "over a year ago", 17 | "seconds_from_now" : "{{time}} seconds from now", 18 | "a_minute_from_now" : "a minute from now", 19 | "minutes_from_now" : "{{time}} minutes from now", 20 | "an_hour_from_now" : "an hour from now", 21 | "hours_from_now" : "{{time}} hours from now", 22 | "a_day_from_now" : "tomorrow", 23 | "days_from_now" : "{{time}} days from now", 24 | "a_week_from_now" : "a week from now", 25 | "weeks_from_now" : "{{time}} weeks from now", 26 | "a_month_from_now" : "a month from now", 27 | "months_from_now" : "{{time}} months from now", 28 | "a_year_from_now" : "a year from now", 29 | "years_from_now" : "{{time}} years from now", 30 | "over_a_year_from_now": "over a year from now" 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /translations/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "just_now" : "recién", 3 | "seconds_ago" : "hace {{time}} segundos", 4 | "a_minute_ago" : "hace un minuto", 5 | "minutes_ago" : "hace {{time}} minutos", 6 | "an_hour_ago" : "hace una hora", 7 | "hours_ago" : "hace {{time}} horas", 8 | "a_day_ago" : "ayer", 9 | "days_ago" : "hace {{time}} días", 10 | "a_week_ago" : "hace una semana", 11 | "weeks_ago" : "hace {{time}} semanas", 12 | "a_month_ago" : "hace un mes", 13 | "months_ago" : "hace {{time}} meses", 14 | "a_year_ago" : "hace un año", 15 | "years_ago" : "hace {{time}} años", 16 | "over_a_year_ago" : "hace mas de un año", 17 | "seconds_from_now" : "dentro de {{time}} segundos", 18 | "a_minute_from_now" : "dentro de un minuto", 19 | "minutes_from_now" : "dentro de {{time}} minutos", 20 | "an_hour_from_now" : "dentro de una hora", 21 | "hours_from_now" : "dentro de {{time}} horas", 22 | "a_day_from_now" : "mañana", 23 | "days_from_now" : "dentro de {{time}} días", 24 | "a_week_from_now" : "dentro de una semana", 25 | "weeks_from_now" : "dentro de {{time}} semanas", 26 | "a_month_from_now" : "dentro de un mes", 27 | "months_from_now" : "dentro de {{time}} meses", 28 | "a_year_from_now" : "dentro de un año", 29 | "years_from_now" : "dentro de {{time}} años", 30 | "over_a_year_from_now": "dentro de mas de un año" 31 | } 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-relative-date", 3 | "version": "2.1.1", 4 | "description": "AngularJS filter to provide relative, human-readable dates.", 5 | "main": "dist/angular-relative-date.js", 6 | "jsnext:main": "src/index.js", 7 | "license": "MIT", 8 | "author": "Joseph Wynn (https://wildlyinaccurate.com/)", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/wildlyinaccurate/angular-relative-date.git" 12 | }, 13 | "dependencies": { 14 | "angular": "^1.5.6", 15 | "angular-translate": "^2.11.0" 16 | }, 17 | "devDependencies": { 18 | "angular-mocks": "^1.5.6", 19 | "babel-core": "^6.9.1", 20 | "babel-preset-es2015": "^6.9.0", 21 | "babelify": "^7.3.0", 22 | "browserify": "^14.4.0", 23 | "gulp": "^3.9.1", 24 | "gulp-derequire": "^2.1.0", 25 | "gulp-rename": "^1.2.2", 26 | "gulp-sourcemaps": "^1.6.0", 27 | "gulp-standard": "^10.0.0", 28 | "gulp-uglify": "^3.0.0", 29 | "gulp-util": "^3.0.7", 30 | "jasmine": "^2.4.1", 31 | "karma": "^1.7.0", 32 | "karma-html2js-preprocessor": "^1.0.0", 33 | "karma-jasmine": "^1.0.2", 34 | "karma-ng-html2js-preprocessor": "^1.0.0", 35 | "karma-ng-scenario": "^1.0.0", 36 | "karma-phantomjs-launcher": "^1.0.0", 37 | "karma-script-launcher": "^1.0.0", 38 | "phantomjs-prebuilt": "^2.1.7", 39 | "vinyl-buffer": "^1.0.0", 40 | "vinyl-source-stream": "^1.1.0" 41 | }, 42 | "scripts": { 43 | "build": "gulp build", 44 | "test": "gulp test" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp' 2 | import gutil from 'gulp-util' 3 | import standard from 'gulp-standard' 4 | import browserify from 'browserify' 5 | import derequire from 'gulp-derequire' 6 | import rename from 'gulp-rename' 7 | import uglify from 'gulp-uglify' 8 | import sourcemaps from 'gulp-sourcemaps' 9 | import source from 'vinyl-source-stream' 10 | import buffer from 'vinyl-buffer' 11 | import { Server } from 'karma' 12 | 13 | gulp.task('default', ['build', 'test']) 14 | gulp.task('build', ['js', 'minify']) 15 | gulp.task('test', ['standard', 'karma']) 16 | 17 | gulp.task('js', () => { 18 | const b = browserify('src/index.js', { 19 | transform: ['babelify'], 20 | standalone: 'relativeDate' 21 | }) 22 | 23 | return b.bundle() 24 | .on('error', (error) => gutil.log('Browserify Error:', error.toString())) 25 | .pipe(source('index.js')) 26 | .pipe(rename('angular-relative-date.js')) 27 | .pipe(buffer()) 28 | .pipe(sourcemaps.init({ loadMaps: true })) 29 | .pipe(sourcemaps.write('.')) 30 | .pipe(derequire()) 31 | .pipe(gulp.dest('dist')) 32 | }) 33 | 34 | gulp.task('minify', ['js'], () => { 35 | return gulp.src('dist/angular-relative-date.js') 36 | .pipe(rename('angular-relative-date.min.js')) 37 | .pipe(sourcemaps.init({ loadMaps: true })) 38 | .pipe(uglify()) 39 | .pipe(sourcemaps.write('.')) 40 | .pipe(gulp.dest('dist')) 41 | }) 42 | 43 | gulp.task('standard', () => { 44 | return gulp.src('{gulpfile.babel.js,src/*.js}') 45 | .pipe(standard()) 46 | .pipe(standard.reporter('default', { breakOnError: true })) 47 | }) 48 | 49 | gulp.task('karma', ['js'], (done) => { 50 | new Server({ 51 | configFile: `${__dirname}/karma.conf.js`, 52 | singleRun: true 53 | }, done).start() 54 | }) 55 | -------------------------------------------------------------------------------- /src/filter.js: -------------------------------------------------------------------------------- 1 | const getTranslate = (injector, translations) => { 2 | if (injector.has('$translate')) { 3 | return injector.get('$translate') 4 | } else { 5 | return { 6 | instant: (id, params) => translations[id].replace('{{time}}', params.time) 7 | } 8 | } 9 | } 10 | 11 | const calculateDelta = (now, date) => Math.round(Math.abs(now - date) / 1000) 12 | 13 | export default function relativeDateFilter ($injector, _now, relativeDateTranslations) { 14 | const $translate = getTranslate($injector, relativeDateTranslations) 15 | 16 | return function (date) { 17 | const now = _now || new Date() 18 | 19 | if (!(date instanceof Date)) { 20 | date = new Date(date) 21 | } 22 | 23 | var delta = null 24 | 25 | const minute = 60 26 | const hour = minute * 60 27 | const day = hour * 24 28 | const week = day * 7 29 | const month = day * 30 30 | const year = day * 365 31 | 32 | delta = calculateDelta(now, date) 33 | 34 | if (delta > day && delta < week) { 35 | date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0) 36 | delta = calculateDelta(now, date) 37 | } 38 | 39 | const translate = (translatePhrase, timeValue) => { 40 | var translateKey 41 | 42 | if (translatePhrase === 'just_now') { 43 | translateKey = translatePhrase 44 | } else if (now >= date) { 45 | translateKey = `${translatePhrase}_ago` 46 | } else { 47 | translateKey = `${translatePhrase}_from_now` 48 | } 49 | 50 | return $translate.instant(translateKey, { 51 | time: timeValue 52 | }) 53 | } 54 | 55 | switch (false) { 56 | case !(delta < 30): 57 | return translate('just_now') 58 | 59 | case !(delta < minute): 60 | return translate('seconds', delta) 61 | 62 | case !(delta < 2 * minute): 63 | return translate('a_minute') 64 | 65 | case !(delta < hour): 66 | return translate('minutes', Math.floor(delta / minute)) 67 | 68 | case Math.floor(delta / hour) !== 1: 69 | return translate('an_hour') 70 | 71 | case !(delta < day): 72 | return translate('hours', Math.floor(delta / hour)) 73 | 74 | case !(delta < day * 2): 75 | return translate('a_day') 76 | 77 | case !(delta < week): 78 | return translate('days', Math.floor(delta / day)) 79 | 80 | case Math.floor(delta / week) !== 1: 81 | return translate('a_week') 82 | 83 | case !(delta < month): 84 | return translate('weeks', Math.floor(delta / week)) 85 | 86 | case Math.floor(delta / month) !== 1: 87 | return translate('a_month') 88 | 89 | case !(delta < year): 90 | return translate('months', Math.floor(delta / month)) 91 | 92 | case Math.floor(delta / year) !== 1: 93 | return translate('a_year') 94 | 95 | default: 96 | return translate('over_a_year') 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /dist/angular-relative-date.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).relativeDate=e()}}(function(){return function e(o,r,t){function a(u,f){if(!r[u]){if(!o[u]){var s="function"==typeof require&&require;if(!f&&s)return s(u,!0);if(n)return n(u,!0);var i=new Error("Cannot find module '"+u+"'");throw i.code="MODULE_NOT_FOUND",i}var _=r[u]={exports:{}};o[u][0].call(_.exports,function(e){var r=o[u][1][e];return a(r||e)},_,_.exports,e,o,r,t)}return r[u].exports}for(var n="function"==typeof require&&require,u=0;uu&&t<604800&&(e=new Date(e.getFullYear(),e.getMonth(),e.getDate(),0,0,0),t=a(r,e));var f=function(o,t){var a;return a="just_now"===o?o:r>=e?o+"_ago":o+"_from_now",n.instant(a,{time:t})};switch(!1){case!(t<30):return f("just_now");case!(t<60):return f("seconds",t);case!(t<120):return f("a_minute");case!(t<3600):return f("minutes",Math.floor(t/60));case 1!==Math.floor(t/3600):return f("an_hour");case!(t day && delta < week) {\n date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);\n delta = calculateDelta(now, date);\n }\n\n var translate = function translate(translatePhrase, timeValue) {\n var translateKey;\n\n if (translatePhrase === 'just_now') {\n translateKey = translatePhrase;\n } else if (now >= date) {\n translateKey = translatePhrase + '_ago';\n } else {\n translateKey = translatePhrase + '_from_now';\n }\n\n return $translate.instant(translateKey, {\n time: timeValue\n });\n };\n\n switch (false) {\n case !(delta < 30):\n return translate('just_now');\n\n case !(delta < minute):\n return translate('seconds', delta);\n\n case !(delta < 2 * minute):\n return translate('a_minute');\n\n case !(delta < hour):\n return translate('minutes', Math.floor(delta / minute));\n\n case Math.floor(delta / hour) !== 1:\n return translate('an_hour');\n\n case !(delta < day):\n return translate('hours', Math.floor(delta / hour));\n\n case !(delta < day * 2):\n return translate('a_day');\n\n case !(delta < week):\n return translate('days', Math.floor(delta / day));\n\n case Math.floor(delta / week) !== 1:\n return translate('a_week');\n\n case !(delta < month):\n return translate('weeks', Math.floor(delta / week));\n\n case Math.floor(delta / month) !== 1:\n return translate('a_month');\n\n case !(delta < year):\n return translate('months', Math.floor(delta / month));\n\n case Math.floor(delta / year) !== 1:\n return translate('a_year');\n\n default:\n return translate('over_a_year');\n }\n };\n}\n\n},{}],2:[function(require,module,exports){\n'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _translations = require('./translations');\n\nvar _translations2 = _interopRequireDefault(_translations);\n\nvar _filter = require('./filter');\n\nvar _filter2 = _interopRequireDefault(_filter);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n/* global angular */\n\nvar relativeDate = angular.module('relativeDate', []);\n\nrelativeDate.value('now', null);\nrelativeDate.value('relativeDateTranslations', _translations2.default);\n\nrelativeDate.filter('relativeDate', ['$injector', 'now', 'relativeDateTranslations', _filter2.default]);\n\nexports.default = relativeDate;\n\n},{\"./filter\":1,\"./translations\":3}],3:[function(require,module,exports){\n'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = {\n just_now: 'just now',\n seconds_ago: '{{time}} seconds ago',\n a_minute_ago: 'a minute ago',\n minutes_ago: '{{time}} minutes ago',\n an_hour_ago: 'an hour ago',\n hours_ago: '{{time}} hours ago',\n a_day_ago: 'yesterday',\n days_ago: '{{time}} days ago',\n a_week_ago: 'a week ago',\n weeks_ago: '{{time}} weeks ago',\n a_month_ago: 'a month ago',\n months_ago: '{{time}} months ago',\n a_year_ago: 'a year ago',\n years_ago: '{{time}} years ago',\n over_a_year_ago: 'over a year ago',\n seconds_from_now: '{{time}} seconds from now',\n a_minute_from_now: 'a minute from now',\n minutes_from_now: '{{time}} minutes from now',\n an_hour_from_now: 'an hour from now',\n hours_from_now: '{{time}} hours from now',\n a_day_from_now: 'tomorrow',\n days_from_now: '{{time}} days from now',\n a_week_from_now: 'a week from now',\n weeks_from_now: '{{time}} weeks from now',\n a_month_from_now: 'a month from now',\n months_from_now: '{{time}} months from now',\n a_year_from_now: 'a year from now',\n years_from_now: '{{time}} years from now',\n over_a_year_from_now: 'over a year from now'\n};\n\n},{}]},{},[2])(2)\n});"],"file":"angular-relative-date.js"} -------------------------------------------------------------------------------- /test/spec/relative-date-filter.js: -------------------------------------------------------------------------------- 1 | var NOW = new Date('2013-09-07T12:00:00Z') 2 | 3 | describe('Filter: relativeDate', function() { 4 | var relativeDate 5 | 6 | beforeEach(function() { 7 | module('relativeDate', function($provide) { 8 | $provide.value('now', NOW) 9 | }) 10 | 11 | inject(function(_$filter_) { 12 | relativeDate = _$filter_('relativeDate') 13 | }) 14 | }) 15 | 16 | it('Allows the `now` value to be set', function() { 17 | inject(function(now) { 18 | expect(now).toEqual(NOW) 19 | }) 20 | }) 21 | 22 | it('Has the correct response for each interval', function() { 23 | // Past 24 | expect(relativeDate('2013-09-07T12:00:00Z')).toEqual('just now') 25 | expect(relativeDate('2013-09-07T11:59:31Z')).toEqual('just now') 26 | expect(relativeDate('2013-09-07T11:59:29Z')).toEqual('31 seconds ago') 27 | expect(relativeDate('2013-09-07T11:59:01Z')).toEqual('59 seconds ago') 28 | expect(relativeDate('2013-09-07T11:59:00Z')).toEqual('a minute ago') 29 | expect(relativeDate('2013-09-07T11:58:01Z')).toEqual('a minute ago') 30 | expect(relativeDate('2013-09-07T11:58:00Z')).toEqual('2 minutes ago') 31 | expect(relativeDate('2013-09-07T11:00:01Z')).toEqual('59 minutes ago') 32 | expect(relativeDate('2013-09-07T11:00:00Z')).toEqual('an hour ago') 33 | expect(relativeDate('2013-09-07T10:00:01Z')).toEqual('an hour ago') 34 | expect(relativeDate('2013-09-07T10:00:00Z')).toEqual('2 hours ago') 35 | expect(relativeDate('2013-09-06T12:00:01Z')).toEqual('23 hours ago') 36 | expect(relativeDate('2013-09-06T12:00:00Z')).toEqual('yesterday') 37 | expect(relativeDate('2013-09-06T00:00:00Z')).toEqual('yesterday') 38 | expect(relativeDate('2013-09-05T22:59:59Z')).toEqual('2 days ago') 39 | expect(relativeDate('2013-09-01')).toEqual('6 days ago') 40 | expect(relativeDate('2013-08-31')).toEqual('a week ago') 41 | expect(relativeDate('2013-08-09')).toEqual('4 weeks ago') 42 | expect(relativeDate('2013-08-08')).toEqual('a month ago') 43 | expect(relativeDate('2013-03-01')).toEqual('6 months ago') 44 | expect(relativeDate('2012-09-07')).toEqual('a year ago') 45 | expect(relativeDate('2012-04-07')).toEqual('a year ago') 46 | expect(relativeDate('2011-04-07')).toEqual('over a year ago') 47 | 48 | // Future 49 | expect(relativeDate('2013-09-07T12:00:31Z')).toEqual('31 seconds from now') 50 | expect(relativeDate('2013-09-07T12:00:59Z')).toEqual('59 seconds from now') 51 | expect(relativeDate('2013-09-07T12:01:00Z')).toEqual('a minute from now') 52 | expect(relativeDate('2013-09-07T12:01:01Z')).toEqual('a minute from now') 53 | expect(relativeDate('2013-09-07T12:02:00Z')).toEqual('2 minutes from now') 54 | expect(relativeDate('2013-09-07T12:59:01Z')).toEqual('59 minutes from now') 55 | expect(relativeDate('2013-09-07T13:00:00Z')).toEqual('an hour from now') 56 | expect(relativeDate('2013-09-07T13:00:01Z')).toEqual('an hour from now') 57 | expect(relativeDate('2013-09-07T14:00:00Z')).toEqual('2 hours from now') 58 | expect(relativeDate('2013-09-08T11:00:01Z')).toEqual('23 hours from now') 59 | expect(relativeDate('2013-09-08T12:00:00Z')).toEqual('tomorrow') 60 | expect(relativeDate('2013-09-09T00:00:00Z')).toEqual('tomorrow') 61 | expect(relativeDate('2013-09-10T22:59:59Z')).toEqual('2 days from now') 62 | expect(relativeDate('2013-09-14')).toEqual('6 days from now') 63 | expect(relativeDate('2013-09-14T12:00:00Z')).toEqual('a week from now') 64 | expect(relativeDate('2013-10-05T12:00:00Z')).toEqual('4 weeks from now') 65 | expect(relativeDate('2013-10-07T12:00:00Z')).toEqual('a month from now') 66 | expect(relativeDate('2014-03-07T12:00:00Z')).toEqual('6 months from now') 67 | expect(relativeDate('2014-09-07T12:00:00Z')).toEqual('a year from now') 68 | expect(relativeDate('2015-01-07T12:00:00Z')).toEqual('a year from now') 69 | expect(relativeDate('2015-10-07T12:00:00Z')).toEqual('over a year from now') 70 | }) 71 | }) 72 | 73 | describe('Filter: relativeDate', function() { 74 | var relativeDate 75 | 76 | beforeEach(function() { 77 | module('relativeDate') 78 | 79 | inject(function(_$filter_) { 80 | relativeDate = _$filter_('relativeDate') 81 | }) 82 | }) 83 | 84 | it('Updates the value of NOW', function(done) { 85 | // Create a date 29 seconds ago (30 is the "just now" cutoff) 86 | var now = new Date(new Date() - 29000) 87 | var flag 88 | 89 | expect(relativeDate(now)).toEqual('just now') 90 | 91 | setTimeout(function() { 92 | expect(relativeDate(now)).toEqual('30 seconds ago') 93 | 94 | done() 95 | }, 1001) 96 | }) 97 | }) 98 | 99 | describe('Filter: relativeDate', function() { 100 | var relativeDate 101 | 102 | beforeEach(function() { 103 | module('relativeDate', function($provide) { 104 | $provide.value('now', NOW) 105 | $provide.value('relativeDateTranslations', { 106 | weeks_ago: '{{time}}週間前', 107 | a_year_ago: '一年前', 108 | hours_from_now: '{{time}}時間今から' 109 | }) 110 | }) 111 | 112 | inject(function(_$filter_) { 113 | relativeDate = _$filter_('relativeDate') 114 | }) 115 | }) 116 | 117 | it('Performs simple translations', function() { 118 | expect(relativeDate('2013-08-09')).toEqual('4週間前') 119 | expect(relativeDate('2012-09-07')).toEqual('一年前') 120 | expect(relativeDate('2013-09-07T14:00:00Z')).toEqual('2時間今から') 121 | }) 122 | }) 123 | 124 | describe('Filter: relativeDate', function() { 125 | var $scope 126 | 127 | beforeEach(function() { 128 | module('myApp', function($provide) { 129 | $provide.value('now', NOW) 130 | }) 131 | 132 | inject(function($rootScope, $controller, $filter) { 133 | $scope = $rootScope.$new() 134 | $controller('TestCtrl', { 135 | $scope: $scope 136 | }) 137 | }) 138 | }) 139 | 140 | describe('Integration with angular-translate', function() { 141 | it('Uses angular-translate when available', function() { 142 | expect($scope.fourWeeksAgo).toEqual('4週間前') 143 | expect($scope.aYearAgo).toEqual('一年前') 144 | expect($scope.twoHoursFromNow).toEqual('2時間今から') 145 | }) 146 | }) 147 | }) 148 | -------------------------------------------------------------------------------- /dist/angular-relative-date.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.relativeDate = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o day && delta < week) { 46 | date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); 47 | delta = calculateDelta(now, date); 48 | } 49 | 50 | var translate = function translate(translatePhrase, timeValue) { 51 | var translateKey; 52 | 53 | if (translatePhrase === 'just_now') { 54 | translateKey = translatePhrase; 55 | } else if (now >= date) { 56 | translateKey = translatePhrase + '_ago'; 57 | } else { 58 | translateKey = translatePhrase + '_from_now'; 59 | } 60 | 61 | return $translate.instant(translateKey, { 62 | time: timeValue 63 | }); 64 | }; 65 | 66 | switch (false) { 67 | case !(delta < 30): 68 | return translate('just_now'); 69 | 70 | case !(delta < minute): 71 | return translate('seconds', delta); 72 | 73 | case !(delta < 2 * minute): 74 | return translate('a_minute'); 75 | 76 | case !(delta < hour): 77 | return translate('minutes', Math.floor(delta / minute)); 78 | 79 | case Math.floor(delta / hour) !== 1: 80 | return translate('an_hour'); 81 | 82 | case !(delta < day): 83 | return translate('hours', Math.floor(delta / hour)); 84 | 85 | case !(delta < day * 2): 86 | return translate('a_day'); 87 | 88 | case !(delta < week): 89 | return translate('days', Math.floor(delta / day)); 90 | 91 | case Math.floor(delta / week) !== 1: 92 | return translate('a_week'); 93 | 94 | case !(delta < month): 95 | return translate('weeks', Math.floor(delta / week)); 96 | 97 | case Math.floor(delta / month) !== 1: 98 | return translate('a_month'); 99 | 100 | case !(delta < year): 101 | return translate('months', Math.floor(delta / month)); 102 | 103 | case Math.floor(delta / year) !== 1: 104 | return translate('a_year'); 105 | 106 | default: 107 | return translate('over_a_year'); 108 | } 109 | }; 110 | } 111 | 112 | },{}],2:[function(_dereq_,module,exports){ 113 | 'use strict'; 114 | 115 | Object.defineProperty(exports, "__esModule", { 116 | value: true 117 | }); 118 | 119 | var _translations = _dereq_('./translations'); 120 | 121 | var _translations2 = _interopRequireDefault(_translations); 122 | 123 | var _filter = _dereq_('./filter'); 124 | 125 | var _filter2 = _interopRequireDefault(_filter); 126 | 127 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 128 | 129 | /* global angular */ 130 | 131 | var relativeDate = angular.module('relativeDate', []); 132 | 133 | relativeDate.value('now', null); 134 | relativeDate.value('relativeDateTranslations', _translations2.default); 135 | 136 | relativeDate.filter('relativeDate', ['$injector', 'now', 'relativeDateTranslations', _filter2.default]); 137 | 138 | exports.default = relativeDate; 139 | 140 | },{"./filter":1,"./translations":3}],3:[function(_dereq_,module,exports){ 141 | 'use strict'; 142 | 143 | Object.defineProperty(exports, "__esModule", { 144 | value: true 145 | }); 146 | exports.default = { 147 | just_now: 'just now', 148 | seconds_ago: '{{time}} seconds ago', 149 | a_minute_ago: 'a minute ago', 150 | minutes_ago: '{{time}} minutes ago', 151 | an_hour_ago: 'an hour ago', 152 | hours_ago: '{{time}} hours ago', 153 | a_day_ago: 'yesterday', 154 | days_ago: '{{time}} days ago', 155 | a_week_ago: 'a week ago', 156 | weeks_ago: '{{time}} weeks ago', 157 | a_month_ago: 'a month ago', 158 | months_ago: '{{time}} months ago', 159 | a_year_ago: 'a year ago', 160 | years_ago: '{{time}} years ago', 161 | over_a_year_ago: 'over a year ago', 162 | seconds_from_now: '{{time}} seconds from now', 163 | a_minute_from_now: 'a minute from now', 164 | minutes_from_now: '{{time}} minutes from now', 165 | an_hour_from_now: 'an hour from now', 166 | hours_from_now: '{{time}} hours from now', 167 | a_day_from_now: 'tomorrow', 168 | days_from_now: '{{time}} days from now', 169 | a_week_from_now: 'a week from now', 170 | weeks_from_now: '{{time}} weeks from now', 171 | a_month_from_now: 'a month from now', 172 | months_from_now: '{{time}} months from now', 173 | a_year_from_now: 'a year from now', 174 | years_from_now: '{{time}} years from now', 175 | over_a_year_from_now: 'over a year from now' 176 | }; 177 | 178 | },{}]},{},[2])(2) 179 | }); 180 | //# sourceMappingURL=angular-relative-date.js.map 181 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-relative-date 2 | 3 | AngularJS filter for creating relative, human-readable dates. 4 | 5 | [![Build Status](https://travis-ci.org/wildlyinaccurate/angular-relative-date.png?branch=master)](https://travis-ci.org/wildlyinaccurate/angular-relative-date) 6 | [![Downloads](https://img.shields.io/npm/dm/angular-relative-date.svg?style=flat-square)](http://npm-stat.com/charts.html?package=angular-relative-date&from=2017-07-01) 7 | ![License](https://img.shields.io/npm/l/angular-relative-date.svg?style=flat-square) 8 | ![size](http://img.badgesize.io/https://unpkg.com/angular-relative-date/dist/angular-relative-date.min.js?label=size&style=flat-square) 9 | ![gzip size](http://img.badgesize.io/https://unpkg.com/angular-relative-date/dist/angular-relative-date.min.js?compression=gzip&label=gzip%20size&style=flat-square) 10 | 11 | > A vanilla JavaScript (i.e. not Angular) version of this module is available: [wildlyinaccurate/tiny-relative-date](https://github.com/wildlyinaccurate/tiny-relative-date) 12 | 13 | ## Usage 14 | 15 | For regular usage, just download and include `dist/angular-relative-date.js` in your application. 16 | 17 | ```html 18 | 19 | ``` 20 | 21 | You can also use the ES6 module directly using a packaging tool like [browserify](http://browserify.org/) or [webpack](https://webpack.github.io/). 22 | 23 | ```js 24 | import relativeDate from 'angular-relative-date' 25 | ``` 26 | 27 | Add the `relativeDate` module to your application's dependencies. 28 | 29 | ```js 30 | angular.module('myApp', ['relativeDate']); 31 | ``` 32 | 33 | Use the filter by passing it date strings or `Date` objects. 34 | 35 | ```html 36 | 42 | 43 |

Date strings work: {{ dateString | relativeDate }}

44 |

And so do Date objects: {{ dateObject | relativeDate }}

45 | ``` 46 | 47 | The above example will look something like this: 48 | 49 | > Date strings work: **a week ago** 50 | > 51 | > And so do `Date` objects: **just now** 52 | 53 | ## i18n 54 | 55 | Simple internationalisation support is available via the `relativeDateTranslations` value. See below for all available translation keys. 56 | 57 | ```html 58 | 67 | 68 |

Last updated: {{ lastUpdated | relativeDate }}

69 | ``` 70 | 71 | The above will output: 72 | 73 | > Last updated: **今** 74 | 75 | As well as the built-in translation, [angular-translate](http://angular-translate.github.io/) is also supported. Simply add the translation keys to your `$translateProvider`. 76 | 77 | ```js 78 | myApp.config(function ($translateProvider) { 79 | $translateProvider.translations('en', { 80 | just_now: 'just now', 81 | seconds_ago: '{{time}} seconds ago', 82 | }); 83 | 84 | $translateProvider.translations('de', { 85 | just_now: 'soeben', 86 | seconds_ago: 'vor {{time}} stunden', 87 | }); 88 | 89 | $translateProvider.preferredLanguage('en'); 90 | }); 91 | ``` 92 | 93 | ### Translation keys 94 | 95 | | Key | Default value | 96 | |------------------------|---------------------------| 97 | | `just_now` | just now | 98 | | `seconds_ago` | {{time}} seconds ago | 99 | | `a_minute_ago` | a minute ago | 100 | | `minutes_ago` | {{time}} minutes ago | 101 | | `an_hour_ago` | an hour ago | 102 | | `hours_ago` | {{time}} hours ago | 103 | | `a_day_ago` | yesterday | 104 | | `days_ago` | {{time}} days ago | 105 | | `a_week_ago` | a week ago | 106 | | `weeks_ago` | {{time}} weeks ago | 107 | | `a_month_ago` | a month ago | 108 | | `months_ago` | {{time}} months ago | 109 | | `a_year_ago` | a year ago | 110 | | `years_ago` | {{time}} years ago | 111 | | `over_a_year_ago` | over a year ago | 112 | | `seconds_from_now` | {{time}} seconds from now | 113 | | `a_minute_from_now` | a minute from now | 114 | | `minutes_from_now` | {{time}} minutes from now | 115 | | `an_hour_from_now` | an hour from now | 116 | | `hours_from_now` | {{time}} hours from now | 117 | | `a_day_from_now` | tomorrow | 118 | | `days_from_now` | {{time}} days from now | 119 | | `a_week_from_now` | a week from now | 120 | | `weeks_from_now` | {{time}} weeks from now | 121 | | `a_month_from_now` | a month from now | 122 | | `months_from_now` | {{time}} months from now | 123 | | `a_year_from_now` | a year from now | 124 | | `years_from_now` | {{time}} years from now | 125 | | `over_a_year_from_now` | over a year from now | 126 | 127 | ## Contributing 128 | 129 | Please modify `angular-relative-date.coffee` and then run `grunt build` to compile and minify the JavaScript (you may need to run `npm install` first). 130 | 131 | Submit your change as a pull request, including a description of the change. Please be sure to add any relevant test cases to `test/spec/relativ-date-filter.js`. 132 | 133 | ## License 134 | 135 | Released under the terms of MIT License: 136 | 137 | The MIT License (MIT) 138 | 139 | Copyright (c) 2015 Joseph Wynn 140 | 141 | Permission is hereby granted, free of charge, to any person obtaining a copy 142 | of this software and associated documentation files (the "Software"), to deal 143 | in the Software without restriction, including without limitation the rights 144 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 145 | copies of the Software, and to permit persons to whom the Software is 146 | furnished to do so, subject to the following conditions: 147 | 148 | The above copyright notice and this permission notice shall be included in all 149 | copies or substantial portions of the Software. 150 | 151 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 152 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 153 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 154 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 155 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 156 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 157 | SOFTWARE. 158 | -------------------------------------------------------------------------------- /dist/angular-relative-date.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["angular-relative-date.min.js"],"names":["f","exports","module","define","amd","window","global","self","this","relativeDate","e","t","n","r","s","o","u","a","require","i","Error","code","l","call","length","1","_dereq_","Object","defineProperty","value","default","$injector","_now","relativeDateTranslations","$translate","getTranslate","date","now","Date","delta","day","hour","calculateDelta","getFullYear","getMonth","getDate","translate","translatePhrase","timeValue","translateKey","instant","time","minute","Math","floor","injector","translations","has","get","id","params","replace","round","abs","2","_interopRequireDefault","obj","__esModule","_translations2","_filter2","angular","filter","./filter","./translations","3","just_now","seconds_ago","a_minute_ago","minutes_ago","an_hour_ago","hours_ago","a_day_ago","days_ago","a_week_ago","weeks_ago","a_month_ago","months_ago","a_year_ago","years_ago","over_a_year_ago","seconds_from_now","a_minute_from_now","minutes_from_now","an_hour_from_now","hours_from_now","a_day_from_now","days_from_now","a_week_from_now","weeks_from_now","a_month_from_now","months_from_now","a_year_from_now","years_from_now","over_a_year_from_now"],"mappings":"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","file":"angular-relative-date.min.js","sourcesContent":["(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.relativeDate = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o day && delta < week) {\n date = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);\n delta = calculateDelta(now, date);\n }\n\n var translate = function translate(translatePhrase, timeValue) {\n var translateKey;\n\n if (translatePhrase === 'just_now') {\n translateKey = translatePhrase;\n } else if (now >= date) {\n translateKey = translatePhrase + '_ago';\n } else {\n translateKey = translatePhrase + '_from_now';\n }\n\n return $translate.instant(translateKey, {\n time: timeValue\n });\n };\n\n switch (false) {\n case !(delta < 30):\n return translate('just_now');\n\n case !(delta < minute):\n return translate('seconds', delta);\n\n case !(delta < 2 * minute):\n return translate('a_minute');\n\n case !(delta < hour):\n return translate('minutes', Math.floor(delta / minute));\n\n case Math.floor(delta / hour) !== 1:\n return translate('an_hour');\n\n case !(delta < day):\n return translate('hours', Math.floor(delta / hour));\n\n case !(delta < day * 2):\n return translate('a_day');\n\n case !(delta < week):\n return translate('days', Math.floor(delta / day));\n\n case Math.floor(delta / week) !== 1:\n return translate('a_week');\n\n case !(delta < month):\n return translate('weeks', Math.floor(delta / week));\n\n case Math.floor(delta / month) !== 1:\n return translate('a_month');\n\n case !(delta < year):\n return translate('months', Math.floor(delta / month));\n\n case Math.floor(delta / year) !== 1:\n return translate('a_year');\n\n default:\n return translate('over_a_year');\n }\n };\n}\n\n},{}],2:[function(_dereq_,module,exports){\n'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _translations = _dereq_('./translations');\n\nvar _translations2 = _interopRequireDefault(_translations);\n\nvar _filter = _dereq_('./filter');\n\nvar _filter2 = _interopRequireDefault(_filter);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\n/* global angular */\n\nvar relativeDate = angular.module('relativeDate', []);\n\nrelativeDate.value('now', null);\nrelativeDate.value('relativeDateTranslations', _translations2.default);\n\nrelativeDate.filter('relativeDate', ['$injector', 'now', 'relativeDateTranslations', _filter2.default]);\n\nexports.default = relativeDate;\n\n},{\"./filter\":1,\"./translations\":3}],3:[function(_dereq_,module,exports){\n'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\nexports.default = {\n just_now: 'just now',\n seconds_ago: '{{time}} seconds ago',\n a_minute_ago: 'a minute ago',\n minutes_ago: '{{time}} minutes ago',\n an_hour_ago: 'an hour ago',\n hours_ago: '{{time}} hours ago',\n a_day_ago: 'yesterday',\n days_ago: '{{time}} days ago',\n a_week_ago: 'a week ago',\n weeks_ago: '{{time}} weeks ago',\n a_month_ago: 'a month ago',\n months_ago: '{{time}} months ago',\n a_year_ago: 'a year ago',\n years_ago: '{{time}} years ago',\n over_a_year_ago: 'over a year ago',\n seconds_from_now: '{{time}} seconds from now',\n a_minute_from_now: 'a minute from now',\n minutes_from_now: '{{time}} minutes from now',\n an_hour_from_now: 'an hour from now',\n hours_from_now: '{{time}} hours from now',\n a_day_from_now: 'tomorrow',\n days_from_now: '{{time}} days from now',\n a_week_from_now: 'a week from now',\n weeks_from_now: '{{time}} weeks from now',\n a_month_from_now: 'a month from now',\n months_from_now: '{{time}} months from now',\n a_year_from_now: 'a year from now',\n years_from_now: '{{time}} years from now',\n over_a_year_from_now: 'over a year from now'\n};\n\n},{}]},{},[2])(2)\n});\n\n"]} --------------------------------------------------------------------------------