diff --git a/src/plugin/advancedFormat/index.js b/src/plugin/advancedFormat/index.js index c7a03701..2e97ee48 100644 --- a/src/plugin/advancedFormat/index.js +++ b/src/plugin/advancedFormat/index.js @@ -13,7 +13,7 @@ export default (o, c, d) => { // locale needed later const locale = this.$locale() const utils = this.$utils() const str = formatStr || FORMAT_DEFAULT - const result = str.replace(/\[([^\]]+)]|Q|wo|ww|w|gggg|Do|X|x|k{1,2}|S/g, (match) => { + const result = str.replace(/\[([^\]]+)]|Q|wo|ww|w|zzz|z|gggg|Do|X|x|k{1,2}|S/g, (match) => { switch (match) { case 'Q': return Math.ceil((this.$M + 1) / 3) @@ -33,6 +33,10 @@ export default (o, c, d) => { // locale needed later return Math.floor(this.$d.getTime() / 1000) case 'x': return this.$d.getTime() + case 'z': + return `[${this.offsetName()}]` + case 'zzz': + return `[${this.offsetName('long')}]` default: return match } diff --git a/src/plugin/duration/index.js b/src/plugin/duration/index.js index 533cd8d7..1c07b160 100644 --- a/src/plugin/duration/index.js +++ b/src/plugin/duration/index.js @@ -60,7 +60,7 @@ class Duration { calMilliseconds() { this.$ms = Object.keys(this.$d).reduce((total, unit) => ( - total + ((this.$d[unit] || 0) * (unitToMS[unit] || 1)) + total + ((this.$d[unit] || 0) * (unitToMS[unit])) ), 0) } @@ -106,7 +106,7 @@ class Duration { } as(unit) { - return this.$ms / (unitToMS[prettyUnit(unit)] || 1) + return this.$ms / (unitToMS[prettyUnit(unit)]) } get(unit) { diff --git a/src/plugin/timezone/index.js b/src/plugin/timezone/index.js index 6746356b..c2caafb5 100644 --- a/src/plugin/timezone/index.js +++ b/src/plugin/timezone/index.js @@ -13,7 +13,8 @@ export default (o, c, d) => { let defaultTimezone const localUtcOffset = d().utcOffset() - const tzOffset = (timestamp, timezone) => { + + const makeFormatParts = (timestamp, timezone, option = {}) => { const date = new Date(timestamp) const dtf = new Intl.DateTimeFormat('en-US', { hour12: false, @@ -23,9 +24,14 @@ export default (o, c, d) => { day: '2-digit', hour: '2-digit', minute: '2-digit', - second: '2-digit' + second: '2-digit', + timeZoneName: option.timeZoneName || 'short' }) - const formatResult = dtf.formatToParts(date) + return dtf.formatToParts(date) + } + + const tzOffset = (timestamp, timezone) => { + const formatResult = makeFormatParts(timestamp, timezone) const filled = [] for (let i = 0; i < formatResult.length; i += 1) { const { type, value } = formatResult[i] @@ -35,13 +41,14 @@ export default (o, c, d) => { filled[pos] = parseInt(value, 10) } } + const hour = filled[3] // Workaround for the same behavior in different node version // https://github.com/nodejs/node/issues/33027 - const hour = filled[3] + /* istanbul ignore next */ const fixedHour = hour === 24 ? 0 : hour const utcString = `${filled[0]}-${filled[1]}-${filled[2]} ${fixedHour}:${filled[4]}:${filled[5]}:000` const utcTs = d.utc(utcString).valueOf() - let asTS = +date + let asTS = +timestamp const over = asTS % 1000 asTS -= over return (utcTs - asTS) / (60 * 1000) @@ -76,7 +83,16 @@ export default (o, c, d) => { proto.tz = function (timezone = defaultTimezone) { const target = this.toDate().toLocaleString('en-US', { timeZone: timezone }) const diff = Math.round((this.toDate() - new Date(target)) / 1000 / 60) - return d(target).utcOffset(localUtcOffset - diff, true).$set(ms, this.$ms) + const ins = d(target).utcOffset(localUtcOffset - diff, true).$set(ms, this.$ms) + ins.$x.$timezone = timezone + return ins + } + + proto.offsetName = function (type) { + // type: short(default) / long + const zone = this.$x.$timezone || d.tz.guess() + const result = makeFormatParts(this.valueOf(), zone, { timeZoneName: type }).find(m => m.type.toLowerCase() === 'timezonename') + return result && result.value } d.tz = function (input, timezone = defaultTimezone) { @@ -89,6 +105,7 @@ export default (o, c, d) => { localTs = localTs || d.utc(input).valueOf() const [targetTs, targetOffset] = fixOffset(localTs, previousOffset, timezone) const ins = d(targetTs).utcOffset(targetOffset) + ins.$x.$timezone = timezone return ins } diff --git a/test/plugin/advancedFormat.test.js b/test/plugin/advancedFormat.test.js index e3ccaddc..5ff743fe 100644 --- a/test/plugin/advancedFormat.test.js +++ b/test/plugin/advancedFormat.test.js @@ -4,8 +4,12 @@ import dayjs from '../../src' import advancedFormat from '../../src/plugin/advancedFormat' import weekOfYear from '../../src/plugin/weekOfYear' import weekYear from '../../src/plugin/weekYear' +import timezone from '../../src/plugin/timezone' +import utc from '../../src/plugin/utc' import '../../src/locale/zh-cn' +dayjs.extend(utc) +dayjs.extend(timezone) dayjs.extend(weekYear) dayjs.extend(weekOfYear) dayjs.extend(advancedFormat) @@ -83,6 +87,14 @@ it('Format Week Year gggg', () => { expect(dayjs(d).format('gggg')).toBe(moment(d).format('gggg')) }) +it('Format offsetName z zzz', () => { + const dtz = dayjs.tz('2012-03-11 01:59:59', 'America/New_York') + expect(dtz.format('z')).toBe('EST') + expect(dtz.format('zzz')).toBe('Eastern Standard Time') + expect(dayjs().format('z')).toBeDefined() + expect(dayjs().format('zzz')).toBeDefined() +}) + it('Skips format strings inside brackets', () => { expect(dayjs().format('[Q]')).toBe('Q') expect(dayjs().format('[Do]')).toBe('Do') diff --git a/test/plugin/timezone.test.js b/test/plugin/timezone.test.js index 343bb626..da6c743f 100644 --- a/test/plugin/timezone.test.js +++ b/test/plugin/timezone.test.js @@ -252,3 +252,17 @@ describe('set Default', () => { expect(tokyo.valueOf()).toBe(1401591600000) }) }) + +describe('Get offsetName', () => { + const dtz = dayjs.tz('2012-03-11 01:59:59', NY) + it('short', () => { + const d = dtz.offsetName('short') + const m = moment.tz('2012-03-11 01:59:59', NY).format('z') + expect(d).toBe(m) + expect(d).toBe('EST') + }) + it('long', () => { + const d = dtz.offsetName('long') + expect(d).toBe('Eastern Standard Time') + }) +})