From 50c183b50918b9e1c92592664c3f966308046c12 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 20:54:18 -0800 Subject: [PATCH 01/44] add bower.json, closes #45 --- bower.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 bower.json diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..8ed1185 --- /dev/null +++ b/bower.json @@ -0,0 +1,13 @@ +{ + "name": "strftime", + "version": "0.8.2", + "main": "strftime.js", + "ignore": [ + "Readme.md", + "Makefile", + "test/*", + "*.json" + ], + "dependencies": {}, + "devDependencies": {} +} \ No newline at end of file From 016223fac47924469c0e1d61646347304728a500 Mon Sep 17 00:00:00 2001 From: Alexandr Nikitin Date: Wed, 18 Jun 2014 10:42:36 +0400 Subject: [PATCH 02/44] Added optimized version --- strftimeV2.js | 497 +++++++++++++++++++++++++++++++++++++++++++++++++ test/testV2.js | 224 ++++++++++++++++++++++ 2 files changed, 721 insertions(+) create mode 100644 strftimeV2.js create mode 100644 test/testV2.js diff --git a/strftimeV2.js b/strftimeV2.js new file mode 100644 index 0000000..928a810 --- /dev/null +++ b/strftimeV2.js @@ -0,0 +1,497 @@ +// +// strftime +// github.com/samsonjs/strftime +// @_sjs +// +// Copyright 2010 - 2013 Sami Samhuri +// +// MIT License +// http://sjs.mit-license.org +// + +;(function() { + "use strict"; + + //// Where to export the API + var namespace, + + DefaultLocale = { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + AM: 'AM', + PM: 'PM', + am: 'am', + pm: 'pm', + formats: { + D: '%m/%d/%y', + F: '%Y-%m-%d', + R: '%H:%M', + T: '%H:%M:%S', + r: '%I:%M:%S %p', + v: '%e-%b-%Y' + } + }, + + defaultStrftime = new Strftime(DefaultLocale, 0, false); + + // CommonJS / Node module + if (typeof module !== 'undefined') { + namespace = module.exports = defaultStrftime; + } + + // Browsers and other environments + else { + // Get the global object. Works in ES3, ES5, and ES5 strict mode. + namespace = (function(){ return this || (1,eval)('this') }()); + } + + namespace.strftime = defaultStrftime; + + function Strftime(locale, customTimezoneOffset, useUtcTimezone) { + var _locale = locale || DefaultLocale, + _customTimezoneOffset = customTimezoneOffset || 0, + _useUtcBasedDate = useUtcTimezone || false, + + // we store unix timestamp value here to not create new Date() each iteration (each millisecond) + // Date.now() is 2 times faster than new Date() + // while millisecond precise is enough here + // this could be very helpful when strftime triggered a lot of times one by one + _cachedDateTimestamp = 0, + _cachedDate; + + function _strftime(format, date) { + var timestamp; + + if(!date) { + var currentTimestamp = Date.now(); + if(currentTimestamp > _cachedDateTimestamp) { + _cachedDateTimestamp = currentTimestamp; + _cachedDate = new Date(_cachedDateTimestamp); + + timestamp = _cachedDateTimestamp; + + if(_useUtcBasedDate) { + // how to avoid duplication of date instantiation for utc here? + // we tied to getTimezoneOffset of the current date + _cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset); + } + } + date = _cachedDate; + } else { + timestamp = date.getTime(); + + if(_useUtcBasedDate) { + date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset); + } + } + + return _processFormat(format, date, _locale, timestamp); + } + + function _processFormat(format, date, locale, timestamp) { + var resultString = '', + padding = null, + isInScope = false, + length = format.length; + + for (var i = 0; i < length; i++) { + + var currentCharCode = format.charCodeAt(i); + + if(isInScope === true) { + // '-' + if (currentCharCode === 45) { + padding = ''; + continue; + } + // '_' + else if (currentCharCode === 95) { + padding = ' '; + continue; + } + // '0' + else if (currentCharCode === 48) { + padding = '0'; + continue; + } + + switch (currentCharCode) { + + // Examples for new Date(0) in GMT + + // 'Thursday' + // case 'A': + case 65: + resultString += locale.days[date.getDay()]; + break; + + // 'January' + // case 'B': + case 66: + resultString += locale.months[date.getMonth()]; + break; + + // '19' + // case 'C': + case 67: + resultString += padTill2(Math.floor(date.getFullYear() / 100), padding); + break; + + // '01/01/70' + // case 'D': + case 68: + resultString += _processFormat(locale.formats.D, date, locale, timestamp); + break; + + // '1970-01-01' + // case 'F': + case 70: + resultString += _processFormat(locale.formats.F, date, locale, timestamp); + break; + + // '00' + // case 'H': + case 72: + resultString += padTill2(date.getHours(), padding); + break; + + // '12' + // case 'I': + case 73: + resultString += padTill2(hours12(date.getHours()), padding); + break; + + // '000' + // case 'L': + case 76: + resultString += padTill3(Math.floor(timestamp % 1000)); + break; + + // '00' + // case 'M': + case 77: + resultString += padTill2(date.getMinutes(), padding); + break; + + // 'am' + // case 'P': + case 80: + resultString += date.getHours() < 12 ? locale.am : locale.pm; + break; + + // '00:00' + // case 'R': + case 82: + resultString += _processFormat(locale.formats.R, date, locale, timestamp); + break; + + // '00' + // case 'S': + case 83: + resultString += padTill2(date.getSeconds(), padding); + break; + + // '00:00:00' + // case 'T': + case 84: + resultString += _processFormat(locale.formats.T, date, locale, timestamp); + break; + + // '00' + // case 'U': + case 85: + resultString += padTill2(weekNumber(date, 'sunday'), padding); + break; + + // '00' + // case 'W': + case 87: + resultString += padTill2(weekNumber(date, 'monday'), padding); + break; + + // '1970' + // case 'Y': + case 89: + resultString += date.getFullYear(); + break; + + // 'GMT' + // case 'Z': + case 90: + if (_useUtcBasedDate && _customTimezoneOffset === 0) { + resultString += "GMT"; + } + else { + // fixme optimize + var tzString = date.toString().match(/\((\w+)\)/); + resultString += tzString && tzString[1] || ''; + } + break; + + // 'Thu' + // case 'a': + case 97: + resultString += locale.shortDays[date.getDay()]; + break; + + // 'Jan' + // case 'b': + case 98: + resultString += locale.shortMonths[date.getMonth()]; + break; + + // '01' + // case 'd': + case 100: + resultString += padTill2(date.getDate(), padding); + break; + + // '01' + // case 'e': + case 101: + resultString += date.getDate(); + break; + + // 'Jan' + // case 'h': + case 104: + resultString += locale.shortMonths[date.getMonth()]; + break; + + // '000' + // case 'j': + case 106: + var y = new Date(date.getFullYear(), 0, 1); + var day = Math.ceil((date.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); + resultString += padTill3(day); + break; + + // ' 0' + // case 'k': + case 107: + resultString += padTill2(date.getHours(), padding == null ? ' ' : padding); + break; + + // '12' + // case 'l': + case 108: + resultString += padTill2(hours12(date.getHours()), padding == null ? ' ' : padding); + break; + + // '01' + // case 'm': + case 109: + resultString += padTill2(date.getMonth() + 1, padding); + break; + + // '\n' + // case 'n': + case 110: + resultString += '\n'; + break; + + // '1st' + // case 'o': + case 111: + resultString += String(date.getDate()) + ordinal(date.getDate()); + break; + + // 'AM' + // case 'p': + case 112: + resultString += date.getHours() < 12 ? locale.AM : locale.PM; + break; + + // '12:00:00 AM' + // case 'r': + case 114: + resultString += _processFormat(locale.formats.r, date, locale, timestamp); + break; + + // '0' + // case 's': + case 115: + resultString += Math.floor(timestamp / 1000); + break; + + // '\t' + // case 't': + case 116: + resultString += '\t'; + break; + + // '4' + // case 'u': + case 117: + var day = date.getDay(); + resultString += day === 0 ? 7 : day; + break; // 1 - 7, Monday is first day of the week + + // '1-Jan-1970' + // case 'v': + case 118: + resultString += _processFormat(locale.formats.v, date, locale, timestamp); + break; + + // '4' + // case 'w': + case 119: + resultString += date.getDay(); + break; // 0 - 6, Sunday is first day of the week + + // '70' + // case 'y': + case 121: + resultString += ('' + date.getFullYear()).slice(2); + break; + + // '+0000' + // case 'z': + case 122: + if (_useUtcBasedDate && _customTimezoneOffset === 0) { + resultString += "+0000"; + } + else { + var off; + if(_customTimezoneOffset !== 0) { + off = _customTimezoneOffset / (60 * 1000); + } + else { + off = -date.getTimezoneOffset(); + } + resultString += (off < 0 ? '-' : '+') + padTill2(Math.floor(Math.abs(off / 60))) + padTill2(Math.abs(off % 60)); + } + break; + + default: + resultString += format[i]; + break; + } + + padding = null; + isInScope = false; + continue; + } + + // '%' + if (currentCharCode === 37) { + isInScope = true; + continue; + } + + resultString += format[i]; + } + + return resultString; + } + + var strftime = _strftime; + + strftime.setLocaleTo = function(locale) { + return new Strftime(locale || _locale, _customTimezoneOffset, _useUtcBasedDate); + }; + + strftime.setTimezoneTo = function(timezone) { + var customTimezoneOffset = _customTimezoneOffset; + var useUtcBasedDate = _useUtcBasedDate; + + var timezoneType = typeof timezone; + if (timezoneType === 'number' || timezoneType === 'string') { + useUtcBasedDate = true; + + // ISO 8601 format timezone string, [-+]HHMM + if (timezoneType === 'string') { + var sign = timezone[0] === '-' ? -1 : 1, + hours = parseInt(timezone.slice(1, 3), 10), + minutes = parseInt(timezone.slice(3, 5), 10); + + customTimezoneOffset = sign * ((60 * hours) + minutes) * 60 * 1000; + // in minutes: 420 + } else if (timezoneType === 'number'){ + customTimezoneOffset = timezone * 60 * 1000; + } + } + + return new Strftime(_locale, customTimezoneOffset, useUtcBasedDate); + }; + + strftime.useUTC = function() { + return new Strftime(_locale, _customTimezoneOffset, true); + }; + + return strftime; + } + + function padTill2(numberToPad, paddingChar) { + if (paddingChar === '' || numberToPad > 9) { + return numberToPad; + } + if (paddingChar == null) { + paddingChar = '0'; + } + return paddingChar + numberToPad; + } + + function padTill3(numberToPad) { + if (numberToPad > 99) { + return numberToPad; + } + if (numberToPad > 9) { + return '0' + numberToPad; + } + return '00' + numberToPad; + } + + function hours12(hour) { + if (hour === 0) { + return 12; + } + else if (hour > 12) { + return hour - 12; + } + return hour; + } + + // firstWeekday: 'sunday' or 'monday', default is 'sunday' + // + // Pilfered & ported from Ruby's strftime implementation. + function weekNumber(date, firstWeekday) { + firstWeekday = firstWeekday || 'sunday'; + + // This works by shifting the weekday back by one day if we + // are treating Monday as the first day of the week. + var weekday = date.getDay(); + if (firstWeekday === 'monday') { + if (weekday === 0) // Sunday + weekday = 6; + else + weekday--; + } + var firstDayOfYear = new Date(date.getFullYear(), 0, 1), + yday = (date - firstDayOfYear) / 86400000, + weekNum = (yday + 7 - weekday) / 7; + + return Math.floor(weekNum); + } + + // Get the ordinal suffix for a number: st, nd, rd, or th + function ordinal(number) { + var i = number % 10; + var ii = number % 100; + + if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { + return 'th'; + } + switch (i) { + case 1: return 'st'; + case 2: return 'nd'; + case 3: return 'rd'; + } + } + + function getTimestampToUtcOffsetFor(date) { + return (date.getTimezoneOffset() || 0) * 60000; + } +}()); diff --git a/test/testV2.js b/test/testV2.js new file mode 100644 index 0000000..61d0f6c --- /dev/null +++ b/test/testV2.js @@ -0,0 +1,224 @@ +#!/usr/bin/env node + +// Based on CoffeeScript by andrewschaaf on github +// +// TODO: +// - past and future dates, especially < 1900 and > 2100 +// - locales +// - look for edge cases + +var assert = require('assert') + , libFilename = process.argv[2] || '../strftimeV2.js' + , lib = require(libFilename) + +// Tue, 07 Jun 2011 18:51:45 GMT + , Time = new Date(1307472705067) + +assert.fn = function(value, msg) { + assert.equal('function', typeof value, msg) +} + +assert.format = function(format, expected, expectedUTC, time) { + time = time || Time + function _assertFmt(expected, name, strftime) { + name = name || 'strftime' + var actual = strftime(format, time) + assert.equal(expected, actual, + name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + + ', expected ' + JSON.stringify(expected)) + } + + if (expected) _assertFmt(expected, 'strftime', lib) + _assertFmt(expectedUTC || expected, 'strftime.UseUTC()', lib.useUTC()) +} + +/// check exports +assert.fn(lib.strftime) +ok('Exports') + +/// time zones +if (process.env.TZ == 'America/Vancouver') { + testTimezone('P[DS]T') + assert.format('%C', '01', '01', new Date(100, 0, 1)) + assert.format('%j', '097', '098', new Date(1365390736236)) + ok('Time zones (' + process.env.TZ + ')') +} +else if (process.env.TZ == 'CET') { + testTimezone('CES?T') + assert.format('%C', '01', '00', new Date(100, 0, 1)) + assert.format('%j', '098', '098', new Date(1365390736236)) + ok('Time zones (' + process.env.TZ + ')') +} +else { + console.log('(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')') +} + +/// check all formats in GMT, most coverage +assert.format('%A', 'Tuesday') +assert.format('%a', 'Tue') +assert.format('%B', 'June') +assert.format('%b', 'Jun') +assert.format('%C', '20') +assert.format('%D', '06/07/11') +assert.format('%d', '07') +assert.format('%-d', '7') +assert.format('%_d', ' 7') +assert.format('%0d', '07') +assert.format('%e', '7') +assert.format('%F', '2011-06-07') +assert.format('%H', null, '18') +assert.format('%h', 'Jun') +assert.format('%I', null, '06') +assert.format('%-I', null, '6') +assert.format('%_I', null, ' 6') +assert.format('%0I', null, '06') +assert.format('%j', null, '158') +assert.format('%k', null, '18') +assert.format('%L', '067') +assert.format('%l', null, ' 6') +assert.format('%-l', null, '6') +assert.format('%_l', null, ' 6') +assert.format('%0l', null, '06') +assert.format('%M', null, '51') +assert.format('%m', '06') +assert.format('%n', '\n') +assert.format('%o', '7th') +assert.format('%P', null, 'pm') +assert.format('%p', null, 'PM') +assert.format('%R', null, '18:51') +assert.format('%r', null, '06:51:45 PM') +assert.format('%S', '45') +assert.format('%s', '1307472705') +assert.format('%T', null, '18:51:45') +assert.format('%t', '\t') +assert.format('%U', '23') +assert.format('%U', '24', null, new Date(+Time + 5 * 86400000)) +assert.format('%u', '2') +assert.format('%v', '7-Jun-2011') +assert.format('%W', '23') +assert.format('%W', '23', null, new Date(+Time + 5 * 86400000)) +assert.format('%w', '2') +assert.format('%Y', '2011') +assert.format('%y', '11') +assert.format('%Z', null, 'GMT') +assert.format('%z', null, '+0000') +assert.format('%%', '%') // any other char +//assert.format('%--', '-') +ok('GMT') + + +/// locales + +var it_IT = +{ days: words('domenica lunedi martedi mercoledi giovedi venerdi sabato') + , shortDays: words('dom lun mar mer gio ven sab') + , months: words('gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre') + , shortMonths: words('gen feb mar apr mag giu lug ago set ott nov dic') + , AM: 'it$AM' + , PM: 'it$PM' + , am: 'it$am' + , pm: 'it$pm' + , formats: { + D: 'it$%m/%d/%y' + , F: 'it$%Y-%m-%d' + , R: 'it$%H:%M' + , r: 'it$%I:%M:%S %p' + , T: 'it$%H:%M:%S' + , v: 'it$%e-%b-%Y' +} +} + +assert.format_it = function(format, expected, expectedUTC) { + function _assertFmt(expected, name, strftime) { + name = name || 'strftime' + var actual = strftime(format, Time) + assert.equal(expected, actual, + name + '("' + format + '", Time) is ' + JSON.stringify(actual) + + ', expected ' + JSON.stringify(expected)) + } + + if (expected) _assertFmt(expected, 'strftime', lib.setLocaleTo(it_IT)) + _assertFmt(expectedUTC || expected, 'strftimeUTC', lib.useUTC().setLocaleTo(it_IT)) +} + +assert.format_it('%A', 'martedi') +assert.format_it('%a', 'mar') +assert.format_it('%B', 'giugno') +assert.format_it('%b', 'giu') +assert.format_it('%D', 'it$06/07/11') +assert.format_it('%F', 'it$2011-06-07') +assert.format_it('%p', null, 'it$PM') +assert.format_it('%P', null, 'it$pm') +assert.format_it('%R', null, 'it$18:51') +assert.format_it('%r', null, 'it$06:51:45 it$PM') +assert.format_it('%T', null, 'it$18:51:45') +assert.format_it('%v', 'it$7-giu-2011') +ok('Localization') + + +/// timezones + +assert.formatTZ = function(format, expected, tz, time) { + time = time || Time; + var actual = lib.setTimezoneTo(tz)(format, time) + assert.equal( + expected, actual, + ('strftime.setTimezoneTo()("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) + ) +} + +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0) +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000') +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120) +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200') +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420) +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700') +assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730') +ok('Time zone offset') + + +/// helpers + +function words(s) { return (s || '').split(' '); } + +function ok(s) { console.log('[ \033[32mOK\033[0m ] ' + s) } + +// Pass a regex or string that matches the timezone abbrev, e.g. %Z above. +// Don't pass GMT! Every date includes it and it will fail. +// Be careful if you pass a regex, it has to quack like the default one. +function testTimezone(regex) { + regex = typeof regex === 'string' ? RegExp('\\((' + regex + ')\\)$') : regex + var match = Time.toString().match(regex) + if (match) { + var off = Time.getTimezoneOffset() + , hourOff = off / 60 + , hourDiff = Math.floor(hourOff) + , hours = 18 - hourDiff + , padSpace24 = hours < 10 ? ' ' : '' + , padZero24 = hours < 10 ? '0' : '' + , hour24 = String(hours) + , padSpace12 = (hours % 12) < 10 ? ' ' : '' + , padZero12 = (hours % 12) < 10 ? '0' : '' + , hour12 = String(hours % 12) + , sign = hourDiff < 0 ? '+' : '-' + , minDiff = Time.getTimezoneOffset() - (hourDiff * 60) + , mins = String(51 - minDiff) + , tz = match[1] + , ampm = hour12 == hour24 ? 'AM' : 'PM' + , R = hour24 + ':' + mins + , r = padZero12 + hour12 + ':' + mins + ':45 ' + ampm + , T = R + ':45' + assert.format('%H', padZero24 + hour24, '18') + assert.format('%I', padZero12 + hour12, '06') + assert.format('%k', padSpace24 + hour24, '18') + assert.format('%l', padSpace12 + hour12, ' 6') + assert.format('%M', mins) + assert.format('%P', ampm.toLowerCase(), 'pm') + assert.format('%p', ampm, 'PM') + assert.format('%R', R, '18:51') + assert.format('%r', r, '06:51:45 PM') + assert.format('%T', T, '18:51:45') + assert.format('%Z', tz, 'GMT') + assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000') + } +} From f36819ad992e0af4e7f2dfee9d8b0d50c47829cc Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 19:24:37 -0800 Subject: [PATCH 03/44] merge V2 code and deprecate the old API --- strftime.js | 827 +++++++++++++++++++++++++++++-------------------- strftimeV2.js | 497 ----------------------------- test/test.js | 340 ++++++++++---------- test/testV2.js | 224 -------------- 4 files changed, 663 insertions(+), 1225 deletions(-) delete mode 100644 strftimeV2.js delete mode 100644 test/testV2.js diff --git a/strftime.js b/strftime.js index cdc5d45..4efa4eb 100644 --- a/strftime.js +++ b/strftime.js @@ -11,356 +11,521 @@ ;(function() { - //// Where to export the API - var namespace; + //// Where to export the API + var namespace, + DefaultLocale = { + days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + AM: 'AM', + PM: 'PM', + am: 'am', + pm: 'pm', + formats: { + D: '%m/%d/%y', + F: '%Y-%m-%d', + R: '%H:%M', + T: '%H:%M:%S', + r: '%I:%M:%S %p', + v: '%e-%b-%Y' + } + }, + + defaultStrftime = new Strftime(DefaultLocale, 0, false); - // CommonJS / Node module - if (typeof module !== 'undefined') { - namespace = module.exports = strftime; - } - - // Browsers and other environments - else { - // Get the global object. Works in ES3, ES5, and ES5 strict mode. - namespace = (function(){ return this || (1,eval)('this') }()); - } - - function words(s) { return (s || '').split(' '); } - - var DefaultLocale = - { days: words('Sunday Monday Tuesday Wednesday Thursday Friday Saturday') - , shortDays: words('Sun Mon Tue Wed Thu Fri Sat') - , months: words('January February March April May June July August September October November December') - , shortMonths: words('Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec') - , AM: 'AM' - , PM: 'PM' - , am: 'am' - , pm: 'pm' - }; - - namespace.strftime = strftime; - function strftime(fmt, d, locale) { - return _strftime(fmt, d, locale); - } - - // locale is optional - namespace.strftimeTZ = strftime.strftimeTZ = strftimeTZ; - function strftimeTZ(fmt, d, locale, timezone) { - if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { - timezone = locale; - locale = undefined; + // CommonJS / Node module + if (typeof module !== 'undefined') { + namespace = module.exports = defaultStrftime; } - return _strftime(fmt, d, locale, { timezone: timezone }); - } - namespace.strftimeUTC = strftime.strftimeUTC = strftimeUTC; - function strftimeUTC(fmt, d, locale) { - return _strftime(fmt, d, locale, { utc: true }); - } + // Browsers and other environments + else { + // Get the global object. Works in ES3, ES5, and ES5 strict mode. + namespace = (function(){ return this || (1,eval)('this') }()); + } - namespace.localizedStrftime = strftime.localizedStrftime = localizedStrftime; - function localizedStrftime(locale) { - return function(fmt, d, options) { - return strftime(fmt, d, locale, options); + // Deprecated API, to be removed in v1.0 + var _deprecationWarnings = {}; + function deprecationWarning(name, instead) { + if (!_deprecationWarnings[name]) { + console.warn("[WARNING] `require('strftime')." + name + "` is deprecated and will be removed in version 1.0. Instead, use `" + instead + "`."); + _deprecationWarnings[name] = true; + } + } + + namespace.strftime = function(fmt, d, locale) { + deprecationWarning("strftime", "require('strftime')(format, date)` or `require('strftime').localize(locale)(format, date)"); + var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime; + return strftime(fmt, d); }; - } - - // d, locale, and options are optional, but you can't leave - // holes in the argument list. If you pass options you have to pass - // in all the preceding args as well. - // - // options: - // - locale [object] an object with the same structure as DefaultLocale - // - timezone [number] timezone offset in minutes from GMT - function _strftime(fmt, d, locale, options) { - options = options || {}; - - // d and locale are optional so check if d is really the locale - if (d && !quacksLikeDate(d)) { - locale = d; - d = undefined; - } - d = d || new Date(); - - locale = locale || DefaultLocale; - locale.formats = locale.formats || {}; - - // Hang on to this Unix timestamp because we might mess with it directly below. - var timestamp = d.getTime(); - - var tz = options.timezone; - var tzType = typeof tz; - - if (options.utc || tzType == 'number' || tzType == 'string') { - d = dateToUTC(d); - } - - if (tz) { - // ISO 8601 format timezone string, [-+]HHMM - // - // Convert to the number of minutes and it'll be applied to the date below. - if (tzType == 'string') { - var sign = tz[0] == '-' ? -1 : 1; - var hours = parseInt(tz.slice(1, 3), 10); - var mins = parseInt(tz.slice(3, 5), 10); - tz = sign * ((60 * hours) + mins); - } - - if (tzType) { - d = new Date(d.getTime() + (tz * 60000)); - } - } - - // Most of the specifiers supported by C's strftime, and some from Ruby. - // Some other syntax extensions from Ruby are supported: %-, %_, and %0 - // to pad with nothing, space, or zero (respectively). - return fmt.replace(/%([-_0]?.)/g, function(_, c) { - var mod, padding; - - if (c.length == 2) { - mod = c[0]; - // omit padding - if (mod == '-') { - padding = ''; + + namespace.strftimeTZ = function(fmt, d, locale, timezone) { + deprecationWarning("strftimeTZ", "require('strftime').timezone(tz)(format, date)` or `require('strftime').timezone(tz).localize(locale)(format, date)"); + if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { + timezone = locale; + locale = undefined; } - // pad with space - else if (mod == '_') { - padding = ' '; + var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); + return strftime(fmt, d); + } + + namespace.strftimeUTC = function(fmt, d, locale) { + deprecationWarning("strftimeUTC", "require('strftime').utc()(format, date)` or `require('strftime').localize(locale).utc()(format, date)"); + var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).utc(); + return strftime(fmt, d); + } + + namespace.localizedStrftime = function(locale) { + deprecationWarning("localizedStrftime", "require('strftime').localize(locale)"); + return defaultStrftime.localize(locale); + } + // End of deprecated API + + function Strftime(locale, customTimezoneOffset, useUtcTimezone) { + var _locale = locale || DefaultLocale, + _customTimezoneOffset = customTimezoneOffset || 0, + _useUtcBasedDate = useUtcTimezone || false, + + // we store unix timestamp value here to not create new Date() each iteration (each millisecond) + // Date.now() is 2 times faster than new Date() + // while millisecond precise is enough here + // this could be very helpful when strftime triggered a lot of times one by one + _cachedDateTimestamp = 0, + _cachedDate; + + function _strftime(format, date) { + var timestamp; + + if(!date) { + var currentTimestamp = Date.now(); + if(currentTimestamp > _cachedDateTimestamp) { + _cachedDateTimestamp = currentTimestamp; + _cachedDate = new Date(_cachedDateTimestamp); + + timestamp = _cachedDateTimestamp; + + if(_useUtcBasedDate) { + // how to avoid duplication of date instantiation for utc here? + // we tied to getTimezoneOffset of the current date + _cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset); + } + } + date = _cachedDate; + } else { + timestamp = date.getTime(); + + if(_useUtcBasedDate) { + date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset); + } + } + + return _processFormat(format, date, _locale, timestamp); } - // pad with zero - else if (mod == '0') { - padding = '0'; + + function _processFormat(format, date, locale, timestamp) { + var resultString = '', + padding = null, + isInScope = false, + length = format.length; + + for (var i = 0; i < length; i++) { + + var currentCharCode = format.charCodeAt(i); + + if(isInScope === true) { + // '-' + if (currentCharCode === 45) { + padding = ''; + continue; + } + // '_' + else if (currentCharCode === 95) { + padding = ' '; + continue; + } + // '0' + else if (currentCharCode === 48) { + padding = '0'; + continue; + } + + switch (currentCharCode) { + + // Examples for new Date(0) in GMT + + // 'Thursday' + // case 'A': + case 65: + resultString += locale.days[date.getDay()]; + break; + + // 'January' + // case 'B': + case 66: + resultString += locale.months[date.getMonth()]; + break; + + // '19' + // case 'C': + case 67: + resultString += padTill2(Math.floor(date.getFullYear() / 100), padding); + break; + + // '01/01/70' + // case 'D': + case 68: + resultString += _processFormat(locale.formats.D, date, locale, timestamp); + break; + + // '1970-01-01' + // case 'F': + case 70: + resultString += _processFormat(locale.formats.F, date, locale, timestamp); + break; + + // '00' + // case 'H': + case 72: + resultString += padTill2(date.getHours(), padding); + break; + + // '12' + // case 'I': + case 73: + resultString += padTill2(hours12(date.getHours()), padding); + break; + + // '000' + // case 'L': + case 76: + resultString += padTill3(Math.floor(timestamp % 1000)); + break; + + // '00' + // case 'M': + case 77: + resultString += padTill2(date.getMinutes(), padding); + break; + + // 'am' + // case 'P': + case 80: + resultString += date.getHours() < 12 ? locale.am : locale.pm; + break; + + // '00:00' + // case 'R': + case 82: + resultString += _processFormat(locale.formats.R, date, locale, timestamp); + break; + + // '00' + // case 'S': + case 83: + resultString += padTill2(date.getSeconds(), padding); + break; + + // '00:00:00' + // case 'T': + case 84: + resultString += _processFormat(locale.formats.T, date, locale, timestamp); + break; + + // '00' + // case 'U': + case 85: + resultString += padTill2(weekNumber(date, 'sunday'), padding); + break; + + // '00' + // case 'W': + case 87: + resultString += padTill2(weekNumber(date, 'monday'), padding); + break; + + // '1970' + // case 'Y': + case 89: + resultString += date.getFullYear(); + break; + + // 'GMT' + // case 'Z': + case 90: + if (_useUtcBasedDate && _customTimezoneOffset === 0) { + resultString += "GMT"; + } + else { + // fixme optimize + var tzString = date.toString().match(/\((\w+)\)/); + resultString += tzString && tzString[1] || ''; + } + break; + + // 'Thu' + // case 'a': + case 97: + resultString += locale.shortDays[date.getDay()]; + break; + + // 'Jan' + // case 'b': + case 98: + resultString += locale.shortMonths[date.getMonth()]; + break; + + // '01' + // case 'd': + case 100: + resultString += padTill2(date.getDate(), padding); + break; + + // '01' + // case 'e': + case 101: + resultString += date.getDate(); + break; + + // 'Jan' + // case 'h': + case 104: + resultString += locale.shortMonths[date.getMonth()]; + break; + + // '000' + // case 'j': + case 106: + var y = new Date(date.getFullYear(), 0, 1); + var day = Math.ceil((date.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); + resultString += padTill3(day); + break; + + // ' 0' + // case 'k': + case 107: + resultString += padTill2(date.getHours(), padding == null ? ' ' : padding); + break; + + // '12' + // case 'l': + case 108: + resultString += padTill2(hours12(date.getHours()), padding == null ? ' ' : padding); + break; + + // '01' + // case 'm': + case 109: + resultString += padTill2(date.getMonth() + 1, padding); + break; + + // '\n' + // case 'n': + case 110: + resultString += '\n'; + break; + + // '1st' + // case 'o': + case 111: + resultString += String(date.getDate()) + ordinal(date.getDate()); + break; + + // 'AM' + // case 'p': + case 112: + resultString += date.getHours() < 12 ? locale.AM : locale.PM; + break; + + // '12:00:00 AM' + // case 'r': + case 114: + resultString += _processFormat(locale.formats.r, date, locale, timestamp); + break; + + // '0' + // case 's': + case 115: + resultString += Math.floor(timestamp / 1000); + break; + + // '\t' + // case 't': + case 116: + resultString += '\t'; + break; + + // '4' + // case 'u': + case 117: + var day = date.getDay(); + resultString += day === 0 ? 7 : day; + break; // 1 - 7, Monday is first day of the week + + // '1-Jan-1970' + // case 'v': + case 118: + resultString += _processFormat(locale.formats.v, date, locale, timestamp); + break; + + // '4' + // case 'w': + case 119: + resultString += date.getDay(); + break; // 0 - 6, Sunday is first day of the week + + // '70' + // case 'y': + case 121: + resultString += ('' + date.getFullYear()).slice(2); + break; + + // '+0000' + // case 'z': + case 122: + if (_useUtcBasedDate && _customTimezoneOffset === 0) { + resultString += "+0000"; + } + else { + var off; + if(_customTimezoneOffset !== 0) { + off = _customTimezoneOffset / (60 * 1000); + } + else { + off = -date.getTimezoneOffset(); + } + resultString += (off < 0 ? '-' : '+') + padTill2(Math.floor(Math.abs(off / 60))) + padTill2(Math.abs(off % 60)); + } + break; + + default: + resultString += format[i]; + break; + } + + padding = null; + isInScope = false; + continue; + } + + // '%' + if (currentCharCode === 37) { + isInScope = true; + continue; + } + + resultString += format[i]; + } + + return resultString; } - else { - // unrecognized, return the format - return _; + + var strftime = _strftime; + + strftime.localize = function(locale) { + return new Strftime(locale || _locale, _customTimezoneOffset, _useUtcBasedDate); + }; + + strftime.timezone = function(timezone) { + var customTimezoneOffset = _customTimezoneOffset; + var useUtcBasedDate = _useUtcBasedDate; + + var timezoneType = typeof timezone; + if (timezoneType === 'number' || timezoneType === 'string') { + useUtcBasedDate = true; + + // ISO 8601 format timezone string, [-+]HHMM + if (timezoneType === 'string') { + var sign = timezone[0] === '-' ? -1 : 1, + hours = parseInt(timezone.slice(1, 3), 10), + minutes = parseInt(timezone.slice(3, 5), 10); + + customTimezoneOffset = sign * ((60 * hours) + minutes) * 60 * 1000; + // in minutes: 420 + } else if (timezoneType === 'number'){ + customTimezoneOffset = timezone * 60 * 1000; + } + } + + return new Strftime(_locale, customTimezoneOffset, useUtcBasedDate); + }; + + strftime.utc = function() { + return new Strftime(_locale, _customTimezoneOffset, true); + }; + + return strftime; + } + + function padTill2(numberToPad, paddingChar) { + if (paddingChar === '' || numberToPad > 9) { + return numberToPad; } - c = c[1]; - } - - switch (c) { - - // Examples for new Date(0) in GMT - - // 'Thursday' - case 'A': return locale.days[d.getDay()]; - - // 'Thu' - case 'a': return locale.shortDays[d.getDay()]; - - // 'January' - case 'B': return locale.months[d.getMonth()]; - - // 'Jan' - case 'b': return locale.shortMonths[d.getMonth()]; - - // '19' - case 'C': return pad(Math.floor(d.getFullYear() / 100), padding); - - // '01/01/70' - case 'D': return _strftime(locale.formats.D || '%m/%d/%y', d, locale); - - // '01' - case 'd': return pad(d.getDate(), padding); - - // '01' - case 'e': return pad(d.getDate(), padding == null ? ' ' : padding); - - // '1970-01-01' - case 'F': return _strftime(locale.formats.F || '%Y-%m-%d', d, locale); - - // '00' - case 'H': return pad(d.getHours(), padding); - - // 'Jan' - case 'h': return locale.shortMonths[d.getMonth()]; - - // '12' - case 'I': return pad(hours12(d), padding); - - // '000' - case 'j': - var y = new Date(d.getFullYear(), 0, 1); - var day = Math.ceil((d.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); - return pad(day, 3); - - // ' 0' - case 'k': return pad(d.getHours(), padding == null ? ' ' : padding); - - // '000' - case 'L': return pad(Math.floor(timestamp % 1000), 3); - - // '12' - case 'l': return pad(hours12(d), padding == null ? ' ' : padding); - - // '00' - case 'M': return pad(d.getMinutes(), padding); - - // '01' - case 'm': return pad(d.getMonth() + 1, padding); - - // '\n' - case 'n': return '\n'; - - // '1st' - case 'o': return String(d.getDate()) + ordinal(d.getDate()); - - // 'am' - case 'P': return d.getHours() < 12 ? locale.am : locale.pm; - - // 'AM' - case 'p': return d.getHours() < 12 ? locale.AM : locale.PM; - - // '00:00' - case 'R': return _strftime(locale.formats.R || '%H:%M', d, locale); - - // '12:00:00 AM' - case 'r': return _strftime(locale.formats.r || '%I:%M:%S %p', d, locale); - - // '00' - case 'S': return pad(d.getSeconds(), padding); - - // '0' - case 's': return Math.floor(timestamp / 1000); - - // '00:00:00' - case 'T': return _strftime(locale.formats.T || '%H:%M:%S', d, locale); - - // '\t' - case 't': return '\t'; - - // '00' - case 'U': return pad(weekNumber(d, 'sunday'), padding); - - // '4' - case 'u': - var day = d.getDay(); - return day == 0 ? 7 : day; // 1 - 7, Monday is first day of the week - - // ' 1-Jan-1970' - case 'v': return _strftime(locale.formats.v || '%e-%b-%Y', d, locale); - - // '00' - case 'W': return pad(weekNumber(d, 'monday'), padding); - - // '4' - case 'w': return d.getDay(); // 0 - 6, Sunday is first day of the week - - // '1970' - case 'Y': return d.getFullYear(); - - // '70' - case 'y': - var y = String(d.getFullYear()); - return y.slice(y.length - 2); - - // 'GMT' - case 'Z': - if (options.utc) { - return "GMT"; - } - else { - var tzString = d.toString().match(/\(([\w\s]+)\)/); - return tzString && tzString[1] || ''; - } - - // '+0000' - case 'z': - if (options.utc) { - return "+0000"; - } - else { - var off = typeof tz == 'number' ? tz : -d.getTimezoneOffset(); - return (off < 0 ? '-' : '+') + pad(Math.floor(Math.abs(off) / 60)) + pad(Math.abs(off) % 60); - } - - default: return c; - } - }); - } - - function dateToUTC(d) { - var msDelta = (d.getTimezoneOffset() || 0) * 60000; - return new Date(d.getTime() + msDelta); - } - - var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; - function quacksLikeDate(x) { - var i = 0 - , n = RequiredDateMethods.length - ; - for (i = 0; i < n; ++i) { - if (typeof x[RequiredDateMethods[i]] != 'function') { - return false; - } - } - return true; - } - - // Default padding is '0' and default length is 2, both are optional. - function pad(n, padding, length) { - // pad(n, ) - if (typeof padding === 'number') { - length = padding; - padding = '0'; + if (paddingChar == null) { + paddingChar = '0'; + } + return paddingChar + numberToPad; } - // Defaults handle pad(n) and pad(n, ) - if (padding == null) { - padding = '0'; + function padTill3(numberToPad) { + if (numberToPad > 99) { + return numberToPad; + } + if (numberToPad > 9) { + return '0' + numberToPad; + } + return '00' + numberToPad; } - length = length || 2; - var s = String(n); - // padding may be an empty string, don't loop forever if it is - if (padding) { - while (s.length < length) s = padding + s; + function hours12(hour) { + if (hour === 0) { + return 12; + } + else if (hour > 12) { + return hour - 12; + } + return hour; } - return s; - } - function hours12(d) { - var hour = d.getHours(); - if (hour == 0) hour = 12; - else if (hour > 12) hour -= 12; - return hour; - } + // firstWeekday: 'sunday' or 'monday', default is 'sunday' + // + // Pilfered & ported from Ruby's strftime implementation. + function weekNumber(date, firstWeekday) { + firstWeekday = firstWeekday || 'sunday'; - // Get the ordinal suffix for a number: st, nd, rd, or th - function ordinal(n) { - var i = n % 10 - , ii = n % 100 - ; - if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { - return 'th'; + // This works by shifting the weekday back by one day if we + // are treating Monday as the first day of the week. + var weekday = date.getDay(); + if (firstWeekday === 'monday') { + if (weekday === 0) // Sunday + weekday = 6; + else + weekday--; + } + var firstDayOfYear = new Date(date.getFullYear(), 0, 1), + yday = (date - firstDayOfYear) / 86400000, + weekNum = (yday + 7 - weekday) / 7; + + return Math.floor(weekNum); } - switch (i) { - case 1: return 'st'; - case 2: return 'nd'; - case 3: return 'rd'; - } - } - // firstWeekday: 'sunday' or 'monday', default is 'sunday' - // - // Pilfered & ported from Ruby's strftime implementation. - function weekNumber(d, firstWeekday) { - firstWeekday = firstWeekday || 'sunday'; + // Get the ordinal suffix for a number: st, nd, rd, or th + function ordinal(number) { + var i = number % 10; + var ii = number % 100; - // This works by shifting the weekday back by one day if we - // are treating Monday as the first day of the week. - var wday = d.getDay(); - if (firstWeekday == 'monday') { - if (wday == 0) // Sunday - wday = 6; - else - wday--; + if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { + return 'th'; + } + switch (i) { + case 1: return 'st'; + case 2: return 'nd'; + case 3: return 'rd'; + } + } + + function getTimestampToUtcOffsetFor(date) { + return (date.getTimezoneOffset() || 0) * 60000; } - var firstDayOfYear = new Date(d.getFullYear(), 0, 1) - , yday = (d - firstDayOfYear) / 86400000 - , weekNum = (yday + 7 - wday) / 7 - ; - return Math.floor(weekNum); - } }()); diff --git a/strftimeV2.js b/strftimeV2.js deleted file mode 100644 index 928a810..0000000 --- a/strftimeV2.js +++ /dev/null @@ -1,497 +0,0 @@ -// -// strftime -// github.com/samsonjs/strftime -// @_sjs -// -// Copyright 2010 - 2013 Sami Samhuri -// -// MIT License -// http://sjs.mit-license.org -// - -;(function() { - "use strict"; - - //// Where to export the API - var namespace, - - DefaultLocale = { - days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], - shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - AM: 'AM', - PM: 'PM', - am: 'am', - pm: 'pm', - formats: { - D: '%m/%d/%y', - F: '%Y-%m-%d', - R: '%H:%M', - T: '%H:%M:%S', - r: '%I:%M:%S %p', - v: '%e-%b-%Y' - } - }, - - defaultStrftime = new Strftime(DefaultLocale, 0, false); - - // CommonJS / Node module - if (typeof module !== 'undefined') { - namespace = module.exports = defaultStrftime; - } - - // Browsers and other environments - else { - // Get the global object. Works in ES3, ES5, and ES5 strict mode. - namespace = (function(){ return this || (1,eval)('this') }()); - } - - namespace.strftime = defaultStrftime; - - function Strftime(locale, customTimezoneOffset, useUtcTimezone) { - var _locale = locale || DefaultLocale, - _customTimezoneOffset = customTimezoneOffset || 0, - _useUtcBasedDate = useUtcTimezone || false, - - // we store unix timestamp value here to not create new Date() each iteration (each millisecond) - // Date.now() is 2 times faster than new Date() - // while millisecond precise is enough here - // this could be very helpful when strftime triggered a lot of times one by one - _cachedDateTimestamp = 0, - _cachedDate; - - function _strftime(format, date) { - var timestamp; - - if(!date) { - var currentTimestamp = Date.now(); - if(currentTimestamp > _cachedDateTimestamp) { - _cachedDateTimestamp = currentTimestamp; - _cachedDate = new Date(_cachedDateTimestamp); - - timestamp = _cachedDateTimestamp; - - if(_useUtcBasedDate) { - // how to avoid duplication of date instantiation for utc here? - // we tied to getTimezoneOffset of the current date - _cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset); - } - } - date = _cachedDate; - } else { - timestamp = date.getTime(); - - if(_useUtcBasedDate) { - date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset); - } - } - - return _processFormat(format, date, _locale, timestamp); - } - - function _processFormat(format, date, locale, timestamp) { - var resultString = '', - padding = null, - isInScope = false, - length = format.length; - - for (var i = 0; i < length; i++) { - - var currentCharCode = format.charCodeAt(i); - - if(isInScope === true) { - // '-' - if (currentCharCode === 45) { - padding = ''; - continue; - } - // '_' - else if (currentCharCode === 95) { - padding = ' '; - continue; - } - // '0' - else if (currentCharCode === 48) { - padding = '0'; - continue; - } - - switch (currentCharCode) { - - // Examples for new Date(0) in GMT - - // 'Thursday' - // case 'A': - case 65: - resultString += locale.days[date.getDay()]; - break; - - // 'January' - // case 'B': - case 66: - resultString += locale.months[date.getMonth()]; - break; - - // '19' - // case 'C': - case 67: - resultString += padTill2(Math.floor(date.getFullYear() / 100), padding); - break; - - // '01/01/70' - // case 'D': - case 68: - resultString += _processFormat(locale.formats.D, date, locale, timestamp); - break; - - // '1970-01-01' - // case 'F': - case 70: - resultString += _processFormat(locale.formats.F, date, locale, timestamp); - break; - - // '00' - // case 'H': - case 72: - resultString += padTill2(date.getHours(), padding); - break; - - // '12' - // case 'I': - case 73: - resultString += padTill2(hours12(date.getHours()), padding); - break; - - // '000' - // case 'L': - case 76: - resultString += padTill3(Math.floor(timestamp % 1000)); - break; - - // '00' - // case 'M': - case 77: - resultString += padTill2(date.getMinutes(), padding); - break; - - // 'am' - // case 'P': - case 80: - resultString += date.getHours() < 12 ? locale.am : locale.pm; - break; - - // '00:00' - // case 'R': - case 82: - resultString += _processFormat(locale.formats.R, date, locale, timestamp); - break; - - // '00' - // case 'S': - case 83: - resultString += padTill2(date.getSeconds(), padding); - break; - - // '00:00:00' - // case 'T': - case 84: - resultString += _processFormat(locale.formats.T, date, locale, timestamp); - break; - - // '00' - // case 'U': - case 85: - resultString += padTill2(weekNumber(date, 'sunday'), padding); - break; - - // '00' - // case 'W': - case 87: - resultString += padTill2(weekNumber(date, 'monday'), padding); - break; - - // '1970' - // case 'Y': - case 89: - resultString += date.getFullYear(); - break; - - // 'GMT' - // case 'Z': - case 90: - if (_useUtcBasedDate && _customTimezoneOffset === 0) { - resultString += "GMT"; - } - else { - // fixme optimize - var tzString = date.toString().match(/\((\w+)\)/); - resultString += tzString && tzString[1] || ''; - } - break; - - // 'Thu' - // case 'a': - case 97: - resultString += locale.shortDays[date.getDay()]; - break; - - // 'Jan' - // case 'b': - case 98: - resultString += locale.shortMonths[date.getMonth()]; - break; - - // '01' - // case 'd': - case 100: - resultString += padTill2(date.getDate(), padding); - break; - - // '01' - // case 'e': - case 101: - resultString += date.getDate(); - break; - - // 'Jan' - // case 'h': - case 104: - resultString += locale.shortMonths[date.getMonth()]; - break; - - // '000' - // case 'j': - case 106: - var y = new Date(date.getFullYear(), 0, 1); - var day = Math.ceil((date.getTime() - y.getTime()) / (1000 * 60 * 60 * 24)); - resultString += padTill3(day); - break; - - // ' 0' - // case 'k': - case 107: - resultString += padTill2(date.getHours(), padding == null ? ' ' : padding); - break; - - // '12' - // case 'l': - case 108: - resultString += padTill2(hours12(date.getHours()), padding == null ? ' ' : padding); - break; - - // '01' - // case 'm': - case 109: - resultString += padTill2(date.getMonth() + 1, padding); - break; - - // '\n' - // case 'n': - case 110: - resultString += '\n'; - break; - - // '1st' - // case 'o': - case 111: - resultString += String(date.getDate()) + ordinal(date.getDate()); - break; - - // 'AM' - // case 'p': - case 112: - resultString += date.getHours() < 12 ? locale.AM : locale.PM; - break; - - // '12:00:00 AM' - // case 'r': - case 114: - resultString += _processFormat(locale.formats.r, date, locale, timestamp); - break; - - // '0' - // case 's': - case 115: - resultString += Math.floor(timestamp / 1000); - break; - - // '\t' - // case 't': - case 116: - resultString += '\t'; - break; - - // '4' - // case 'u': - case 117: - var day = date.getDay(); - resultString += day === 0 ? 7 : day; - break; // 1 - 7, Monday is first day of the week - - // '1-Jan-1970' - // case 'v': - case 118: - resultString += _processFormat(locale.formats.v, date, locale, timestamp); - break; - - // '4' - // case 'w': - case 119: - resultString += date.getDay(); - break; // 0 - 6, Sunday is first day of the week - - // '70' - // case 'y': - case 121: - resultString += ('' + date.getFullYear()).slice(2); - break; - - // '+0000' - // case 'z': - case 122: - if (_useUtcBasedDate && _customTimezoneOffset === 0) { - resultString += "+0000"; - } - else { - var off; - if(_customTimezoneOffset !== 0) { - off = _customTimezoneOffset / (60 * 1000); - } - else { - off = -date.getTimezoneOffset(); - } - resultString += (off < 0 ? '-' : '+') + padTill2(Math.floor(Math.abs(off / 60))) + padTill2(Math.abs(off % 60)); - } - break; - - default: - resultString += format[i]; - break; - } - - padding = null; - isInScope = false; - continue; - } - - // '%' - if (currentCharCode === 37) { - isInScope = true; - continue; - } - - resultString += format[i]; - } - - return resultString; - } - - var strftime = _strftime; - - strftime.setLocaleTo = function(locale) { - return new Strftime(locale || _locale, _customTimezoneOffset, _useUtcBasedDate); - }; - - strftime.setTimezoneTo = function(timezone) { - var customTimezoneOffset = _customTimezoneOffset; - var useUtcBasedDate = _useUtcBasedDate; - - var timezoneType = typeof timezone; - if (timezoneType === 'number' || timezoneType === 'string') { - useUtcBasedDate = true; - - // ISO 8601 format timezone string, [-+]HHMM - if (timezoneType === 'string') { - var sign = timezone[0] === '-' ? -1 : 1, - hours = parseInt(timezone.slice(1, 3), 10), - minutes = parseInt(timezone.slice(3, 5), 10); - - customTimezoneOffset = sign * ((60 * hours) + minutes) * 60 * 1000; - // in minutes: 420 - } else if (timezoneType === 'number'){ - customTimezoneOffset = timezone * 60 * 1000; - } - } - - return new Strftime(_locale, customTimezoneOffset, useUtcBasedDate); - }; - - strftime.useUTC = function() { - return new Strftime(_locale, _customTimezoneOffset, true); - }; - - return strftime; - } - - function padTill2(numberToPad, paddingChar) { - if (paddingChar === '' || numberToPad > 9) { - return numberToPad; - } - if (paddingChar == null) { - paddingChar = '0'; - } - return paddingChar + numberToPad; - } - - function padTill3(numberToPad) { - if (numberToPad > 99) { - return numberToPad; - } - if (numberToPad > 9) { - return '0' + numberToPad; - } - return '00' + numberToPad; - } - - function hours12(hour) { - if (hour === 0) { - return 12; - } - else if (hour > 12) { - return hour - 12; - } - return hour; - } - - // firstWeekday: 'sunday' or 'monday', default is 'sunday' - // - // Pilfered & ported from Ruby's strftime implementation. - function weekNumber(date, firstWeekday) { - firstWeekday = firstWeekday || 'sunday'; - - // This works by shifting the weekday back by one day if we - // are treating Monday as the first day of the week. - var weekday = date.getDay(); - if (firstWeekday === 'monday') { - if (weekday === 0) // Sunday - weekday = 6; - else - weekday--; - } - var firstDayOfYear = new Date(date.getFullYear(), 0, 1), - yday = (date - firstDayOfYear) / 86400000, - weekNum = (yday + 7 - weekday) / 7; - - return Math.floor(weekNum); - } - - // Get the ordinal suffix for a number: st, nd, rd, or th - function ordinal(number) { - var i = number % 10; - var ii = number % 100; - - if ((ii >= 11 && ii <= 13) || i === 0 || i >= 4) { - return 'th'; - } - switch (i) { - case 1: return 'st'; - case 2: return 'nd'; - case 3: return 'rd'; - } - } - - function getTimestampToUtcOffsetFor(date) { - return (date.getTimezoneOffset() || 0) * 60000; - } -}()); diff --git a/test/test.js b/test/test.js index 48572cd..9ff0153 100755 --- a/test/test.js +++ b/test/test.js @@ -6,219 +6,213 @@ // - past and future dates, especially < 1900 and > 2100 // - look for edge cases -var assert = require('assert') - , libFilename = process.argv[2] || '../strftime.js' - , lib = require(libFilename) - - // Tue, 07 Jun 2011 18:51:45 GMT - , TestTime = new Date(1307472705067) +var assert = require('assert'), + libFilename = process.argv[2] || '../strftime.js', + strftime = require(libFilename), + strftimeUTC = strftime.utc(), + Time = new Date(1307472705067); // Tue, 07 Jun 2011 18:51:45 GMT assert.fn = function(value, msg) { - assert.equal('function', typeof value, msg) + assert.equal('function', typeof value, msg); +}; + +function assertFormat(time, format, expected, name, strftime) { + var actual = strftime(format, time); + assert.equal(expected, actual, + name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + + ', expected ' + JSON.stringify(expected)); } assert.format = function(format, expected, expectedUTC, time) { - time = time || TestTime - function _assertFmt(expected, name) { - name = name || 'strftime' - var actual = lib[name](format, time) - assert.equal(expected, actual, - name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) - + ', expected ' + JSON.stringify(expected)) - } + time = time || Time; + if (expected) { assertFormat(time, format, expected, 'strftime', strftime); } + assertFormat(time, format, expectedUTC || expected, 'strftime.utc()', strftimeUTC); +}; - if (expected) _assertFmt(expected, 'strftime') - _assertFmt(expectedUTC || expected, 'strftimeUTC') -} +/// check deprecated exports +assert.fn(strftime.strftime); +assert.fn(strftime.strftimeTZ); +assert.fn(strftime.strftimeUTC); +assert.fn(strftime.localizedStrftime); +ok('Deprecated exports'); /// check exports -assert.fn(lib.strftime) -assert.fn(lib.strftimeUTC) -assert.fn(lib.localizedStrftime) -ok('Exports') +assert.fn(strftime.localize); +assert.fn(strftime.timezone); +assert.fn(strftime.utc); +ok('Exports'); /// time zones if (process.env.TZ == 'America/Vancouver') { - testTimezone('P[DS]T') - assert.format('%C', '01', '01', new Date(100, 0, 1)) - assert.format('%j', '097', '098', new Date(1365390736236)) - ok('Time zones (' + process.env.TZ + ')') + testTimezone('P[DS]T'); + assert.format('%C', '01', '01', new Date(100, 0, 1)); + assert.format('%j', '097', '098', new Date(1365390736236)); + ok('Time zones (' + process.env.TZ + ')'); } else if (process.env.TZ == 'CET') { - testTimezone('CES?T') - assert.format('%C', '01', '00', new Date(100, 0, 1)) - assert.format('%j', '098', '098', new Date(1365390736236)) - ok('Time zones (' + process.env.TZ + ')') + testTimezone('CES?T'); + assert.format('%C', '01', '00', new Date(100, 0, 1)); + assert.format('%j', '098', '098', new Date(1365390736236)); + ok('Time zones (' + process.env.TZ + ')'); } else { - console.log('(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')') + console.log('(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')'); } /// check all formats in GMT, most coverage -assert.format('%A', 'Tuesday') -assert.format('%a', 'Tue') -assert.format('%B', 'June') -assert.format('%b', 'Jun') -assert.format('%C', '20') -assert.format('%D', '06/07/11') -assert.format('%d', '07') -assert.format('%-d', '7') -assert.format('%_d', ' 7') -assert.format('%0d', '07') -assert.format('%e', ' 7') -assert.format('%F', '2011-06-07') -assert.format('%H', null, '18') -assert.format('%h', 'Jun') -assert.format('%I', null, '06') -assert.format('%-I', null, '6') -assert.format('%_I', null, ' 6') -assert.format('%0I', null, '06') -assert.format('%j', null, '158') -assert.format('%k', null, '18') -assert.format('%L', '067') -assert.format('%l', null, ' 6') -assert.format('%-l', null, '6') -assert.format('%_l', null, ' 6') -assert.format('%0l', null, '06') -assert.format('%M', null, '51') -assert.format('%m', '06') -assert.format('%n', '\n') -assert.format('%o', '7th') -assert.format('%P', null, 'pm') -assert.format('%p', null, 'PM') -assert.format('%R', null, '18:51') -assert.format('%r', null, '06:51:45 PM') -assert.format('%S', '45') -assert.format('%s', '1307472705') -assert.format('%T', null, '18:51:45') -assert.format('%t', '\t') -assert.format('%U', '23') -assert.format('%U', '24', null, new Date(+TestTime + 5 * 86400000)) -assert.format('%u', '2') -assert.format('%v', ' 7-Jun-2011') -assert.format('%W', '23') -assert.format('%W', '23', null, new Date(+TestTime + 5 * 86400000)) -assert.format('%w', '2') -assert.format('%Y', '2011') -assert.format('%y', '11') -assert.format('%Z', null, 'GMT') -assert.format('%z', null, '+0000') -assert.format('%%', '%') // any other char -ok('GMT') +assert.format('%A', 'Tuesday'); +assert.format('%a', 'Tue'); +assert.format('%B', 'June'); +assert.format('%b', 'Jun'); +assert.format('%C', '20'); +assert.format('%D', '06/07/11'); +assert.format('%d', '07'); +assert.format('%-d', '7'); +assert.format('%_d', ' 7'); +assert.format('%0d', '07'); +assert.format('%e', '7'); +assert.format('%F', '2011-06-07'); +assert.format('%H', null, '18'); +assert.format('%h', 'Jun'); +assert.format('%I', null, '06'); +assert.format('%-I', null, '6'); +assert.format('%_I', null, ' 6'); +assert.format('%0I', null, '06'); +assert.format('%j', null, '158'); +assert.format('%k', null, '18'); +assert.format('%L', '067'); +assert.format('%l', null, ' 6'); +assert.format('%-l', null, '6'); +assert.format('%_l', null, ' 6'); +assert.format('%0l', null, '06'); +assert.format('%M', null, '51'); +assert.format('%m', '06'); +assert.format('%n', '\n'); +assert.format('%o', '7th'); +assert.format('%P', null, 'pm'); +assert.format('%p', null, 'PM'); +assert.format('%R', null, '18:51'); +assert.format('%r', null, '06:51:45 PM'); +assert.format('%S', '45'); +assert.format('%s', '1307472705'); +assert.format('%T', null, '18:51:45'); +assert.format('%t', '\t'); +assert.format('%U', '23'); +assert.format('%U', '24', null, new Date(+Time + 5 * 86400000)); +assert.format('%u', '2'); +assert.format('%v', '7-Jun-2011'); +assert.format('%W', '23'); +assert.format('%W', '23', null, new Date(+Time + 5 * 86400000)); +assert.format('%w', '2'); +assert.format('%Y', '2011'); +assert.format('%y', '11'); +assert.format('%Z', null, 'GMT'); +assert.format('%z', null, '+0000'); +assert.format('%%', '%') // any other char; +ok('GMT'); /// locales -var it_IT = -{ days: words('domenica lunedi martedi mercoledi giovedi venerdi sabato') -, shortDays: words('dom lun mar mer gio ven sab') -, months: words('gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre') -, shortMonths: words('gen feb mar apr mag giu lug ago set ott nov dic') -, AM: 'it$AM' -, PM: 'it$PM' -, am: 'it$am' -, pm: 'it$pm' -, formats: { - D: 'it$%m/%d/%y' - , F: 'it$%Y-%m-%d' - , R: 'it$%H:%M' - , r: 'it$%I:%M:%S %p' - , T: 'it$%H:%M:%S' - , v: 'it$%e-%b-%Y' - } -} +var it_IT = { + days: words('domenica lunedi martedi mercoledi giovedi venerdi sabato'), + shortDays: words('dom lun mar mer gio ven sab'), + months: words('gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre'), + shortMonths: words('gen feb mar apr mag giu lug ago set ott nov dic'), + AM: 'it$AM', + PM: 'it$PM', + am: 'it$am', + pm: 'it$pm', + formats: { + D: 'it$%m/%d/%y', + F: 'it$%Y-%m-%d', + R: 'it$%H:%M', + r: 'it$%I:%M:%S %p', + T: 'it$%H:%M:%S', + v: 'it$%e-%b-%Y' + } + }; +var strftimeIT = strftime.localize(it_IT), + strftimeITUTC = strftimeIT.utc(); assert.format_it = function(format, expected, expectedUTC) { - function _assertFmt(expected, name) { - name = name || 'strftime' - var actual = lib[name](format, TestTime, it_IT) - assert.equal(expected, actual, - name + '("' + format + '", Time) is ' + JSON.stringify(actual) - + ', expected ' + JSON.stringify(expected)) - } + if (expected) { assertFormat(Time, format, expected, 'strftime.localize(it_IT)', strftimeIT) } + assertFormat(Time, format, expectedUTC || expected, 'strftime.localize(it_IT).utc()', strftimeITUTC) +}; - if (expected) _assertFmt(expected, 'strftime') - _assertFmt(expectedUTC || expected, 'strftimeUTC') -} - -assert.format_it('%A', 'martedi') -assert.format_it('%a', 'mar') -assert.format_it('%B', 'giugno') -assert.format_it('%b', 'giu') -assert.format_it('%D', 'it$06/07/11') -assert.format_it('%F', 'it$2011-06-07') -assert.format_it('%p', null, 'it$PM') -assert.format_it('%P', null, 'it$pm') -assert.format_it('%R', null, 'it$18:51') -assert.format_it('%r', null, 'it$06:51:45 it$PM') -assert.format_it('%T', null, 'it$18:51:45') -assert.format_it('%v', 'it$ 7-giu-2011') -ok('Localization') +assert.format_it('%A', 'martedi'); +assert.format_it('%a', 'mar'); +assert.format_it('%B', 'giugno'); +assert.format_it('%b', 'giu'); +assert.format_it('%D', 'it$06/07/11'); +assert.format_it('%F', 'it$2011-06-07'); +assert.format_it('%p', null, 'it$PM'); +assert.format_it('%P', null, 'it$pm'); +assert.format_it('%R', null, 'it$18:51'); +assert.format_it('%r', null, 'it$06:51:45 it$PM'); +assert.format_it('%T', null, 'it$18:51:45'); +assert.format_it('%v', 'it$7-giu-2011'); +ok('Localization'); /// timezones assert.formatTZ = function(format, expected, tz, time) { - time = time || TestTime; - var actual = lib.strftimeTZ(format, time, tz) - assert.equal( - expected, actual, - ('strftime("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) - ) -} + assertFormat(time || Time, format, expected, 'strftime.timezone(' + tz + ')', strftime.timezone(tz)); +}; -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0) -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000') -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120) -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200') -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420) -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700') -assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730') -ok('Time zone offset') +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0); +assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000'); +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120); +assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200'); +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420); +assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700'); +assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730'); +ok('Time zone offset'); /// helpers function words(s) { return (s || '').split(' '); } -function ok(s) { console.log('[ \033[32mOK\033[0m ] ' + s) } +function ok(s) { console.log('[ \033[32mOK\033[0m ] ' + s); } // Pass a regex or string that matches the timezone abbrev, e.g. %Z above. // Don't pass GMT! Every date includes it and it will fail. // Be careful if you pass a regex, it has to quack like the default one. function testTimezone(regex) { - regex = typeof regex === 'string' ? RegExp('\\((' + regex + ')\\)$') : regex - var match = TestTime.toString().match(regex) - if (match) { - var off = TestTime.getTimezoneOffset() - , hourOff = off / 60 - , hourDiff = Math.floor(hourOff) - , hours = 18 - hourDiff - , padSpace24 = hours < 10 ? ' ' : '' - , padZero24 = hours < 10 ? '0' : '' - , hour24 = String(hours) - , padSpace12 = (hours % 12) < 10 ? ' ' : '' - , padZero12 = (hours % 12) < 10 ? '0' : '' - , hour12 = String(hours % 12) - , sign = hourDiff < 0 ? '+' : '-' - , minDiff = TestTime.getTimezoneOffset() - (hourDiff * 60) - , mins = String(51 - minDiff) - , tz = match[1] - , ampm = hour12 == hour24 ? 'AM' : 'PM' - , R = hour24 + ':' + mins - , r = padZero12 + hour12 + ':' + mins + ':45 ' + ampm - , T = R + ':45' - assert.format('%H', padZero24 + hour24, '18') - assert.format('%I', padZero12 + hour12, '06') - assert.format('%k', padSpace24 + hour24, '18') - assert.format('%l', padSpace12 + hour12, ' 6') - assert.format('%M', mins) - assert.format('%P', ampm.toLowerCase(), 'pm') - assert.format('%p', ampm, 'PM') - assert.format('%R', R, '18:51') - assert.format('%r', r, '06:51:45 PM') - assert.format('%T', T, '18:51:45') - assert.format('%Z', tz, 'GMT') - assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000') - } + regex = typeof regex === 'string' ? RegExp('\\((' + regex + ')\\)$') : regex; + var match = Time.toString().match(regex); + if (match) { + var off = Time.getTimezoneOffset(), + hourOff = off / 60, + hourDiff = Math.floor(hourOff), + hours = 18 - hourDiff, + padSpace24 = hours < 10 ? ' ' : '', + padZero24 = hours < 10 ? '0' : '', + hour24 = String(hours), + padSpace12 = (hours % 12) < 10 ? ' ' : '', + padZero12 = (hours % 12) < 10 ? '0' : '', + hour12 = String(hours % 12), + sign = hourDiff < 0 ? '+' : '-', + minDiff = Time.getTimezoneOffset() - (hourDiff * 60), + mins = String(51 - minDiff), + tz = match[1], + ampm = hour12 == hour24 ? 'AM' : 'PM', + R = hour24 + ':' + mins, + r = padZero12 + hour12 + ':' + mins + ':45 ' + ampm, + T = R + ':45'; + assert.format('%H', padZero24 + hour24, '18'); + assert.format('%I', padZero12 + hour12, '06'); + assert.format('%k', padSpace24 + hour24, '18'); + assert.format('%l', padSpace12 + hour12, ' 6'); + assert.format('%M', mins); + assert.format('%P', ampm.toLowerCase(), 'pm'); + assert.format('%p', ampm, 'PM'); + assert.format('%R', R, '18:51'); + assert.format('%r', r, '06:51:45 PM'); + assert.format('%T', T, '18:51:45'); + assert.format('%Z', tz, 'GMT'); + assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000'); + } } diff --git a/test/testV2.js b/test/testV2.js deleted file mode 100644 index 61d0f6c..0000000 --- a/test/testV2.js +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/env node - -// Based on CoffeeScript by andrewschaaf on github -// -// TODO: -// - past and future dates, especially < 1900 and > 2100 -// - locales -// - look for edge cases - -var assert = require('assert') - , libFilename = process.argv[2] || '../strftimeV2.js' - , lib = require(libFilename) - -// Tue, 07 Jun 2011 18:51:45 GMT - , Time = new Date(1307472705067) - -assert.fn = function(value, msg) { - assert.equal('function', typeof value, msg) -} - -assert.format = function(format, expected, expectedUTC, time) { - time = time || Time - function _assertFmt(expected, name, strftime) { - name = name || 'strftime' - var actual = strftime(format, time) - assert.equal(expected, actual, - name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) - + ', expected ' + JSON.stringify(expected)) - } - - if (expected) _assertFmt(expected, 'strftime', lib) - _assertFmt(expectedUTC || expected, 'strftime.UseUTC()', lib.useUTC()) -} - -/// check exports -assert.fn(lib.strftime) -ok('Exports') - -/// time zones -if (process.env.TZ == 'America/Vancouver') { - testTimezone('P[DS]T') - assert.format('%C', '01', '01', new Date(100, 0, 1)) - assert.format('%j', '097', '098', new Date(1365390736236)) - ok('Time zones (' + process.env.TZ + ')') -} -else if (process.env.TZ == 'CET') { - testTimezone('CES?T') - assert.format('%C', '01', '00', new Date(100, 0, 1)) - assert.format('%j', '098', '098', new Date(1365390736236)) - ok('Time zones (' + process.env.TZ + ')') -} -else { - console.log('(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')') -} - -/// check all formats in GMT, most coverage -assert.format('%A', 'Tuesday') -assert.format('%a', 'Tue') -assert.format('%B', 'June') -assert.format('%b', 'Jun') -assert.format('%C', '20') -assert.format('%D', '06/07/11') -assert.format('%d', '07') -assert.format('%-d', '7') -assert.format('%_d', ' 7') -assert.format('%0d', '07') -assert.format('%e', '7') -assert.format('%F', '2011-06-07') -assert.format('%H', null, '18') -assert.format('%h', 'Jun') -assert.format('%I', null, '06') -assert.format('%-I', null, '6') -assert.format('%_I', null, ' 6') -assert.format('%0I', null, '06') -assert.format('%j', null, '158') -assert.format('%k', null, '18') -assert.format('%L', '067') -assert.format('%l', null, ' 6') -assert.format('%-l', null, '6') -assert.format('%_l', null, ' 6') -assert.format('%0l', null, '06') -assert.format('%M', null, '51') -assert.format('%m', '06') -assert.format('%n', '\n') -assert.format('%o', '7th') -assert.format('%P', null, 'pm') -assert.format('%p', null, 'PM') -assert.format('%R', null, '18:51') -assert.format('%r', null, '06:51:45 PM') -assert.format('%S', '45') -assert.format('%s', '1307472705') -assert.format('%T', null, '18:51:45') -assert.format('%t', '\t') -assert.format('%U', '23') -assert.format('%U', '24', null, new Date(+Time + 5 * 86400000)) -assert.format('%u', '2') -assert.format('%v', '7-Jun-2011') -assert.format('%W', '23') -assert.format('%W', '23', null, new Date(+Time + 5 * 86400000)) -assert.format('%w', '2') -assert.format('%Y', '2011') -assert.format('%y', '11') -assert.format('%Z', null, 'GMT') -assert.format('%z', null, '+0000') -assert.format('%%', '%') // any other char -//assert.format('%--', '-') -ok('GMT') - - -/// locales - -var it_IT = -{ days: words('domenica lunedi martedi mercoledi giovedi venerdi sabato') - , shortDays: words('dom lun mar mer gio ven sab') - , months: words('gennaio febbraio marzo aprile maggio giugno luglio agosto settembre ottobre novembre dicembre') - , shortMonths: words('gen feb mar apr mag giu lug ago set ott nov dic') - , AM: 'it$AM' - , PM: 'it$PM' - , am: 'it$am' - , pm: 'it$pm' - , formats: { - D: 'it$%m/%d/%y' - , F: 'it$%Y-%m-%d' - , R: 'it$%H:%M' - , r: 'it$%I:%M:%S %p' - , T: 'it$%H:%M:%S' - , v: 'it$%e-%b-%Y' -} -} - -assert.format_it = function(format, expected, expectedUTC) { - function _assertFmt(expected, name, strftime) { - name = name || 'strftime' - var actual = strftime(format, Time) - assert.equal(expected, actual, - name + '("' + format + '", Time) is ' + JSON.stringify(actual) - + ', expected ' + JSON.stringify(expected)) - } - - if (expected) _assertFmt(expected, 'strftime', lib.setLocaleTo(it_IT)) - _assertFmt(expectedUTC || expected, 'strftimeUTC', lib.useUTC().setLocaleTo(it_IT)) -} - -assert.format_it('%A', 'martedi') -assert.format_it('%a', 'mar') -assert.format_it('%B', 'giugno') -assert.format_it('%b', 'giu') -assert.format_it('%D', 'it$06/07/11') -assert.format_it('%F', 'it$2011-06-07') -assert.format_it('%p', null, 'it$PM') -assert.format_it('%P', null, 'it$pm') -assert.format_it('%R', null, 'it$18:51') -assert.format_it('%r', null, 'it$06:51:45 it$PM') -assert.format_it('%T', null, 'it$18:51:45') -assert.format_it('%v', 'it$7-giu-2011') -ok('Localization') - - -/// timezones - -assert.formatTZ = function(format, expected, tz, time) { - time = time || Time; - var actual = lib.setTimezoneTo(tz)(format, time) - assert.equal( - expected, actual, - ('strftime.setTimezoneTo()("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)) - ) -} - -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', 0) -assert.formatTZ('%F %r %z', '2011-06-07 06:51:45 PM +0000', '+0000') -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', 120) -assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200') -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420) -assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700') -assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730') -ok('Time zone offset') - - -/// helpers - -function words(s) { return (s || '').split(' '); } - -function ok(s) { console.log('[ \033[32mOK\033[0m ] ' + s) } - -// Pass a regex or string that matches the timezone abbrev, e.g. %Z above. -// Don't pass GMT! Every date includes it and it will fail. -// Be careful if you pass a regex, it has to quack like the default one. -function testTimezone(regex) { - regex = typeof regex === 'string' ? RegExp('\\((' + regex + ')\\)$') : regex - var match = Time.toString().match(regex) - if (match) { - var off = Time.getTimezoneOffset() - , hourOff = off / 60 - , hourDiff = Math.floor(hourOff) - , hours = 18 - hourDiff - , padSpace24 = hours < 10 ? ' ' : '' - , padZero24 = hours < 10 ? '0' : '' - , hour24 = String(hours) - , padSpace12 = (hours % 12) < 10 ? ' ' : '' - , padZero12 = (hours % 12) < 10 ? '0' : '' - , hour12 = String(hours % 12) - , sign = hourDiff < 0 ? '+' : '-' - , minDiff = Time.getTimezoneOffset() - (hourDiff * 60) - , mins = String(51 - minDiff) - , tz = match[1] - , ampm = hour12 == hour24 ? 'AM' : 'PM' - , R = hour24 + ':' + mins - , r = padZero12 + hour12 + ':' + mins + ':45 ' + ampm - , T = R + ':45' - assert.format('%H', padZero24 + hour24, '18') - assert.format('%I', padZero12 + hour12, '06') - assert.format('%k', padSpace24 + hour24, '18') - assert.format('%l', padSpace12 + hour12, ' 6') - assert.format('%M', mins) - assert.format('%P', ampm.toLowerCase(), 'pm') - assert.format('%p', ampm, 'PM') - assert.format('%R', R, '18:51') - assert.format('%r', r, '06:51:45 PM') - assert.format('%T', T, '18:51:45') - assert.format('%Z', tz, 'GMT') - assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000') - } -} From f5217499671d7ce7274d8377cc639a95bef088dd Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 19:27:48 -0800 Subject: [PATCH 04/44] add @alexandrnikitin to contributors --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9571a28..470ec84 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "Sami Samhuri (http://samhuri.net)", "Andrew Schaaf (http://andrewschaaf.com/)", "Rob Colburn (http://robcolburn.com/)", - "Ryan Stafford (http://droffats.net/)" + "Ryan Stafford (http://droffats.net/)", + "Alexandr Nikitin " ], "repository": { "type": "git", From f1581a3c9d0dbf828ba402f8f3d789fcd5482eba Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 19:28:03 -0800 Subject: [PATCH 05/44] bump version to 0.9.0 --- component.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/component.json b/component.json index c3c352a..790ad5c 100644 --- a/component.json +++ b/component.json @@ -3,7 +3,7 @@ "repo": "samsonjs/strftime", "description": "strftime date formatting", "keywords": ["strftime", "format", "date", "time"], - "version": "0.8.2", + "version": "0.9.0", "main": "strftime.js", "scripts": ["strftime.js"] } diff --git a/package.json b/package.json index 470ec84..1575bdc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "strftime", "description": "strftime for JavaScript", - "version": "0.8.2", + "version": "0.9.0", "homepage": "http://samhuri.net/proj/strftime", "author": "Sami Samhuri ", "contributors": [ From 6ab81c89cb988904697360d6d56f3a5721291e93 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 19:36:10 -0800 Subject: [PATCH 06/44] code style --- strftime.js | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/strftime.js b/strftime.js index 4efa4eb..f4c87ca 100644 --- a/strftime.js +++ b/strftime.js @@ -87,35 +87,36 @@ _customTimezoneOffset = customTimezoneOffset || 0, _useUtcBasedDate = useUtcTimezone || false, - // we store unix timestamp value here to not create new Date() each iteration (each millisecond) - // Date.now() is 2 times faster than new Date() - // while millisecond precise is enough here - // this could be very helpful when strftime triggered a lot of times one by one + // we store unix timestamp value here to not create new Date() each iteration (each millisecond) + // Date.now() is 2 times faster than new Date() + // while millisecond precise is enough here + // this could be very helpful when strftime triggered a lot of times one by one _cachedDateTimestamp = 0, _cachedDate; function _strftime(format, date) { var timestamp; - if(!date) { + if (!date) { var currentTimestamp = Date.now(); - if(currentTimestamp > _cachedDateTimestamp) { + if (currentTimestamp > _cachedDateTimestamp) { _cachedDateTimestamp = currentTimestamp; _cachedDate = new Date(_cachedDateTimestamp); timestamp = _cachedDateTimestamp; - if(_useUtcBasedDate) { + if (_useUtcBasedDate) { // how to avoid duplication of date instantiation for utc here? // we tied to getTimezoneOffset of the current date _cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset); } } date = _cachedDate; - } else { + } + else { timestamp = date.getTime(); - if(_useUtcBasedDate) { + if (_useUtcBasedDate) { date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset); } } @@ -133,7 +134,7 @@ var currentCharCode = format.charCodeAt(i); - if(isInScope === true) { + if (isInScope === true) { // '-' if (currentCharCode === 45) { padding = ''; @@ -442,7 +443,8 @@ customTimezoneOffset = sign * ((60 * hours) + minutes) * 60 * 1000; // in minutes: 420 - } else if (timezoneType === 'number'){ + } + else if (timezoneType === 'number') { customTimezoneOffset = timezone * 60 * 1000; } } From e16f49f4c06d55752adbf4e215870628c3aa2336 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 19:59:38 -0800 Subject: [PATCH 07/44] update readme for 0.9 API --- Readme.md | 67 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/Readme.md b/Readme.md index f61a89e..7fa2481 100644 --- a/Readme.md +++ b/Readme.md @@ -9,7 +9,15 @@ from Ruby. Installation ============ -npm install strftime + npm install strftime + + +The New API in 0.9 +================== + +The current version, 0.9, deprecates the older API that exported several functions: `strftimeTZ`, `strftimeUTC`, and `localizedStrftime`. In addition to this the exported function referenced itself as `require('strftime').strftime` for consistency with the other functions. *These functions are deprecated in 0.9 and will be removed in 1.0.* + +Now you only need the single object exported and you can create a specialized version of it using the functions `utc()`, `localize(locale)`, and `timezone(offset)`. You can no longer pass in a timezone or locale on each call to `strftime` which is a regression. If you need this let me know and we will add it back into the API. Usage @@ -24,40 +32,44 @@ If you want to localize it: var strftime = require('strftime') var it_IT = { - days: [ 'domenica', 'lunedi', 'martedi', 'mercoledi', 'giovedi', 'venerdi', 'sabato' ], - shortDays: [ 'dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab' ], - - months: [ 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', - 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre' ], - - shortMonths: [ 'gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', - 'set', 'ott', 'nov', 'dic' ], + days: ['domenica', 'lunedi', 'martedi', 'mercoledi', 'giovedi', 'venerdi', 'sabato'], + shortDays: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'], + months: ['gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'], + shortMonths: ['gen', 'feb', 'mar', 'apr', 'mag', 'giu', 'lug', 'ago', 'set', 'ott', 'nov', 'dic'], AM: 'AM', - PM: 'PM' + PM: 'PM', + am: 'am', + pm: 'pm', + formats: { + D: '%m/%d/%y', + F: '%Y-%m-%d', + R: '%H:%M', + r: '%I:%M:%S %p', + T: '%H:%M:%S', + v: '%e-%b-%Y' + } } - console.log(strftime('%B %d, %Y %H:%M:%S', it_IT)) // => aprile 28, 2011 18:21:08 - console.log(strftime('%B %d, %Y %H:%M:%S', new Date(1307472705067), it_IT)) // => giugno 7, 2011 18:51:45 - -And if you don't want to pass a localization object every time you can get a localized `strftime` function like so: - - var strftime = require('strftime') - var it_IT = { /* same as above */ } - var strftime_IT = strftime.localizedStrftime(it_IT) - console.log(strftime_IT('%B %d, %Y %H:%M:%S')) // aprile 28, 2011 18:21:08 + var strftimeIT = strftime.localize(it_IT) + console.log(strftimeIT('%B %d, %Y %H:%M:%S')) // => aprile 28, 2011 18:21:08 + console.log(strftimeIT('%B %d, %Y %H:%M:%S', new Date(1307472705067))) // => giugno 7, 2011 18:51:45 Time zones can be passed in as an offset from GMT in minutes. - var strftimeTZ = require('strftime').strftimeTZ - console.log(strftimeTZ('%B %d, %y %H:%M:%S', new Date(1307472705067), -420)) // => June 07, 11 11:51:45 - console.log(strftimeTZ('%F %T', new Date(1307472705067), 120)) // => 2011-06-07 20:51:45 + var strftime = require('strftime') + var strftimePDT = strftime.timezone(-420) + var strftimeCEST = strftime.timezone(120) + console.log(strftimePDT('%B %d, %y %H:%M:%S', new Date(1307472705067))) // => June 07, 11 11:51:45 + console.log(strftimeCEST('%F %T', new Date(1307472705067))) // => 2011-06-07 20:51:45 Alternatively you can use the timezone format used by ISO 8601, `+HHMM` or `-HHMM`. - var strftimeTZ = require('strftime').strftimeTZ - console.log(strftimeTZ('', new Date(1307472705067), '-0700')) // => June 07, 11 11:51:45 - console.log(strftimeTZ('%F %T', new Date(1307472705067), '+0200')) // => 2011-06-07 20:51:45 + var strftime = require('strftime') + var strftimePDT = strftime.timezone('-0700') + var strftimeCEST = strftime.timezone('+0200') + console.log(strftimePDT('', new Date(1307472705067))) // => June 07, 11 11:51:45 + console.log(strftimeCEST('%F %T', new Date(1307472705067))) // => 2011-06-07 20:51:45 Supported Specifiers @@ -120,16 +132,17 @@ solves some awkwardness with formats like `%l`. Contributors ============ +* [Rob Colburn](https://github.com/robcolburn) +* [Alexandr Nikitin](https://github.com/alexandrnikitin) * [Sami Samhuri](https://github.com/samsonjs) * [Andrew Schaaf](https://github.com/andrewschaaf) -* [Rob Colburn](https://github.com/robcolburn) * [Ryan Stafford](https://github.com/ryanstafford) License ======= -Copyright 2010 - 2013 Sami Samhuri sami@samhuri.net +Copyright 2010 - 2015 Sami Samhuri sami@samhuri.net [MIT license](http://sjs.mit-license.org) From 6bc6888fffa2215531ea53a97532f400fe0df207 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 20:49:37 -0800 Subject: [PATCH 08/44] add support for %c, %x, and %X (closes #43) based on @alexandrnikitin's commit here: https://github.com/alexandrnikitin/strftime/commit/f25c89bb0fdcc5cd9640c168ebd886c3fdff652e --- Readme.md | 24 +++++++++++++++--------- strftime.js | 23 ++++++++++++++++++++++- test/test.js | 16 ++++++++++++++-- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/Readme.md b/Readme.md index 7fa2481..9a9c86b 100644 --- a/Readme.md +++ b/Readme.md @@ -44,9 +44,12 @@ If you want to localize it: D: '%m/%d/%y', F: '%Y-%m-%d', R: '%H:%M', + X: '%T', + c: '%a %b %d %X %Y', r: '%I:%M:%S %p', T: '%H:%M:%S', - v: '%e-%b-%Y' + v: '%e-%b-%Y', + x: '%D' } } var strftimeIT = strftime.localize(it_IT) @@ -85,10 +88,11 @@ e.g. `%q` becomes `q`. Use `%%` to get a literal `%` sign. - B: full month name - b: abbreviated month name - C: AD century (year / 100), padded to 2 digits -- D: equivalent to `%m/%d/%y` +- c: equivalent to `%a %b %d %X %Y` in en-US (based on locale) +- D: equivalent to `%m/%d/%y` in en-US (based on locale) - d: day of the month, padded to 2 digits (01-31) - e: day of the month, padded with a leading space for single digit values (1-31) -- F: equivalent to `%Y-%m-%d` +- F: equivalent to `%Y-%m-%d` in en-US (based on locale) - H: the hour (24-hour clock), padded to 2 digits (00-23) - h: the same as %b (abbreviated month name) - I: the hour (12-hour clock), padded to 2 digits (01-12) @@ -100,19 +104,21 @@ e.g. `%q` becomes `q`. Use `%%` to get a literal `%` sign. - m: the month, padded to 2 digits (01-12) - n: newline character - o: day of the month as an ordinal (without padding), e.g. 1st, 2nd, 3rd, 4th, ... -- P: "am" or "pm" in lowercase [Ruby extension] -- p: "AM" or "PM" -- R: equivalent to `%H:%M` -- r: equivalent to `%I:%M:%S %p` +- P: "am" or "pm" in lowercase (Ruby extension, based on locale) +- p: "AM" or "PM" (based on locale) +- R: equivalent to `%H:%M` in en-US (based on locale) +- r: equivalent to `%I:%M:%S %p` in en-US (based on locale) - S: the second, padded to 2 digits (00-60) - s: the number of seconds since the Epoch, UTC -- T: equivalent to `%H:%M:%S` +- T: equivalent to `%H:%M:%S` in en-US (based on locale) - t: tab character - U: week number of the year, Sunday as the first day of the week, padded to 2 digits (00-53) - u: the weekday, Monday as the first day of the week (1-7) -- v: equivalent to `%e-%b-%Y` +- v: equivalent to `%e-%b-%Y` in en-US (based on locale) - W: week number of the year, Monday as the first day of the week, padded to 2 digits (00-53) - w: the weekday, Sunday as the first day of the week (0-6) +- X: equivalent to `%D` in en-US (based on locale) +- x: equivalent to `%T` in en-US (based on locale) - Y: the year with the century - y: the year without the century (00-99) - Z: the time zone name, replaced with an empty string if it is not found diff --git a/strftime.js b/strftime.js index f4c87ca..add6a49 100644 --- a/strftime.js +++ b/strftime.js @@ -27,8 +27,11 @@ F: '%Y-%m-%d', R: '%H:%M', T: '%H:%M:%S', + X: '%T', + c: '%a %b %d %X %Y', r: '%I:%M:%S %p', - v: '%e-%b-%Y' + v: '%e-%b-%Y', + x: '%D' } }, @@ -245,6 +248,12 @@ resultString += padTill2(weekNumber(date, 'monday'), padding); break; + // '16:00:00' + // case 'X': + case 88: + resultString += _processFormat(locale.formats.X, date, locale, timestamp); + break; + // '1970' // case 'Y': case 89: @@ -276,6 +285,12 @@ resultString += locale.shortMonths[date.getMonth()]; break; + // '' + // case 'c': + case 99: + resultString += _processFormat(locale.formats.c, date, locale, timestamp); + break; + // '01' // case 'd': case 100: @@ -375,6 +390,12 @@ resultString += date.getDay(); break; // 0 - 6, Sunday is first day of the week + // '12/31/69' + // case 'x': + case 120: + resultString += _processFormat(locale.formats.x, date, locale, timestamp); + break; + // '70' // case 'y': case 121: diff --git a/test/test.js b/test/test.js index 9ff0153..42911b3 100755 --- a/test/test.js +++ b/test/test.js @@ -46,13 +46,19 @@ ok('Exports'); if (process.env.TZ == 'America/Vancouver') { testTimezone('P[DS]T'); assert.format('%C', '01', '01', new Date(100, 0, 1)); + assert.format('%X', '11:51:45', '18:51:45'); + assert.format('%c', 'Tue Jun 07 11:51:45 2011', 'Tue Jun 07 18:51:45 2011'); assert.format('%j', '097', '098', new Date(1365390736236)); + assert.format('%x', '06/07/11'); ok('Time zones (' + process.env.TZ + ')'); } else if (process.env.TZ == 'CET') { testTimezone('CES?T'); assert.format('%C', '01', '00', new Date(100, 0, 1)); + assert.format('%X', '20:51:45', '18:51:45'); + assert.format('%c', 'Tue Jun 07 20:51:45 2011', 'Tue Jun 07 18:51:45 2011'); assert.format('%j', '098', '098', new Date(1365390736236)); + assert.format('%x', '06/07/11'); ok('Time zones (' + process.env.TZ + ')'); } else { @@ -127,9 +133,12 @@ var it_IT = { D: 'it$%m/%d/%y', F: 'it$%Y-%m-%d', R: 'it$%H:%M', - r: 'it$%I:%M:%S %p', T: 'it$%H:%M:%S', - v: 'it$%e-%b-%Y' + X: '%T', + c: '%a %b %d %X %Y', + r: 'it$%I:%M:%S %p', + v: 'it$%e-%b-%Y', + x: '%D' } }; @@ -144,6 +153,7 @@ assert.format_it('%A', 'martedi'); assert.format_it('%a', 'mar'); assert.format_it('%B', 'giugno'); assert.format_it('%b', 'giu'); +assert.format_it('%c', null, 'mar giu 07 it$18:51:45 2011'); assert.format_it('%D', 'it$06/07/11'); assert.format_it('%F', 'it$2011-06-07'); assert.format_it('%p', null, 'it$PM'); @@ -152,6 +162,8 @@ assert.format_it('%R', null, 'it$18:51'); assert.format_it('%r', null, 'it$06:51:45 it$PM'); assert.format_it('%T', null, 'it$18:51:45'); assert.format_it('%v', 'it$7-giu-2011'); +assert.format_it('%x', null, 'it$06/07/11'); +assert.format_it('%X', null, 'it$18:51:45'); ok('Localization'); From 603326eaed175b7bbaae655c930473bd261c4edb Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sat, 7 Feb 2015 20:51:33 -0800 Subject: [PATCH 09/44] code style and copyright --- strftime.js | 10 +++++----- test/test.js | 10 ++++------ 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/strftime.js b/strftime.js index add6a49..2c726d4 100644 --- a/strftime.js +++ b/strftime.js @@ -3,7 +3,7 @@ // github.com/samsonjs/strftime // @_sjs // -// Copyright 2010 - 2013 Sami Samhuri +// Copyright 2010 - 2015 Sami Samhuri // // MIT License // http://sjs.mit-license.org @@ -45,7 +45,7 @@ // Browsers and other environments else { // Get the global object. Works in ES3, ES5, and ES5 strict mode. - namespace = (function(){ return this || (1,eval)('this') }()); + namespace = (function(){ return this || (1,eval)('this'); }()); } // Deprecated API, to be removed in v1.0 @@ -71,18 +71,18 @@ } var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); return strftime(fmt, d); - } + }; namespace.strftimeUTC = function(fmt, d, locale) { deprecationWarning("strftimeUTC", "require('strftime').utc()(format, date)` or `require('strftime').localize(locale).utc()(format, date)"); var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).utc(); return strftime(fmt, d); - } + }; namespace.localizedStrftime = function(locale) { deprecationWarning("localizedStrftime", "require('strftime').localize(locale)"); return defaultStrftime.localize(locale); - } + }; // End of deprecated API function Strftime(locale, customTimezoneOffset, useUtcTimezone) { diff --git a/test/test.js b/test/test.js index 42911b3..d212402 100755 --- a/test/test.js +++ b/test/test.js @@ -18,9 +18,7 @@ assert.fn = function(value, msg) { function assertFormat(time, format, expected, name, strftime) { var actual = strftime(format, time); - assert.equal(expected, actual, - name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) - + ', expected ' + JSON.stringify(expected)); + assert.equal(expected, actual, name + '("' + format + '", ' + time + ') is ' + JSON.stringify(actual) + ', expected ' + JSON.stringify(expected)); } assert.format = function(format, expected, expectedUTC, time) { @@ -114,7 +112,7 @@ assert.format('%Y', '2011'); assert.format('%y', '11'); assert.format('%Z', null, 'GMT'); assert.format('%z', null, '+0000'); -assert.format('%%', '%') // any other char; +assert.format('%%', '%'); // any other char ok('GMT'); @@ -145,8 +143,8 @@ var it_IT = { var strftimeIT = strftime.localize(it_IT), strftimeITUTC = strftimeIT.utc(); assert.format_it = function(format, expected, expectedUTC) { - if (expected) { assertFormat(Time, format, expected, 'strftime.localize(it_IT)', strftimeIT) } - assertFormat(Time, format, expectedUTC || expected, 'strftime.localize(it_IT).utc()', strftimeITUTC) + if (expected) { assertFormat(Time, format, expected, 'strftime.localize(it_IT)', strftimeIT); } + assertFormat(Time, format, expectedUTC || expected, 'strftime.localize(it_IT).utc()', strftimeITUTC); }; assert.format_it('%A', 'martedi'); From 14ad6dc9021bea56ca53af87e8b1b7f0f63d8b91 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 8 Feb 2015 20:42:58 -0800 Subject: [PATCH 10/44] release v0.8.3 for bower --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 8ed1185..84ad15f 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "strftime", - "version": "0.8.2", + "version": "0.8.3", "main": "strftime.js", "ignore": [ "Readme.md", From 9e191bf5c6a60201c7493e45807c968074bec498 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 8 Feb 2015 20:44:15 -0800 Subject: [PATCH 11/44] ignore test directory in bower.json --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 84ad15f..ea48f3b 100644 --- a/bower.json +++ b/bower.json @@ -5,7 +5,7 @@ "ignore": [ "Readme.md", "Makefile", - "test/*", + "test", "*.json" ], "dependencies": {}, From b0a4d5a84a64cc887f80213fb8a2f68fc107c324 Mon Sep 17 00:00:00 2001 From: Alexandr Nikitin Date: Tue, 3 Mar 2015 12:26:23 +0200 Subject: [PATCH 12/44] Fix conversion of date to UTC Method based on one of SO answers: http://stackoverflow.com/questions/948532/how-do-you-convert-a-javascript-date-to-utc --- strftime.js | 14 ++++++++++---- test/test.js | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/strftime.js b/strftime.js index cdc5d45..6845863 100644 --- a/strftime.js +++ b/strftime.js @@ -279,10 +279,16 @@ }); } - function dateToUTC(d) { - var msDelta = (d.getTimezoneOffset() || 0) * 60000; - return new Date(d.getTime() + msDelta); - } + function dateToUTC(d) { + return new Date( + d.getUTCFullYear(), + d.getUTCMonth(), + d.getUTCDate(), + d.getUTCHours(), + d.getUTCMinutes(), + d.getUTCSeconds(), + d.getUTCMilliseconds()); + } var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; function quacksLikeDate(x) { diff --git a/test/test.js b/test/test.js index 48572cd..e2f2ec3 100755 --- a/test/test.js +++ b/test/test.js @@ -104,6 +104,7 @@ assert.format('%y', '11') assert.format('%Z', null, 'GMT') assert.format('%z', null, '+0000') assert.format('%%', '%') // any other char +assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)) ok('GMT') From f7799a1d216ddda62a8b156d9846ff65aa115533 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Wed, 4 Mar 2015 09:14:58 -0800 Subject: [PATCH 13/44] correct fuzzy interpretation of old years by new Date() --- strftime.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/strftime.js b/strftime.js index 6845863..1d06d10 100644 --- a/strftime.js +++ b/strftime.js @@ -280,14 +280,22 @@ } function dateToUTC(d) { - return new Date( - d.getUTCFullYear(), + var year = d.getUTCFullYear(); + var date = new Date( + year, d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds(), - d.getUTCMilliseconds()); + d.getUTCMilliseconds() + ); + // In old dates, years is incorrectly interpreted as a 2-digit year with base 1900. + // Correct this by setting the year explicitly after the fuzzy creation process. + if (date.getFullYear() != year) { + date.setFullYear(year); + } + return date; } var RequiredDateMethods = ['getTime', 'getTimezoneOffset', 'getDay', 'getDate', 'getMonth', 'getFullYear', 'getYear', 'getHours', 'getMinutes', 'getSeconds']; From 4de2693e51005eb8cefdebf747256fbedde74e45 Mon Sep 17 00:00:00 2001 From: Cory Heslip Date: Wed, 4 Mar 2015 16:50:39 -0700 Subject: [PATCH 14/44] added support for extended offset format --- strftime.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/strftime.js b/strftime.js index 1d06d10..2955183 100644 --- a/strftime.js +++ b/strftime.js @@ -114,8 +114,8 @@ // Most of the specifiers supported by C's strftime, and some from Ruby. // Some other syntax extensions from Ruby are supported: %-, %_, and %0 // to pad with nothing, space, or zero (respectively). - return fmt.replace(/%([-_0]?.)/g, function(_, c) { - var mod, padding; + return fmt.replace(/%([-_0:]?.)/g, function(_, c) { + var mod, padding, ext; if (c.length == 2) { mod = c[0]; @@ -131,6 +131,9 @@ else if (mod == '0') { padding = '0'; } + else if (mod == ":") { + ext = true; + } else { // unrecognized, return the format return _; @@ -267,11 +270,12 @@ // '+0000' case 'z': if (options.utc) { - return "+0000"; + return ext ? "+00:00" : "+0000"; } else { var off = typeof tz == 'number' ? tz : -d.getTimezoneOffset(); - return (off < 0 ? '-' : '+') + pad(Math.floor(Math.abs(off) / 60)) + pad(Math.abs(off) % 60); + var sep = ext ? ":" : ""; // separator for extended offset + return (off < 0 ? '-' : '+') + pad(Math.floor(Math.abs(off) / 60)) + sep + pad(Math.abs(off) % 60); } default: return c; From 1222467e47d310659f535ad95d0a578a737e54bb Mon Sep 17 00:00:00 2001 From: Cory Heslip Date: Wed, 4 Mar 2015 17:18:19 -0700 Subject: [PATCH 15/44] added tests and updated docs --- Readme.md | 5 +++-- test/test.js | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index f61a89e..ee67fd0 100644 --- a/Readme.md +++ b/Readme.md @@ -111,11 +111,12 @@ e.g. `%q` becomes `q`. Use `%%` to get a literal `%` sign. For more detail see `man 3 strftime` as the format specifiers should behave identically. If behaviour differs please [file a bug](https://github.com/samsonjs/strftime/issues/new). -Any specifier can be modified with `-`, `_`, or `0` as well, as in Ruby. +Any specifier can be modified with `-`, `_`, `0`, or `:` as well, as in Ruby. Using `%-` will omit any leading zeroes or spaces, `%_` will force spaces for padding instead of the default, and `%0` will force zeroes for padding. There's some redundancy here as `%-d` and `%e` have the same result, but it -solves some awkwardness with formats like `%l`. +solves some awkwardness with formats like `%l`. Using `%:` for time zone offset, +as in `%:z` will insert a colon as a delimiter. Contributors ============ diff --git a/test/test.js b/test/test.js index e2f2ec3..c6f91e9 100755 --- a/test/test.js +++ b/test/test.js @@ -103,6 +103,7 @@ assert.format('%Y', '2011') assert.format('%y', '11') assert.format('%Z', null, 'GMT') assert.format('%z', null, '+0000') +assert.format('%:z', null, '+00:00') assert.format('%%', '%') // any other char assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)) ok('GMT') @@ -175,6 +176,7 @@ assert.formatTZ('%F %r %z', '2011-06-07 08:51:45 PM +0200', '+0200') assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', -420) assert.formatTZ('%F %r %z', '2011-06-07 11:51:45 AM -0700', '-0700') assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730') +assert.formatTZ('%F %r %:z', '2011-06-07 11:21:45 AM -07:30', '-0730') ok('Time zone offset') @@ -221,5 +223,6 @@ function testTimezone(regex) { assert.format('%T', T, '18:51:45') assert.format('%Z', tz, 'GMT') assert.format('%z', sign + '0' + Math.abs(hourDiff) + '00', '+0000') + assert.format('%:z', sign + '0' + Math.abs(hourDiff) + ':00', '+00:00') } } From 49568677a7b24712308f52bef953094de7171bf5 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Thu, 5 Mar 2015 16:51:05 -0800 Subject: [PATCH 16/44] v0.8.4 --- bower.json | 2 +- component.json | 2 +- package.json | 2 +- strftime-min.js | 16 ++++++++-------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/bower.json b/bower.json index ea48f3b..0eb519b 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "strftime", - "version": "0.8.3", + "version": "0.8.4", "main": "strftime.js", "ignore": [ "Readme.md", diff --git a/component.json b/component.json index c3c352a..764f0e5 100644 --- a/component.json +++ b/component.json @@ -3,7 +3,7 @@ "repo": "samsonjs/strftime", "description": "strftime date formatting", "keywords": ["strftime", "format", "date", "time"], - "version": "0.8.2", + "version": "0.8.4", "main": "strftime.js", "scripts": ["strftime.js"] } diff --git a/package.json b/package.json index 9571a28..d488e82 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "strftime", "description": "strftime for JavaScript", - "version": "0.8.2", + "version": "0.8.4", "homepage": "http://samhuri.net/proj/strftime", "author": "Sami Samhuri ", "contributors": [ diff --git a/strftime-min.js b/strftime-min.js index afb03e1..2146911 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,8 +1,8 @@ -(function(){function i(c,a,b){return g(c,a,b)}function g(c,a,b,j){j=j||{};a&&!n(a)&&(b=a,a=void 0);a=a||new Date;b=b||o;b.formats=b.formats||{};var i=a.getTime(),h=j.timezone,e=typeof h;if(j.utc||e=="number"||e=="string")a=p(a);if(h){if(e=="string")var k=h[0]=="-"?-1:1,q=parseInt(h.slice(1,3),10),r=parseInt(h.slice(3,5),10),h=k*(60*q+r);e&&(a=new Date(a.getTime()+h*6E4))}return c.replace(/%([-_0]?.)/g,function(c,e){var d;if(e.length==2){d=e[0];if(d=="-")d="";else if(d=="_")d=" ";else if(d=="0")d= -"0";else return c;e=e[1]}switch(e){case "A":return b.days[a.getDay()];case "a":return b.shortDays[a.getDay()];case "B":return b.months[a.getMonth()];case "b":return b.shortMonths[a.getMonth()];case "C":return f(Math.floor(a.getFullYear()/100),d);case "D":return g(b.formats.D||"%m/%d/%y",a,b);case "d":return f(a.getDate(),d);case "e":return f(a.getDate(),d==null?" ":d);case "F":return g(b.formats.F||"%Y-%m-%d",a,b);case "H":return f(a.getHours(),d);case "h":return b.shortMonths[a.getMonth()];case "I":return f(l(a), -d);case "j":return d=new Date(a.getFullYear(),0,1),d=Math.ceil((a.getTime()-d.getTime())/864E5),f(d,3);case "k":return f(a.getHours(),d==null?" ":d);case "L":return f(Math.floor(i%1E3),3);case "l":return f(l(a),d==null?" ":d);case "M":return f(a.getMinutes(),d);case "m":return f(a.getMonth()+1,d);case "n":return"\n";case "o":return String(a.getDate())+s(a.getDate());case "P":return a.getHours()<12?b.am:b.pm;case "p":return a.getHours()<12?b.AM:b.PM;case "R":return g(b.formats.R||"%H:%M",a,b);case "r":return g(b.formats.r|| -"%I:%M:%S %p",a,b);case "S":return f(a.getSeconds(),d);case "s":return Math.floor(i/1E3);case "T":return g(b.formats.T||"%H:%M:%S",a,b);case "t":return"\t";case "U":return f(m(a,"sunday"),d);case "u":return d=a.getDay(),d==0?7:d;case "v":return g(b.formats.v||"%e-%b-%Y",a,b);case "W":return f(m(a,"monday"),d);case "w":return a.getDay();case "Y":return a.getFullYear();case "y":return d=String(a.getFullYear()),d.slice(d.length-2);case "Z":return j.utc?"GMT":(d=a.toString().match(/\(([\w\s]+)\)/))&& -d[1]||"";case "z":return j.utc?"+0000":(d=typeof h=="number"?h:-a.getTimezoneOffset(),(d<0?"-":"+")+f(Math.floor(Math.abs(d)/60))+f(Math.abs(d)%60));default:return e}})}function p(c){var a=(c.getTimezoneOffset()||0)*6E4;return new Date(c.getTime()+a)}function n(c){for(var a=0,b=k.length,a=0;a12&&(c-=12);return c}function s(c){var a=c%10;c%=100;if(c>=11&&c<=13||a===0||a>=4)return"th";switch(a){case 1:return"st";case 2:return"nd";case 3:return"rd"}}function m(c,a){var a=a||"sunday",b=c.getDay();a=="monday"&&(b==0?b=6:b--);var e=new Date(c.getFullYear(),0,1);return Math.floor(((c-e)/864E5+7-b)/7)}var e;e=typeof module!=="undefined"?module.exports=i:function(){return this||(0,eval)("this")}();var o={days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),shortDays:"Sun Mon Tue Wed Thu Fri Sat".split(" "), -months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),AM:"AM",PM:"PM",am:"am",pm:"pm"};e.strftime=i;e.strftimeTZ=i.strftimeTZ=function(c,a,b,e){if((typeof b=="number"||typeof b=="string")&&e==null)e=b,b=void 0;return g(c,a,b,{timezone:e})};e.strftimeUTC=i.strftimeUTC=function(c,a,b){return g(c,a,b,{utc:!0})};e.localizedStrftime=i.localizedStrftime=function(c){return function(a, -b){return g(a,b,c)}};var k=["getTime","getTimezoneOffset","getDay","getDate","getMonth","getFullYear","getYear","getHours","getMinutes","getSeconds"]})(); +(function(){function k(c,a,b){return h(c,a,b)}function h(c,a,b,l){l=l||{};a&&!p(a)&&(b=a,a=void 0);a=a||new Date;b=b||q;b.formats=b.formats||{};var k=a.getTime(),i=l.timezone,d=typeof i;if(l.utc||d=="number"||d=="string")a=r(a);if(i){if(d=="string")var m=i[0]=="-"?-1:1,s=parseInt(i.slice(1,3),10),t=parseInt(i.slice(3,5),10),i=m*(60*s+t);d&&(a=new Date(a.getTime()+i*6E4))}return c.replace(/%([-_0:]?.)/g,function(c,d){var j,e,g;if(d.length==2){j=d[0];if(j=="-")e="";else if(j=="_")e=" ";else if(j=="0")e= +"0";else if(j==":")g=!0;else return c;d=d[1]}switch(d){case "A":return b.days[a.getDay()];case "a":return b.shortDays[a.getDay()];case "B":return b.months[a.getMonth()];case "b":return b.shortMonths[a.getMonth()];case "C":return f(Math.floor(a.getFullYear()/100),e);case "D":return h(b.formats.D||"%m/%d/%y",a,b);case "d":return f(a.getDate(),e);case "e":return f(a.getDate(),e==null?" ":e);case "F":return h(b.formats.F||"%Y-%m-%d",a,b);case "H":return f(a.getHours(),e);case "h":return b.shortMonths[a.getMonth()]; +case "I":return f(n(a),e);case "j":return g=new Date(a.getFullYear(),0,1),g=Math.ceil((a.getTime()-g.getTime())/864E5),f(g,3);case "k":return f(a.getHours(),e==null?" ":e);case "L":return f(Math.floor(k%1E3),3);case "l":return f(n(a),e==null?" ":e);case "M":return f(a.getMinutes(),e);case "m":return f(a.getMonth()+1,e);case "n":return"\n";case "o":return String(a.getDate())+u(a.getDate());case "P":return a.getHours()<12?b.am:b.pm;case "p":return a.getHours()<12?b.AM:b.PM;case "R":return h(b.formats.R|| +"%H:%M",a,b);case "r":return h(b.formats.r||"%I:%M:%S %p",a,b);case "S":return f(a.getSeconds(),e);case "s":return Math.floor(k/1E3);case "T":return h(b.formats.T||"%H:%M:%S",a,b);case "t":return"\t";case "U":return f(o(a,"sunday"),e);case "u":return g=a.getDay(),g==0?7:g;case "v":return h(b.formats.v||"%e-%b-%Y",a,b);case "W":return f(o(a,"monday"),e);case "w":return a.getDay();case "Y":return a.getFullYear();case "y":return g=String(a.getFullYear()),g.slice(g.length-2);case "Z":return l.utc?"GMT": +(g=a.toString().match(/\(([\w\s]+)\)/))&&g[1]||"";case "z":return l.utc?g?"+00:00":"+0000":(j=typeof i=="number"?i:-a.getTimezoneOffset(),(j<0?"-":"+")+f(Math.floor(Math.abs(j)/60))+(g?":":"")+f(Math.abs(j)%60));default:return d}})}function r(c){var a=c.getUTCFullYear(),c=new Date(a,c.getUTCMonth(),c.getUTCDate(),c.getUTCHours(),c.getUTCMinutes(),c.getUTCSeconds(),c.getUTCMilliseconds());c.getFullYear()!=a&&c.setFullYear(a);return c}function p(c){for(var a=0,b=m.length,a=0;a12&&(c-=12);return c}function u(c){var a=c%10;c%=100;if(c>=11&&c<=13||a===0||a>=4)return"th";switch(a){case 1:return"st";case 2:return"nd";case 3:return"rd"}}function o(c,a){var a=a||"sunday",b=c.getDay();a=="monday"&&(b==0?b=6:b--);var d=new Date(c.getFullYear(),0,1);return Math.floor(((c-d)/864E5+7-b)/7)} +var d;d=typeof module!=="undefined"?module.exports=k:function(){return this||(0,eval)("this")}();var q={days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),shortDays:"Sun Mon Tue Wed Thu Fri Sat".split(" "),months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),AM:"AM",PM:"PM",am:"am",pm:"pm"};d.strftime=k;d.strftimeTZ=k.strftimeTZ=function(c,a,b,d){if((typeof b== +"number"||typeof b=="string")&&d==null)d=b,b=void 0;return h(c,a,b,{timezone:d})};d.strftimeUTC=k.strftimeUTC=function(c,a,b){return h(c,a,b,{utc:!0})};d.localizedStrftime=k.localizedStrftime=function(c){return function(a,b){return h(a,b,c)}};var m=["getTime","getTimezoneOffset","getDay","getDate","getMonth","getFullYear","getYear","getHours","getMinutes","getSeconds"]})(); From ff9b94b3d9d474e654dc15a68ec842d156bfe0f7 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Thu, 5 Mar 2015 17:02:53 -0800 Subject: [PATCH 17/44] minify & update bower.json --- bower.json | 2 +- strftime-min.js | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/bower.json b/bower.json index 0eb519b..70663f6 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "strftime", - "version": "0.8.4", + "version": "0.9.0", "main": "strftime.js", "ignore": [ "Readme.md", diff --git a/strftime-min.js b/strftime-min.js index 2146911..d00e090 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,8 +1,10 @@ -(function(){function k(c,a,b){return h(c,a,b)}function h(c,a,b,l){l=l||{};a&&!p(a)&&(b=a,a=void 0);a=a||new Date;b=b||q;b.formats=b.formats||{};var k=a.getTime(),i=l.timezone,d=typeof i;if(l.utc||d=="number"||d=="string")a=r(a);if(i){if(d=="string")var m=i[0]=="-"?-1:1,s=parseInt(i.slice(1,3),10),t=parseInt(i.slice(3,5),10),i=m*(60*s+t);d&&(a=new Date(a.getTime()+i*6E4))}return c.replace(/%([-_0:]?.)/g,function(c,d){var j,e,g;if(d.length==2){j=d[0];if(j=="-")e="";else if(j=="_")e=" ";else if(j=="0")e= -"0";else if(j==":")g=!0;else return c;d=d[1]}switch(d){case "A":return b.days[a.getDay()];case "a":return b.shortDays[a.getDay()];case "B":return b.months[a.getMonth()];case "b":return b.shortMonths[a.getMonth()];case "C":return f(Math.floor(a.getFullYear()/100),e);case "D":return h(b.formats.D||"%m/%d/%y",a,b);case "d":return f(a.getDate(),e);case "e":return f(a.getDate(),e==null?" ":e);case "F":return h(b.formats.F||"%Y-%m-%d",a,b);case "H":return f(a.getHours(),e);case "h":return b.shortMonths[a.getMonth()]; -case "I":return f(n(a),e);case "j":return g=new Date(a.getFullYear(),0,1),g=Math.ceil((a.getTime()-g.getTime())/864E5),f(g,3);case "k":return f(a.getHours(),e==null?" ":e);case "L":return f(Math.floor(k%1E3),3);case "l":return f(n(a),e==null?" ":e);case "M":return f(a.getMinutes(),e);case "m":return f(a.getMonth()+1,e);case "n":return"\n";case "o":return String(a.getDate())+u(a.getDate());case "P":return a.getHours()<12?b.am:b.pm;case "p":return a.getHours()<12?b.AM:b.PM;case "R":return h(b.formats.R|| -"%H:%M",a,b);case "r":return h(b.formats.r||"%I:%M:%S %p",a,b);case "S":return f(a.getSeconds(),e);case "s":return Math.floor(k/1E3);case "T":return h(b.formats.T||"%H:%M:%S",a,b);case "t":return"\t";case "U":return f(o(a,"sunday"),e);case "u":return g=a.getDay(),g==0?7:g;case "v":return h(b.formats.v||"%e-%b-%Y",a,b);case "W":return f(o(a,"monday"),e);case "w":return a.getDay();case "Y":return a.getFullYear();case "y":return g=String(a.getFullYear()),g.slice(g.length-2);case "Z":return l.utc?"GMT": -(g=a.toString().match(/\(([\w\s]+)\)/))&&g[1]||"";case "z":return l.utc?g?"+00:00":"+0000":(j=typeof i=="number"?i:-a.getTimezoneOffset(),(j<0?"-":"+")+f(Math.floor(Math.abs(j)/60))+(g?":":"")+f(Math.abs(j)%60));default:return d}})}function r(c){var a=c.getUTCFullYear(),c=new Date(a,c.getUTCMonth(),c.getUTCDate(),c.getUTCHours(),c.getUTCMinutes(),c.getUTCSeconds(),c.getUTCMilliseconds());c.getFullYear()!=a&&c.setFullYear(a);return c}function p(c){for(var a=0,b=m.length,a=0;a12&&(c-=12);return c}function u(c){var a=c%10;c%=100;if(c>=11&&c<=13||a===0||a>=4)return"th";switch(a){case 1:return"st";case 2:return"nd";case 3:return"rd"}}function o(c,a){var a=a||"sunday",b=c.getDay();a=="monday"&&(b==0?b=6:b--);var d=new Date(c.getFullYear(),0,1);return Math.floor(((c-d)/864E5+7-b)/7)} -var d;d=typeof module!=="undefined"?module.exports=k:function(){return this||(0,eval)("this")}();var q={days:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),shortDays:"Sun Mon Tue Wed Thu Fri Sat".split(" "),months:"January February March April May June July August September October November December".split(" "),shortMonths:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),AM:"AM",PM:"PM",am:"am",pm:"pm"};d.strftime=k;d.strftimeTZ=k.strftimeTZ=function(c,a,b,d){if((typeof b== -"number"||typeof b=="string")&&d==null)d=b,b=void 0;return h(c,a,b,{timezone:d})};d.strftimeUTC=k.strftimeUTC=function(c,a,b){return h(c,a,b,{utc:!0})};d.localizedStrftime=k.localizedStrftime=function(c){return function(a,b){return h(a,b,c)}};var m=["getTime","getTimezoneOffset","getDay","getDate","getMonth","getFullYear","getYear","getHours","getMinutes","getSeconds"]})(); +(function(){function h(a,d){q[a]||(console.warn("[WARNING] `require('strftime')."+a+"` is deprecated and will be removed in version 1.0. Instead, use `"+d+"`."),q[a]=!0)}function p(a,d,i){function m(a,b,f,k){for(var c="",e=null,d=!1,i=a.length,j=!1,g=0;g99?Math.floor(k%1E3):Math.floor(k%1E3)>9?"0"+Math.floor(k%1E3):"00"+Math.floor(k%1E3);break;case 77:c+=l(b.getMinutes(),e);break;case 80:c+=b.getHours()<12?f.am:f.pm;break;case 82:c+=m(f.formats.R,b,f,k);break;case 83:c+=l(b.getSeconds(),e);break;case 84:c+=m(f.formats.T,b,f,k);break;case 85:c+=l(s(b,"sunday"), +e);break;case 87:c+=l(s(b,"monday"),e);break;case 88:c+=m(f.formats.X,b,f,k);break;case 89:c+=b.getFullYear();break;case 90:o&&n===0?c+="GMT":(e=b.toString().match(/\((\w+)\)/),c+=e&&e[1]||"");break;case 97:c+=f.shortDays[b.getDay()];break;case 98:c+=f.shortMonths[b.getMonth()];break;case 99:c+=m(f.formats.c,b,f,k);break;case 100:c+=l(b.getDate(),e);break;case 101:c+=l(b.getDate(),e==null?" ":e);break;case 104:c+=f.shortMonths[b.getMonth()];break;case 106:e=new Date(b.getFullYear(),0,1);e=Math.ceil((b.getTime()- +e.getTime())/864E5);c+=e>99?e:e>9?"0"+e:"00"+e;break;case 107:c+=l(b.getHours(),e==null?" ":e);break;case 108:c+=l(r(b.getHours()),e==null?" ":e);break;case 109:c+=l(b.getMonth()+1,e);break;case 110:c+="\n";break;case 111:c+=String(b.getDate())+u(b.getDate());break;case 112:c+=b.getHours()<12?f.AM:f.PM;break;case 114:c+=m(f.formats.r,b,f,k);break;case 115:c+=Math.floor(k/1E3);break;case 116:c+="\t";break;case 117:e=b.getDay();c+=e===0?7:e;break;case 118:c+=m(f.formats.v,b,f,k);break;case 119:c+=b.getDay(); +break;case 120:c+=m(f.formats.x,b,f,k);break;case 121:c+=(""+b.getFullYear()).slice(2);break;case 122:o&&n===0?c+=j?"+00:00":"+0000":(e=n!==0?n/6E4:-b.getTimezoneOffset(),d=j?":":"",h=Math.abs(e%60),c+=(e<0?"-":"+")+l(Math.floor(Math.abs(e/60)))+d+l(h));break;default:c+=a[g]}e=null;d=!1}else h===37?d=!0:c+=a[g]}return c}var j=a||t,n=d||0,o=i||!1,g=0,h,a=function(a,b){var f;if(b)f=b.getTime(),o&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+n));else{var d=Date.now();d>g&&(g=d,h=new Date(g), +f=g,o&&(h=new Date(g+(h.getTimezoneOffset()||0)*6E4+n)));b=h}return m(a,b,j,f)};a.localize=function(a){return new p(a||j,n,o)};a.timezone=function(a){var b=n,f=o,d=typeof a;if(d==="number"||d==="string")f=!0,d==="string"?(b=a[0]==="-"?-1:1,d=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*d+a)*6E4):d==="number"&&(b=a*6E4);return new p(j,b,f)};a.utc=function(){return new p(j,n,!0)};return a}function l(a,d){if(d===""||a>9)return a;d==null&&(d="0");return d+a}function r(a){if(a===0)return 12; +else if(a>12)return a-12;return a}function s(a,d){var d=d||"sunday",i=a.getDay();d==="monday"&&(i===0?i=6:i--);var h=new Date(a.getFullYear(),0,1);return Math.floor(((a-h)/864E5+7-i)/7)}function u(a){var d=a%10;a%=100;if(a>=11&&a<=13||d===0||d>=4)return"th";switch(d){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var g,t={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March", +"April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},j=new p(t,0,!1);g=typeof module!=="undefined"?module.exports=j:function(){return this||(0,eval)("this")}();var q={};g.strftime=function(a,d,i){h("strftime","require('strftime')(format, date)` or `require('strftime').localize(locale)(format, date)"); +return(i?j.localize(i):j)(a,d)};g.strftimeTZ=function(a,d,i,g){h("strftimeTZ","require('strftime').timezone(tz)(format, date)` or `require('strftime').timezone(tz).localize(locale)(format, date)");if((typeof i=="number"||typeof i=="string")&&g==null)g=i,i=void 0;return(i?j.localize(i):j).timezone(g)(a,d)};g.strftimeUTC=function(a,d,g){h("strftimeUTC","require('strftime').utc()(format, date)` or `require('strftime').localize(locale).utc()(format, date)");return(g?j.localize(g):j).utc()(a,d)};g.localizedStrftime= +function(a){h("localizedStrftime","require('strftime').localize(locale)");return j.localize(a)}})(); From 6bf19b4454bfb07d97b844d5593694f8bd762a47 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Thu, 5 Mar 2015 18:29:15 -0800 Subject: [PATCH 18/44] remove test directory --- Makefile | 8 ++++---- test/test.js => test.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename test/test.js => test.js (99%) diff --git a/Makefile b/Makefile index d3e3124..9a5354d 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,11 @@ real-minify: strftime.js closure |strftime-min.js test: - TZ=America/Vancouver node test/test.js - TZ=CET node test/test.js + TZ=America/Vancouver node test.js + TZ=CET node test.js test-minified: minify - TZ=America/Vancouver node test/test.js ../strftime-min.js - TZ=CET node test/test.js ../strftime-min.js + TZ=America/Vancouver node test.js ./strftime-min.js + TZ=CET node test.js ./strftime-min.js .PHONY: test test-minified diff --git a/test/test.js b/test.js similarity index 99% rename from test/test.js rename to test.js index f26d137..0b0a974 100755 --- a/test/test.js +++ b/test.js @@ -7,7 +7,7 @@ // - look for edge cases var assert = require('assert'), - libFilename = process.argv[2] || '../strftime.js', + libFilename = process.argv[2] || './strftime.js', strftime = require(libFilename), strftimeUTC = strftime.utc(), Time = new Date(1307472705067); // Tue, 07 Jun 2011 18:51:45 GMT From 23cd5feb982870636724cdd06d2c7a480dd59226 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 14:46:41 -0700 Subject: [PATCH 19/44] code formatting / nitpicks --- strftime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strftime.js b/strftime.js index bed30ae..00c877a 100644 --- a/strftime.js +++ b/strftime.js @@ -45,7 +45,7 @@ // Browsers and other environments else { // Get the global object. Works in ES3, ES5, and ES5 strict mode. - namespace = (function(){ return this || (1,eval)('this'); }()); + namespace = (function() { return this || (1,eval)('this'); }()); } // Deprecated API, to be removed in v1.0 From bfe34d92b5675b236af581ddb7e0bf77f213f268 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 14:48:16 -0700 Subject: [PATCH 20/44] polyfill Date.now for old browsers --- strftime.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/strftime.js b/strftime.js index 00c877a..5d45d8d 100644 --- a/strftime.js +++ b/strftime.js @@ -85,6 +85,13 @@ }; // End of deprecated API + // Polyfill Date.now for old browsers. + if (typeof Date.now !== 'function') { + Date.now = function() { + return +new Date(); + }; + } + function Strftime(locale, customTimezoneOffset, useUtcTimezone) { var _locale = locale || DefaultLocale, _customTimezoneOffset = customTimezoneOffset || 0, From c6464d013084094c1460afc3f83581eb817ff61c Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 14:49:10 -0700 Subject: [PATCH 21/44] make the CommonJS / Node export backwards compatible also improves deprecation notices --- strftime.js | 83 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/strftime.js b/strftime.js index 5d45d8d..977a76c 100644 --- a/strftime.js +++ b/strftime.js @@ -11,9 +11,7 @@ ;(function() { - //// Where to export the API - var namespace, - DefaultLocale = { + var DefaultLocale = { days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], @@ -34,53 +32,96 @@ x: '%D' } }, - - defaultStrftime = new Strftime(DefaultLocale, 0, false); + defaultStrftime = new Strftime(DefaultLocale, 0, false), + isCommonJS = typeof module !== 'undefined', + namespace; // CommonJS / Node module - if (typeof module !== 'undefined') { - namespace = module.exports = defaultStrftime; + if (isCommonJS) { + namespace = module.exports = adaptedStrftime; + namespace.strftime = deprecatedStrftime; } - // Browsers and other environments else { // Get the global object. Works in ES3, ES5, and ES5 strict mode. namespace = (function() { return this || (1,eval)('this'); }()); + namespace.strftime = adaptedStrftime; } // Deprecated API, to be removed in v1.0 + var _require = isCommonJS ? "require('strftime')" : "strftime"; var _deprecationWarnings = {}; function deprecationWarning(name, instead) { if (!_deprecationWarnings[name]) { - console.warn("[WARNING] `require('strftime')." + name + "` is deprecated and will be removed in version 1.0. Instead, use `" + instead + "`."); + if (typeof console !== 'undefined' && typeof console.warn == 'function') { + console.warn("[WARNING] " + name + " is deprecated and will be removed in version 1.0. Instead, use `" + instead + "`."); + } _deprecationWarnings[name] = true; } } - namespace.strftime = function(fmt, d, locale) { - deprecationWarning("strftime", "require('strftime')(format, date)` or `require('strftime').localize(locale)(format, date)"); + namespace.strftimeTZ = deprecatedStrftimeTZ; + namespace.strftimeUTC = deprecatedStrftimeUTC; + namespace.localizedStrftime = deprecatedStrftimeLocalized; + + // Adapt the old API while preserving the new API. + function adaptForwards(fn) { + fn.localize = defaultStrftime.localize.bind(defaultStrftime); + fn.timezone = defaultStrftime.timezone.bind(defaultStrftime); + fn.utc = defaultStrftime.utc.bind(defaultStrftime); + } + + adaptForwards(adaptedStrftime); + function adaptedStrftime(fmt, d, locale) { + if (locale) { + deprecationWarning("`" + _require + "(format, date, locale)`", _require + ".localize(locale)(format, [date])"); + } var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime; return strftime(fmt, d); - }; - - namespace.strftimeTZ = function(fmt, d, locale, timezone) { - deprecationWarning("strftimeTZ", "require('strftime').timezone(tz)(format, date)` or `require('strftime').timezone(tz).localize(locale)(format, date)"); + } + + adaptForwards(deprecatedStrftime); + function deprecatedStrftime(fmt, d, locale) { + if (locale) { + deprecationWarning("`" + _require + ".strftime(format, date, locale)`", _require + ".localize(locale)(format, [date])"); + } + else { + deprecationWarning("`" + _require + ".strftime(format, [date])`", _require + "(format, [date])"); + } + var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime; + return strftime(fmt, d); + } + + function deprecatedStrftimeTZ(fmt, d, locale, timezone) { if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { timezone = locale; locale = undefined; } - var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); + + if (locale) { + deprecationWarning("`" + _require + ".strftimeTZ(format, date, locale, tz)`", _require + ".timezone(tz).localize(locale)(format, [date])"); + } + else { + deprecationWarning("`" + _require + ".strftimeTZ(format, date, tz)`", _require + ".timezone(tz)(format, [date])"); + } + + var strftime = (locale ? defaultStrftime.timezone(timezone).localize(locale) : defaultStrftime).timezone(timezone); return strftime(fmt, d); }; - namespace.strftimeUTC = function(fmt, d, locale) { - deprecationWarning("strftimeUTC", "require('strftime').utc()(format, date)` or `require('strftime').localize(locale).utc()(format, date)"); - var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).utc(); + function deprecatedStrftimeUTC(fmt, d, locale) { + if (locale) { + deprecationWarning("`" + _require + ".strftimeUTC(format, date, locale)`", _require + ".localize(locale).utc()(format, [date])"); + } + else { + deprecationWarning("`" + _require + ".strftimeUTC(format, [date])`", _require + ".utc()(format, [date])"); + } + var strftime = (locale ? defaultStrftime.utc().localize(locale) : defaultStrftime).utc(); return strftime(fmt, d); }; - namespace.localizedStrftime = function(locale) { - deprecationWarning("localizedStrftime", "require('strftime').localize(locale)"); + function deprecatedStrftimeLocalized(locale) { + deprecationWarning("`" + _require + ".localizedStrftime(locale)`", _require + ".localize(locale)"); return defaultStrftime.localize(locale); }; // End of deprecated API From 1403c1e6a6599162026367f926792725a13ad36f Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 15:43:13 -0700 Subject: [PATCH 22/44] don't ignore browsers in the readme --- Readme.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 7725f2b..3fd3723 100644 --- a/Readme.md +++ b/Readme.md @@ -15,7 +15,7 @@ Installation The New API in 0.9 ================== -The current version, 0.9, deprecates the older API that exported several functions: `strftimeTZ`, `strftimeUTC`, and `localizedStrftime`. In addition to this the exported function referenced itself as `require('strftime').strftime` for consistency with the other functions. *These functions are deprecated in 0.9 and will be removed in 1.0.* +The current version, 0.9, deprecates the older API that exported several functions: `strftimeTZ`, `strftimeUTC`, and `localizedStrftime`. In addition to this the exported function referenced itself as `require('strftime').strftime` or `window.strftime.strftime` for consistency with the other functions. *These functions are deprecated in 0.9 and will be removed in 1.0.* Now you only need the single object exported and you can create a specialized version of it using the functions `utc()`, `localize(locale)`, and `timezone(offset)`. You can no longer pass in a timezone or locale on each call to `strftime` which is a regression. If you need this let me know and we will add it back into the API. @@ -23,14 +23,14 @@ Now you only need the single object exported and you can create a specialized ve Usage ===== - var strftime = require('strftime') + var strftime = require('strftime') // not required in browsers console.log(strftime('%B %d, %Y %H:%M:%S')) // => April 28, 2011 18:21:08 console.log(strftime('%F %T', new Date(1307472705067))) // => 2011-06-07 18:51:45 If you want to localize it: - var strftime = require('strftime') + var strftime = require('strftime') // not required in browsers var it_IT = { days: ['domenica', 'lunedi', 'martedi', 'mercoledi', 'giovedi', 'venerdi', 'sabato'], shortDays: ['dom', 'lun', 'mar', 'mer', 'gio', 'ven', 'sab'], @@ -59,7 +59,7 @@ If you want to localize it: Time zones can be passed in as an offset from GMT in minutes. - var strftime = require('strftime') + var strftime = require('strftime') // not required in browsers var strftimePDT = strftime.timezone(-420) var strftimeCEST = strftime.timezone(120) console.log(strftimePDT('%B %d, %y %H:%M:%S', new Date(1307472705067))) // => June 07, 11 11:51:45 @@ -68,7 +68,7 @@ Time zones can be passed in as an offset from GMT in minutes. Alternatively you can use the timezone format used by ISO 8601, `+HHMM` or `-HHMM`. - var strftime = require('strftime') + var strftime = require('strftime') // not required in browsers var strftimePDT = strftime.timezone('-0700') var strftimeCEST = strftime.timezone('+0200') console.log(strftimePDT('', new Date(1307472705067))) // => June 07, 11 11:51:45 From e6b696cabd2488731984a48470fcc96a506c9fee Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 15:44:00 -0700 Subject: [PATCH 23/44] minify --- strftime-min.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/strftime-min.js b/strftime-min.js index d00e090..0cbe605 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,10 +1,11 @@ -(function(){function h(a,d){q[a]||(console.warn("[WARNING] `require('strftime')."+a+"` is deprecated and will be removed in version 1.0. Instead, use `"+d+"`."),q[a]=!0)}function p(a,d,i){function m(a,b,f,k){for(var c="",e=null,d=!1,i=a.length,j=!1,g=0;g99?Math.floor(k%1E3):Math.floor(k%1E3)>9?"0"+Math.floor(k%1E3):"00"+Math.floor(k%1E3);break;case 77:c+=l(b.getMinutes(),e);break;case 80:c+=b.getHours()<12?f.am:f.pm;break;case 82:c+=m(f.formats.R,b,f,k);break;case 83:c+=l(b.getSeconds(),e);break;case 84:c+=m(f.formats.T,b,f,k);break;case 85:c+=l(s(b,"sunday"), -e);break;case 87:c+=l(s(b,"monday"),e);break;case 88:c+=m(f.formats.X,b,f,k);break;case 89:c+=b.getFullYear();break;case 90:o&&n===0?c+="GMT":(e=b.toString().match(/\((\w+)\)/),c+=e&&e[1]||"");break;case 97:c+=f.shortDays[b.getDay()];break;case 98:c+=f.shortMonths[b.getMonth()];break;case 99:c+=m(f.formats.c,b,f,k);break;case 100:c+=l(b.getDate(),e);break;case 101:c+=l(b.getDate(),e==null?" ":e);break;case 104:c+=f.shortMonths[b.getMonth()];break;case 106:e=new Date(b.getFullYear(),0,1);e=Math.ceil((b.getTime()- -e.getTime())/864E5);c+=e>99?e:e>9?"0"+e:"00"+e;break;case 107:c+=l(b.getHours(),e==null?" ":e);break;case 108:c+=l(r(b.getHours()),e==null?" ":e);break;case 109:c+=l(b.getMonth()+1,e);break;case 110:c+="\n";break;case 111:c+=String(b.getDate())+u(b.getDate());break;case 112:c+=b.getHours()<12?f.AM:f.PM;break;case 114:c+=m(f.formats.r,b,f,k);break;case 115:c+=Math.floor(k/1E3);break;case 116:c+="\t";break;case 117:e=b.getDay();c+=e===0?7:e;break;case 118:c+=m(f.formats.v,b,f,k);break;case 119:c+=b.getDay(); -break;case 120:c+=m(f.formats.x,b,f,k);break;case 121:c+=(""+b.getFullYear()).slice(2);break;case 122:o&&n===0?c+=j?"+00:00":"+0000":(e=n!==0?n/6E4:-b.getTimezoneOffset(),d=j?":":"",h=Math.abs(e%60),c+=(e<0?"-":"+")+l(Math.floor(Math.abs(e/60)))+d+l(h));break;default:c+=a[g]}e=null;d=!1}else h===37?d=!0:c+=a[g]}return c}var j=a||t,n=d||0,o=i||!1,g=0,h,a=function(a,b){var f;if(b)f=b.getTime(),o&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+n));else{var d=Date.now();d>g&&(g=d,h=new Date(g), -f=g,o&&(h=new Date(g+(h.getTimezoneOffset()||0)*6E4+n)));b=h}return m(a,b,j,f)};a.localize=function(a){return new p(a||j,n,o)};a.timezone=function(a){var b=n,f=o,d=typeof a;if(d==="number"||d==="string")f=!0,d==="string"?(b=a[0]==="-"?-1:1,d=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*d+a)*6E4):d==="number"&&(b=a*6E4);return new p(j,b,f)};a.utc=function(){return new p(j,n,!0)};return a}function l(a,d){if(d===""||a>9)return a;d==null&&(d="0");return d+a}function r(a){if(a===0)return 12; -else if(a>12)return a-12;return a}function s(a,d){var d=d||"sunday",i=a.getDay();d==="monday"&&(i===0?i=6:i--);var h=new Date(a.getFullYear(),0,1);return Math.floor(((a-h)/864E5+7-i)/7)}function u(a){var d=a%10;a%=100;if(a>=11&&a<=13||d===0||d>=4)return"th";switch(d){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var g,t={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March", -"April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},j=new p(t,0,!1);g=typeof module!=="undefined"?module.exports=j:function(){return this||(0,eval)("this")}();var q={};g.strftime=function(a,d,i){h("strftime","require('strftime')(format, date)` or `require('strftime').localize(locale)(format, date)"); -return(i?j.localize(i):j)(a,d)};g.strftimeTZ=function(a,d,i,g){h("strftimeTZ","require('strftime').timezone(tz)(format, date)` or `require('strftime').timezone(tz).localize(locale)(format, date)");if((typeof i=="number"||typeof i=="string")&&g==null)g=i,i=void 0;return(i?j.localize(i):j).timezone(g)(a,d)};g.strftimeUTC=function(a,d,g){h("strftimeUTC","require('strftime').utc()(format, date)` or `require('strftime').localize(locale).utc()(format, date)");return(g?j.localize(g):j).utc()(a,d)};g.localizedStrftime= -function(a){h("localizedStrftime","require('strftime').localize(locale)");return j.localize(a)}})(); +(function(){function k(a,e){s[a]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+a+" is deprecated and will be removed in version 1.0. Instead, use `"+e+"`."),s[a]=!0)}function t(a){a.localize=g.localize.bind(g);a.timezone=g.timezone.bind(g);a.utc=g.utc.bind(g)}function r(a,e,c){c&&k("`"+i+"(format, date, locale)`",i+".localize(locale)(format, [date])");return(c?g.localize(c):g)(a,e)}function u(a,e,c){c?k("`"+i+".strftime(format, date, locale)`",i+".localize(locale)(format, [date])"): +k("`"+i+".strftime(format, [date])`",i+"(format, [date])");return(c?g.localize(c):g)(a,e)}function p(a,e,c){function m(a,b,h,c){for(var d="",f=null,e=!1,i=a.length,j=!1,o=0;o99?Math.floor(c%1E3):Math.floor(c%1E3)>9?"0"+Math.floor(c%1E3):"00"+Math.floor(c%1E3);break;case 77:d+=l(b.getMinutes(),f);break;case 80:d+=b.getHours()<12?h.am:h.pm;break;case 82:d+=m(h.formats.R,b,h,c);break;case 83:d+=l(b.getSeconds(),f);break;case 84:d+=m(h.formats.T,b,h,c);break;case 85:d+=l(w(b,"sunday"),f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=m(h.formats.X,b,h,c); +break;case 89:d+=b.getFullYear();break;case 90:k&&g===0?d+="GMT":(f=b.toString().match(/\((\w+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=m(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()-f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+= +l(b.getHours(),f==null?" ":f);break;case 108:d+=l(v(b.getHours()),f==null?" ":f);break;case 109:d+=l(b.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(b.getDate())+z(b.getDate());break;case 112:d+=b.getHours()<12?h.AM:h.PM;break;case 114:d+=m(h.formats.r,b,h,c);break;case 115:d+=Math.floor(c/1E3);break;case 116:d+="\t";break;case 117:f=b.getDay();d+=f===0?7:f;break;case 118:d+=m(h.formats.v,b,h,c);break;case 119:d+=b.getDay();break;case 120:d+=m(h.formats.x,b,h,c);break;case 121:d+= +(""+b.getFullYear()).slice(2);break;case 122:k&&g===0?d+=j?"+00:00":"+0000":(f=g!==0?g/6E4:-b.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=a[o]}f=null;e=!1}else n===37?e=!0:d+=a[o]}return d}var i=a||x,g=e||0,k=c||!1,j=0,q,a=function(a,b){var c;if(b)c=b.getTime(),k&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+g));else{var e=Date.now();e>j&&(j=e,q=new Date(j),c=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+g))); +b=q}return m(a,b,i,c)};a.localize=function(a){return new p(a||i,g,k)};a.timezone=function(a){var b=g,c=k,e=typeof a;if(e==="number"||e==="string")c=!0,e==="string"?(b=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*e+a)*6E4):e==="number"&&(b=a*6E4);return new p(i,b,c)};a.utc=function(){return new p(i,g,!0)};return a}function l(a,e){if(e===""||a>9)return a;e==null&&(e="0");return e+a}function v(a){if(a===0)return 12;else if(a>12)return a-12;return a}function w(a,e){var e= +e||"sunday",c=a.getDay();e==="monday"&&(c===0?c=6:c--);var g=new Date(a.getFullYear(),0,1);return Math.floor(((a-g)/864E5+7-c)/7)}function z(a){var e=a%10;a%=100;if(a>=11&&a<=13||e===0||e>=4)return"th";switch(e){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var x={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October", +"November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},g=new p(x,0,!1),y=typeof module!=="undefined",j;y?(j=module.exports=r,j.strftime=u):(j=function(){return this||(0,eval)("this")}(),j.strftime=r);var i=y?"require('strftime')":"strftime",s={};j.strftimeTZ=function(a,e,c,j){if((typeof c=="number"|| +typeof c=="string")&&j==null)j=c,c=void 0;c?k("`"+i+".strftimeTZ(format, date, locale, tz)`",i+".timezone(tz).localize(locale)(format, [date])"):k("`"+i+".strftimeTZ(format, date, tz)`",i+".timezone(tz)(format, [date])");return(c?g.timezone(j).localize(c):g).timezone(j)(a,e)};j.strftimeUTC=function(a,e,c){c?k("`"+i+".strftimeUTC(format, date, locale)`",i+".localize(locale).utc()(format, [date])"):k("`"+i+".strftimeUTC(format, [date])`",i+".utc()(format, [date])");return(c?g.utc().localize(c):g).utc()(a, +e)};j.localizedStrftime=function(a){k("`"+i+".localizedStrftime(locale)`",i+".localize(locale)");return g.localize(a)};t(r);t(u);if(typeof Date.now!=="function")Date.now=function(){return+new Date}})(); From 543e81ca832f947c9828c746e31c980588d1f85a Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 16:19:27 -0700 Subject: [PATCH 24/44] add install instructions for bower and component --- Readme.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Readme.md b/Readme.md index 3fd3723..95552f9 100644 --- a/Readme.md +++ b/Readme.md @@ -1,16 +1,25 @@ strftime ======== -strftime for JavaScript, works in Node.js and browsers, supports localization. -Most standard specifiers from C are supported as well as some other extensions -from Ruby. +strftime for JavaScript. Works in (at least) node.js and browsers. Supports localization and timezones. Most standard specifiers from C are supported as well as some other extensions from Ruby. Installation ============ +[node](https://nodejs.org): + npm install strftime +[bower](http://bower.io): + + bower install strftime + +[component](https://github.com/componentjs/component): + + component install samsonjs/strftime + +Or you can copy [strftime.js](https://github.com/samsonjs/strftime/blob/master/strftime.js) wherever you want to use it, whether that's with a <script> tag or `require` or anything else. The New API in 0.9 ================== From affbd8e1cd444076b7fd39b3648aa80760562208 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 16:45:59 -0700 Subject: [PATCH 25/44] improve backwards compatibility, fix a couple bugs --- strftime.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/strftime.js b/strftime.js index 977a76c..184f1d8 100644 --- a/strftime.js +++ b/strftime.js @@ -73,8 +73,13 @@ adaptForwards(adaptedStrftime); function adaptedStrftime(fmt, d, locale) { + // d and locale are optional, check if this is (format, locale) + if (d && d.days) { + locale = d; + d = undefined; + } if (locale) { - deprecationWarning("`" + _require + "(format, date, locale)`", _require + ".localize(locale)(format, [date])"); + deprecationWarning("`" + _require + "(format, [date], [locale])`", _require + ".localize(locale)(format, [date])"); } var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime; return strftime(fmt, d); @@ -83,7 +88,7 @@ adaptForwards(deprecatedStrftime); function deprecatedStrftime(fmt, d, locale) { if (locale) { - deprecationWarning("`" + _require + ".strftime(format, date, locale)`", _require + ".localize(locale)(format, [date])"); + deprecationWarning("`" + _require + ".strftime(format, [date], [locale])`", _require + ".localize(locale)(format, [date])"); } else { deprecationWarning("`" + _require + ".strftime(format, [date])`", _require + "(format, [date])"); @@ -93,6 +98,7 @@ } function deprecatedStrftimeTZ(fmt, d, locale, timezone) { + // locale is optional, check if this is (format, date, timezone) if ((typeof locale == 'number' || typeof locale == 'string') && timezone == null) { timezone = locale; locale = undefined; @@ -105,10 +111,11 @@ deprecationWarning("`" + _require + ".strftimeTZ(format, date, tz)`", _require + ".timezone(tz)(format, [date])"); } - var strftime = (locale ? defaultStrftime.timezone(timezone).localize(locale) : defaultStrftime).timezone(timezone); + var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); return strftime(fmt, d); }; + var utcStrftime = defaultStrftime.utc(); function deprecatedStrftimeUTC(fmt, d, locale) { if (locale) { deprecationWarning("`" + _require + ".strftimeUTC(format, date, locale)`", _require + ".localize(locale).utc()(format, [date])"); @@ -116,7 +123,7 @@ else { deprecationWarning("`" + _require + ".strftimeUTC(format, [date])`", _require + ".utc()(format, [date])"); } - var strftime = (locale ? defaultStrftime.utc().localize(locale) : defaultStrftime).utc(); + var strftime = locale ? utcStrftime.localize(locale) : utcStrftime; return strftime(fmt, d); }; From f4a2c852c39697af54f292db0ce0e2a346fdae84 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 16:54:22 -0700 Subject: [PATCH 26/44] readme formatting and improved deprecation warnings --- Readme.md | 10 ++-------- strftime.js | 12 ++++++------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/Readme.md b/Readme.md index 95552f9..97e1168 100644 --- a/Readme.md +++ b/Readme.md @@ -135,15 +135,9 @@ e.g. `%q` becomes `q`. Use `%%` to get a literal `%` sign. of UTC and a minus sign for those west of UTC, hours and minutes follow each padded to 2 digits and with no delimiter between them -For more detail see `man 3 strftime` as the format specifiers should behave -identically. If behaviour differs please [file a bug](https://github.com/samsonjs/strftime/issues/new). +For more detail see `man 3 strftime` as the format specifiers should behave identically. If behaviour differs please [file a bug](https://github.com/samsonjs/strftime/issues/new). -Any specifier can be modified with `-`, `_`, `0`, or `:` as well, as in Ruby. -Using `%-` will omit any leading zeroes or spaces, `%_` will force spaces -for padding instead of the default, and `%0` will force zeroes for padding. -There's some redundancy here as `%-d` and `%e` have the same result, but it -solves some awkwardness with formats like `%l`. Using `%:` for time zone offset, -as in `%:z` will insert a colon as a delimiter. +Any specifier can be modified with `-`, `_`, `0`, or `:` as well, as in Ruby. Using `%-` will omit any leading zeroes or spaces, `%_` will force spaces for padding instead of the default, and `%0` will force zeroes for padding. There's some redundancy here as `%-d` and `%e` have the same result, but it solves some awkwardness with formats like `%l`. Using `%:` for time zone offset, as in `%:z` will insert a colon as a delimiter. Contributors ============ diff --git a/strftime.js b/strftime.js index 184f1d8..21b181a 100644 --- a/strftime.js +++ b/strftime.js @@ -79,7 +79,7 @@ d = undefined; } if (locale) { - deprecationWarning("`" + _require + "(format, [date], [locale])`", _require + ".localize(locale)(format, [date])"); + deprecationWarning("`" + _require + "(format, [date], [locale])`", "var s = " + _require + ".localize(locale); s(format, [date])"); } var strftime = locale ? defaultStrftime.localize(locale) : defaultStrftime; return strftime(fmt, d); @@ -88,7 +88,7 @@ adaptForwards(deprecatedStrftime); function deprecatedStrftime(fmt, d, locale) { if (locale) { - deprecationWarning("`" + _require + ".strftime(format, [date], [locale])`", _require + ".localize(locale)(format, [date])"); + deprecationWarning("`" + _require + ".strftime(format, [date], [locale])`", "var s = " + _require + ".localize(locale); s(format, [date])"); } else { deprecationWarning("`" + _require + ".strftime(format, [date])`", _require + "(format, [date])"); @@ -105,10 +105,10 @@ } if (locale) { - deprecationWarning("`" + _require + ".strftimeTZ(format, date, locale, tz)`", _require + ".timezone(tz).localize(locale)(format, [date])"); + deprecationWarning("`" + _require + ".strftimeTZ(format, date, locale, tz)`", "var s = " + _require + ".localize(locale).timezone(tz); s(format, [date])` or `var s = " + _require + ".localize(locale); s.timezone(tz)(format, [date])"); } else { - deprecationWarning("`" + _require + ".strftimeTZ(format, date, tz)`", _require + ".timezone(tz)(format, [date])"); + deprecationWarning("`" + _require + ".strftimeTZ(format, date, tz)`", "var s = " + _require + ".timezone(tz); s(format, [date])` or `" + _require + ".timezone(tz)(format, [date])"); } var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); @@ -118,10 +118,10 @@ var utcStrftime = defaultStrftime.utc(); function deprecatedStrftimeUTC(fmt, d, locale) { if (locale) { - deprecationWarning("`" + _require + ".strftimeUTC(format, date, locale)`", _require + ".localize(locale).utc()(format, [date])"); + deprecationWarning("`" + _require + ".strftimeUTC(format, date, locale)`", "var s = " + _require + ".localize(locale).utc(); s(format, [date])"); } else { - deprecationWarning("`" + _require + ".strftimeUTC(format, [date])`", _require + ".utc()(format, [date])"); + deprecationWarning("`" + _require + ".strftimeUTC(format, [date])`", "var s = " + _require + ".utc(); s(format, [date])"); } var strftime = locale ? utcStrftime.localize(locale) : utcStrftime; return strftime(fmt, d); From 4dcc65547708b3cc90f55e81daae1c0d073cc9a8 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 15 Mar 2015 17:02:08 -0700 Subject: [PATCH 27/44] minify --- strftime-min.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/strftime-min.js b/strftime-min.js index 0cbe605..ea4c8d2 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,11 +1,11 @@ -(function(){function k(a,e){s[a]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+a+" is deprecated and will be removed in version 1.0. Instead, use `"+e+"`."),s[a]=!0)}function t(a){a.localize=g.localize.bind(g);a.timezone=g.timezone.bind(g);a.utc=g.utc.bind(g)}function r(a,e,c){c&&k("`"+i+"(format, date, locale)`",i+".localize(locale)(format, [date])");return(c?g.localize(c):g)(a,e)}function u(a,e,c){c?k("`"+i+".strftime(format, date, locale)`",i+".localize(locale)(format, [date])"): -k("`"+i+".strftime(format, [date])`",i+"(format, [date])");return(c?g.localize(c):g)(a,e)}function p(a,e,c){function m(a,b,h,c){for(var d="",f=null,e=!1,i=a.length,j=!1,o=0;o99?Math.floor(c%1E3):Math.floor(c%1E3)>9?"0"+Math.floor(c%1E3):"00"+Math.floor(c%1E3);break;case 77:d+=l(b.getMinutes(),f);break;case 80:d+=b.getHours()<12?h.am:h.pm;break;case 82:d+=m(h.formats.R,b,h,c);break;case 83:d+=l(b.getSeconds(),f);break;case 84:d+=m(h.formats.T,b,h,c);break;case 85:d+=l(w(b,"sunday"),f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=m(h.formats.X,b,h,c); -break;case 89:d+=b.getFullYear();break;case 90:k&&g===0?d+="GMT":(f=b.toString().match(/\((\w+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=m(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()-f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+= -l(b.getHours(),f==null?" ":f);break;case 108:d+=l(v(b.getHours()),f==null?" ":f);break;case 109:d+=l(b.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(b.getDate())+z(b.getDate());break;case 112:d+=b.getHours()<12?h.AM:h.PM;break;case 114:d+=m(h.formats.r,b,h,c);break;case 115:d+=Math.floor(c/1E3);break;case 116:d+="\t";break;case 117:f=b.getDay();d+=f===0?7:f;break;case 118:d+=m(h.formats.v,b,h,c);break;case 119:d+=b.getDay();break;case 120:d+=m(h.formats.x,b,h,c);break;case 121:d+= -(""+b.getFullYear()).slice(2);break;case 122:k&&g===0?d+=j?"+00:00":"+0000":(f=g!==0?g/6E4:-b.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=a[o]}f=null;e=!1}else n===37?e=!0:d+=a[o]}return d}var i=a||x,g=e||0,k=c||!1,j=0,q,a=function(a,b){var c;if(b)c=b.getTime(),k&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+g));else{var e=Date.now();e>j&&(j=e,q=new Date(j),c=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+g))); -b=q}return m(a,b,i,c)};a.localize=function(a){return new p(a||i,g,k)};a.timezone=function(a){var b=g,c=k,e=typeof a;if(e==="number"||e==="string")c=!0,e==="string"?(b=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*e+a)*6E4):e==="number"&&(b=a*6E4);return new p(i,b,c)};a.utc=function(){return new p(i,g,!0)};return a}function l(a,e){if(e===""||a>9)return a;e==null&&(e="0");return e+a}function v(a){if(a===0)return 12;else if(a>12)return a-12;return a}function w(a,e){var e= -e||"sunday",c=a.getDay();e==="monday"&&(c===0?c=6:c--);var g=new Date(a.getFullYear(),0,1);return Math.floor(((a-g)/864E5+7-c)/7)}function z(a){var e=a%10;a%=100;if(a>=11&&a<=13||e===0||e>=4)return"th";switch(e){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var x={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October", -"November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},g=new p(x,0,!1),y=typeof module!=="undefined",j;y?(j=module.exports=r,j.strftime=u):(j=function(){return this||(0,eval)("this")}(),j.strftime=r);var i=y?"require('strftime')":"strftime",s={};j.strftimeTZ=function(a,e,c,j){if((typeof c=="number"|| -typeof c=="string")&&j==null)j=c,c=void 0;c?k("`"+i+".strftimeTZ(format, date, locale, tz)`",i+".timezone(tz).localize(locale)(format, [date])"):k("`"+i+".strftimeTZ(format, date, tz)`",i+".timezone(tz)(format, [date])");return(c?g.timezone(j).localize(c):g).timezone(j)(a,e)};j.strftimeUTC=function(a,e,c){c?k("`"+i+".strftimeUTC(format, date, locale)`",i+".localize(locale).utc()(format, [date])"):k("`"+i+".strftimeUTC(format, [date])`",i+".utc()(format, [date])");return(c?g.utc().localize(c):g).utc()(a, -e)};j.localizedStrftime=function(a){k("`"+i+".localizedStrftime(locale)`",i+".localize(locale)");return g.localize(a)};t(r);t(u);if(typeof Date.now!=="function")Date.now=function(){return+new Date}})(); +(function(){function k(a,c){s[a]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+a+" is deprecated and will be removed in version 1.0. Instead, use `"+c+"`."),s[a]=!0)}function t(a){a.localize=i.localize.bind(i);a.timezone=i.timezone.bind(i);a.utc=i.utc.bind(i)}function r(a,c,e){c&&c.days&&(e=c,c=void 0);e&&k("`"+g+"(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])");return(e?i.localize(e):i)(a,c)}function u(a,c,e){e?k("`"+g+ +".strftime(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])"):k("`"+g+".strftime(format, [date])`",g+"(format, [date])");return(e?i.localize(e):i)(a,c)}function p(a,c,e){function g(a,b,h,c){for(var d="",f=null,e=!1,i=a.length,j=!1,o=0;o99?Math.floor(c%1E3):Math.floor(c%1E3)>9?"0"+Math.floor(c%1E3):"00"+Math.floor(c%1E3);break;case 77:d+=l(b.getMinutes(),f);break;case 80:d+=b.getHours()<12?h.am:h.pm;break;case 82:d+=g(h.formats.R,b,h,c);break;case 83:d+=l(b.getSeconds(),f);break;case 84:d+=g(h.formats.T,b,h,c);break;case 85:d+=l(w(b,"sunday"), +f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=g(h.formats.X,b,h,c);break;case 89:d+=b.getFullYear();break;case 90:k&&m===0?d+="GMT":(f=b.toString().match(/\((\w+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=g(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()- +f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+=l(b.getHours(),f==null?" ":f);break;case 108:d+=l(v(b.getHours()),f==null?" ":f);break;case 109:d+=l(b.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(b.getDate())+A(b.getDate());break;case 112:d+=b.getHours()<12?h.AM:h.PM;break;case 114:d+=g(h.formats.r,b,h,c);break;case 115:d+=Math.floor(c/1E3);break;case 116:d+="\t";break;case 117:f=b.getDay();d+=f===0?7:f;break;case 118:d+=g(h.formats.v,b,h,c);break;case 119:d+=b.getDay(); +break;case 120:d+=g(h.formats.x,b,h,c);break;case 121:d+=(""+b.getFullYear()).slice(2);break;case 122:k&&m===0?d+=j?"+00:00":"+0000":(f=m!==0?m/6E4:-b.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=a[o]}f=null;e=!1}else n===37?e=!0:d+=a[o]}return d}var i=a||x,m=c||0,k=e||!1,j=0,q,a=function(a,b){var c;if(b)c=b.getTime(),k&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+m));else{var e=Date.now();e>j&&(j=e,q=new Date(j), +c=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+m)));b=q}return g(a,b,i,c)};a.localize=function(a){return new p(a||i,m,k)};a.timezone=function(a){var b=m,c=k,e=typeof a;if(e==="number"||e==="string")c=!0,e==="string"?(b=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*e+a)*6E4):e==="number"&&(b=a*6E4);return new p(i,b,c)};a.utc=function(){return new p(i,m,!0)};return a}function l(a,c){if(c===""||a>9)return a;c==null&&(c="0");return c+a}function v(a){if(a===0)return 12; +else if(a>12)return a-12;return a}function w(a,c){var c=c||"sunday",e=a.getDay();c==="monday"&&(e===0?e=6:e--);var g=new Date(a.getFullYear(),0,1);return Math.floor(((a-g)/864E5+7-e)/7)}function A(a){var c=a%10;a%=100;if(a>=11&&a<=13||c===0||c>=4)return"th";switch(c){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var x={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April", +"May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},i=new p(x,0,!1),y=typeof module!=="undefined",j;y?(j=module.exports=r,j.strftime=u):(j=function(){return this||(0,eval)("this")}(),j.strftime=r);var g=y?"require('strftime')":"strftime",s= +{};j.strftimeTZ=function(a,c,e,j){if((typeof e=="number"||typeof e=="string")&&j==null)j=e,e=void 0;e?k("`"+g+".strftimeTZ(format, date, locale, tz)`","var s = "+g+".localize(locale).timezone(tz); s(format, [date])` or `var s = "+g+".localize(locale); s.timezone(tz)(format, [date])"):k("`"+g+".strftimeTZ(format, date, tz)`","var s = "+g+".timezone(tz); s(format, [date])` or `"+g+".timezone(tz)(format, [date])");return(e?i.localize(e):i).timezone(j)(a,c)};j.strftimeUTC=function(a,c,e){e?k("`"+g+".strftimeUTC(format, date, locale)`", +"var s = "+g+".localize(locale).utc(); s(format, [date])"):k("`"+g+".strftimeUTC(format, [date])`","var s = "+g+".utc(); s(format, [date])");return(e?z.localize(e):z)(a,c)};j.localizedStrftime=function(a){k("`"+g+".localizedStrftime(locale)`",g+".localize(locale)");return i.localize(a)};t(r);t(u);var z=i.utc();if(typeof Date.now!=="function")Date.now=function(){return+new Date}})(); From 7b1151c7c0f6f18b9d41e3dd88e847ff99822079 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 17:32:56 -0700 Subject: [PATCH 28/44] re-fix issue #38 which was lost in the v0.9 merge --- strftime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strftime.js b/strftime.js index 21b181a..67651c2 100644 --- a/strftime.js +++ b/strftime.js @@ -329,7 +329,7 @@ } else { // fixme optimize - var tzString = date.toString().match(/\((\w+)\)/); + var tzString = date.toString().match(/\(([\w\s]+)\)/); resultString += tzString && tzString[1] || ''; } break; From 437beabe4332de5463f71310ad81e121be2db8a0 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 17:33:08 -0700 Subject: [PATCH 29/44] add missing contributors to readme & package.json --- Readme.md | 5 +++++ package.json | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 97e1168..e560d96 100644 --- a/Readme.md +++ b/Readme.md @@ -144,10 +144,15 @@ Contributors * [Rob Colburn](https://github.com/robcolburn) * [Cory Heslip](https://github.com/cheslip) +* [TJ Holowaychuk](https://github.com/tj) +* [Forbes Lindesay](https://github.com/ForbesLindesay) * [Alexandr Nikitin](https://github.com/alexandrnikitin) +* [Ryan Regalado](https://github.com/d48) * [Sami Samhuri](https://github.com/samsonjs) * [Andrew Schaaf](https://github.com/andrewschaaf) * [Ryan Stafford](https://github.com/ryanstafford) +* [w0den](https://github.com/w0den) +* [John Zwinck](https://github.com/jzwinck) License diff --git a/package.json b/package.json index 1575bdc..0303713 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,12 @@ "Andrew Schaaf (http://andrewschaaf.com/)", "Rob Colburn (http://robcolburn.com/)", "Ryan Stafford (http://droffats.net/)", - "Alexandr Nikitin " + "Alexandr Nikitin ", + "TJ Holowaychuk (http://tjholowaychuk.com/)", + "John Zwinck (https://github.com/jzwinck)", + "Forbes Lindesay (https://github.com/ForbesLindesay)", + "Ryan Regalado (https://github.com/d48)", + "w0den (https://github.com/w0den)" ], "repository": { "type": "git", From 4676d05afeac462218663b4de250010f9169430d Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 17:47:11 -0700 Subject: [PATCH 30/44] add a changelog --- Changelog.md | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ Readme.md | 1 + 2 files changed, 228 insertions(+) create mode 100644 Changelog.md diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..e722d40 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,227 @@ +v0.9.1 on 2015-03-16 +-------------------- + +- re-fix [issue #38](https://github.com/samsonjs/strftime/pull/38) which was lost in the v0.9 merge + +- add this changelog + +v0.9.0 on 2015-03-15 +-------------------- + +This release marks the final run up to v1.0, which should be released by March 2016. + +The headline feature is a huge performance boost resulting from [this contest](http://hola.org/challenge_js). [Alexandr Nikitin](https://github.com/alexandrnikitin) has essentially [rewritten](https://github.com/samsonjs/strftime/pull/41) the code and [the results](http://jsperf.com/strftime-optimization/2) speak for themselves. + +Along with this the API has been unified and cleaned up. `strftimeTZ`, `strftimeUTC`, and `localizedStrftime` have all been deprecated in favour of the following functions: `timezone(tz)`, `utc()`, and `localize(locale)`. You use them like so: + + var strftime = require('strftime'); // not required in web browsers + + var strftimeIT = strftime.localize(anItalianLocale); + var strftimePST = strftime.timezone('-0800'); + var strftimeUTC = strftime.utc(); + + // You can combine them + var strftimeIT_PST = strftimeIT.timezone('-0800'); + + // And chain them all at once + var strftimeIT_PST = strftime.localize(anItalianLocale).timezone('-0800'); + +The previous API is deprecated and will be removed for v1.0. The good news is that the previous API is supported by adapting the new API, so you get most of the performance benefits before you even update your code to use the new API. + +The new API does not support passing in a custom timezone or locale on each call to `strftime`. This is a regression so if you really need this use case [let us know](https://github.com/samsonjs/strftime/issues/new) and we'll figure something out. + +Thanks to all contributors that have helped to improve this library over the past 4 years. + +v0.8.4 on 2015-03-05 +-------------------- + +- fix conversion of dates to UTC + Thanks to [Alexandr Nikitin](https://github.com/alexandrnikitin) + +- extend `%z` with a colon separator in timezone offsets, `"[+-]HH:MM"` + Thanks to [Cory Heslip](https://github.com/cheslip) + +- ignore irrelevant files in bower.json + +v0.8.3 on 2015-02-08 +-------------------- + +First release for [Bower](http://bower.io), and only released for Bower. + +v0.8.2 on 2014-08-08 +-------------------- + +- fix `%e` which is supposed to be padded with a space + +v0.8.1 on 2014-06-17 +-------------------- + +- fix `%Z` when the timezone contains spaces + Thanks to [w0den](https://github.com/w0den) + +- fix examples using `%Y` in the readme + Thanks to [Ryan Regalado](https://github.com/d48) + +- fix a bug when specifying minutes in the timezone + Thanks to [Alexandr Nikitin](https://github.com/alexandrnikitin) + +v0.8.0 on 2014-01-29 +-------------------- + +- allow timezones to be specified as strings of the form `"+0100"` or `"-0800"` (`[+-]HHMM`) + +- fix a bug running tests where the environment variable `TZ` is empty and the system timezone is not PST/PDT + +v0.7.0 on 2013-11-08 +-------------------- + +- add support for passing in explicit timezones with `strftimeTZ` which accepts numeric offsets from GMT, in minutes + +v0.6.2 on 2013-08-29 +-------------------- + +- expose `strftimeUTC` and `localizedStrftime` properly in browsers + +v0.6.1 on 2013-06-13 +-------------------- + +- fix a bug where `RequiredDateMethods` was created as a global + +v0.6.0 on 2013-05-15 +-------------------- + +- add `%o` to get the day of the month as an ordinal (in English) + +v0.5.2 on 2013-04-07 +-------------------- + +- add some Ruby extension prefixes: `-`, `_`, and `0`, and they work like so: + `strftime('%-d') // => "7"` + `strftime('%_d') // => " 7"` + `strftime('%0d') // => "07"` + +- fix padding the day-of-year in `%j` + +- add a minified version of the code to the repo for easy distribution with some package managers + +v0.5.1 on 2013-03-07 +-------------------- + +- remove deprecated `getLocalizedStrftime` function + +- make `%C` pad the century with spaces, like C + +- list all supported specifiers in the readme, it's no longer fair to say "look at `man 3 strftime`" + +- use fixed dates in the readme instead of "now", so people can execute the examples and see the same results + Thanks to [John Zwinck](https://github.com/jzwinck) + +- fix `%z` for timezones greater than GMT + +- support any `Date`-like objects instead of checking for actual instances of `Date` + +v0.5.0 on 2013-01-05 +-------------------- + +- add week numbers `%U` and `%W` + +- add support for [component](https://github.com/componentjs/component) + Thanks to [TJ Holowaychuk](https://github.com/tj) + +v0.4.8 on 2012-11-13 +-------------------- + +- add `%j` and `%C`, thanks to [Ryan Stafford](https://github.com/ryanstafford) + +v0.4.7 on 2012-06-08 +-------------------- + +- add `%P` which is "am" or "pm", like `%p` but lowercase + (this makes no sense, and I am sorry for propagating this madness) + Thanks to [Rob Colburn](https://github.com/robcolburn) + +- export the `strftime` function directly in [node](https://nodejs.org) so you can write `strftime = require('strftime')` instead of `strftime = require('strftime').strftime` + +- added contributors to the readme and package.json + +v0.4.6 on 2011-06-13 +-------------------- + +- rename `getLocalizedStrftime(locale)` to `localizedStrftime(locale)` + The old name is deprecated and will stick around until v0.5 or v0.6. + +- add tests for locales + +v0.4.5 on 2011-06-08 +-------------------- + +- fix the sign of `%z`, which is something like "+0100" or "-0800" (`[+-]HHMM`) + +- improve test coverage + +v0.4.4 on 2011-06-07 +-------------------- + +- fix `%L` for values < 100 + +- convert tests from CoffeeScript to JavaScript + (nothing personal, just keeping the dependencies trim) + +v0.4.3 on 2011-06-05 +-------------------- + +This release was all [Andrew Schaaf](https://github.com/andrewschaaf). + +- add some tests + +- fix `%s` which is seconds since the Unix epoch, but was in milliseconds + +- add `%L` for 3-digit milliseconds + +v0.4.2 on 2011-06-05 +-------------------- + +- add `strftimeUTC` for ignoring timezones + Thanks to [Andrew Schaaf](https://github.com/andrewschaaf) + +- support exporting to the top level object in ES5 strict mode + +v0.4.1 on 2011-06-02 +-------------------- + +- fix `%y` for years outside the range [1900, 2099] + +v0.4.0 on 2011-04-28 +-------------------- + +- add support for localization + +v0.3.0 on 2010-12-17 +-------------------- + +- fix export for browsers + +v0.2.3 on 2010-12-15 +-------------------- + +- set required [node](https://nodejs.org) version to 0.2 instead of 0.3 in package.json + +v0.2.2 on 2010-11-14 +-------------------- + +- fix module export + +v0.2.1 on 2010-11-11 +-------------------- + +- bug fix for recursive formats + +v0.2.0 on 2010-11-11 +-------------------- + +- use `String.prototype.replace` instead of a `for` loop + +v0.1.0 on 2010-11-11 +-------------------- + +Initial release. \ No newline at end of file diff --git a/Readme.md b/Readme.md index e560d96..9ff8664 100644 --- a/Readme.md +++ b/Readme.md @@ -28,6 +28,7 @@ The current version, 0.9, deprecates the older API that exported several functio Now you only need the single object exported and you can create a specialized version of it using the functions `utc()`, `localize(locale)`, and `timezone(offset)`. You can no longer pass in a timezone or locale on each call to `strftime` which is a regression. If you need this let me know and we will add it back into the API. +[More details are available in the changelog](https://github.com/samsonjs/strftime/blob/master/Changelog.md). Usage ===== From 765f3f19466dd2d1a23c033a58ce2a5018b3ea11 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 17:47:57 -0700 Subject: [PATCH 31/44] minify --- strftime-min.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/strftime-min.js b/strftime-min.js index ea4c8d2..d867937 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,7 +1,7 @@ (function(){function k(a,c){s[a]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+a+" is deprecated and will be removed in version 1.0. Instead, use `"+c+"`."),s[a]=!0)}function t(a){a.localize=i.localize.bind(i);a.timezone=i.timezone.bind(i);a.utc=i.utc.bind(i)}function r(a,c,e){c&&c.days&&(e=c,c=void 0);e&&k("`"+g+"(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])");return(e?i.localize(e):i)(a,c)}function u(a,c,e){e?k("`"+g+ ".strftime(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])"):k("`"+g+".strftime(format, [date])`",g+"(format, [date])");return(e?i.localize(e):i)(a,c)}function p(a,c,e){function g(a,b,h,c){for(var d="",f=null,e=!1,i=a.length,j=!1,o=0;o99?Math.floor(c%1E3):Math.floor(c%1E3)>9?"0"+Math.floor(c%1E3):"00"+Math.floor(c%1E3);break;case 77:d+=l(b.getMinutes(),f);break;case 80:d+=b.getHours()<12?h.am:h.pm;break;case 82:d+=g(h.formats.R,b,h,c);break;case 83:d+=l(b.getSeconds(),f);break;case 84:d+=g(h.formats.T,b,h,c);break;case 85:d+=l(w(b,"sunday"), -f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=g(h.formats.X,b,h,c);break;case 89:d+=b.getFullYear();break;case 90:k&&m===0?d+="GMT":(f=b.toString().match(/\((\w+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=g(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()- +f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=g(h.formats.X,b,h,c);break;case 89:d+=b.getFullYear();break;case 90:k&&m===0?d+="GMT":(f=b.toString().match(/\(([\w\s]+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=g(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()- f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+=l(b.getHours(),f==null?" ":f);break;case 108:d+=l(v(b.getHours()),f==null?" ":f);break;case 109:d+=l(b.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(b.getDate())+A(b.getDate());break;case 112:d+=b.getHours()<12?h.AM:h.PM;break;case 114:d+=g(h.formats.r,b,h,c);break;case 115:d+=Math.floor(c/1E3);break;case 116:d+="\t";break;case 117:f=b.getDay();d+=f===0?7:f;break;case 118:d+=g(h.formats.v,b,h,c);break;case 119:d+=b.getDay(); break;case 120:d+=g(h.formats.x,b,h,c);break;case 121:d+=(""+b.getFullYear()).slice(2);break;case 122:k&&m===0?d+=j?"+00:00":"+0000":(f=m!==0?m/6E4:-b.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=a[o]}f=null;e=!1}else n===37?e=!0:d+=a[o]}return d}var i=a||x,m=c||0,k=e||!1,j=0,q,a=function(a,b){var c;if(b)c=b.getTime(),k&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+m));else{var e=Date.now();e>j&&(j=e,q=new Date(j), c=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+m)));b=q}return g(a,b,i,c)};a.localize=function(a){return new p(a||i,m,k)};a.timezone=function(a){var b=m,c=k,e=typeof a;if(e==="number"||e==="string")c=!0,e==="string"?(b=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*e+a)*6E4):e==="number"&&(b=a*6E4);return new p(i,b,c)};a.utc=function(){return new p(i,m,!0)};return a}function l(a,c){if(c===""||a>9)return a;c==null&&(c="0");return c+a}function v(a){if(a===0)return 12; From dcc5d54c1b324d911b6342fb1fbef18cf8718fdc Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 17:47:35 -0700 Subject: [PATCH 32/44] v0.9.1 --- bower.json | 2 +- component.json | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bower.json b/bower.json index 70663f6..34202bb 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "strftime", - "version": "0.9.0", + "version": "0.9.1", "main": "strftime.js", "ignore": [ "Readme.md", diff --git a/component.json b/component.json index 790ad5c..d122a28 100644 --- a/component.json +++ b/component.json @@ -3,7 +3,7 @@ "repo": "samsonjs/strftime", "description": "strftime date formatting", "keywords": ["strftime", "format", "date", "time"], - "version": "0.9.0", + "version": "0.9.1", "main": "strftime.js", "scripts": ["strftime.js"] } diff --git a/package.json b/package.json index 0303713..c130232 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "strftime", "description": "strftime for JavaScript", - "version": "0.9.0", + "version": "0.9.1", "homepage": "http://samhuri.net/proj/strftime", "author": "Sami Samhuri ", "contributors": [ From 8ba1f03a71245cb4293ef36a2422581ab34bbbe9 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 18:02:34 -0700 Subject: [PATCH 33/44] warn about possible misuse of %:: or %::: modifiers --- strftime.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/strftime.js b/strftime.js index 67651c2..e20e4c1 100644 --- a/strftime.js +++ b/strftime.js @@ -211,6 +211,11 @@ } // ':' else if (currentCharCode === 58) { + if (extendedTZ) { + if (typeof console !== 'undefined' && typeof console.warn == 'function') { + console.warn("[WARNING] detected use of unsupported %:: or %::: modifiers to strftime"); + } + } extendedTZ = true; continue; } From 30fd95dbba29f6b4c29b51281f2b6f6ca2819b8b Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 18:02:54 -0700 Subject: [PATCH 34/44] vapourize some stray semicolons --- strftime.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/strftime.js b/strftime.js index e20e4c1..37635ab 100644 --- a/strftime.js +++ b/strftime.js @@ -113,7 +113,7 @@ var strftime = (locale ? defaultStrftime.localize(locale) : defaultStrftime).timezone(timezone); return strftime(fmt, d); - }; + } var utcStrftime = defaultStrftime.utc(); function deprecatedStrftimeUTC(fmt, d, locale) { @@ -125,12 +125,12 @@ } var strftime = locale ? utcStrftime.localize(locale) : utcStrftime; return strftime(fmt, d); - }; + } function deprecatedStrftimeLocalized(locale) { deprecationWarning("`" + _require + ".localizedStrftime(locale)`", _require + ".localize(locale)"); return defaultStrftime.localize(locale); - }; + } // End of deprecated API // Polyfill Date.now for old browsers. From 1d4365f3d56272e135132203eae86559e04ab4f1 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 16 Mar 2015 18:07:52 -0700 Subject: [PATCH 35/44] try to fix syntax highlighting on GitHub --- Changelog.md | 2 ++ Readme.md | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Changelog.md b/Changelog.md index e722d40..18c524c 100644 --- a/Changelog.md +++ b/Changelog.md @@ -14,6 +14,7 @@ The headline feature is a huge performance boost resulting from [this contest](h Along with this the API has been unified and cleaned up. `strftimeTZ`, `strftimeUTC`, and `localizedStrftime` have all been deprecated in favour of the following functions: `timezone(tz)`, `utc()`, and `localize(locale)`. You use them like so: +```JavaScript var strftime = require('strftime'); // not required in web browsers var strftimeIT = strftime.localize(anItalianLocale); @@ -25,6 +26,7 @@ Along with this the API has been unified and cleaned up. `strftimeTZ`, `strftime // And chain them all at once var strftimeIT_PST = strftime.localize(anItalianLocale).timezone('-0800'); +``` The previous API is deprecated and will be removed for v1.0. The good news is that the previous API is supported by adapting the new API, so you get most of the performance benefits before you even update your code to use the new API. diff --git a/Readme.md b/Readme.md index 9ff8664..a6edf00 100644 --- a/Readme.md +++ b/Readme.md @@ -33,13 +33,16 @@ Now you only need the single object exported and you can create a specialized ve Usage ===== +```JavaScript var strftime = require('strftime') // not required in browsers console.log(strftime('%B %d, %Y %H:%M:%S')) // => April 28, 2011 18:21:08 console.log(strftime('%F %T', new Date(1307472705067))) // => 2011-06-07 18:51:45 +``` If you want to localize it: +```JavaScript var strftime = require('strftime') // not required in browsers var it_IT = { days: ['domenica', 'lunedi', 'martedi', 'mercoledi', 'giovedi', 'venerdi', 'sabato'], @@ -65,25 +68,27 @@ If you want to localize it: var strftimeIT = strftime.localize(it_IT) console.log(strftimeIT('%B %d, %Y %H:%M:%S')) // => aprile 28, 2011 18:21:08 console.log(strftimeIT('%B %d, %Y %H:%M:%S', new Date(1307472705067))) // => giugno 7, 2011 18:51:45 - +``` Time zones can be passed in as an offset from GMT in minutes. +```JavaScript var strftime = require('strftime') // not required in browsers var strftimePDT = strftime.timezone(-420) var strftimeCEST = strftime.timezone(120) console.log(strftimePDT('%B %d, %y %H:%M:%S', new Date(1307472705067))) // => June 07, 11 11:51:45 console.log(strftimeCEST('%F %T', new Date(1307472705067))) // => 2011-06-07 20:51:45 - +``` Alternatively you can use the timezone format used by ISO 8601, `+HHMM` or `-HHMM`. +```JavaScript var strftime = require('strftime') // not required in browsers var strftimePDT = strftime.timezone('-0700') var strftimeCEST = strftime.timezone('+0200') console.log(strftimePDT('', new Date(1307472705067))) // => June 07, 11 11:51:45 console.log(strftimeCEST('%F %T', new Date(1307472705067))) // => 2011-06-07 20:51:45 - +``` Supported Specifiers ==================== From 002ac8ca4c782cd351c0f10943c1aa501fbb9930 Mon Sep 17 00:00:00 2001 From: Alexandr Nikitin Date: Thu, 26 Mar 2015 21:40:46 +0200 Subject: [PATCH 36/44] Add field report tests for bug in %U in #56 --- test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test.js b/test.js index 0b0a974..5b6fd62 100755 --- a/test.js +++ b/test.js @@ -115,6 +115,9 @@ assert.format('%z', null, '+0000'); assert.format('%:z', null, '+00:00'); assert.format('%%', '%'); // any other char assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)); +assert.format('%U', '13', "12", (new Date('03-26-2017 00:00:00'))); +assert.format('%U', '13', null, (new Date('03-27-2017 00:00:00'))); +assert.format('%U', '14', "13", (new Date('04-02-2017 00:00:00'))); ok('GMT'); From 067ae77ad962bf5b45ea72a3d4fa90a266a157a1 Mon Sep 17 00:00:00 2001 From: Alexandr Nikitin Date: Thu, 26 Mar 2015 21:43:57 +0200 Subject: [PATCH 37/44] Fix day number calculation taking DST into account Based on the SO answer http://stackoverflow.com/a/15289883/974487 --- strftime.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/strftime.js b/strftime.js index 37635ab..c05c3f0 100644 --- a/strftime.js +++ b/strftime.js @@ -595,8 +595,10 @@ else weekday--; } - var firstDayOfYear = new Date(date.getFullYear(), 0, 1), - yday = (date - firstDayOfYear) / 86400000, + + var firstDayOfYearUtc = Date.UTC(date.getFullYear(), 0, 1), + dateUtc = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()), + yday = Math.floor((dateUtc - firstDayOfYearUtc) / 86400000), weekNum = (yday + 7 - weekday) / 7; return Math.floor(weekNum); From ab3d4a052ea48363e5c1684f5aff9d90f3ce2a30 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Thu, 26 Mar 2015 14:44:26 -0700 Subject: [PATCH 38/44] Revert "Fixes #56 (Bug in %U)" --- strftime.js | 6 ++---- test.js | 3 --- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/strftime.js b/strftime.js index c05c3f0..37635ab 100644 --- a/strftime.js +++ b/strftime.js @@ -595,10 +595,8 @@ else weekday--; } - - var firstDayOfYearUtc = Date.UTC(date.getFullYear(), 0, 1), - dateUtc = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()), - yday = Math.floor((dateUtc - firstDayOfYearUtc) / 86400000), + var firstDayOfYear = new Date(date.getFullYear(), 0, 1), + yday = (date - firstDayOfYear) / 86400000, weekNum = (yday + 7 - weekday) / 7; return Math.floor(weekNum); diff --git a/test.js b/test.js index 5b6fd62..0b0a974 100755 --- a/test.js +++ b/test.js @@ -115,9 +115,6 @@ assert.format('%z', null, '+0000'); assert.format('%:z', null, '+00:00'); assert.format('%%', '%'); // any other char assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)); -assert.format('%U', '13', "12", (new Date('03-26-2017 00:00:00'))); -assert.format('%U', '13', null, (new Date('03-27-2017 00:00:00'))); -assert.format('%U', '14', "13", (new Date('04-02-2017 00:00:00'))); ok('GMT'); From aee0e19edc343068969aa095c1000c75a0d302da Mon Sep 17 00:00:00 2001 From: Alexandr Nikitin Date: Sun, 29 Mar 2015 11:38:17 +0300 Subject: [PATCH 39/44] Revert "Revert "Fixes #56 (Bug in %U)"" This reverts commit ab3d4a052ea48363e5c1684f5aff9d90f3ce2a30. --- strftime.js | 6 ++++-- test.js | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/strftime.js b/strftime.js index 37635ab..c05c3f0 100644 --- a/strftime.js +++ b/strftime.js @@ -595,8 +595,10 @@ else weekday--; } - var firstDayOfYear = new Date(date.getFullYear(), 0, 1), - yday = (date - firstDayOfYear) / 86400000, + + var firstDayOfYearUtc = Date.UTC(date.getFullYear(), 0, 1), + dateUtc = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()), + yday = Math.floor((dateUtc - firstDayOfYearUtc) / 86400000), weekNum = (yday + 7 - weekday) / 7; return Math.floor(weekNum); diff --git a/test.js b/test.js index 0b0a974..5b6fd62 100755 --- a/test.js +++ b/test.js @@ -115,6 +115,9 @@ assert.format('%z', null, '+0000'); assert.format('%:z', null, '+00:00'); assert.format('%%', '%'); // any other char assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)); +assert.format('%U', '13', "12", (new Date('03-26-2017 00:00:00'))); +assert.format('%U', '13', null, (new Date('03-27-2017 00:00:00'))); +assert.format('%U', '14', "13", (new Date('04-02-2017 00:00:00'))); ok('GMT'); From 48d143eb90a4faa7dc55766921115c40b8fa5279 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Sun, 29 Mar 2015 14:16:12 -0700 Subject: [PATCH 40/44] always use GMT to construct times in tests --- test.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/test.js b/test.js index 5b6fd62..bc60e7b 100755 --- a/test.js +++ b/test.js @@ -48,6 +48,10 @@ if (process.env.TZ == 'America/Vancouver') { assert.format('%c', 'Tue Jun 07 11:51:45 2011', 'Tue Jun 07 18:51:45 2011'); assert.format('%j', '097', '098', new Date(1365390736236)); assert.format('%x', '06/07/11'); + assert.format('%U', '12', null, new Date('2017-03-25 00:00:00 +0000')); + assert.format('%U', '12', '13', new Date('2017-03-26 00:00:00 +0000')); + assert.format('%U', '13', null, new Date('2017-03-27 00:00:00 +0000')); + assert.format('%U', '13', '14', new Date('2017-04-02 00:00:00 +0000')); ok('Time zones (' + process.env.TZ + ')'); } else if (process.env.TZ == 'CET') { @@ -57,6 +61,10 @@ else if (process.env.TZ == 'CET') { assert.format('%c', 'Tue Jun 07 20:51:45 2011', 'Tue Jun 07 18:51:45 2011'); assert.format('%j', '098', '098', new Date(1365390736236)); assert.format('%x', '06/07/11'); + assert.format('%U', '12', null, new Date('2017-03-25 00:00:00 +0000')); + assert.format('%U', '13', null, new Date('2017-03-26 00:00:00 +0000')); + assert.format('%U', '13', null, new Date('2017-03-27 00:00:00 +0000')); + assert.format('%U', '14', null, new Date('2017-04-02 00:00:00 +0000')); ok('Time zones (' + process.env.TZ + ')'); } else { @@ -115,9 +123,10 @@ assert.format('%z', null, '+0000'); assert.format('%:z', null, '+00:00'); assert.format('%%', '%'); // any other char assert.format('%F %T', null, '1970-01-01 00:00:00', new Date(0)); -assert.format('%U', '13', "12", (new Date('03-26-2017 00:00:00'))); -assert.format('%U', '13', null, (new Date('03-27-2017 00:00:00'))); -assert.format('%U', '14', "13", (new Date('04-02-2017 00:00:00'))); +assert.format('%U', null, '12', new Date('2017-03-25 00:00:00 +0000')); +assert.format('%U', null, '13', new Date('2017-03-26 00:00:00 +0000')); +assert.format('%U', null, '13', new Date('2017-03-27 00:00:00 +0000')); +assert.format('%U', null, '14', new Date('2017-04-02 00:00:00 +0000')); ok('GMT'); From 29111d3bbb63a8ae4700ed7d4b7b30e7ffe6539f Mon Sep 17 00:00:00 2001 From: Peter deHaan Date: Sat, 23 May 2015 16:08:48 -0700 Subject: [PATCH 41/44] Update license attribute specifying the type and URL is deprecated: https://docs.npmjs.com/files/package.json#license http://npm1k.org/ --- package.json | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/package.json b/package.json index c130232..fde529f 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,7 @@ "engines": { "node": ">=0.2.0" }, - "licenses": [ - { - "type": "MIT", - "url": "http://sjs.mit-license.org" - } - ], + "license": "MIT", "dependencies": {}, "devDependencies": {}, "optionalDependencies": {} From 93326a4d733b3fa20356b60ff8d4ba4cdd1c31e1 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Fri, 29 May 2015 17:45:20 -0700 Subject: [PATCH 42/44] fix cached timestamps, closes #63 --- strftime.js | 3 +++ test.js | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/strftime.js b/strftime.js index c05c3f0..d34ad58 100644 --- a/strftime.js +++ b/strftime.js @@ -169,6 +169,9 @@ _cachedDate = new Date(_cachedDateTimestamp + getTimestampToUtcOffsetFor(_cachedDate) + _customTimezoneOffset); } } + else { + timestamp = _cachedDateTimestamp; + } date = _cachedDate; } else { diff --git a/test.js b/test.js index bc60e7b..66db148 100755 --- a/test.js +++ b/test.js @@ -195,6 +195,25 @@ assert.formatTZ('%F %r %z', '2011-06-07 11:21:45 AM -0730', '-0730'); assert.formatTZ('%F %r %:z', '2011-06-07 11:21:45 AM -07:30', '-0730'); ok('Time zone offset'); +/// caching +(function() { + // this test fails when the 2 calls cross a millisecond boundary, so try a number of times + var CacheAttempts = 10; + var MaxFailures = 1; + var failures = 0; + for (var i = 0; i < CacheAttempts; ++i) { + var expectedMillis = strftime('%L'); + var millis = strftime('%L'); + if (expectedMillis != millis) { + ++failures; + } + } + if (failures > MaxFailures) { + assert.fail('timestamp caching appears to be broken (' + failures + ' failed attempts out of ' + CacheAttempts + ')'); + } +}()); +ok('Cached timestamps'); + /// helpers From b852daca88bd4f055c1d6e0b91d7d1d707cf32f9 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Fri, 29 May 2015 17:52:25 -0700 Subject: [PATCH 43/44] v0.9.2 --- Changelog.md | 15 +++++++++++++++ bower.json | 2 +- component.json | 2 +- package.json | 2 +- strftime-min.js | 23 ++++++++++++----------- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Changelog.md b/Changelog.md index 18c524c..131d76b 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,18 @@ +v0.9.2 on 2015-05-29 +-------------------- + +- fix a caching bug, which was a regression in 0.9.0 ([issue #63](https://github.com/samsonjs/strftime/issues/63)) + +- update license attribute in package.json as required by npm + Thanks to [Peter deHaan](https://github.com/pdehaan) + +- construct GMT times used in tests in a more robust way + +- fix a bug calculating week numbers ([issue #56](https://github.com/samsonjs/strftime/issues/56)) + Thanks to [Alexandr Nikitin](https://github.com/alexandrnikitin) + +- warn about possible misuse of %:: or %::: modifiers + v0.9.1 on 2015-03-16 -------------------- diff --git a/bower.json b/bower.json index 34202bb..048c438 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "strftime", - "version": "0.9.1", + "version": "0.9.2", "main": "strftime.js", "ignore": [ "Readme.md", diff --git a/component.json b/component.json index d122a28..226451e 100644 --- a/component.json +++ b/component.json @@ -3,7 +3,7 @@ "repo": "samsonjs/strftime", "description": "strftime date formatting", "keywords": ["strftime", "format", "date", "time"], - "version": "0.9.1", + "version": "0.9.2", "main": "strftime.js", "scripts": ["strftime.js"] } diff --git a/package.json b/package.json index fde529f..0c312c7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "strftime", "description": "strftime for JavaScript", - "version": "0.9.1", + "version": "0.9.2", "homepage": "http://samhuri.net/proj/strftime", "author": "Sami Samhuri ", "contributors": [ diff --git a/strftime-min.js b/strftime-min.js index d867937..ee2bbc9 100644 --- a/strftime-min.js +++ b/strftime-min.js @@ -1,11 +1,12 @@ -(function(){function k(a,c){s[a]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+a+" is deprecated and will be removed in version 1.0. Instead, use `"+c+"`."),s[a]=!0)}function t(a){a.localize=i.localize.bind(i);a.timezone=i.timezone.bind(i);a.utc=i.utc.bind(i)}function r(a,c,e){c&&c.days&&(e=c,c=void 0);e&&k("`"+g+"(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])");return(e?i.localize(e):i)(a,c)}function u(a,c,e){e?k("`"+g+ -".strftime(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])"):k("`"+g+".strftime(format, [date])`",g+"(format, [date])");return(e?i.localize(e):i)(a,c)}function p(a,c,e){function g(a,b,h,c){for(var d="",f=null,e=!1,i=a.length,j=!1,o=0;o99?Math.floor(c%1E3):Math.floor(c%1E3)>9?"0"+Math.floor(c%1E3):"00"+Math.floor(c%1E3);break;case 77:d+=l(b.getMinutes(),f);break;case 80:d+=b.getHours()<12?h.am:h.pm;break;case 82:d+=g(h.formats.R,b,h,c);break;case 83:d+=l(b.getSeconds(),f);break;case 84:d+=g(h.formats.T,b,h,c);break;case 85:d+=l(w(b,"sunday"), -f);break;case 87:d+=l(w(b,"monday"),f);break;case 88:d+=g(h.formats.X,b,h,c);break;case 89:d+=b.getFullYear();break;case 90:k&&m===0?d+="GMT":(f=b.toString().match(/\(([\w\s]+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[b.getDay()];break;case 98:d+=h.shortMonths[b.getMonth()];break;case 99:d+=g(h.formats.c,b,h,c);break;case 100:d+=l(b.getDate(),f);break;case 101:d+=l(b.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[b.getMonth()];break;case 106:f=new Date(b.getFullYear(),0,1);f=Math.ceil((b.getTime()- -f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+=l(b.getHours(),f==null?" ":f);break;case 108:d+=l(v(b.getHours()),f==null?" ":f);break;case 109:d+=l(b.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(b.getDate())+A(b.getDate());break;case 112:d+=b.getHours()<12?h.AM:h.PM;break;case 114:d+=g(h.formats.r,b,h,c);break;case 115:d+=Math.floor(c/1E3);break;case 116:d+="\t";break;case 117:f=b.getDay();d+=f===0?7:f;break;case 118:d+=g(h.formats.v,b,h,c);break;case 119:d+=b.getDay(); -break;case 120:d+=g(h.formats.x,b,h,c);break;case 121:d+=(""+b.getFullYear()).slice(2);break;case 122:k&&m===0?d+=j?"+00:00":"+0000":(f=m!==0?m/6E4:-b.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=a[o]}f=null;e=!1}else n===37?e=!0:d+=a[o]}return d}var i=a||x,m=c||0,k=e||!1,j=0,q,a=function(a,b){var c;if(b)c=b.getTime(),k&&(b=new Date(b.getTime()+(b.getTimezoneOffset()||0)*6E4+m));else{var e=Date.now();e>j&&(j=e,q=new Date(j), -c=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+m)));b=q}return g(a,b,i,c)};a.localize=function(a){return new p(a||i,m,k)};a.timezone=function(a){var b=m,c=k,e=typeof a;if(e==="number"||e==="string")c=!0,e==="string"?(b=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),b=b*(60*e+a)*6E4):e==="number"&&(b=a*6E4);return new p(i,b,c)};a.utc=function(){return new p(i,m,!0)};return a}function l(a,c){if(c===""||a>9)return a;c==null&&(c="0");return c+a}function v(a){if(a===0)return 12; -else if(a>12)return a-12;return a}function w(a,c){var c=c||"sunday",e=a.getDay();c==="monday"&&(e===0?e=6:e--);var g=new Date(a.getFullYear(),0,1);return Math.floor(((a-g)/864E5+7-e)/7)}function A(a){var c=a%10;a%=100;if(a>=11&&a<=13||c===0||c>=4)return"th";switch(c){case 1:return"st";case 2:return"nd";case 3:return"rd"}}var x={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April", -"May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p",v:"%e-%b-%Y",x:"%D"}},i=new p(x,0,!1),y=typeof module!=="undefined",j;y?(j=module.exports=r,j.strftime=u):(j=function(){return this||(0,eval)("this")}(),j.strftime=r);var g=y?"require('strftime')":"strftime",s= -{};j.strftimeTZ=function(a,c,e,j){if((typeof e=="number"||typeof e=="string")&&j==null)j=e,e=void 0;e?k("`"+g+".strftimeTZ(format, date, locale, tz)`","var s = "+g+".localize(locale).timezone(tz); s(format, [date])` or `var s = "+g+".localize(locale); s.timezone(tz)(format, [date])"):k("`"+g+".strftimeTZ(format, date, tz)`","var s = "+g+".timezone(tz); s(format, [date])` or `"+g+".timezone(tz)(format, [date])");return(e?i.localize(e):i).timezone(j)(a,c)};j.strftimeUTC=function(a,c,e){e?k("`"+g+".strftimeUTC(format, date, locale)`", -"var s = "+g+".localize(locale).utc(); s(format, [date])"):k("`"+g+".strftimeUTC(format, [date])`","var s = "+g+".utc(); s(format, [date])");return(e?z.localize(e):z)(a,c)};j.localizedStrftime=function(a){k("`"+g+".localizedStrftime(locale)`",g+".localize(locale)");return i.localize(a)};t(r);t(u);var z=i.utc();if(typeof Date.now!=="function")Date.now=function(){return+new Date}})(); +(function(){function k(b,a){s[b]||(typeof console!=="undefined"&&typeof console.warn=="function"&&console.warn("[WARNING] "+b+" is deprecated and will be removed in version 1.0. Instead, use `"+a+"`."),s[b]=!0)}function t(b){b.localize=i.localize.bind(i);b.timezone=i.timezone.bind(i);b.utc=i.utc.bind(i)}function r(b,a,e){a&&a.days&&(e=a,a=void 0);e&&k("`"+g+"(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])");return(e?i.localize(e):i)(b,a)}function u(b,a,e){e?k("`"+g+ +".strftime(format, [date], [locale])`","var s = "+g+".localize(locale); s(format, [date])"):k("`"+g+".strftime(format, [date])`",g+"(format, [date])");return(e?i.localize(e):i)(b,a)}function p(b,a,e){function g(b,c,h,a){for(var d="",f=null,e=!1,i=b.length,j=!1,o=0;o99?Math.floor(a%1E3):Math.floor(a%1E3)>9?"0"+Math.floor(a%1E3):"00"+Math.floor(a%1E3);break;case 77:d+=l(c.getMinutes(),f);break;case 80:d+=c.getHours()<12?h.am:h.pm;break;case 82:d+= +g(h.formats.R,c,h,a);break;case 83:d+=l(c.getSeconds(),f);break;case 84:d+=g(h.formats.T,c,h,a);break;case 85:d+=l(w(c,"sunday"),f);break;case 87:d+=l(w(c,"monday"),f);break;case 88:d+=g(h.formats.X,c,h,a);break;case 89:d+=c.getFullYear();break;case 90:k&&m===0?d+="GMT":(f=c.toString().match(/\(([\w\s]+)\)/),d+=f&&f[1]||"");break;case 97:d+=h.shortDays[c.getDay()];break;case 98:d+=h.shortMonths[c.getMonth()];break;case 99:d+=g(h.formats.c,c,h,a);break;case 100:d+=l(c.getDate(),f);break;case 101:d+= +l(c.getDate(),f==null?" ":f);break;case 104:d+=h.shortMonths[c.getMonth()];break;case 106:f=new Date(c.getFullYear(),0,1);f=Math.ceil((c.getTime()-f.getTime())/864E5);d+=f>99?f:f>9?"0"+f:"00"+f;break;case 107:d+=l(c.getHours(),f==null?" ":f);break;case 108:d+=l(v(c.getHours()),f==null?" ":f);break;case 109:d+=l(c.getMonth()+1,f);break;case 110:d+="\n";break;case 111:d+=String(c.getDate())+A(c.getDate());break;case 112:d+=c.getHours()<12?h.AM:h.PM;break;case 114:d+=g(h.formats.r,c,h,a);break;case 115:d+= +Math.floor(a/1E3);break;case 116:d+="\t";break;case 117:f=c.getDay();d+=f===0?7:f;break;case 118:d+=g(h.formats.v,c,h,a);break;case 119:d+=c.getDay();break;case 120:d+=g(h.formats.x,c,h,a);break;case 121:d+=(""+c.getFullYear()).slice(2);break;case 122:k&&m===0?d+=j?"+00:00":"+0000":(f=m!==0?m/6E4:-c.getTimezoneOffset(),e=j?":":"",n=Math.abs(f%60),d+=(f<0?"-":"+")+l(Math.floor(Math.abs(f/60)))+e+l(n));break;default:d+=b[o]}f=null;e=!1}else n===37?e=!0:d+=b[o]}return d}var i=b||x,m=a||0,k=e||!1,j=0, +q,b=function(b,c){var a;c?(a=c.getTime(),k&&(c=new Date(c.getTime()+(c.getTimezoneOffset()||0)*6E4+m))):(a=Date.now(),a>j?(j=a,q=new Date(j),a=j,k&&(q=new Date(j+(q.getTimezoneOffset()||0)*6E4+m))):a=j,c=q);return g(b,c,i,a)};b.localize=function(a){return new p(a||i,m,k)};b.timezone=function(a){var c=m,b=k,e=typeof a;if(e==="number"||e==="string")b=!0,e==="string"?(c=a[0]==="-"?-1:1,e=parseInt(a.slice(1,3),10),a=parseInt(a.slice(3,5),10),c=c*(60*e+a)*6E4):e==="number"&&(c=a*6E4);return new p(i,c, +b)};b.utc=function(){return new p(i,m,!0)};return b}function l(b,a){if(a===""||b>9)return b;a==null&&(a="0");return a+b}function v(b){if(b===0)return 12;else if(b>12)return b-12;return b}function w(b,a){var a=a||"sunday",e=b.getDay();a==="monday"&&(e===0?e=6:e--);var g=Date.UTC(b.getFullYear(),0,1),i=Date.UTC(b.getFullYear(),b.getMonth(),b.getDate());return Math.floor((Math.floor((i-g)/864E5)+7-e)/7)}function A(b){var a=b%10;b%=100;if(b>=11&&b<=13||a===0||a>=4)return"th";switch(a){case 1:return"st"; +case 2:return"nd";case 3:return"rd"}}var x={days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],AM:"AM",PM:"PM",am:"am",pm:"pm",formats:{D:"%m/%d/%y",F:"%Y-%m-%d",R:"%H:%M",T:"%H:%M:%S",X:"%T",c:"%a %b %d %X %Y",r:"%I:%M:%S %p", +v:"%e-%b-%Y",x:"%D"}},i=new p(x,0,!1),y=typeof module!=="undefined",j;y?(j=module.exports=r,j.strftime=u):(j=function(){return this||(0,eval)("this")}(),j.strftime=r);var g=y?"require('strftime')":"strftime",s={};j.strftimeTZ=function(b,a,e,j){if((typeof e=="number"||typeof e=="string")&&j==null)j=e,e=void 0;e?k("`"+g+".strftimeTZ(format, date, locale, tz)`","var s = "+g+".localize(locale).timezone(tz); s(format, [date])` or `var s = "+g+".localize(locale); s.timezone(tz)(format, [date])"):k("`"+ +g+".strftimeTZ(format, date, tz)`","var s = "+g+".timezone(tz); s(format, [date])` or `"+g+".timezone(tz)(format, [date])");return(e?i.localize(e):i).timezone(j)(b,a)};j.strftimeUTC=function(b,a,e){e?k("`"+g+".strftimeUTC(format, date, locale)`","var s = "+g+".localize(locale).utc(); s(format, [date])"):k("`"+g+".strftimeUTC(format, [date])`","var s = "+g+".utc(); s(format, [date])");return(e?z.localize(e):z)(b,a)};j.localizedStrftime=function(b){k("`"+g+".localizedStrftime(locale)`",g+".localize(locale)"); +return i.localize(b)};t(r);t(u);var z=i.utc();if(typeof Date.now!=="function")Date.now=function(){return+new Date}})(); From d6f6e7435155baa5854686a9383d3cd0ba1706b1 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Thu, 11 Jun 2015 09:53:06 -0700 Subject: [PATCH 44/44] fix example code --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index a6edf00..0c07a06 100644 --- a/Readme.md +++ b/Readme.md @@ -86,7 +86,7 @@ Alternatively you can use the timezone format used by ISO 8601, `+HHMM` or `-HHM var strftime = require('strftime') // not required in browsers var strftimePDT = strftime.timezone('-0700') var strftimeCEST = strftime.timezone('+0200') - console.log(strftimePDT('', new Date(1307472705067))) // => June 07, 11 11:51:45 + console.log(strftimePDT('%F %T', new Date(1307472705067))) // => June 07, 11 11:51:45 console.log(strftimeCEST('%F %T', new Date(1307472705067))) // => 2011-06-07 20:51:45 ```