fix: update timezone plugin to support keepLocalTime
fix #1149
Here is a code sample from Moment's timezone. I would like to achieve the `true` flag so only the offset changes when time stays the same.
```
var m = moment.tz("2013-11-18 11:55", "America/Toronto");
m.format();                           // 2013-11-18T11:55:00-05:00
m.tz('Europe/Berlin', true).format()  // 2013-11-18T11:55:00+01:00
```

The use case would be:

I have something like an open hour: `08:00` to `16:00`, and want to set that as `America/New_York`, i.e. `8:00 AM EDT` to `16:00PM EDT`.

Current behavior:

```
dayjs("08:00", "hh:mm").tz('America/New_York') => 2020-10-19T11:00:00-04:00 (depending on current timezone, in this case, America/Los_Angeles)
```

Desired behavior:
```
dayjs("08:00", "hh:mm").tz('America/New_York', true) => 2020-10-19T08:00:00-04:00
```


Only changing the timezone (similar to moment.tz(keeptime=true))
diff --git a/src/plugin/timezone/index.js b/src/plugin/timezone/index.js
index 3fe1bad07..06dd27c1f 100644
--- a/src/plugin/timezone/index.js
+++ b/src/plugin/timezone/index.js
@@ -1,3 +1,5 @@
+import { MIN, MS } from '../../constant'
+
 const typeToPos = {
   year: 0,
   month: 1,
@@ -7,8 +9,6 @@ const typeToPos = {
   second: 5
 }
 
-const ms = 'ms'
-
 // Cache time-zone lookups from Intl.DateTimeFormat,
 // as it is a *very* slow method.
 const dtfCache = {}
@@ -94,10 +94,15 @@ export default (o, c, d) => {
 
   const proto = c.prototype
 
-  proto.tz = function (timezone = defaultTimezone) {
+  proto.tz = function (timezone = defaultTimezone, keepLocalTime) {
+    const oldOffset = this.utcOffset()
     const target = this.toDate().toLocaleString('en-US', { timeZone: timezone })
     const diff = Math.round((this.toDate() - new Date(target)) / 1000 / 60)
-    const ins = d(target).$set(ms, this.$ms).utcOffset(localUtcOffset - diff, true)
+    let ins = d(target).$set(MS, this.$ms).utcOffset(localUtcOffset - diff, true)
+    if (keepLocalTime) {
+      const newOffset = ins.utcOffset()
+      ins = ins.add(oldOffset - newOffset, MIN)
+    }
     ins.$x.$timezone = timezone
     return ins
   }
diff --git a/types/plugin/timezone.d.ts b/types/plugin/timezone.d.ts
index 558558562..491f87465 100644
--- a/types/plugin/timezone.d.ts
+++ b/types/plugin/timezone.d.ts
@@ -5,7 +5,7 @@ export = plugin
 
 declare module 'dayjs' {
   interface Dayjs {
-    tz(timezone?: string): Dayjs
+    tz(timezone?: string, keepLocalTime?: boolean): Dayjs
   }
 
   interface DayjsTimezone {

diff --git a/test/plugin/timezone.test.js b/test/plugin/timezone.test.js
index e9fb71f45..1f733baf6 100644
--- a/test/plugin/timezone.test.js
+++ b/test/plugin/timezone.test.js
@@ -1,8 +1,8 @@
 import MockDate from 'mockdate'
 import moment from 'moment-timezone'
 import dayjs from '../../src'
-import utc from '../../src/plugin/utc'
 import timezone from '../../src/plugin/timezone'
+import utc from '../../src/plugin/utc'
 
 dayjs.extend(utc)
 dayjs.extend(timezone)
@@ -260,6 +260,14 @@ describe('set Default', () => {
   })
 })
 
+describe('keepLocalTime', () => {
+  const base = dayjs.tz('2013-11-18 11:55', 'America/Toronto')
+  it('keepLocalTime', () => {
+    expect(base.tz('Europe/Berlin').format()).toBe('2013-11-18T17:55:00+01:00')
+    expect(base.tz('Europe/Berlin', true).format()).toBe('2013-11-18T11:55:00+01:00')
+  })
+})
+
 describe('Get offsetName', () => {
   const dtz = dayjs.tz('2012-03-11 01:59:59', NY)
   it('short', () => {

{"test/plugin/timezone.test.js": {"run": "PASS", "test": "FAIL", "fix": "PASS"}}
{"test/timezone.test.js:Add Time days (DST)": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/de.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/sk.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/advancedFormat.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/weekYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/timezone.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isSameOrBefore.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/pluralGetSet.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/timezone.test.js:Diff (DST)": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/keys.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/utils.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/relativeTime.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/parse.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/localizedFormat.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/updateLocale.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/constructor.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/weekday.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isLeapYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/query.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/localeData.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/zh.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/declarations.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/ru.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/dayOfYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/timezone.test.js:UTC add day in DST": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/manipulate.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/cs.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/en.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/get-set.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/utc.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/quarterOfYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/objectSupport.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/fi.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/sv.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/toArray.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/timezone.test.js:Utc Offset": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/utc-utcOffset.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/sr-cyrl.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/br.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isMoment.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isYesterday.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/pl.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/toObject.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/sr.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isSameOrAfter.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/weekOfYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/comparison.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/et.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isTomorrow.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/calendar.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/timezone.test.js:UTC and utcOffset": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/arraySupport.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isToday.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/hr.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/badMutable.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/customParseFormat.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/duration.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isoWeek.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/minMax.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isoWeeksInYear.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/buddhistEra.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/uk.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/display.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/lt.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/locale/zh-cn.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "test/plugin/isBetween.test.js": {"run": "PASS", "test": "PASS", "fix": "PASS"}}
{"test/plugin/timezone.test.js": {"run": "PASS", "test": "FAIL", "fix": "PASS"}}
{"passed_count": 69, "failed_count": 0, "skipped_count": 0, "passed_tests": ["test/timezone.test.js:Add Time days (DST)", "test/get-set.test.js", "test/locale/de.test.js", "test/plugin.test.js", "test/plugin/utc.test.js", "test/plugin/quarterOfYear.test.js", "test/plugin/objectSupport.test.js", "test/locale/fi.test.js", "test/locale/sk.test.js", "test/locale/sv.test.js", "test/plugin/advancedFormat.test.js", "test/plugin/toArray.test.js", "test/plugin/weekYear.test.js", "test/timezone.test.js", "test/timezone.test.js:Utc Offset", "test/plugin/isSameOrBefore.test.js", "test/plugin/pluralGetSet.test.js", "test/timezone.test.js:Diff (DST)", "test/plugin/utc-utcOffset.test.js", "test/locale/sr-cyrl.test.js", "test/utils.test.js", "test/locale/br.test.js", "test/plugin/relativeTime.test.js", "test/parse.test.js", "test/locale/keys.test.js", "test/plugin/isMoment.test.js", "test/plugin/isYesterday.test.js", "test/locale/pl.test.js", "test/plugin/toObject.test.js", "test/locale/sr.test.js", "test/plugin/localizedFormat.test.js", "test/plugin/updateLocale.test.js", "test/constructor.test.js", "test/plugin/weekday.test.js", "test/plugin/isSameOrAfter.test.js", "test/plugin/weekOfYear.test.js", "test/plugin/isLeapYear.test.js", "test/comparison.test.js", "test/query.test.js", "test/plugin/localeData.test.js", "test/locale/et.test.js", "test/plugin/isTomorrow.test.js", "test/plugin/calendar.test.js", "test/timezone.test.js:UTC and utcOffset", "test/plugin/arraySupport.test.js", "test/locale/zh.test.js", "test/plugin/isToday.test.js", "test/plugin/declarations.test.js", "test/locale/hr.test.js", "test/plugin/timezone.test.js", "test/locale.test.js", "test/plugin/badMutable.test.js", "test/plugin/customParseFormat.test.js", "test/locale/ru.test.js", "test/plugin/duration.test.js", "test/plugin/isoWeek.test.js", "test/plugin/dayOfYear.test.js", "test/plugin/minMax.test.js", "test/plugin/isoWeeksInYear.test.js", "test/timezone.test.js:UTC add day in DST", "test/plugin/buddhistEra.test.js", "test/manipulate.test.js", "test/locale/cs.test.js", "test/locale/uk.test.js", "test/display.test.js", "test/locale/lt.test.js", "test/locale/zh-cn.test.js", "test/locale/en.test.js", "test/plugin/isBetween.test.js"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 68, "failed_count": 1, "skipped_count": 0, "passed_tests": ["test/timezone.test.js:Add Time days (DST)", "test/get-set.test.js", "test/locale/de.test.js", "test/plugin.test.js", "test/plugin/utc.test.js", "test/plugin/quarterOfYear.test.js", "test/plugin/objectSupport.test.js", "test/locale/fi.test.js", "test/locale/sk.test.js", "test/locale/sv.test.js", "test/plugin/advancedFormat.test.js", "test/plugin/weekYear.test.js", "test/plugin/toArray.test.js", "test/timezone.test.js", "test/timezone.test.js:Utc Offset", "test/plugin/isSameOrBefore.test.js", "test/plugin/pluralGetSet.test.js", "test/timezone.test.js:Diff (DST)", "test/plugin/utc-utcOffset.test.js", "test/locale/sr-cyrl.test.js", "test/utils.test.js", "test/locale/br.test.js", "test/plugin/relativeTime.test.js", "test/parse.test.js", "test/locale/keys.test.js", "test/plugin/isMoment.test.js", "test/plugin/isYesterday.test.js", "test/locale/pl.test.js", "test/plugin/toObject.test.js", "test/locale/sr.test.js", "test/plugin/localizedFormat.test.js", "test/plugin/updateLocale.test.js", "test/constructor.test.js", "test/plugin/weekday.test.js", "test/plugin/isSameOrAfter.test.js", "test/plugin/weekOfYear.test.js", "test/comparison.test.js", "test/plugin/isLeapYear.test.js", "test/query.test.js", "test/plugin/localeData.test.js", "test/plugin/isTomorrow.test.js", "test/plugin/calendar.test.js", "test/locale/et.test.js", "test/timezone.test.js:UTC and utcOffset", "test/plugin/arraySupport.test.js", "test/locale/zh.test.js", "test/plugin/isToday.test.js", "test/plugin/declarations.test.js", "test/locale/hr.test.js", "test/plugin/badMutable.test.js", "test/locale.test.js", "test/plugin/customParseFormat.test.js", "test/locale/ru.test.js", "test/plugin/duration.test.js", "test/plugin/isoWeek.test.js", "test/plugin/dayOfYear.test.js", "test/plugin/minMax.test.js", "test/plugin/isoWeeksInYear.test.js", "test/timezone.test.js:UTC add day in DST", "test/manipulate.test.js", "test/display.test.js", "test/locale/cs.test.js", "test/locale/uk.test.js", "test/plugin/buddhistEra.test.js", "test/locale/lt.test.js", "test/locale/zh-cn.test.js", "test/locale/en.test.js", "test/plugin/isBetween.test.js"], "failed_tests": ["test/plugin/timezone.test.js"], "skipped_tests": []}
{"passed_count": 69, "failed_count": 0, "skipped_count": 0, "passed_tests": ["test/timezone.test.js:Add Time days (DST)", "test/plugin.test.js", "test/get-set.test.js", "test/locale/de.test.js", "test/plugin/utc.test.js", "test/plugin/quarterOfYear.test.js", "test/plugin/objectSupport.test.js", "test/locale/fi.test.js", "test/locale/sk.test.js", "test/locale/sv.test.js", "test/plugin/advancedFormat.test.js", "test/plugin/weekYear.test.js", "test/plugin/toArray.test.js", "test/timezone.test.js", "test/timezone.test.js:Utc Offset", "test/plugin/isSameOrBefore.test.js", "test/plugin/pluralGetSet.test.js", "test/timezone.test.js:Diff (DST)", "test/plugin/utc-utcOffset.test.js", "test/locale/sr-cyrl.test.js", "test/utils.test.js", "test/locale/br.test.js", "test/plugin/relativeTime.test.js", "test/parse.test.js", "test/locale/keys.test.js", "test/plugin/isMoment.test.js", "test/plugin/isYesterday.test.js", "test/locale/pl.test.js", "test/plugin/toObject.test.js", "test/locale/sr.test.js", "test/plugin/localizedFormat.test.js", "test/plugin/updateLocale.test.js", "test/constructor.test.js", "test/plugin/weekday.test.js", "test/plugin/isSameOrAfter.test.js", "test/plugin/weekOfYear.test.js", "test/comparison.test.js", "test/plugin/isLeapYear.test.js", "test/query.test.js", "test/plugin/localeData.test.js", "test/plugin/isTomorrow.test.js", "test/plugin/calendar.test.js", "test/locale/et.test.js", "test/timezone.test.js:UTC and utcOffset", "test/plugin/arraySupport.test.js", "test/locale/zh.test.js", "test/plugin/isToday.test.js", "test/locale/hr.test.js", "test/plugin/declarations.test.js", "test/plugin/timezone.test.js", "test/locale.test.js", "test/plugin/badMutable.test.js", "test/plugin/customParseFormat.test.js", "test/locale/ru.test.js", "test/plugin/isoWeek.test.js", "test/plugin/duration.test.js", "test/plugin/minMax.test.js", "test/plugin/dayOfYear.test.js", "test/plugin/isoWeeksInYear.test.js", "test/timezone.test.js:UTC add day in DST", "test/manipulate.test.js", "test/plugin/buddhistEra.test.js", "test/locale/uk.test.js", "test/display.test.js", "test/locale/cs.test.js", "test/locale/lt.test.js", "test/locale/zh-cn.test.js", "test/locale/en.test.js", "test/plugin/isBetween.test.js"], "failed_tests": [], "skipped_tests": []}