lib/twitter_cldr/js/mustache/implementation/calendars/datetime.coffee (220 lines of code) (raw):
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
class TwitterCldr.DateTimeFormatter
constructor: ->
@weekday_keys = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]
@methods = # ignoring u, l, g, j, A
'G': 'era'
'y': 'year'
'Y': 'year_of_week_of_year'
'Q': 'quarter'
'q': 'quarter_stand_alone'
'M': 'month'
'L': 'month_stand_alone'
'w': 'week_of_year'
'W': 'week_of_month'
'd': 'day'
'D': 'day_of_month'
'F': 'day_of_week_in_month'
'E': 'weekday'
'e': 'weekday_local'
'c': 'weekday_local_stand_alone'
'a': 'period'
'h': 'hour'
'H': 'hour'
'K': 'hour'
'k': 'hour'
'm': 'minute'
's': 'second'
'S': 'second_fraction'
'z': 'timezone'
'Z': 'timezone'
'v': 'timezone_generic_non_location'
'V': 'timezone_metazone'
@data: ->
TwitterCldr.get_data().DateTimeFormatter
tokens: ->
@constructor.data().tokens
format: (obj, options) ->
format_token = (token) =>
result = ""
switch token.type
when "pattern"
@result_for_token(token, obj)
else
token.value.replace(/'([^']+)'/g, '$1')
tokens = @get_tokens(obj, options)
(format_token(token) for token in tokens).join("")
get_tokens: (obj, options) ->
format = options.format || "date_time"
type = options.type || "default"
if format == "additional"
@tokens()["date_time"][format][@additional_format_selector().find_closest(options.type)]
else
@tokens()[format][type]
result_for_token: (token, date) ->
this[@methods[token.value[0]]](date, token.value, token.value.length)
additional_format_selector: ->
new TwitterCldr.AdditionalDateFormatSelector(@tokens()["date_time"]["additional"])
@additional_formats: ->
new TwitterCldr.DateTimeFormatter().additional_format_selector().patterns()
era: (date, pattern, length) ->
switch length
when 0
choices = ["", ""]
when 1, 2, 3
choices = TwitterCldr.Calendar.calendar()["eras"]["abbr"]
else
choices = TwitterCldr.Calendar.calendar()["eras"]["name"]
index = if (date.getFullYear() < 0) then 0 else 1
result = choices[index]
if result? then result else @era(date, pattern[0..-2], length - 1)
year: (date, pattern, length) ->
year = date.getFullYear().toString()
if length == 2
if year.length != 1
year = year.slice(-2)
if length > 1
year = ("0000" + year).slice(-length)
year
year_of_week_of_year: (date, pattern, length) ->
throw 'not implemented'
day_of_week_in_month: (date, pattern, length) -> # e.g. 2nd Wed in July
throw 'not implemented'
quarter: (date, pattern, length) ->
# the bitwise OR is used here to truncate the decimal produced by the / 3
quarter = ((date.getMonth() / 3) | 0) + 1
switch length
when 1
quarter.toString()
when 2
("0000" + quarter.toString()).slice(-length)
when 3
TwitterCldr.Calendar.quarters({format: 'format', names_form: 'abbreviated'})[quarter]
when 4
TwitterCldr.Calendar.quarters({format: 'format', names_form: 'wide'})[quarter]
quarter_stand_alone: (date, pattern, length) ->
quarter = (date.getMonth() - 1) / 3 + 1
switch length
when 1
quarter.toString()
when 2
("0000" + quarter.toString()).slice(-length)
when 3
throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
when 4
throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
when 5
TwitterCldr.Calendar.quarters({format: 'stand-alone', names_form: 'narrow'})[quarter]
month: (date, pattern, length) ->
month = date.getMonth()
month_str = (month + 1).toString()
switch length
when 1
month_str
when 2
("0000" + month_str).slice(-length)
when 3
TwitterCldr.Calendar.months({format: 'format', names_form: 'abbreviated'})[month]
when 4
TwitterCldr.Calendar.months({format: 'format', names_form: 'wide'})[month]
when 5
throw 'not yet implemented (requires cldr\'s "multiple inheritance")'
else
throw "Unknown date format"
month_stand_alone: (date, pattern, length) ->
month = date.getMonth()
month_str = (month + 1).toString()
switch length
when 1
month_str
when 2
("0000" + month_str).slice(-length)
when 3
TwitterCldr.Calendar.months({format: 'stand-alone', names_form: 'abbreviated'})[month]
when 4
TwitterCldr.Calendar.months({format: 'stand-alone', names_form: 'wide'})[month]
when 5
TwitterCldr.Calendar.months({format: 'stand-alone', names_form: 'narrow'})[month]
else
throw "Unknown date format"
day: (date, pattern, length) ->
switch length
when 1
date.getDate().toString()
when 2
("0000" + date.getDate().toString()).slice(-length)
weekday: (date, pattern, length) ->
key = @weekday_keys[date.getDay()]
switch length
when 1, 2, 3
TwitterCldr.Calendar.weekdays({format: 'format', names_form: 'abbreviated'})[key]
when 4
TwitterCldr.Calendar.weekdays({format: 'format', names_form: 'wide'})[key]
when 5
TwitterCldr.Calendar.weekdays({format: 'stand-alone', names_form: 'narrow'})[key]
weekday_local: (date, pattern, length) ->
# "Like E except adds a numeric value depending on the local starting day of the week"
# CLDR does not contain data as to which day is the first day of the week, so we will assume Monday (Ruby default)
switch length
when 1, 2
day = date.getDay()
if day == 0 then "7" else day.toString()
else
@weekday(date, pattern, length)
weekday_local_stand_alone: (date, pattern, length) ->
switch length
when 1
@weekday_local(date, pattern, length)
else
@weekday(date, pattern, length)
period: (time, pattern, length) ->
if time.getHours() > 11
TwitterCldr.Calendar.periods({format: 'format', names_form: 'wide'})["pm"]
else
TwitterCldr.Calendar.periods({format: 'format', names_form: 'wide'})["am"]
hour: (time, pattern, length) ->
hour = time.getHours()
switch pattern[0]
when 'h'
if hour > 12
hour = hour - 12
else if hour == 0
hour = 12
when 'K'
if hour > 11
hour = hour - 12
when 'k'
if hour == 0
hour = 24
if length == 1
hour.toString()
else
("000000" + hour.toString()).slice(-length)
minute: (time, pattern, length) ->
if length == 1
time.getMinutes().toString()
else
("000000" + time.getMinutes().toString()).slice(-length)
second: (time, pattern, length) ->
if length == 1
time.getSeconds().toString()
else
("000000" + time.getSeconds().toString()).slice(-length)
second_fraction: (time, pattern, length) ->
if length > 6
throw 'can not use the S format with more than 6 digits'
("000000" + Math.round(Math.pow(time.getMilliseconds() * 100.0, 6 - length)).toString()).slice(-length)
timezone: (time, pattern, length) ->
offset = time.getTimezoneOffset()
hours = ("00" + (Math.floor(Math.abs(offset) / 60)).toString()).slice(-2)
minutes = ("00" + (Math.abs(offset) % 60).toString()).slice(-2)
sign = if offset > 0 then "-" else "+" # timezone sign is opposite to offset sign
offsetString = sign + hours + ":" + minutes
switch length
when 1, 2, 3
offsetString
else
"UTC" + offsetString
timezone_generic_non_location: (time, pattern, length) ->
throw 'not yet implemented (requires timezone translation data")'