Chronos is one of the many Smalltalk-related blogs syndicated on Planet Smalltalk
χρόνος

Discussion of the Essence# programming language, and related issues and technologies.

Blog Timezone: America/Los_Angeles [Winter: -0800 hhmm | Summer: -0700 hhmm] 
Your local time:  

2006-01-29

Chronos Version B1.18 Published

Version B1.18 includes some new functionality, some design/code improvements, and improved/corrected class/method comments. It also includes a few bug fixes for some rather obscure bugs--things I happened to find while browsing the code and thinking up new things to test. The new version is available from the Chronos web site.

I also spent some time refining the site's aesthetics--but more about that below.

Much of the new functionality involves improved flexibility in date/time fomratting:


  • The ability to suppress the printing of a date's year;

  • The ability to print the time-of-day before the date;

  • The ability to use a ChronosPritingPolicy specification array literal wherever a ChronosPrintPolicy instance or key is usable (e.g., "Timepoint now printStringUsing: #(hideSubsecondFraction)" instead of "Timepoint now printStringUsing: (ChronosPrintPolicy applying: #(hideSubsecondFraction))";

  • The ability to override the default print format for a specific instance, without affecting the global default. Example: "Timepoint now withDefaultPrintPolicy: #(hideSubsecondFraction)." (The ANSI-Smalltalk Standard strictly requires specific default formats for DateAndTime and Duration instances--the required default formats are based on the ISO 8601 Standard.)


Also, in support of the use of JavaScript to enable web pages to show timestamps in the local time of each viewer (see AJAX × Date × Time × Time zones - best practices by Johan Sundstrom (a.k.a "ecmanaut,")) I added the class methods #unixEpoch, #javaEpoch, #st80Epoch and #msWindowsNTEpoch to ChronosSystemClock, making it easy to write code such as the following:

[ :timepoint |
| args utTimepoint generatedString |
utTimepoint := timepoint asUT.
args := Array
with: (utTimepoint withDefaultPrintPolicy: #rfc2822)
with: (utTimepoint millisecondsSince: ChronosSystemClock javaEpoch).
generatedString := '
%<noscript>%<p>Page published <1p> (UT: Universal Time)%</p>%</noscript>
%<script type="text/javascript">
document.write(''Page published ''+formatDateAndTimeAsRFC2822(new Date(<2p>)))
%</script>' expandMacrosWithArguments: args]
value: Timepoint now


The above code produces the following html/JavaScript code, suitiable for inclusion in a web page:


<noscript><p>Page published Sun, 29 Jan 2006 12:10:41 +0000 (UT: Universal Time)</p></noscript>
<script type="text/javascript">
document.write('Page published '+formatDateAndTimeAsRFC2822(new Date(1138536641146)))
</script>


Of course, one must have a JavaScript libray included into the web page that defines the function "formatDateAndTimeAsRFC2822()" (or the equivalent.) The idea is that the source code on the web page specifies the timestamp as a count of milliseconds since the Java epoch (1970-01-01T00:00:00Z,) and relies on the user's operating system, browser and JavaScript execution environment to correctly convert that milliseconds-since-the-Java-epoch count (which is relative to Universal Time) into the user's local date and time.

Here's the JavaScript code I developed for use on the Chronos web site, which ultimately derives from the code published by ecmanaut:


<script type="text/javascript">
function toInteger(n){
return (n < 0 ? - 1 : + 1) * Math.floor(Math.abs(n) + 0.5);
}
function zeropad(n) {
return n>9 ? n : '0'+n;
}
function formatTimeZoneOffset(time, elementSeparator) {
var minutesWestOfUT=time.getTimezoneOffset()
var absOffsetInMinutes=Math.abs(minutesWestOfUT)
var offsetInHours=toInteger(absOffsetInMinutes / 60)
var offsetMinutes = absOffsetInMinutes % 60
var isWestOfUT = minutesWestOfUT > 0
return (isWestOfUT ? '-' : '+')+zeropad(offsetInHours)+elementSeparator+zeropad(offsetMinutes)
}
function formatTimeOfDay(time) {
var hour=time.getHours()
var minute=time.getMinutes()
var second=time.getSeconds()
return zeropad(hour)+':'+zeropad(minute)+':'+zeropad(second)
}
function abbreviationOfMonth(time) {
return ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][time.getMonth()]
}
function formatDateAsYMD(time, elementSeparator) {
var dayOfMonth=time.getDate()
var month=time.getMonth() + 1
var year=time.getFullYear()
return year+elementSeparator+zeropad(month)+elementSeparator+zeropad(dayOfMonth)
}
function formatDateAsMDY(time, mdSeparator, dySeparator) {
var dayOfMonth=time.getDate()
var year=time.getFullYear()
return abbreviationOfMonth(time)+mdSeparator+zeropad(dayOfMonth)+dySeparator+year
}
function formatDateAsDMY(time, dmSeparator, mySeparator) {
var dayOfMonth=time.getDate()
var year=time.getFullYear()
return zeropad(dayOfMonth)+dmSeparator+abbreviationOfMonth(time)+mySeparator+year
}
function abbreviationOfDayOfWeek(time) {
return ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][time.getDay()]
}
function formatDateAsRFC2822(time) {
return abbreviationOfDayOfWeek(time)+', '+formatDateAsDMY(time, ' ', ' ')
}

function formatDateAndTimeAsISO8601(time) {
return formatDateAsYMD(time,'-')+'T'+formatTimeOfDay(time)+formatTimeZoneOffset(time, ':')
}
function formatDateAndTimeAsRFC2822(time) {
return formatDateAsRFC2822(time)+' '+formatTimeOfDay(time)+' '+formatTimeZoneOffset(time, '')
}
function startClock()
{
document.getElementById('clock').innerHTML=formatDateAndTimeAsRFC2822(new Date())
t=setTimeout('startClock()',500)
}
</script>


Now that the Chronos web site uses the above JavaScript functions, it is able to display time to the viewer in his or her local time. If JavaScript is disabled, I have code that generates a <noscript> section which presents the timestamp in Uiversal Time.


No comments: