/*
* Javascript Humane Dates
* Copyright (c) 2008 Dean Landolt (deanlandolt.com)
* Re-write by Zach Leatherman (zachleat.com)
*
* Adopted from the John Resig's pretty.js
* at http://ejohn.org/blog/javascript-pretty-date
* and henrah's proposed modification
* at http://ejohn.org/blog/javascript-pretty-date/#comment-297458
*
* Licensed under the MIT license.
*/
/**
* @param {String or Date} date_str either an ISO8601 date string or a Date object.
* Note: ISO8601 dates are always formatted using UTC/GMT timezone.
* Example: 2009-06-03T20:06:44Z
*/
function humane_date(date_str){
var time_formats = [
[1, '1 second'],
[60, 'seconds', 1],
[90, '1 Minute'], // 60*1.5
[3600, 'Minutes', 60], // 60*60, 60
[5400, '1 Hour'], // 60*60*1.5
[86400, 'Hours', 3600], // 60*60*24, 60*60
[129600, '1 Day'], // 60*60*24*1.5
[604800, 'Days', 86400], // 60*60*24*7, 60*60*24
[907200, '1 Week'], // 60*60*24*7*1.5
[2628000, 'Weeks', 604800], // 60*60*24*(365/12), 60*60*24*7
[3942000, '1 Month'], // 60*60*24*(365/12)*1.5
[31536000, 'Months', 2628000], // 60*60*24*365, 60*60*24*(365/12)
[47304000, '1 Year'], // 60*60*24*365*1.5
[3153600000, 'Years', 31536000], // 60*60*24*365*100, 60*60*24*365
[4730400000, '1 Century'], // 60*60*24*365*100*1.5
];
var time = ('' + date_str).replace(/-/g,"/").replace(/[TZ]/g," "),
dt = new Date,
seconds = (date_str instanceof Date ? (dt - date_str)
: (dt - new Date(time) + (dt.getTimezoneOffset() * 60000))) / 1000,
token = ' ago',
i = 0,
format;
if (seconds < 0) {
seconds = Math.abs(seconds);
token = ' from now';
}
while (format = time_formats[i++]) {
if (seconds < format[0]) {
if (format.length == 2) {
return format[1] + token
} else {
return Math.round(seconds / format[2]) + ' ' + format[1] + token;
}
}
}
// overflow for centuries
if(seconds > 4730400000)
return Math.round(seconds / 4730400000) + ' Centuries' + token;
return date_str;
};
if(typeof jQuery != 'undefined') {
jQuery.fn.humane_dates = function(){
return this.each(function(){
var date = humane_date(this.title);
if(date && jQuery(this).text() != date) // don't modify the dom if we don't have to
jQuery(this).text(date);
});
};
}
Monday, July 06, 2009
Tweaks to Zach's humane Date script
I like Zach's humane Date script (based on work by Dean Landolt, John Resig, and henrah), but I wanted to be able to pass in an actual Date object in addition to just an ISO8601 date string. I also wanted it to be able to handle future dates (e.g. "10 minutes from now"). Here's the result:
Friday, April 17, 2009
JSON Annotations
Suppose you want a generic parser that will turn JSON into a strongly-typed Java object graph. For certain kinds of object graphs you either have to parse into generic objects and then convert, or hint the parser at every step -- a tedious process. What if those type hints were embedded within the JSON itself?
Option 1. Processing Instructions
This approach specifies a reserved prefix for meta-attributes, of which @type is one. Borrowing an idea from sed's variable syntax for find-and-replace separators, you can wrap the entire payload in one outer object that specifies what the metadata prefix is. That way if a given payload would clash with the default metadata prefix, it can be changed easily.{ "meta": "@"
"data": {
"@type": "java.util.HashMap",
"Joe" : {
"@type": "jeoftp.Person"
"firstName": "Joseph",
"lastName": "Robinson",
"age": 45,
"birthday": new Date(23493822934)
},
"Sue" : {
"@type": "jeoftp.Person"
...
}
}
}
Option 2. Wrap Typed Objects with Annotations
Another way to annotate objects with their types is to wrap each object that needs specific type information within a meta-object that tells us its type. The parser would need to know how to recognize a meta-object vice a regular one.{
"@class" : "java.util.HashMap",
"@data" : {
"Joe" : {
"@class" : "jeoftp.Person",
"@data" : {
"firstName": "Joseph",
"lastName": "Robinson",
"age": 45,
"birthday": new Date(23493822934)
}
},
"Sue" : {
"@class" : "jeoftp.Person",
"@data" : { ... }
}
}
}
Option 3. Embed Annotations in Comments
You could also embed type information in comments. This approach borrows from Javadoc, Python docstrings, etc. This would certainly break some JSON parsers, but the advantage is that it strictly demarcates metadata from data.{
/* @type java.util.HashMap */
"Joe" : {
/* @type jeoftp.Person */
"firstName": "Joseph",
"lastName": "Robinson",
"age": 45,
"birthday": new Date(23493822934)
},
"Sue" : {
/* @type jeoftp.Person */
...
}
}
If your type parser was smart enough, perhaps you could even handle generics:
{
/* @type java.util.HashMap */
"Joe" : {
"firstName": "Joseph",
"lastName": "Robinson",
"age": 45,
"birthday": new Date(23493822934)
},
"Sue" : {
...
}
}
I haven't settled on one approach yet, but after reading this I'm leaning toward option 1 -- specifying a metadata prefix -- because it is valid in curent JSON syntax, easy to parse, and relatively compact.Monday, March 23, 2009
Determine the Java TimeZone of your web visitors using client-side javascript
You want your Java web application to know what TimeZone your visitors are in. You can use client-side javascript code like the following to produce a timezone string that Java can understand:
function getTimezone() {
var tzo = new Date().getTimezoneOffset(); //returns timezone offset in minutes
function pad(num, digits) {
num = String(num); while (num.length < digits) { num="0"+num; }; return num;
}
return "GMT" + (tzo > 0 ? "-" : "+") + pad(Math.floor(tzo/60), 2) + ":" + pad(tzo%60, 2);
}
This will produce strings like GMT-04:00 and GMT-07:00 which you can then pass up to the server and into TimeZone.getTimeZone() to produce a TimeZone object.
Subscribe to:
Posts (Atom)