CuteTime

jquery-logo-256 02_facebook-cutetime Many online social products, and more continue to, avoid a formal timestamp format…

2009-10-10 23:14:17 and Thu, October 29, 2004 12:14:19 PM

… opting for more user friendly, “warm and fuzzy,” human-readable styles…

9 days ago and 5 years ago.

As a result, and also in my quest to always help provide my clients free, cheap and easy to use tools, I have been on the lookout for a jQuery plugin that would provide the ability to easily…01_digg-cutetime

  • convert timestamps to ‘cuter’ language-styled forms (e.g. yesterday, 2 hours ago, last year, in the future!),
  • customize the time scales and output formatting, and
  • update automatically and/or manually the displayed CuteTime(s).

While there are other similar tools out there in JavaScript, PHP, and, I am sure, many other languages, none adequately met my goals. Therefore, I created the jQuery CuteTime plugin.

Usage

CuteTime is a customizable jQuery plugin (jQuery.cuteTime) that automatically converts timestamps to formats much cuter. It also has the ability to manually and/or automatically update timestamps on a controlled interval.

  • If used via Selector, CuteTime replaces the text of the provided object with a cuteTime.
  • If used as a function, CuteTime returns a string containing a cuteTime version of the provided timestamp.
// METHOD
$('.timestamp').cuteTime();
$('.timestamp').cuteTime({ /* OPTIONS * / });

cutetime_object = $('.timestamp').cuteTime();
cutetime_object.update_cuteness();

// FUNCTION
$.cuteTime('2009/10/12 22:11:19');
$.cuteTime({ /* OPTIONS * / }, '2009-11-24T19:20:30+01:00');

As a Function

If used as a function, CuteTime returns a string containing a cuteTime version of the provided timestamp.

$(document).ready(function () {
	// timestamp MUST be a valid Date().parse 'able' format
	$('.predetermined').text(
		$.cuteTime('2009/10/12 22:11:19')
	);
	$('.predetermined2').text(
		$.cuteTime(settings, '2009-11-24T13:15:30Z')
	);
});
<html>
	<body>
		<div class='predetermined'></div>
		<div class='predetermined2'></div>
	</body>
</html>


As a Method

If used via Selector, CuteTime replaces the text of the provided object with a cuteTime.

$(document).ready(function () {
	$('.timestamp').cuteTime();
});
<html>
	<body>
		<div class="timestamp">
			2009/10/12 22:11:19
		</div>
		<div class="timestamp">
			2008/11/01 07:11:00
		</div>
		<div class="timestamp">
			2018/11/01 07:11:00
		</div>
		<div class="timestamp"></div>
		<div class="timestamp" cutetime="1980/10/12 22:11:19">
			2009/10/12 22:11:19
		</div>
		<div class="timestamp" cutetime="asd">
			10/12/2009 22:11:19
		</div>
		<div class="timestamp" cutetime="asd">
			aoisd
		</div>
		<div class="timestamp" cutetime="asd"></div>
	</body>
</html>

When initialized, the cuteTime() call either updates or assigns the 'cutetime' attribute to the provided objects. Method implementation supports chaining, returning the jQuery object.

e.g. <div class='timestamp' cutetime='2009 10 12 22:11:19'>2009 10 12 22:11:19</div>

If the cutetime attribute already exists within the provided object, then the text within the object is ignored in the cutification process. If the cutetime attribute does not exist or an invalid one is provided, then a valid cutetime attribute is assigned to the object.

If the cutetime attribute is missing, then it is calculated from the text of the provided object.

If neither cutetime attribute nor valid object text exist, then the timestamp is assumed to be 'now'.

When using CuteTime in the form...

&lt;br /&gt;
$(document).ready(function () {
	remember_the_cuteness = $('.timestamp').cuteTime();
});

... the following methods can be used ...

// stops all automatic updates of refresh-enabled timestamps
remember_the_cuteness.stop_cuteness();

// (re)starts the automatic updating of timestamps
// REMINDER: make sure refresh is set to &gt; 0
remember_the_cuteness.start_cuteness();

// updates timestamps of the provided objects
remember_the_cuteness.update_cuteness();

Settings

By default, automatic updating is disabled and the following CuteTimes can be displayed...

the future!
just now
a few seconds ago
a minute ago
x minutes ago
an hour ago
x hours ago
yesterday
x days ago
last month
x months ago
last year
x years ago

To change these settings, they can either be accessed directly...

$.fn.cuteTime.settings.refresh = 10000;

... or at the time of initialization ...

my_cutetime = $('.timestamp_move').cuteTime({ refresh: 60000*10 });

The default settings data structure is...

$.fn.cuteTime.settings = {
	refresh: -1,			// time in milliseconds before next refresh of page data; -1 == no refresh
	time_ranges: [
		{bound: Number.NEGATIVE_INFINITY,	// IMPORANT: bounds MUST be in ascending order, from negative infinity to positive infinity
			cuteness: 'the future!',			unit_size: 0},
		{bound: 0,
			cuteness: 'just now',				unit_size: 0},
		{bound: 20 * 1000,
			cuteness: 'a few seconds ago',		unit_size: 0},
		{bound: 60 * 1000,
			cuteness: 'a minute ago',			unit_size: 0},
		{bound: 60 * 1000 * 2,
			cuteness: ' minutes ago',			unit_size: 60 * 1000},
		{bound: 60 * 1000 * 60,
			cuteness: 'an hour ago',			unit_size: 0},
		{bound: 60 * 1000 * 60 * 2,
			cuteness: ' hours ago',				unit_size: 60 * 1000 * 60},
		{bound: 60 * 1000 * 60 * 24,
			cuteness: 'yesterday',				unit_size: 0},
		{bound: 60 * 1000 * 60 * 24 * 2,
			cuteness: ' days ago',				unit_size: 60 * 1000 * 60 * 24},
		{bound: 60 * 1000 * 60 * 24 * 30,
			cuteness: 'last month',				unit_size: 0},
		{bound: 60 * 1000 * 60 * 24 * 30 * 2,
			cuteness: ' months ago',			unit_size: 60 * 1000 * 60 * 24 * 30},
		{bound: 60 * 1000 * 60 * 24 * 30 * 12,
			cuteness: 'last year',				unit_size: 0},
		{bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
			cuteness: ' years ago',				unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
		{bound: Number.POSITIVE_INFINITY,
			cuteness: 'a blinkle ago',			unit_size: 0}
	]
};

All modifications to the settings are non-constructive.  This means that you need to specify all the non-default settings you wish to have applied on each cuteTime.update_cuteness() or cuteTime() call.

The parameters are defined (and all can be overridden) thus...

  • refresh
    • time in milliseconds before next refresh of page data;
    • a value of -1 disables refreshing
  • time_ranges
    • the array of bound_structures that delineate the cute descriptions associated with time_ranges
    • time_range's boundary structures consist of the following variables...
  • time_range[x].bound
    • the value is an integer representing the time difference between the provided timestamp and now
    • the lower inclusive bound, or starting point, for using the 'cuteness' string that describes the current timestamp
    • the exclusive upper bound is defined by the next boundary structure definition in the time_ranges array [current boundary + 1]
  • time_range[x].cuteness
    • string to use in place of the current timestamp (e.g. 'yesterday')
  • time_range[x].unit_size
    • the integer divisor in milliseconds to apply to the calculated time difference
    • if unit_size > 0 then a number value is prepended to the cuteness string as calculated by time_difference / unit_size (e.g. 4 hours ago)
    • if unit_size = 0, then no number is prepended to the cuteness string (e.g. an hour ago)

%CT% and International Support

Originally, CuteTime was developed with a less than universal syntactic centricity.  Basically, CuteTime originally could hanle the cuteness of presenting...

"a few seconds ago"
"last month"

...as well as prepend values resulting in...

" hours ago" becoming "4 hours ago"
" seconds ago" becoming "18 seconds ago".

Now, in addition to supporting the prepending of the computed CuteTime,

  • the calculation can be inserted within the cuteness string, and
  • both formatted HTML styling and proper character accenting can be applied...

...resulting in the additional support for...

"il y a %CT% minutes" becoming "il y a 4 minutes"
"l\'ann&eacute;e derni&egrave;re" becoming "l'année dernière"
"<span style='color: red; font-weight: bold'>in the future<span>" becoming "in the future"

Date & Time

Formatting of timestamps is the bane of many a developer.  Especially onerous is the handling of "standard" time formatting by the front-end developer.  The JavaScript Date Object() supports the IETF standard, defined in RFC 822 Section 5, at least in FireFox, with most backend systems providing and storing (or at least converting to) dates in ISO8601 form.

Now, when converting a normal time into a CuteTime it can be either formatted in a manner compatible with the JavaScript Date() Object ...

Thu Oct 15 2009 22:11:19 GMT-0400 (Eastern Daylight Time)
Oct 15 2009 22:11:19

... or ISO8601 ...

2009-11-24T19:20:30+01:00
2009-11
2009-11-24T13:15:30Z

If you are counting on leveraging the JavaScript Date() Object handling of your timestamp, make sure you use timestamps that are fully recognized by the JavaScript Date object’s Parse method in all the browser versions you want to support. Otherwise, prepare for a headache.  ;-)

Get It

You can download CuteTime, dual licensed under GPL and MIT, from...

jQuery Repository
http://plugins.jquery.com/project/CuteTime

Git
Public Clone URL: git://github.com/theproductguy/CuteTime.git
GitHub: http://github.com/theproductguy/CuteTime

Zip
jQuery.cuteTime-source-bundle_1.1.1_20100201.zip

Demo

http://theproductguy.com/cutetime/cutetime.demo.html

Release Notes

Version 1.0 - 2009/10/17
Initial Release.

Version 1.0.5 - 2009/11/10
[UPDATED] updated cutetime attribute to be HTML 5 custom attribute compatible and more flexible in the future; using data-timestamp and global constant TS_ATTR
[UPDATED] test/demo HTML files to work with new TS_ATTR
[UPDATE] minified version of javascript compiled with Google's Closure Tools (new)
[FIXED] setting behavior is not as desired THEREFORE updated settings (temporarily) to be DESTRUCTIVE between updates
[FEATURE] added translations.txt to act as repository for all language translations for the CuteTime  cuteness translations

Version 1.0.6 - 2009.11.19
[FEATURE] added Spansish time translation to the translations.txt file (courtesy of Alex Hernandez)

Version 1.1 - 2009.11.26
[FEATURE] implemented case-sensitive variable %CT% that can be used anywhere within the cuteness strings; if not specified, and number insertion is called for, then prepends number to provided string; if no number is called for, then the %CT% is removed from the final string
[FEATURE] added support for foreign language characters and HTML within the cuteness strings
[FEATURE] accepts timestamps in format compatible with either/both JavaScript Date() Object as well as ISO8601
[UPDATED] test/demo files to also demo foreign language and %CT%
[UPDATED] test/demo files to also demo ISO8601
[FEATURE] settings can be submitted as parameter to CuteTime function call
[FEATURE] added French time translation to the translations.txt file (courtesy of Bruno Morency)
[FIXED] documentation to indicate that Number.NEGATIVE_INFINITY and Number.POSTIVE_INFINITY should be used within the bounds

Version 1.1.1 - 2010.02.01
[FEATURE] added Russian time translation to the translations.txt file (courtesy of Jansen Price)

If you find this useful, or have any questions, ideas, or issues, leave a comment.

Enjoy!

Jeremy Horn
The Product Guy

<!--[if !mso]> <! st1\:*{behavior:url(#ieooui) } -->

$(document).ready(function () {

// timestamp MUST be a valid Date().parse 'able' format

$.cuteTime('2009/10/12 22:11:19');

});

33 Responses to “CuteTime”

  1. Kenneth Auchenberg Says:

    I have one initial comment about this plugin, and its the usage of the custom element attribute “cutetime”. This attribute is invalid HTML, and without a custom DTD its also invalid XHTML. To be HTML5 valid you would have to use a data-attribute, such as “data-cutetime”.

    What is it you want to do with the orginal timestamp, since you expose it as a element attrbute? You could use jQuery.data to store the orginal timestamp in the internal jQuery data-object. It would be way faster, because you minimize the DOM-access. But this way the timestamp would not be exposed in the DOM, and therefore not accessible from ouside of the jQuery context.

    If you do want to expose the orginal timestamp into the DOM, and therefore into the semantics of the markup, then I think you should consider using the HTML5 data-attributes, and in that case I would rename the attribute to “date” or “timestamp”, since its information that describes the date-context in a generic way.

    Just my cents..

    -Kenneth Auchenberg

  2. Jeremy Horn Says:

    Thanks to Vincent Rolfs we have an example of how to use CuteTime in a multilingual setting. Vincent’s German example follows…

    $(‘.timestamp’).cuteTime({
    time_ranges: [
    {bound: NEG_INF,
    cuteness: 'in der Zukunft!', unit_size: 0},
    {bound: 0,
    cuteness: 'gerade jetzt', unit_size: 0},
    {bound: 20 * 1000,
    cuteness: 'vor ein paar Sekunden', unit_size: 0},
    {bound: 60 * 1000,
    cuteness: 'vor einer Minute', unit_size: 0},
    {bound: 60 * 1000 * 2,
    cuteness: ' Minuten her', unit_size: 60 * 1000},
    {bound: 60 * 1000 * 60,
    cuteness: 'vor einer Stunde', unit_size: 0},
    {bound: 60 * 1000 * 60 * 2,
    cuteness: ' Stunden her', unit_size: 60 * 1000 * 60},
    {bound: 60 * 1000 * 60 * 24,
    cuteness: 'Gestern', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 2,
    cuteness: ' Tage her', unit_size: 60 * 1000 * 60 * 24},
    {bound: 60 * 1000 * 60 * 24 * 30,
    cuteness: 'letzen Monat', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 2,
    cuteness: ' Monate her', unit_size: 60 * 1000 * 60 * 24 * 30},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12,
    cuteness: 'letztes Jahr', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
    cuteness: ' Jahre her', unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
    {bound: POS_INF,
    cuteness: 'vor langer Zeit', unit_size: 0}
    ]
    });

  3. Alex Hernandez Says:

    Hey, nice work, this my translation to Spanish .

    thanks.

    SETTINGS = {
    time_ranges: [
    {bound: NEG_INF,
    cuteness: 'el futuro!', unit_size: 0},
    {bound: 0,
    cuteness: 'en este momento', unit_size: 0},
    {bound: 20 * 1000,
    cuteness: 'hace unos segundos', unit_size: 0},
    {bound: 60 * 1000,
    cuteness: 'hace un minuto', unit_size: 0},
    {bound: 60 * 1000 * 2,
    cuteness: ' minutos, unit_size: 60 * 1000},
    {bound: 60 * 1000 * 60,
    cuteness: 'hace una hora atrás', unit_size: 0},
    {bound: 60 * 1000 * 60 * 2,
    cuteness: ' horas', unit_size: 60 * 1000 * 60},
    {bound: 60 * 1000 * 60 * 24,
    cuteness: 'ayer', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 2,
    cuteness: ' días', unit_size: 60 * 1000 * 60 * 24},
    {bound: 60 * 1000 * 60 * 24 * 30,
    cuteness: 'en el último mes', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 2,
    cuteness: ' meses atrás', unit_size: 60 * 1000 * 60 * 24 * 30},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12,
    cuteness: 'el año pasado', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
    cuteness: ' años', unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
    {bound: POS_INF,
    cuteness: 'hace rato', unit_size: 0}
    ]
    };

  4. CuteTime jQuery Plugin Ajax Help W3C Tag Says:

    [...] CuteTime is a customizable jQuery plugin that automatically converts timestamps to formats much cuter (i.e., yesterday, 2 hours ago, last year, in the future, etc). Also has the ability to dynamically re-update and/or automatically update timestamps on a controlled interval. [...]

  5. khaled attia Says:

    How can i use unix time with this ?

  6. Farid Says:

    Hi, thanks for this great plugin!

    I started a translation in french, but there is a little difficulty :

    X hours ago => il y a X heures

    There is a way to place the X inside the sentence ?

  7. FaridSafi Says:

    Hi again, I finally find a way

    this is my french traduction :

    {bound: NEG_INF, // IMPORANT: bounds MUST be in ascending order, from negative infinity to positive infinity
    cuteness: ‘le future!’, unit_size: 0},
    {bound: 0,
    cuteness: “a l’instant”, unit_size: 0},
    {bound: 20 * 1000,
    cuteness: ‘il y a quelques secondes’, unit_size: 0},
    {bound: 60 * 1000,
    cuteness: ‘il y a 1 minute’, unit_size: 0},
    {bound: 60 * 1000 * 2,
    cuteness: ‘il y a X minutes’, unit_size: 60 * 1000},
    {bound: 60 * 1000 * 60,
    cuteness: ‘il y a 1 heure’, unit_size: 0},
    {bound: 60 * 1000 * 60 * 2,
    cuteness: ‘il y a X heures’, unit_size: 60 * 1000 * 60},
    {bound: 60 * 1000 * 60 * 24,
    cuteness: ‘hier’, unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 2,
    cuteness: ‘il y a X jours’, unit_size: 60 * 1000 * 60 * 24},
    {bound: 60 * 1000 * 60 * 24 * 30,
    cuteness: ‘il y a 1 mois’, unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 2,
    cuteness: ‘il y a X mois’, unit_size: 60 * 1000 * 60 * 24 * 30},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12,
    cuteness: “il y a 1 an”, unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
    cuteness: ‘il y a X ans’, unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
    {bound: POS_INF,
    cuteness: ‘a blinkle ago’, unit_size: 0}

    then, replace :
    cute_time = calculated_time + timespan['cuteness'];
    by :
    var reg=new RegExp(“(X)”, “g”);
    cute_time = timespan['cuteness'].replace(reg,calculated_time);

  8. CuteTime The Product Guy | Squico Says:

    [...] In: JQuery plugins 27 Nov 2009 Go to Source [...]

  9. sam Says:

    hi, this is great! i want to use this for events, so would need it to output future dates. ie: this event is in 3 days 7h 12m 23sec

    is this a possible feature to tweak into this great plugin?

    thanks!

    • Jeremy Horn Says:

      Sam – You sure can define future cutetime language and time ranges. You can define the ranges to be in the past or the future via the settings as desired. However, the plugin will only display 1 unit of granularity. In your example you could say something is going to happen “in about 3 days” or “in 72 hours”.

  10. uberVU - social comments Says:

    Social comments and analytics for this post…

    This post was mentioned on Twitter by macroman66: Excelente plugin de #jquery para convertir fechas tipo timestamp a fecha coloquiales. Util para foros o chats http://icio.us/30la5b...

  11. Twitted by FGRibreau Says:

    [...] This post was Twitted by FGRibreau [...]

  12. Julio Says:

    CuteTime is great!! xD, but… I’m making a website and i’m using DatePicker and i saw that when i had using CuteTime this wasn’t working and same with DatePicker..

    Only works the wich was declared first.

    Somebody can help me with a crack or some settings thanks.

  13. Simon Says:

    Hi,

    Looks like a great plugin, we would just like to suggest one update to your above settings code. Shouldnt the last bound be positive infinity? Currently you have both first and last bound as “Number.NEGATIVE_INFINITY” :)

  14. jQuery Plugin: CuteTime, C’est Magnifique! (v 1.1) [UPDATE] « The Product Guy Says:

    [...] For more details about the latest CuteTime improvements and their implementation, visit http://tpgblog.com/CuteTime [...]

  15. Carlos Moutinho Says:

    Hi. Thank you for a great plugin.
    Here’s my translation to Portuguese (Portugal)

    var portuguese = {
    time_ranges: [
    {bound: Number.NEGATIVE_INFINITY,
    cuteness: 'o futuro!', unit_size: 0},
    {bound: 0,
    cuteness: 'agora mesmo', unit_size: 0},
    {bound: 20 * 1000,
    cuteness: 'há uns segundos', unit_size: 0},
    {bound: 60 * 1000,
    cuteness: 'há um minuto', unit_size: 0},
    {bound: 60 * 1000 * 2,
    cuteness: 'há %CT% minutos', unit_size: 60 * 1000},
    {bound: 60 * 1000 * 60,
    cuteness: 'acerca de há uma hora atrás', unit_size: 0},
    {bound: 60 * 1000 * 60 * 2,
    cuteness: 'há %CT% horas atrás', unit_size: 60 * 1000 * 60},
    {bound: 60 * 1000 * 60 * 24,
    cuteness: 'ontem', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 2,
    cuteness: 'há %CT% dias', unit_size: 60 * 1000 * 60 * 24},
    {bound: 60 * 1000 * 60 * 24 * 30,
    cuteness: 'no mês passado', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 2,
    cuteness: 'há %CT% meses atrás', unit_size: 60 * 1000 * 60 * 24 * 30},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12,
    cuteness: 'no ano passado', unit_size: 0},
    {bound: 60 * 1000 * 60 * 24 * 30 * 12 * 2,
    cuteness: 'há %CT% anos', unit_size: 60 * 1000 * 60 * 24 * 30 * 12},
    {bound: Number.POSITIVE_INFINITY,
    cuteness: 'há bué tempo', unit_size: 0}
    ]
    };

  16. Florian Says:

    Thank you for this interesting plugin.

    But there seems to be a problem with calculation of spans greater than 24 hours.

    Let’s say it is 2010-01-03 12:00:00 for example and I want to get the cute time for 2010-01-01 18:00:00 it will return “yesterday” – that is not correct.

    Tested this with IE8 and FF 3.6

    • Jeremy Horn Says:

      Thank you. The calculation is correct. In my examples I have defined yesterday to be between 24 and 48 hours ago — you example falls right within that window. The great thing about CuteTime is that it allows for the customization of times, units and timespans to suit your needs. Thereby allowing you to remove the “yesterday” label or even redefine it. Hope this helps clarify.

  17. Jordan Says:

    Is there any chance you could extend this plugin to take MySQL date formats? Namely, ‘YYYY-MM-DD G:m:s’ where G is the 24 hour time.


Leave a Reply