Browse files

Extracted and packaged moment.isocalendar

I also ported the random test to mocha and should.js.  I added a
Makefile to aid in testing.  This is now a node.js package also.
  • Loading branch information...
0 parents commit 56a4c571bc5fbd5a6dd6e8648f5b59480afe84f4 Rocky Meza committed Jan 4, 2012
Showing with 248 additions and 0 deletions.
  1. +1 −0 .gitignore
  2. +3 −0 Makefile
  3. +24 −0 README.md
  4. +10 −0 index.html
  5. +60 −0 moment.isocalendar.js
  6. +27 −0 package.json
  7. +16 −0 test/helpers/date2iso.py
  8. +24 −0 test/helpers/iso2date.py
  9. +83 −0 test/isocalendar.js
1 .gitignore
@@ -0,0 +1 @@
+node_modules
3 Makefile
@@ -0,0 +1,3 @@
+.PHONY: test
+test:
+ ./node_modules/.bin/mocha
24 README.md
@@ -0,0 +1,24 @@
+# moment.isocalendar.js
+This plugin provides a Python-like isocalendar method to moment objects.
+
+## How to use?
+Simply call the `isocalendar` method on any moment object. It returns an array
+of four items: `year`, `week_of_year`, `day_of_week`, `minutes_since_midnight`.
+
+```javascript
+moment(new Date(2011, 11, 23, 14, 30)).isocalendar();
+// [2011, 51, 5, 870]
+```
+
+Additionally, there is a function that provides the inverse functionality, it
+takes an isocalendar array and returns a moment object.
+
+```javascript
+moment.fromIsocalendar([2011, 51, 5, 870]).format('LLLL');
+// "Friday, December 23 2011 2:30 PM"
+```
+
+## How to test?
+Make sure you have all the dependencies and run `make test`. You will also need
+Python installed on your computer as the tests compare results against those
+returned from Python. (Python scripts can be found in `test/helpers/`.
10 index.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<html>
+ <head>
+ <title>moment.isocalendar.js</title>
+ <script src="node_modules/moment/moment.js"></script>
+ <script src="moment.isocalendar.js"></script>
+ </head>
+ <body>
+ </body>
+</html>
60 moment.isocalendar.js
@@ -0,0 +1,60 @@
+if ( typeof require != 'undefined' ) {
+ var moment = require('moment');
+}
+;(function(moment) {
+
+ var dayOne = function(year) {
+ return moment(new Date(year, 0, 1, 0, 0, 0));
+ }
+
+ , firstIsoWeekOfYear = function(year) {
+ var m = dayOne(year);
+
+ // ISO week is the first week with a Thursday, so if the first
+ // day of the year is Friday, move to next Sunday.
+ if ( m.day() > 4 ) {
+ m.add('weeks', 1);
+ }
+
+ m.subtract('days', m.day());
+
+ return m;
+ }
+ ;
+
+ moment.fn.isocalendar = function() {
+ var year = this.year()
+ , firstSunday = firstIsoWeekOfYear(year)
+ , week = Math.floor(this.diff(firstSunday, 'weeks', true)) + 1
+ , day = this.day()
+ , minute = this.hours() * 60 + this.minutes()
+ ;
+
+ if ( week == 53 && firstIsoWeekOfYear(year + 1) <= this )
+ {
+ year += 1;
+ week = 1;
+ }
+ else if ( week < 1 )
+ {
+ year -= 1;
+ week = moment(new Date(year, 11, 31, 0, 0)).isocalendar()[1];
+ }
+
+ return [ year
+ , week
+ , day
+ , minute
+ ];
+ };
+
+ moment.fromIsocalendar = function(year, week, day, minute) {
+ var date = firstIsoWeekOfYear(year).add({
+ weeks: week - 1
+ , days: day
+ , minutes: minute
+ });
+
+ return date;
+ };
+})(moment);
27 package.json
@@ -0,0 +1,27 @@
+{ "name": "moment-isocalendar"
+, "version": "0.0.1"
+, "description": ""
+, "homepage": "https://github.com/rockymeza/moment-isocalendar"
+, "author": "Rocky Meza <rockymeza@gmail.com> (http://rockymeza.com)"
+, "keywords": [ "moment"
+ , "isocalendar"
+ , "iso"
+ , "date"
+ ]
+, "main": "./moment.isocalendar"
+, "engines": { "node": "*"
+ }
+, "dependencies": { "moment": ">=1.0.0"
+ }
+, "devDependencies": { "mocha": "*"
+ , "should": "*"
+ }
+, "repository": { "type": "git"
+ , "url": "https://github.com/rockymeza/moment-isocalendar.git"
+ }
+, "bugs": { "url": "https://github.com/rockymeza/moment-isocalendar/issues"
+ }
+, "licenses" : [ { "type" : "MIT"
+ }
+ ]
+}
16 test/helpers/date2iso.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import sys
+import datetime
+import json
+
+date = datetime.datetime(*map(int, sys.argv[1:]))
+date += datetime.timedelta(days=1)
+
+year, week, day = date.isocalendar()
+minutes = date.hour * 60 + date.minute
+
+ret = (year, week, day - 1, minutes)
+
+print(json.dumps(ret))
24 test/helpers/iso2date.py
@@ -0,0 +1,24 @@
+#!/usr/bin/env python
+from __future__ import print_function
+
+import sys
+import datetime
+import json
+
+year, week, day, minutes = map(int, sys.argv[1:])
+
+first_day = datetime.datetime.strptime('%04d-%02d-1' % (year, week), '%Y-%W-%w')
+if datetime.date(year, 1, 4).isoweekday() > 4:
+ first_day -= datetime.timedelta(days=7)
+
+date = first_day + datetime.timedelta(days=day - 1, minutes=minutes)
+
+ret = [
+ date.year,
+ date.month,
+ date.day,
+ date.hour,
+ date.minute,
+ ]
+
+print(json.dumps(ret))
83 test/isocalendar.js
@@ -0,0 +1,83 @@
+var moment = require('moment')
+ , should = require('should')
+ , exec = require('child_process').exec;
+
+require('../moment.isocalendar');
+;(function(m) {
+
+ function date2iso(date, done) {
+ var date_string = date.format('YYYY M D H m');
+
+ exec('python test/helpers/date2iso.py ' + date_string, function(error, stdin, stdout) {
+ var expected = JSON.parse(stdin);
+
+ date.isocalendar().should.eql(expected);
+
+ if ( done )
+ done();
+ });
+ }
+
+ function iso2date(date, done) {
+ var iso = date.isocalendar()
+ , iso_string = iso.join(' ');
+
+ exec('python test/helpers/iso2date.py ' + iso_string, function(error, stdin, stdout) {
+ var resp = JSON.parse(stdin)
+ , expected = moment(new Date(resp[0], resp[1] - 1, resp[2], resp[3], resp[4]))
+ , actual = moment.fromIsocalendar.apply(moment, iso);
+
+ actual.format('LLLL').should.equal(expected.format('LLLL'));
+ });
+
+ if ( done )
+ done();
+ }
+
+ function testBackAndForth(date, done) {
+ var relative = date.isocalendar()
+ , date2 = moment.fromIsocalendar.apply(moment, relative)
+ , relative2 = date2.isocalendar()
+ ;
+
+ date.format('LLLL').should.equal(date2.format('LLLL'));
+ relative.should.eql(relative2);
+
+ if ( done )
+ done();
+ }
+
+ function rand(max) {
+ return Math.floor(Math.random() * max);
+ }
+
+ function doDone(bool, done) {
+ return function() { if ( bool ) done(); };
+ }
+
+ function randomly(times, func, done) {
+ for (var i = times; i > 0; i--) {
+ var date = moment(new Date(2000, 0, 1, 0, 0)).add('minutes', rand(365 * 100 * 60 * 24));
+
+ func(date, doDone(i == 1, done));
+ }
+ }
+
+ describe('isocalendar', function() {
+ // if you start spawning too much, test start failing
+ var times = 50;
+
+ it('random testBackAndForth', function(done) {
+ randomly(times, testBackAndForth, done);
+ });
+
+ it('random iso2date', function(done) {
+ randomly(times, iso2date, done);
+ });
+
+ it('random date2iso', function(done) {
+ randomly(times, date2iso, done);
+ });
+ });
+
+})(moment);

0 comments on commit 56a4c57

Please sign in to comment.