如何覆盖内置类型

By default time.Duration prints it in the format 2h0m0s etc.

However, I want to print it as 2 Hours or 2 Hours 1 Min

One way, I can do that is to create a new struct TimeDurationStruct and create a String() function. I have done the same in golang playground

Working Code

package main

import (
    "fmt"
    "time"
    "math"
)

type TimeDurationStruct struct {
    t time.Duration
}

func (i *TimeDurationStruct) Set(t time.Duration) {
    i.t = t
}

func (i TimeDurationStruct) String() string {
    duration := i.t

    var dayString, hourMinString string
    var days, hours float64

    totalHours := duration.Hours()
    minutes := math.Mod(duration.Minutes(), 60.0)
    if totalHours < 24.0 {
        hours = totalHours
    } else {
        hours = math.Mod(totalHours, 24.0)
        days = totalHours / 24.0
    }

    if hours == 0 {

    } else if hours < 1 {
        if minutes == 1 {
            hourMinString = "1 Min"
        } else {
            hourMinString = fmt.Sprintf("%g Mins", minutes)
        }
    } else if hours >= 1 && hours < 2 {
        if minutes == 0 {
            hourMinString = "1 Hour"
        } else if minutes == 1 {
            hourMinString = "1 Hour 1 Min"
        } else {
            hourMinString = fmt.Sprintf("1 Hour %g Mins", minutes)
        }
    } else {
        if minutes == 0 {
            hourMinString = fmt.Sprintf("%g Hours", hours)
        } else if minutes == 1 {
            hourMinString = fmt.Sprintf("%g Hours 1 Min", hours)
        } else {
            hourMinString = fmt.Sprintf("%g Hours %g Mins", hours, minutes)
        }
    }

    if days > 0 {
        if days == 1 {
            dayString = "1 Day"
        } else {
            dayString = fmt.Sprintf("%g Days ", days)
        }
    }

    return dayString + hourMinString
}

func main() {
    t := time.Now()
    d := t.Add(2 * time.Hour).Sub(t)
    fmt.Println(d)
    var i TimeDurationStruct
    i.Set(d)
    fmt.Println(i)
}

Questions

  1. Instead of a structure type, is it possible to override time.Duration type. E.g

    type TimeDurationStruct time.Duration
    

    I tried it here, but it does not work...

  2. Is there a better/easier way ?

Following on from your question edit, yes you can achieve this effect without a struct. The problem is that when you define your type with:

type TimeDurationStruct time.Duration

your new TimeDurationStruct type will not inherit any of the methods from time.Duration like you had when you used the type embedding option. You can still access those methods, but you will need to perform a type cast. So the start of your String method should be modified to read something like:

func (i TimeDurationStruct) String() string {
    duration := time.Duration(i)
    ...