]> git.ipfire.org Git - thirdparty/moment.git/commitdiff
[feature] Add support for eras in en and jp
authorCaleb Cauthon <calebcauthon@users.noreply.github.com>
Sun, 15 Apr 2018 06:09:18 +0000 (01:09 -0500)
committerIskren Chernev <iskren.chernev@gmail.com>
Mon, 27 Apr 2020 00:11:10 +0000 (03:11 +0300)
src/lib/create/from-string-and-format.js
src/lib/create/parsing-flags.js
src/lib/create/valid.js
src/lib/format/format.js
src/lib/locale/en.js
src/lib/locale/prototype.js
src/lib/moment/prototype.js
src/lib/units/era.js [new file with mode: 0644]
src/locale/ja.js
src/test/locale/en.js
src/test/locale/ja.js

index b6c5082ea5181926e3d39534b92b8f58517e5303..df55f17050363fdedbbb9bf92ef4ab242e064375 100644 (file)
@@ -8,7 +8,7 @@ import {
     formattingTokens,
 } from '../format/format';
 import checkOverflow from './check-overflow';
-import { HOUR } from '../units/constants';
+import { YEAR, HOUR } from '../units/constants';
 import { hooks } from '../utils/hooks';
 import getParsingFlags from './parsing-flags';
 
@@ -40,7 +40,8 @@ export function configFromStringAndFormat(config) {
         token,
         skipped,
         stringLength = string.length,
-        totalParsedInputLength = 0;
+        totalParsedInputLength = 0,
+        era;
 
     tokens =
         expandFormat(config._f, config._locale).match(formattingTokens) || [];
@@ -99,6 +100,12 @@ export function configFromStringAndFormat(config) {
         config._meridiem
     );
 
+    // handle era
+    era = getParsingFlags(config).era;
+    if (era !== null) {
+        config._a[YEAR] = config._locale.erasConvertYear(era, config._a[YEAR]);
+    }
+
     configFromArray(config);
     checkOverflow(config);
 }
index 4c75977187cdbc95f2b48c928961739c74164463..65a377db1d3c949b34b1e83bce093ebb39e62afe 100644 (file)
@@ -7,11 +7,13 @@ function defaultParsingFlags() {
         overflow: -2,
         charsLeftOver: 0,
         nullInput: false,
+        invalidEra: null,
         invalidMonth: null,
         invalidFormat: false,
         userInvalidated: false,
         iso: false,
         parsedDateParts: [],
+        era: null,
         meridiem: null,
         rfc2822: false,
         weekdayMismatch: false,
index 38be121659b781ec34dc0ae53440797df54ef4d3..b25c7d1161f6b400c26a6cd89bb357943fc9b32e 100644 (file)
@@ -13,6 +13,7 @@ export function isValid(m) {
                 !isNaN(m._d.getTime()) &&
                 flags.overflow < 0 &&
                 !flags.empty &&
+                !flags.invalidEra &&
                 !flags.invalidMonth &&
                 !flags.invalidWeekday &&
                 !flags.weekdayMismatch &&
index 53b00d687c84d7fc22e2acd11987d48ee367b751..177788f2ad23db7d64a95852339b18d301324b2b 100644 (file)
@@ -1,7 +1,7 @@
 import zeroFill from '../utils/zero-fill';
 import isFunction from '../utils/is-function';
 
-var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,
+var formattingTokens = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,
     localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
     formatFunctions = {},
     formatTokenFunctions = {};
index c54866159179629b315c8e16253843d7dfbb2857..470bd27a7c9c38b210a1c3f65ceea61b46e82d46 100644 (file)
@@ -3,6 +3,24 @@ import { getSetGlobalLocale } from './locales';
 import toInt from '../utils/to-int';
 
 getSetGlobalLocale('en', {
+    eras: [
+        {
+            since: '0001-01-01',
+            until: +Infinity,
+            offset: 1,
+            name: 'Anno Domini',
+            narrow: 'AD',
+            abbr: 'AD',
+        },
+        {
+            since: '0000-12-31',
+            until: -Infinity,
+            offset: 1,
+            name: 'Before Christ',
+            narrow: 'BC',
+            abbr: 'BC',
+        },
+    ],
     dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,
     ordinal: function (number) {
         var b = number % 10,
index eb523d033fe04716b85828cf683e75ec3427f34a..2057f695268dfd4e399c174a0e309182c0bc591a 100644 (file)
@@ -20,6 +20,22 @@ proto.relativeTime = relativeTime;
 proto.pastFuture = pastFuture;
 proto.set = set;
 
+// Eras
+import {
+    localeEras,
+    localeErasParse,
+    localeErasConvertYear,
+    erasAbbrRegex,
+    erasNameRegex,
+    erasNarrowRegex,
+} from '../units/era';
+proto.eras = localeEras;
+proto.erasParse = localeErasParse;
+proto.erasConvertYear = localeErasConvertYear;
+proto.erasAbbrRegex = erasAbbrRegex;
+proto.erasNameRegex = erasNameRegex;
+proto.erasNarrowRegex = erasNarrowRegex;
+
 // Month
 import {
     localeMonthsParse,
index 46ff54ab96b5e37ab8e1db865db855037f8155a7..bbea60146df3ac8b470108ee768a513708a22c73 100644 (file)
@@ -69,6 +69,13 @@ proto.unix = unix;
 proto.valueOf = valueOf;
 proto.creationData = creationData;
 
+// Era
+import { getEraName, getEraNarrow, getEraAbbr, getEraYear } from '../units/era';
+proto.eraName = getEraName;
+proto.eraNarrow = getEraNarrow;
+proto.eraAbbr = getEraAbbr;
+proto.eraYear = getEraYear;
+
 // Year
 import { getSetYear, getIsLeapYear } from '../units/year';
 proto.year = getSetYear;
diff --git a/src/lib/units/era.js b/src/lib/units/era.js
new file mode 100644 (file)
index 0000000..28c7149
--- /dev/null
@@ -0,0 +1,289 @@
+import { addFormatToken } from '../format/format';
+import { addRegexToken, matchUnsigned, regexEscape } from '../parse/regex';
+import { addParseToken } from '../parse/token';
+import { YEAR } from './constants';
+import { hooks as moment } from '../utils/hooks';
+import { getLocale } from '../locale/locales';
+import getParsingFlags from '../create/parsing-flags';
+import hasOwnProp from '../utils/has-own-prop';
+
+addFormatToken('N', 0, 0, 'eraAbbr');
+addFormatToken('NN', 0, 0, 'eraAbbr');
+addFormatToken('NNN', 0, 0, 'eraAbbr');
+addFormatToken('NNNN', 0, 0, 'eraName');
+addFormatToken('NNNNN', 0, 0, 'eraNarrow');
+
+addFormatToken('y', ['y', 1], 'yo', 'eraYear');
+addFormatToken('y', ['yy', 2], 0, 'eraYear');
+addFormatToken('y', ['yyy', 3], 0, 'eraYear');
+addFormatToken('y', ['yyyy', 4], 0, 'eraYear');
+
+addRegexToken('N', matchEraAbbr);
+addRegexToken('NN', matchEraAbbr);
+addRegexToken('NNN', matchEraAbbr);
+addRegexToken('NNNN', matchEraName);
+addRegexToken('NNNNN', matchEraNarrow);
+
+addParseToken(['N', 'NN', 'NNN', 'NNNN', 'NNNNN'], function (
+    input,
+    array,
+    config,
+    token
+) {
+    var era = config._locale.erasParse(input, token, config._strict);
+    if (era) {
+        getParsingFlags(config).era = era;
+    } else {
+        getParsingFlags(config).invalidEra = input;
+    }
+});
+
+addRegexToken('y', matchUnsigned);
+addRegexToken('yy', matchUnsigned);
+addRegexToken('yyy', matchUnsigned);
+addRegexToken('yyyy', matchUnsigned);
+addRegexToken('yo', matchEraYearOrdinal);
+
+addParseToken(['y', 'yy', 'yyy', 'yyyy'], YEAR);
+addParseToken(['yo'], function (input, array, config, token) {
+    var match;
+    if (config._locale._eraYearOrdinalRegex) {
+        match = input.match(config._locale._eraYearOrdinalRegex);
+    }
+
+    if (config._locale.eraYearOrdinalParse) {
+        array[YEAR] = config._locale.eraYearOrdinalParse(input, match);
+    } else {
+        array[YEAR] = parseInt(input, 10);
+    }
+});
+
+export function localeEras(m, format) {
+    var i,
+        l,
+        date,
+        eras = this._eras || getLocale('en')._eras;
+    for (i = 0, l = eras.length; i < l; ++i) {
+        switch (typeof eras[i].since) {
+            case 'string':
+                // truncate time
+                date = moment(eras[i].since).startOf('day');
+                eras[i].since = date.valueOf();
+                break;
+        }
+
+        switch (typeof eras[i].until) {
+            case 'undefined':
+                eras[i].until = +Infinity;
+                break;
+            case 'string':
+                // truncate time
+                date = moment(eras[i].until).startOf('day').valueOf();
+                eras[i].until = date.valueOf();
+                break;
+        }
+    }
+    return eras;
+}
+
+export function localeErasParse(eraName, format, strict) {
+    var i,
+        l,
+        eras = this.eras(),
+        name,
+        abbr,
+        narrow;
+    eraName = eraName.toUpperCase();
+
+    for (i = 0, l = eras.length; i < l; ++i) {
+        name = eras[i].name.toUpperCase();
+        abbr = eras[i].abbr.toUpperCase();
+        narrow = eras[i].narrow.toUpperCase();
+
+        if (strict) {
+            switch (format) {
+                case 'N':
+                case 'NN':
+                case 'NNN':
+                    if (abbr === eraName) {
+                        return eras[i];
+                    }
+                    break;
+
+                case 'NNNN':
+                    if (name === eraName) {
+                        return eras[i];
+                    }
+                    break;
+
+                case 'NNNNN':
+                    if (narrow === eraName) {
+                        return eras[i];
+                    }
+                    break;
+            }
+        } else if ([name, abbr, narrow].indexOf(eraName) >= 0) {
+            return eras[i];
+        }
+    }
+}
+
+export function localeErasConvertYear(era, year) {
+    var dir = era.since <= era.until ? +1 : -1;
+    if (year === undefined) {
+        return moment(era.since).year();
+    } else {
+        return moment(era.since).year() + (year - era.offset) * dir;
+    }
+}
+
+export function getEraName() {
+    var i,
+        l,
+        val,
+        eras = this.localeData().eras();
+    for (i = 0, l = eras.length; i < l; ++i) {
+        // truncate time
+        val = this.startOf('day').valueOf();
+
+        if (eras[i].since <= val && val <= eras[i].until) {
+            return eras[i].name;
+        }
+        if (eras[i].until <= val && val <= eras[i].since) {
+            return eras[i].name;
+        }
+    }
+
+    return '';
+}
+
+export function getEraNarrow() {
+    var i,
+        l,
+        val,
+        eras = this.localeData().eras();
+    for (i = 0, l = eras.length; i < l; ++i) {
+        // truncate time
+        val = this.startOf('day').valueOf();
+
+        if (eras[i].since <= val && val <= eras[i].until) {
+            return eras[i].narrow;
+        }
+        if (eras[i].until <= val && val <= eras[i].since) {
+            return eras[i].narrow;
+        }
+    }
+
+    return '';
+}
+
+export function getEraAbbr() {
+    var i,
+        l,
+        val,
+        eras = this.localeData().eras();
+    for (i = 0, l = eras.length; i < l; ++i) {
+        // truncate time
+        val = this.startOf('day').valueOf();
+
+        if (eras[i].since <= val && val <= eras[i].until) {
+            return eras[i].abbr;
+        }
+        if (eras[i].until <= val && val <= eras[i].since) {
+            return eras[i].abbr;
+        }
+    }
+
+    return '';
+}
+
+export function getEraYear() {
+    var i,
+        l,
+        dir,
+        val,
+        eras = this.localeData().eras();
+    for (i = 0, l = eras.length; i < l; ++i) {
+        dir = eras[i].since <= eras[i].until ? +1 : -1;
+
+        // truncate time
+        val = this.startOf('day').valueOf();
+
+        if (
+            (eras[i].since <= val && val <= eras[i].until) ||
+            (eras[i].until <= val && val <= eras[i].since)
+        ) {
+            return (
+                (this.year() - moment(eras[i].since).year()) * dir +
+                eras[i].offset
+            );
+        }
+    }
+
+    return this.year();
+}
+
+export function erasNameRegex(isStrict) {
+    if (!hasOwnProp(this, '_erasNameRegex')) {
+        computeErasParse.call(this);
+    }
+    return isStrict ? this._erasNameRegex : this._erasRegex;
+}
+
+export function erasAbbrRegex(isStrict) {
+    if (!hasOwnProp(this, '_erasAbbrRegex')) {
+        computeErasParse.call(this);
+    }
+    return isStrict ? this._erasAbbrRegex : this._erasRegex;
+}
+
+export function erasNarrowRegex(isStrict) {
+    if (!hasOwnProp(this, '_erasNarrowRegex')) {
+        computeErasParse.call(this);
+    }
+    return isStrict ? this._erasNarrowRegex : this._erasRegex;
+}
+
+function matchEraAbbr(isStrict, locale) {
+    return locale.erasAbbrRegex(isStrict);
+}
+
+function matchEraName(isStrict, locale) {
+    return locale.erasNameRegex(isStrict);
+}
+
+function matchEraNarrow(isStrict, locale) {
+    return locale.erasNarrowRegex(isStrict);
+}
+
+function matchEraYearOrdinal(isStrict, locale) {
+    return locale._eraYearOrdinalRegex || matchUnsigned;
+}
+
+function computeErasParse() {
+    var abbrPieces = [],
+        namePieces = [],
+        narrowPieces = [],
+        mixedPieces = [],
+        i,
+        l,
+        eras = this.eras();
+
+    for (i = 0, l = eras.length; i < l; ++i) {
+        namePieces.push(regexEscape(eras[i].name));
+        abbrPieces.push(regexEscape(eras[i].abbr));
+        narrowPieces.push(regexEscape(eras[i].narrow));
+
+        mixedPieces.push(regexEscape(eras[i].name));
+        mixedPieces.push(regexEscape(eras[i].abbr));
+        mixedPieces.push(regexEscape(eras[i].narrow));
+    }
+
+    this._erasRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');
+    this._erasNameRegex = new RegExp('^(' + namePieces.join('|') + ')', 'i');
+    this._erasAbbrRegex = new RegExp('^(' + abbrPieces.join('|') + ')', 'i');
+    this._erasNarrowRegex = new RegExp(
+        '^(' + narrowPieces.join('|') + ')',
+        'i'
+    );
+}
index 827d42d8b013970820ef4a02c2d4d6f429e033c6..612a36984254ff70c008b91eec1d27954a4eca21 100644 (file)
@@ -5,6 +5,59 @@
 import moment from '../moment';
 
 export default moment.defineLocale('ja', {
+    eras: [
+        {
+            since: '1989-01-08',
+            offset: 1,
+            name: '平成',
+            narrow: '㍻',
+            abbr: 'H',
+        },
+        {
+            since: '1926-12-25',
+            until: '1989-01-07',
+            offset: 1,
+            name: '昭和',
+            narrow: '㍼',
+            abbr: 'S',
+        },
+        {
+            since: '1912-07-30',
+            until: '1926-12-24',
+            offset: 1,
+            name: '大正',
+            narrow: '㍽',
+            abbr: 'T',
+        },
+        {
+            since: '1873-01-01',
+            until: '1912-07-29',
+            offset: 6,
+            name: '明治',
+            narrow: '㍾',
+            abbr: 'M',
+        },
+        {
+            since: '0001-01-01',
+            until: '1873-12-31',
+            offset: 1,
+            name: '西暦',
+            narrow: 'AD',
+            abbr: 'AD',
+        },
+        {
+            since: '0000-12-31',
+            until: -Infinity,
+            offset: 1,
+            name: '紀元前',
+            narrow: 'BC',
+            abbr: 'BC',
+        },
+    ],
+    eraYearOrdinalRegex: /(元|\d+)年/,
+    eraYearOrdinalParse: function (input, match) {
+        return match[1] === '元' ? 1 : parseInt(match[1] || input, 10);
+    },
     months: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
     monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split(
         '_'
@@ -58,6 +111,8 @@ export default moment.defineLocale('ja', {
     dayOfMonthOrdinalParse: /\d{1,2}日/,
     ordinal: function (number, period) {
         switch (period) {
+            case 'y':
+                return number === 1 ? '元年' : number + '年';
             case 'd':
             case 'D':
             case 'DDD':
index 561efed599f2c4ce60459e8a2b776973b07db64d..afc8621d06c701abec71d239f94704ea9d394264 100644 (file)
@@ -67,6 +67,80 @@ test('format', function (assert) {
     }
 });
 
+test('parse era', function (assert) {
+    assert.equal(moment('2010 AD', 'y N', true).isValid(), true, '2010 AD');
+    assert.equal(moment('2010 AD', 'y N', true).year(), 2010, '2010 AD');
+
+    assert.equal(
+        moment('2010 Anno Domini', 'y N', true).isValid(),
+        false,
+        '2010 Anno Domini'
+    );
+    assert.equal(
+        moment('2010 Anno Domini', 'y N', false).isValid(),
+        true,
+        '2010 Anno Domini'
+    );
+    assert.equal(
+        moment('2010 Anno Domini', 'y NNNN', true).isValid(),
+        true,
+        '2010 Anno Domini'
+    );
+    assert.equal(
+        moment('2010 Anno Domini', 'y NNNN', true).year(),
+        2010,
+        '2010 Anno Domini'
+    );
+    assert.equal(
+        moment('2010 Anno Domini', 'y N', false).year(),
+        2010,
+        '2010 Anno Domini'
+    );
+
+    assert.equal(moment('469 BC', 'y N', true).isValid(), true, '469 BC');
+    assert.equal(moment('469 BC', 'y N', true).year(), -468, '469 BC');
+
+    assert.equal(
+        moment('469 Before Christ', 'y NNNN', true).isValid(),
+        true,
+        '469 Before Christ'
+    );
+    assert.equal(
+        moment('469 Before Christ', 'y NNNN', true).year(),
+        -468,
+        '469 Before Christ'
+    );
+});
+
+test('format era', function (assert) {
+    var a = [
+            ['+000001-01-01', 'N, NN, NNN', 'AD, AD, AD'],
+            ['+000001-01-01', 'NNNN', 'Anno Domini'],
+            ['+000001-01-01', 'NNNNN', 'AD'],
+            ['+000001-01-01', 'y', '1'],
+
+            ['+000000-12-31', 'N, NN, NNN', 'BC, BC, BC'],
+            ['+000000-12-31', 'NNNN', 'Before Christ'],
+            ['+000000-12-31', 'NNNNN', 'BC'],
+            ['+000000-12-31', 'y', '1'],
+
+            ['-000001-12-31', 'N, NN, NNN', 'BC, BC, BC'],
+            ['-000001-12-31', 'NNNN', 'Before Christ'],
+            ['-000001-12-31', 'NNNNN', 'BC'],
+            ['-000001-12-31', 'y', '2'],
+        ],
+        i,
+        l;
+
+    for (i = 0, l = a.length; i < l; ++i) {
+        assert.equal(
+            moment(a[i][0]).format(a[i][1]),
+            a[i][2],
+            a[i][0] + '; ' + a[i][1] + ' ---> ' + a[i][2]
+        );
+    }
+});
+
 test('format ordinal', function (assert) {
     assert.equal(moment([2011, 0, 1]).format('DDDo'), '1st', '1st');
     assert.equal(moment([2011, 0, 2]).format('DDDo'), '2nd', '2nd');
index 1ceea04e5fce49a8ba25648cc531375915eb65e1..7f0ca5ab413c946dcd7b48bf1dfd0a361f6d65ae 100644 (file)
@@ -64,6 +64,135 @@ test('format', function (assert) {
     }
 });
 
+test('parse era', function (assert) {
+    // strict
+    assert.equal(
+        moment('平成30年', 'NNNNy年', true).isValid(),
+        true,
+        '平成30年'
+    );
+    assert.equal(moment('平成30年', 'NNNNy年', true).year(), 2018, '平成30年');
+    assert.equal(
+        moment('平成30年', 'NNNNyo', true).isValid(),
+        true,
+        '平成30年'
+    );
+    assert.equal(moment('平成30年', 'NNNNyo', true).year(), 2018, '平成30年');
+
+    assert.equal(moment('平成30年', 'Ny年', true).isValid(), false, '平成30年');
+    assert.equal(moment('平成30年', 'Ny年', false).isValid(), true, '平成30年');
+    assert.equal(moment('㍻30年', 'Ny年', true).isValid(), false, '㍻30年');
+    assert.equal(moment('㍻30年', 'Ny年', false).isValid(), true, '㍻30年');
+    assert.equal(moment('H30年', 'Ny年', false).isValid(), true, 'H30年');
+
+    // abbrv
+    assert.equal(moment('H30年', 'Ny年', true).isValid(), true, 'H30年');
+    assert.equal(moment('H30年', 'Ny年', true).year(), 2018, 'H30年');
+    assert.equal(moment('H30年', 'NNNNy年', true).isValid(), false, 'H30年');
+    assert.equal(moment('H30年', 'NNNNNy年', true).isValid(), false, 'H30年');
+
+    // narrow
+    assert.equal(moment('㍻30年', 'Ny年', true).isValid(), false, '㍻30年');
+    assert.equal(moment('㍻30年', 'NNNNy年', true).isValid(), false, '㍻30年');
+    assert.equal(moment('㍻30年', 'NNNNNy年', true).isValid(), true, '㍻30年');
+    assert.equal(moment('㍻30年', 'NNNNNy年', true).year(), 2018, '㍻30年');
+
+    // ordinal year
+    assert.equal(moment('平成30年', 'NNNNyo', true).year(), 2018, '平成30年');
+    assert.equal(moment('平成元年', 'NNNNyo', true).year(), 1989, '平成元年');
+
+    // old eras
+    assert.equal(moment('昭和64年', 'NNNNyo', true).year(), 1989, '昭和64年');
+    assert.equal(moment('昭和元年', 'NNNNyo', true).year(), 1926, '昭和元年');
+    assert.equal(moment('大正元年', 'NNNNyo', true).year(), 1912, '大正元年');
+    assert.equal(moment('明治6年', 'NNNNyo', true).year(), 1873, '明治6年');
+});
+
+test('format era', function (assert) {
+    var a = [
+            /* First day of Heisei Era */
+            ['+001989-01-08', 'N, NN, NNN', 'H, H, H'],
+            ['+001989-01-08', 'NNNN', '平成'],
+            ['+001989-01-08', 'NNNNN', '㍻'],
+            ['+001989-01-08', 'y yy yyy yyyy', '1 01 001 0001'],
+            ['+001989-01-08', 'yo', '元年'],
+
+            /* Last day of Showa Era */
+            ['+001989-01-07', 'N, NN, NNN', 'S, S, S'],
+            ['+001989-01-07', 'NNNN', '昭和'],
+            ['+001989-01-07', 'NNNNN', '㍼'],
+            ['+001989-01-07', 'y yy yyy yyyy', '64 64 064 0064'],
+            ['+001989-01-07', 'yo', '64年'],
+
+            /* Last day of Showa Era */
+            ['+001926-12-25', 'N, NN, NNN', 'S, S, S'],
+            ['+001926-12-25', 'NNNN', '昭和'],
+            ['+001926-12-25', 'NNNNN', '㍼'],
+            ['+001926-12-25', 'y yy yyy yyyy', '1 01 001 0001'],
+            ['+001926-12-25', 'yo', '元年'],
+
+            /* Last day of Taisho Era */
+            ['+001926-12-24', 'N, NN, NNN', 'T, T, T'],
+            ['+001926-12-24', 'NNNN', '大正'],
+            ['+001926-12-24', 'NNNNN', '㍽'],
+            ['+001926-12-24', 'y yy yyy yyyy', '15 15 015 0015'],
+            ['+001926-12-24', 'yo', '15年'],
+
+            /* First day of Taisho Era */
+            ['+001912-07-30', 'N, NN, NNN', 'T, T, T'],
+            ['+001912-07-30', 'NNNN', '大正'],
+            ['+001912-07-30', 'NNNNN', '㍽'],
+            ['+001912-07-30', 'y yy yyy yyyy', '1 01 001 0001'],
+            ['+001912-07-30', 'yo', '元年'],
+
+            /* Last day of Meiji Era */
+            ['+001912-07-29', 'N, NN, NNN', 'M, M, M'],
+            ['+001912-07-29', 'NNNN', '明治'],
+            ['+001912-07-29', 'NNNNN', '㍾'],
+            ['+001912-07-29', 'y yy yyy yyyy', '45 45 045 0045'],
+            ['+001912-07-29', 'yo', '45年'],
+
+            /* The day the Japanese government had began using the Gregorian calendar */
+            ['+001873-01-01', 'N, NN, NNN', 'M, M, M'],
+            ['+001873-01-01', 'NNNN', '明治'],
+            ['+001873-01-01', 'NNNNN', '㍾'],
+            ['+001873-01-01', 'y yy yyy yyyy', '6 06 006 0006'],
+            ['+001873-01-01', 'yo', '6年'],
+
+            /* Christinan Era */
+            ['+001872-12-31', 'N, NN, NNN', 'AD, AD, AD'],
+            ['+001872-12-31', 'NNNN', '西暦'],
+            ['+001872-12-31', 'NNNNN', 'AD'],
+            ['+001872-12-31', 'y yy yyy yyyy', '1872 1872 1872 1872'],
+            ['+001872-12-31', 'yo', '1872年'],
+
+            ['+000001-01-01', 'N, NN, NNN', 'AD, AD, AD'],
+            ['+000001-01-01', 'NNNN', '西暦'],
+            ['+000001-01-01', 'NNNNN', 'AD'],
+            ['+000001-01-01', 'y', '1'],
+
+            ['+000000-12-31', 'N, NN, NNN', 'BC, BC, BC'],
+            ['+000000-12-31', 'NNNN', '紀元前'],
+            ['+000000-12-31', 'NNNNN', 'BC'],
+            ['+000000-12-31', 'y', '1'],
+
+            ['-000001-12-31', 'N, NN, NNN', 'BC, BC, BC'],
+            ['-000001-12-31', 'NNNN', '紀元前'],
+            ['-000001-12-31', 'NNNNN', 'BC'],
+            ['-000001-12-31', 'y', '2'],
+        ],
+        i,
+        l;
+
+    for (i = 0, l = a.length; i < l; ++i) {
+        assert.equal(
+            moment(a[i][0]).format(a[i][1]),
+            a[i][2],
+            a[i][0] + '; ' + a[i][1] + ' ---> ' + a[i][2]
+        );
+    }
+});
+
 test('format month', function (assert) {
     var expected = '1月 1月_2月 2月_3月 3月_4月 4月_5月 5月_6月 6月_7月 7月_8月 8月_9月 9月_10月 10月_11月 11月_12月 12月'.split(
             '_'