Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update timezone plugin to support getting offset name e.g. EST #1069

Merged
merged 2 commits into from
Sep 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/plugin/advancedFormat/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions src/plugin/duration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down Expand Up @@ -106,7 +106,7 @@ class Duration {
}

as(unit) {
return this.$ms / (unitToMS[prettyUnit(unit)] || 1)
return this.$ms / (unitToMS[prettyUnit(unit)])
}

get(unit) {
Expand Down
29 changes: 23 additions & 6 deletions src/plugin/timezone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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]
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand All @@ -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
}

Expand Down
12 changes: 12 additions & 0 deletions test/plugin/advancedFormat.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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')
Expand Down
14 changes: 14 additions & 0 deletions test/plugin/timezone.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
})
})