Skip to content

Instantly share code, notes, and snippets.

@Fardinak
Last active August 29, 2015 14:21
Show Gist options
  • Save Fardinak/449b4842751579eb1510 to your computer and use it in GitHub Desktop.
Save Fardinak/449b4842751579eb1510 to your computer and use it in GitHub Desktop.
A Multi-Calendar-System DateTime Service based on Moment.js (and moment-jalaali)
define(['ng', 'moment-jalaali'],
function(ng, moment) {
var mod = ng.module('app.service.datetime', []);
mod.run(['$rootScope', function($rootScope) {
$rootScope.$on('$languageChangeSuccess', function(evt, newLang) {
if(newLang === 'fa') moment.loadPersian();
else moment.locale('en');
});
}]);
mod.service('calendarSystem', function() {
var availableSystems = {
GREGORIAN: 0,
JALALI: 1
};
var currentSystem = 0;
var findByValue = function(value) {
for(key in availableSystems)
if(value === availableSystems[key])
return key;
return null;
};
return {
SYSTEM: availableSystems,
set: function(value) {
if(!ng.isNumber(value))
throw new TypeError('A system must be represented with it\'s corresponding integer value.');
if(!findByValue(value))
throw new Error('The provided system is not defined!');
currentSystem = value;
},
get: function() {
return currentSystem;
},
toString: function() {
var key = findByValue(currentSystem);
if(key)
return key.substr(0, 1) + key.substr(1).toLowerCase();
else
return "Unknown";
}
};
});
// TODO: Switch to mod.provider and join-in the calendarSystem service
mod.factory('datetimeService', ['calendarSystem', function(calendarSystem) {
// TODO: Add support for forced Gregorian formatting like Jalali (jM -> gM OR use parameters)
// var formattingTokens = /(\\)?(j|g)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|w[o|w]?|YYYYY|YYYY|YY|gg(ggg?)?|)/g,
var formattingTokens = /(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|w[o|w]?|YYYYY|YYYY|YY|gg(ggg?)?|)/g,
sharedTokens = ['M', 'MM', 'MMM', 'MMMM', 'D', 'DD', 'DDD', 'w', 'YY', 'YYYY', 'YYYYY', 'gg', 'gggg', 'ggggg'];
// Bind directly
var _simpleBind = function(fn) {
return function() {
var result = this.$moment[fn].apply(this.$moment, arguments);
return moment.isMoment(result) ? this : result;
};
};
// Bind to jFn or fn based on calendar system flag
var _gjBind = function(fn) {
var jFn = 'j' + fn.substr(0, 1).toUpperCase() + fn.substr(1);
return function() {
var result = this.$moment[this.isJalali ? jFn : fn].apply(this.$moment, arguments);
return moment.isMoment(result) ? this : result;
}
};
// Bind directly but reformat specified parameter
var _gjParamBind = function(fn, paramIndex) {
return function() {
if(this.isJalali) {
var value = arguments[paramIndex];
arguments[paramIndex] = 'j' + value;
}
var result = this.$moment[fn].apply(this.$moment, arguments);
return moment.isMoment(result) ? this : result;
}
};
function DTS() {
// General functions
this.isDSTShifted = _simpleBind('isDSTShifted');
this.invalidAt = _simpleBind('invalidAt');
this.isValid = _simpleBind('isValid');
this.local = _simpleBind('local');
this.parsingFlags = _simpleBind('parsingFlags');
this.unix = _simpleBind('unix');
this.utc = _simpleBind('utc');
this.weekday = _simpleBind('weekday');
this.toString = _simpleBind('toString');
this.toDate = _simpleBind('toDate');
this.toISOString = _simpleBind('toISOString');
this.toArray = _simpleBind('toArray');
this.valueOf = _simpleBind('valueOf');
// Calculating functions
this.add = _gjParamBind('add', 1); // reformats add(1, 'month') to add(1, 'jMonth') if the jalali flag is set
this.endOf = _gjParamBind('endOf', 0);
this.startOf = _gjParamBind('startOf', 0);
this.subtract = _gjParamBind('subtract', 1);
// Shared date functions
this.date = _gjBind('date'); // reformats date(...) to jDate(...) if the jalali flag is set
this.dates = _gjBind('dates');
this.dayOfYear = _gjBind('dayOfYear');
this.month = _gjBind('month');
this.months = _gjBind('months');
this.week = _gjBind('week');
this.weekYear = _gjBind('weekYear');
this.weeks = _gjBind('weeks');
this.year = _gjBind('year');
this.years = _gjBind('years');
// Gregorian-specific functions
this.gDate = _simpleBind('date');
this.gDates = _simpleBind('dates');
this.gDayOfYear = _simpleBind('dayOfYear');
this.gMonth = _simpleBind('month');
this.gMonths = _simpleBind('months');
this.gWeek = _simpleBind('week');
this.gWeekYear = _simpleBind('weekYear');
this.gWeeks = _simpleBind('weeks');
this.gYear = _simpleBind('year');
this.gYears = _simpleBind('years');
// Jalali-specific functions
this.jDate = _simpleBind('jDate');
this.jDates = _simpleBind('jDates');
this.jDayOfYear = _simpleBind('jDayOfYear');
this.jMonth = _simpleBind('jMonth');
this.jMonths = _simpleBind('jMonths');
this.jWeek = _simpleBind('jWeek');
this.jWeekYear = _simpleBind('jWeekYear');
this.jWeeks = _simpleBind('jWeeks');
this.jYear = _simpleBind('jYear');
this.jYears = _simpleBind('jYears');
// Special bindings
this.clone = function() {
var dts = new DateTimeService();
dts.$moment = this.$moment.clone.call(this.$moment);
dts.isJalali = this.isJalali;
return dts;
};
this.format = function(format) {
if (this.isJalali) {
format = format.replace(formattingTokens, function(m) {
return (sharedTokens.indexOf(m) > -1 ? 'j' : '') + m;
});
}
return this.$moment.format.apply(this.$moment, arguments);
};
// TODO: Replace with the following line when jMoment.isSame is available in jMoment
// this.isSame = _gjParamBind('isSame', 1);
this.isSame = function(input, units) {
var inputMs;
units = (units || 'millisecond').toLowerCase();
if (units === 'millisecond') {
input = DateTimeService(input);
return +this === +input;
} else {
inputMs = +DateTimeService(input);
return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));
}
};
};
function DateTimeService(input, format, lang, utc) {
if(input instanceof DTS) return input;
var dts = new DTS;
if(utc)
dts.$moment = moment.utc(input, format, lang);
else
dts.$moment = moment(input, format, lang);
dts.isJalali = calendarSystem.get() === calendarSystem.SYSTEM.JALALI;
return dts;
};
return DateTimeService;
}]);
return mod;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment