diff --git a/src/plugin/utc/index.js b/src/plugin/utc/index.js
--- a/src/plugin/utc/index.js
+++ b/src/plugin/utc/index.js
@@ -45,7 +45,7 @@ export default (option, Dayjs, dayjs) => {
   }
 
   const oldUtcOffset = proto.utcOffset
-  proto.utcOffset = function (input) {
+  proto.utcOffset = function (input, keepLocalTime) {
     const { u } = this.$utils()
     if (u(input)) {
       if (this.$u) {
@@ -57,7 +57,12 @@ export default (option, Dayjs, dayjs) => {
       return oldUtcOffset.call(this)
     }
     const offset = Math.abs(input) <= 16 ? input * 60 : input
-    let ins
+    let ins = this
+    if (keepLocalTime) {
+      ins.$offset = offset
+      ins.$u = input === 0
+      return ins
+    }
     if (input !== 0) {
       ins = this.local().add(offset + localOffset, MIN)
       ins.$offset = offset
diff --git a/types/plugin/utc.d.ts b/types/plugin/utc.d.ts
--- a/types/plugin/utc.d.ts
+++ b/types/plugin/utc.d.ts
@@ -12,7 +12,7 @@ declare module 'dayjs' {
 
     isUTC(): boolean
 
-    utcOffset(offset: number): Dayjs
+    utcOffset(offset: number, keepLocalTime?: boolean): Dayjs
   }
 
   export function utc(config?: ConfigType, format?: string): Dayjs

diff --git a/test/plugin/utc-utcOffset.test.js b/test/plugin/utc-utcOffset.test.js
--- a/test/plugin/utc-utcOffset.test.js
+++ b/test/plugin/utc-utcOffset.test.js
@@ -58,6 +58,23 @@ it('utcOffset(0) enable utc mode', () => {
   expect(dayjs().utcOffset(0).isUTC()).toBeTruthy()
 })
 
+it('utcOffset keepLocalTime', () => {
+  const d = '2000-01-01T06:00:00Z'
+  expect(dayjs.utc(d).utcOffset(5, true).format())
+    .toBe(moment.utc(d).utcOffset(5, true).format())
+  expect(dayjs.utc(d).utcOffset(0, true).format())
+    .toBe(moment.utc(d).utcOffset(0, true).format())
+  expect(dayjs.utc(d).utcOffset(-5, true).format())
+    .toBe(moment.utc(d).utcOffset(-5, true).format())
+  const d2 = '2016-01-01 00:00:00'
+  expect(dayjs(d2).utcOffset(0, true).format())
+    .toBe(moment(d2).utcOffset(0, true).format())
+  expect(dayjs(d2).utcOffset(-5, true).format())
+    .toBe(moment(d2).utcOffset(-5, true).format())
+  expect(dayjs(d2).utcOffset(5, true).format())
+    .toBe(moment(d2).utcOffset(5, true).format())
+})
+
 test('UTC mode', () => {
   const d = dayjs.utc('2000-01-01T06:00:00Z')
   expect(d.isUTC()).toBeTruthy()

How to keep the existing time of day when using utcOffset() for creating moments in time
From https://momentjs.com/docs/#/manipulating/utc-offset/ :

> The utcOffset function has an optional second parameter which accepts a boolean value indicating whether to keep the existing time of day.
> One use of this feature is if you want to construct a moment with a specific time zone offset using only numeric input values:
```javascript
moment([2016, 0, 1, 0, 0, 0]).utcOffset(-5, true)   // Equivalent to "2016-01-01T00:00:00-05:00"
```

I use this feature a lot for defining specific moments in time. How would I do this with dayjs? As far as i know there is no second boolean argument to `dayjs.utcOffset()`, at least not according to the docs https://day.js.org/docs/en/manipulate/utc-offset .

**Information**
 - Day.js Version: 1.8.28
 - OS: Windows 8.1
 - Time zone: CEST (Berlin)


What this used for? Any demo code, please?
In my case, it is for unit testing, when I want to make sure that any string parsing is removed from the equation, e.g.:
```typescript
import moment, { Moment } from "moment"

function createMoment(year: number, month: number, day: number, hour: number, minute: number, second: number, millis: number, utcOffset: number): Moment {
    return moment([year,month-1,day,hour,minute,second,millis]).utcOffset(utcOffset, true)
}

describe("stringify", () => {
    it("produces correct ISO8601 timestamp strings", () => {
        const testMoment = createMoment(2019,11,26,17,28,35,518,+3)
        const expectedJson: string = "\"2019-11-26T17:28:35.518+03:00\""
        // ###############
        const actualJson = JSON.stringify(testMoment)
        // ###############
        expect(actualJson).toEqual(expectedJson)
    })
})
```

Also, I want to abstract over the used date library (momentjs, dayjs, etc.) in my code by means of introducing a `MTimestamp`module, so I have tests like this:
```typescript
import { MTimestamp } from "../../../../App/services/util/timestamp"

describe("parseISO8601 with isValid", () => {
    const testTimestamp = MTimestamp.create(2019,11,26,17,28,35,518,+3)

    it.each([
            ["2019-11-26T17:28:35.5185231+03:00"],
            ["2019-11-26T17:28:35.518+03:00"],
            ["2019-11-26T14:28:35.518+00:00"],
            ["2019-11-26T14:28:35.518Z"],
        ])("parses valid timestamp string", (dateString: string) => {
        const expectedUnixMillis = testTimestamp.valueOf()
        // ###############
        const actualTimestamp = MTimestamp.parseISO8601(dateString)
        const actualUnixMillies = actualTimestamp.valueOf()
        // ###############
        expect(MTimestamp.isValid(actualTimestamp)).toBe(true)
        expect(actualUnixMillies).toEqual(expectedUnixMillis)
    })

    it.each([
            ["gadk"],
            ["2019-2-26T17:28:35.518+03:00"],
            ["19-11-26T17:28:35.518+03:00"],
            ["2019-11-26T17-28-35.518+03:00"],
        ])("detects invalid timestamp string", (dateString: string) => {
        // ###############
        const actualTimestamp = MTimestamp.parseISO8601(dateString)
        // ###############
        expect(MTimestamp.isValid(actualTimestamp)).toBe(false)
    })

})

describe("toISO8601String", () => {
    const testTimestamp = MTimestamp.create(2019,11,26,17,28,35,518,+3)

    it("preserves timezone information", () =>{
        const expectedString = "2019-11-26T17:28:35.518+03:00"
        // ###############
        const actualString = MTimestamp.toISO8601String(testTimestamp)
        // ###############
        expect(actualString).toEqual(expectedString)
    })
})
```
where `MTimestamp.create` internally uses `utcOffset`.
I have tests like these, so that I can switch third party libraries easily (if necessary) and still make sure that the API contracts are met.
Still a little confused. What's the difference in format result between the second parameter true or false?
The difference is what user `abrwn` also describes in #937. With `true` the offset is simply set/overwritten, with `false` the time is converted to said offset.

Quoting the moment.js documentation:

> - Passing false (the default) will keep the same instant in Universal Time, but the local time will change.
> - Passing true will keep the same local time, but at the expense of choosing a different point in Universal Time.

Example:
```typescript
console.log(moment([2019,11-1,26,17,28,35,518]).utcOffset(+3, true))
// output:    Moment<2019-11-26T17:28:35+03:00>

console.log(moment([2019,11-1,26,17,28,35,518]).utcOffset(+3, false))
// output:    Moment<2019-11-26T19:28:35+03:00>
```
Note: I have CEST (GMT+02).
test/timezone.test.js(1) test/timezone.test.js(2) test/timezone.test.js(3) test/timezone.test.js(4)
test/plugin/utc-utcOffset.test.js