diff --git a/core/language/en-GB/Misc.multids b/core/language/en-GB/Misc.multids
index 62d41adfa..8fb500364 100644
--- a/core/language/en-GB/Misc.multids
+++ b/core/language/en-GB/Misc.multids
@@ -27,6 +27,7 @@ Error/EditConflict: File changed on server
Error/Filter: Filter error
Error/FilterSyntax: Syntax error in filter expression
Error/IsFilterOperator: Filter Error: Unknown operand for the 'is' filter operator
+Error/FormatFilterOperator: Filter Error: Unknown suffix for the 'format' filter operator
Error/LoadingPluginLibrary: Error loading plugin library
Error/NetworkErrorAlert: `
''Network Error''
It looks like the connection to the server has been lost. This may indicate a problem with your network connection. Please attempt to restore network connectivity before continuing.
''Any unsaved changes will be automatically synchronised when connectivity is restored''.`
Error/RecursiveTransclusion: Recursive transclusion error in transclude widget
diff --git a/core/modules/filters/format.js b/core/modules/filters/format.js
new file mode 100644
index 000000000..2fc786d88
--- /dev/null
+++ b/core/modules/filters/format.js
@@ -0,0 +1,46 @@
+/*\
+title: $:/core/modules/filters/format.js
+type: application/javascript
+module-type: filteroperator
+Filter operator for formatting strings
+\*/
+(function(){
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+var formatFilterOperators;
+
+function getFormatFilterOperators() {
+ if(!formatFilterOperators) {
+ formatFilterOperators = {};
+ $tw.modules.applyMethods("formatfilteroperator",formatFilterOperators);
+ }
+ return formatFilterOperators;
+}
+
+/*
+Export our filter function
+*/
+exports.format = function(source,operator,options) {
+ // Dispatch to the correct formatfilteroperator
+ var formatFilterOperators = getFormatFilterOperators();
+ if(operator.suffix) {
+ var formatFilterOperator = formatFilterOperators[operator.suffix];
+ if(formatFilterOperator) {
+ return formatFilterOperator(source,operator.operand,options);
+ } else {
+ return [$tw.language.getString("Error/FormatFilterOperator")];
+ }
+ } else {
+ // Return all unchanged if the suffix is missing
+ var results = [];
+ source(function(tiddler,title) {
+ results.push(title);
+ });
+ return results;
+ }
+};
+
+})();
\ No newline at end of file
diff --git a/core/modules/filters/format/date.js b/core/modules/filters/format/date.js
new file mode 100644
index 000000000..1b29c5bfb
--- /dev/null
+++ b/core/modules/filters/format/date.js
@@ -0,0 +1,26 @@
+/*\
+title: $:/core/modules/filters/format/date.js
+type: application/javascript
+module-type: formatfilteroperator
+\*/
+(function(){
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+/*
+Export our filter function
+*/
+exports.date = function(source,operand,options) {
+ var results = [];
+ source(function(tiddler,title) {
+ var value = $tw.utils.parseDate(title);
+ if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
+ results.push($tw.utils.formatDateString(value,operand || "YYYY MM DD 0hh:0mm"));
+ }
+ });
+ return results;
+};
+
+})();
\ No newline at end of file
diff --git a/core/modules/filters/format/relativedate.js b/core/modules/filters/format/relativedate.js
new file mode 100644
index 000000000..262aeaaf2
--- /dev/null
+++ b/core/modules/filters/format/relativedate.js
@@ -0,0 +1,26 @@
+/*\
+title: $:/core/modules/filters/format/relativedate.js
+type: application/javascript
+module-type: formatfilteroperator
+\*/
+(function(){
+
+/*jslint node: true, browser: true */
+/*global $tw: false */
+"use strict";
+
+/*
+Export our filter function
+*/
+exports.relativedate = function(source,operand,options) {
+ var results = [];
+ source(function(tiddler,title) {
+ var value = $tw.utils.parseDate(title);
+ if(value && $tw.utils.isDate(value) && value.toString() !== "Invalid Date") {
+ results.push($tw.utils.getRelativeDate((new Date()) - (new Date(value))).description);
+ }
+ });
+ return results;
+};
+
+})();
\ No newline at end of file